diff options
| -rw-r--r-- | src/compiler.rs | 55 | ||||
| -rw-r--r-- | src/lib.rs | 19 | ||||
| -rw-r--r-- | src/vm.rs | 91 |
3 files changed, 126 insertions, 39 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index d12ee4b..193d16c 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -117,6 +117,8 @@ pub(crate) struct Compiler { blobs: Vec<Blob>, functions: HashMap<String, (usize, RustFunction)>, + constants: Vec<Value>, + strings: Vec<String>, } macro_rules! push_frame { @@ -187,9 +189,32 @@ impl Compiler { blobs: Vec::new(), functions: HashMap::new(), + + constants: vec![Value::Nil], + strings: Vec::new(), } } + fn nil_value(&self) -> usize { + self.constants.iter() + .enumerate() + .find_map(|(i, x)| + match x { + Value::Nil => Some(i), + _ => None, + }).unwrap() + } + + fn add_constant(&mut self, value: Value) -> usize { + self.constants.push(value); + self.constants.len() - 1 + } + + fn intern_string(&mut self, string: String) -> usize { + self.strings.push(string); + self.strings.len() - 1 + } + fn frame(&self) -> &Frame { let last = self.frames.len() - 1; &self.frames[last] @@ -336,7 +361,8 @@ impl Compiler { Token::String(s) => { Value::String(Rc::from(s)) } _ => { error!(self, "Cannot parse value."); Value::Bool(false) } }; - add_op(self, block, Op::Constant(value)); + let constant = self.add_constant(value); + add_op(self, block, Op::Constant(constant)); } fn grouping_or_tuple(&mut self, block: &mut Block) { @@ -586,7 +612,7 @@ impl Compiler { Op::Pop | Op::PopUpvalue => {} Op::Return => { break; } , _ => { - add_op(self, &mut function_block, Op::Constant(Value::Nil)); + add_op(self, &mut function_block, Op::Constant(self.nil_value())); add_op(self, &mut function_block, Op::Return); break; } @@ -594,7 +620,7 @@ impl Compiler { } if function_block.ops.is_empty() { - add_op(self, &mut function_block, Op::Constant(Value::Nil)); + add_op(self, &mut function_block, Op::Constant(self.nil_value())); add_op(self, &mut function_block, Op::Return); } @@ -602,9 +628,9 @@ impl Compiler { let function_block = Rc::new(RefCell::new(function_block)); - let func = Op::Constant(Value::Function(Vec::new(), Rc::clone(&function_block))); + let constant = self.add_constant(Value::Function(Vec::new(), Rc::clone(&function_block))); self.blocks[block_id] = function_block; - add_op(self, block, func); + add_op(self, block, Op::Constant(constant)); } fn variable_expression(&mut self, block: &mut Block) { @@ -623,7 +649,8 @@ impl Compiler { Token::Dot => { self.eat(); if let Token::Identifier(field) = self.eat() { - add_op(self, block, Op::Get(String::from(field))); + let string = self.intern_string(String::from(field)); + add_op(self, block, Op::Get(string)); } else { error!(self, "Expected fieldname after '.'."); break; @@ -636,12 +663,14 @@ impl Compiler { } } } else if let Some(blob) = self.find_blob(&name) { - add_op(self, block, Op::Constant(Value::Blob(blob))); + let string = self.add_constant(Value::Blob(blob)); + add_op(self, block, Op::Constant(string)); if self.peek() == Token::LeftParen { self.call(block); } } else if let Some(slot) = self.find_extern_function(&name) { - add_op(self, block, Op::Constant(Value::ExternFunction(slot))); + let string = self.add_constant(Value::ExternFunction(slot)); + add_op(self, block, Op::Constant(string)); self.call(block); } else { error!(self, format!("Using undefined variable {}.", name)); @@ -675,7 +704,8 @@ impl Compiler { fn definition_statement(&mut self, name: &str, typ: Type, block: &mut Block) { let slot = self.define_variable(name, typ.clone(), block); self.expression(block); - add_op(self, block, Op::Define(typ)); + let constant = self.add_constant(Value::Ty(typ)); + add_op(self, block, Op::Define(constant)); if let Ok(slot) = slot { self.stack_mut()[slot].active = true; @@ -940,6 +970,7 @@ impl Compiler { return Err(()); }; + let field = self.intern_string(field); let op = match self.peek() { Token::Equal => { self.eat(); @@ -959,7 +990,7 @@ impl Compiler { } }; add_op(self, block, Op::Copy); - add_op(self, block, Op::Get(field.clone())); + add_op(self, block, Op::Get(field)); self.eat(); self.expression(block); add_op(self, block, op); @@ -1096,7 +1127,7 @@ impl Compiler { self.statement(&mut block); expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); } - add_op(self, &mut block, Op::Constant(Value::Nil)); + add_op(self, &mut block, Op::Constant(self.nil_value())); add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); @@ -1107,6 +1138,8 @@ impl Compiler { blocks: self.blocks.clone(), blobs: self.blobs.iter().map(|x| Rc::new(x.clone())).collect(), functions: functions.iter().map(|(_, f)| *f).collect(), + constants: self.constants.clone(), + strings: self.strings.clone(), }) } else { Err(self.errors.clone()) @@ -162,6 +162,7 @@ impl From<Type> for Value { #[derive(Clone)] pub enum Value { + Ty(Type), Blob(usize), BlobInstance(usize, Rc<RefCell<Vec<Value>>>), Tuple(Rc<Vec<Value>>), @@ -178,6 +179,7 @@ pub enum Value { impl Debug for Value { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Value::Ty(ty) => write!(fmt, "(type {:?})", ty), Value::Blob(i) => write!(fmt, "(blob {})", i), Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v), Value::Float(f) => write!(fmt, "(float {})", f), @@ -286,7 +288,7 @@ impl Blob { /// machine carries out when running the /// "byte-code". /// -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] pub enum Op { /// This instruction should never be run. /// Finding it in a program is a critical error. @@ -307,11 +309,11 @@ pub enum Op { /// /// {A, B} - Copy - {A, B, B} Copy, - /// Adds the given value to the top of the stack. + /// Adds the value indexed in the `constants-vector` to the top of the stack. /// Also links upvalues if the value is a function. /// /// {A} - Constant(B) - {A, B} - Constant(Value), + Constant(usize), /// Creates a new [Tuple] with the given size and place it on the top /// of the stack. /// @@ -326,15 +328,17 @@ pub enum Op { /// Looks up a field by the given name /// and replaces the parent with it. /// Currently only expects [Value::Blob]. + /// (name is looked up in the internal string-list) /// /// {O} - Get(F) - {O.F} - Get(String), + Get(usize), /// Looks up a field by the given name /// and replaces the current value in the object. /// Currently only expects [Value::Blob]. + /// (name is looked up in the internal string-list) /// /// {O} - Set(F) - {} - Set(String), + Set(usize), /// Adds the two top elements on the stack, /// using the function [op::add]. The result @@ -452,9 +456,10 @@ pub enum Op { /// makes sure the top value on the stack /// is of the given type, and is ment to signal /// that the "variable" is added. + /// (The type is looked up in the constants vector) /// /// Does not affect the stack. - Define(Type), + Define(usize), /// Calls "something" with the given number /// of arguments. The callable value is @@ -702,6 +707,8 @@ pub struct Prog { pub blocks: Vec<Rc<RefCell<Block>>>, pub blobs: Vec<Rc<Blob>>, pub functions: Vec<RustFunction>, + pub constants: Vec<Value>, + pub strings: Vec<String>, } #[cfg(test)] @@ -62,6 +62,8 @@ pub struct VM { frames: Vec<Frame>, blobs: Vec<Rc<Blob>>, + constants: Vec<Value>, + strings: Vec<String>, pub print_blocks: bool, pub print_ops: bool, @@ -96,7 +98,11 @@ impl VM { stack_len: 0, stack: unsafe { alloc(Layout::array::<Value>(10_000).unwrap()) as *mut Value }, //TODO fix max len frames: Vec::new(), + blobs: Vec::new(), + constants: Vec::new(), + strings: Vec::new(), + print_blocks: false, print_ops: false, @@ -171,9 +177,24 @@ impl VM { &mut self.frames[last] } + fn constant(&self, slot: usize) -> &Value { + &self.constants[slot] + } + + fn ty(&self, slot: usize) -> &Type { + match &self.constants[slot] { + Value::Ty(ty) => ty, + _ => self.crash_and_burn(), + } + } + + fn string(&self, slot: usize) -> &String { + &self.strings[slot] + } + fn op(&self) -> Op { let ip = self.frame().ip; - self.frame().block.borrow().ops[ip].clone() + self.frame().block.borrow().ops[ip] } /// Stop the program, violently @@ -236,7 +257,8 @@ impl VM { Op::Constant(value) => { let offset = self.frame().stack_offset; - let value = match value { + let constant = self.constant(value).clone(); + let value = match constant { Value::Function(_, block) => { let mut ups = Vec::new(); for (slot, is_up, _) in block.borrow().upvalues.iter() { @@ -254,7 +276,7 @@ impl VM { } Value::Function(ups, block) }, - _ => value.clone(), + value => value, }; self.push(value); } @@ -279,21 +301,23 @@ impl VM { Op::Get(field) => { let inst = self.pop(); + let field = self.string(field); if let Value::BlobInstance(ty, values) = inst { - let slot = self.blobs[ty].fields.get(&field).unwrap().0; + let slot = self.blobs[ty].fields.get(field).unwrap().0; self.push(values.borrow()[slot].clone()); } else { - error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); + error!(self, ErrorKind::RuntimeTypeError(op, vec![inst])); } } Op::Set(field) => { let (inst, value) = self.poppop(); + let field = self.string(field); if let Value::BlobInstance(ty, values) = inst { - let slot = self.blobs[ty].fields.get(&field).unwrap().0; + let slot = self.blobs[ty].fields.get(field).unwrap().0; values.borrow_mut()[slot] = value; } else { - error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); + error!(self, ErrorKind::RuntimeTypeError(op, vec![inst])); } } @@ -468,6 +492,9 @@ impl VM { pub(crate) fn init(&mut self, prog: &Prog) { let block = Rc::clone(&prog.blocks[0]); self.blobs = prog.blobs.clone(); + self.constants = prog.constants.clone(); + self.strings = prog.strings.clone(); + self.extern_functions = prog.functions.clone(); self.stack_len = 0; self.frames.clear(); @@ -509,8 +536,8 @@ impl VM { Op::Yield => {} - Op::Constant(ref value) => { - match value.clone() { + Op::Constant(value) => { + match self.constant(value).clone() { Value::Function(_, block) => { self.push(Value::Function(Vec::new(), block.clone())); @@ -533,14 +560,14 @@ impl VM { } else { if ty != suggestion { error!(self, - ErrorKind::TypeError(op.clone(), + ErrorKind::TypeError(op, vec![ty.clone(), suggestion.clone()]), "Failed to infer type.".to_string()); } } }; }, - _ => { + value => { self.push(value.clone()); } } @@ -548,26 +575,27 @@ impl VM { Op::Get(field) => { let inst = self.pop(); + let field = self.string(field); if let Value::BlobInstance(ty, _) = inst { - let value = Value::from(&self.blobs[ty].fields.get(&field).unwrap().1); + let value = Value::from(&self.blobs[ty].fields.get(field).unwrap().1); self.push(value); } else { self.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); + error!(self, ErrorKind::RuntimeTypeError(op, vec![inst])); } } Op::Set(field) => { - let value = self.pop(); - let inst = self.pop(); + let (inst, value) = self.poppop(); + let field = self.string(field); if let Value::BlobInstance(ty, _) = inst { - let ty = &self.blobs[ty].fields.get(&field).unwrap().1; + let ty = &self.blobs[ty].fields.get(field).unwrap().1; if ty != &Type::from(&value) { - error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst])); + error!(self, ErrorKind::RuntimeTypeError(op, vec![inst])); } } else { - error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst])); + error!(self, ErrorKind::RuntimeTypeError(op, vec![inst])); } } @@ -604,7 +632,23 @@ impl VM { self.pop(); } - Op::Define(_) => {} + Op::Define(ty) => { + let ty = self.ty(ty); + let top_type = self.stack.last().unwrap().into(); + match (ty, top_type) { + (Type::Unknown, top_type) + if top_type != Type::Unknown => {} + (a, b) if a != &b => { + error!(self, + ErrorKind::TypeError( + op, + vec![a.clone(), b.clone()]), + format!("Tried to assign a type {:?} to type {:?}.", a, b) + ); + } + _ => {} + } + } Op::Call(num_args) => { let new_base = self.stack_len - 1 - num_args; @@ -639,7 +683,7 @@ impl VM { let stack_args: Vec<_> = stack_args.iter().map(|x| x.into()).collect(); if args != &stack_args { error!(self, - ErrorKind::TypeError(op.clone(), vec![]), + ErrorKind::TypeError(op, vec![]), format!("Expected args of type {:?} but got {:?}.", args, stack_args)); } @@ -664,7 +708,7 @@ impl VM { } _ => { error!(self, - ErrorKind::TypeError(op.clone(), vec![Type::from(self.get(new_base))]), + ErrorKind::TypeError(op, vec![Type::from(self.get(new_base))]), format!("Tried to call non-function {:?}", self.get(new_base))); } } @@ -673,7 +717,7 @@ impl VM { Op::JmpFalse(_) => { match self.pop() { Value::Bool(_) => {}, - a => { error!(self, ErrorKind::TypeError(op.clone(), vec![a.into()])) }, + a => { error!(self, ErrorKind::TypeError(op, vec![a.into()])) }, } } _ => { @@ -734,6 +778,9 @@ impl VM { let mut errors = Vec::new(); self.blobs = prog.blobs.clone(); + self.constants = prog.constants.clone(); + self.strings = prog.strings.clone(); + self.extern_functions = prog.functions.clone(); for block in prog.blocks.iter() { errors.append(&mut self.typecheck_block(Rc::clone(block))); |
