diff options
| author | Edvard Thörnros <edvard.thornros@gmail.com> | 2021-02-01 20:57:55 +0100 |
|---|---|---|
| committer | Edvard Thörnros <edvard.thornros@gmail.com> | 2021-02-01 21:38:34 +0100 |
| commit | e86852857bc6f6ca1e1cd81db494071c5d9e3ff1 (patch) | |
| tree | 71f111699dd0d7526dbe5ee334c477db6e0362e0 /src | |
| parent | e9ce94d72e1e8e51b7843b414504a07e132813e1 (diff) | |
| parent | fd4868df1fd24c05bce5c92cf8289fa755f25875 (diff) | |
| download | sylt-e86852857bc6f6ca1e1cd81db494071c5d9e3ff1.tar.gz | |
Merge branch 'main' into vectors
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiler.rs | 85 | ||||
| -rw-r--r-- | src/lib.rs | 42 | ||||
| -rw-r--r-- | src/tokenizer.rs | 3 | ||||
| -rw-r--r-- | src/vm.rs | 138 |
4 files changed, 202 insertions, 66 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index 6c01ea3..9a1d1e5 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -674,9 +674,38 @@ impl Compiler { } } - fn assign(&mut self, name: &str, block: &mut Block) { + fn assign(&mut self, block: &mut Block) { + let name = match self.eat() { + Token::Identifier(name) => name, + _ => { + error!(self, format!("Expected identifier in assignment")); + return; + } + }; + + let op = match self.eat() { + Token::Equal => None, + + Token::PlusEqual => Some(Op::Add), + Token::MinusEqual => Some(Op::Sub), + Token::StarEqual => Some(Op::Mul), + Token::SlashEqual => Some(Op::Div), + + _ => { + error!(self, format!("Expected '=' in assignment")); + return; + } + }; + if let Some(var) = self.find_variable(&name) { - self.expression(block); + if let Some(op) = op { + block.add(Op::Copy, self.line()); + self.expression(block); + block.add(op, self.line()); + } else { + self.expression(block); + } + if var.upvalue { block.add(Op::AssignUpvalue(var.slot), self.line()); } else { @@ -901,14 +930,31 @@ impl Compiler { return Err(()); }; - if self.peek() == Token::Equal { - self.eat(); - self.expression(block); - block.add(Op::Set(field), self.line()); - return Ok(()); - } else { - block.add(Op::Get(field), self.line()); - } + let op = match self.peek() { + Token::Equal => { + self.eat(); + self.expression(block); + block.add(Op::Set(field), self.line()); + return Ok(()); + } + + Token::PlusEqual => Op::Add, + Token::MinusEqual => Op::Sub, + Token::StarEqual => Op::Mul, + Token::SlashEqual => Op::Div, + + _ => { + block.add(Op::Get(field), self.line()); + continue; + } + }; + block.add(Op::Copy, self.line()); + block.add(Op::Get(field.clone()), self.line()); + self.eat(); + self.expression(block); + block.add(op, self.line()); + block.add(Op::Set(field), self.line()); + return Ok(()); } Token::LeftParen => { self.call(block); @@ -936,6 +982,16 @@ impl Compiler { block.add(Op::Print, self.line()); } + (Token::Identifier(_), Token::Equal, ..) | + (Token::Identifier(_), Token::PlusEqual, ..) | + (Token::Identifier(_), Token::MinusEqual, ..) | + (Token::Identifier(_), Token::SlashEqual, ..) | + (Token::Identifier(_), Token::StarEqual, ..) + + => { + self.assign(block); + } + (Token::Identifier(_), Token::Dot, ..) => { let block_length = block.ops.len(); let token_length = self.curr; @@ -958,16 +1014,15 @@ impl Compiler { } } - (Token::Identifier(name), Token::ColonEqual, ..) => { + (Token::Yield, ..) => { self.eat(); - self.eat(); - self.definition_statement(&name, Type::UnknownType, block); + block.add(Op::Yield, self.line()); } - (Token::Identifier(name), Token::Equal, ..) => { + (Token::Identifier(name), Token::ColonEqual, ..) => { self.eat(); self.eat(); - self.assign(&name, block); + self.definition_statement(&name, Type::UnknownType, block); } (Token::Blob, Token::Identifier(_), ..) => { @@ -21,6 +21,22 @@ pub fn run_file(path: &Path, print: bool, functions: Vec<(String, RustFunction)> run(tokenizer::file_to_tokens(path), path, print, functions) } +pub fn compile_file(path: &Path, + print: bool, + functions: Vec<(String, RustFunction)> + ) -> Result<vm::VM, Vec<Error>> { + let tokens = tokenizer::file_to_tokens(path); + match compiler::compile("main", path, tokens, &functions) { + Ok(prog) => { + let mut vm = vm::VM::new().print_blocks(print).print_ops(print); + vm.typecheck(&prog)?; + vm.init(&prog); + Ok(vm) + } + Err(errors) => Err(errors), + } +} + pub fn run_string(s: &str, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec<Error>> { run(tokenizer::string_to_tokens(s), Path::new("builtin"), print, functions) } @@ -30,7 +46,8 @@ pub fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String Ok(prog) => { let mut vm = vm::VM::new().print_blocks(print).print_ops(print); vm.typecheck(&prog)?; - if let Err(e) = vm.run(&prog) { + vm.init(&prog); + if let Err(e) = vm.run() { Err(vec![e]) } else { Ok(()) @@ -316,6 +333,26 @@ a() <=> 4 test_file!(scoping, "tests/scoping.tdy"); test_file!(for_, "tests/for.tdy"); + + test_multiple!( + op_assign, + add: "a := 1\na += 1\na <=> 2", + sub: "a := 2\na -= 1\na <=> 1", + mul: "a := 2\na *= 2\na <=> 4", + div: "a := 2\na /= 2\na <=> 1", + cluster: " +blob A { a: int } +a := A() +a.a = 0 +a.a += 1 +a.a <=> 1 +a.a *= 2 +a.a <=> 2 +a.a /= 2 +a.a <=> 1 +a.a -= 1 +a.a <=> 0" + ); } #[derive(Clone)] @@ -523,6 +560,7 @@ pub enum Op { Pop, PopUpvalue, + Copy, Constant(Value), Tuple(usize), @@ -561,7 +599,9 @@ pub enum Op { Call(usize), Print, + Return, + Yield, } #[derive(Debug)] diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 7bd0849..28172a3 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -35,6 +35,9 @@ pub enum Token { #[token("print")] Print, + #[token("yield")] + Yield, + #[token("ret")] Ret, @@ -66,7 +66,9 @@ pub struct VM { } -enum OpResult { +#[derive(Eq, PartialEq)] +pub enum OpResult { + Yield, Continue, Done, } @@ -110,8 +112,15 @@ impl VM { Rc::new(RefCell::new(UpValue::new(slot)))) } + fn push(&mut self, value: Value) { + self.stack.push(value); + } + fn pop(&mut self) -> Value { - self.stack.pop().unwrap() + match self.stack.pop() { + Some(x) => x, + None => self.crash_and_burn(), + } } fn poppop(&mut self) -> (Value, Value) { @@ -143,6 +152,17 @@ impl VM { self.frame().block.borrow().ops[ip].clone() } + fn crash_and_burn(&self) -> ! { + println!("\n\n !!!POPPING EMPTY STACK - DUMPING EVERYTHING!!!\n"); + self.print_stack(); + println!("\n"); + self.frame().block.borrow().debug_print(); + println!(" ip: {}, line: {}\n", + self.frame().ip.blue(), + self.frame().block.borrow().line(self.frame().ip).blue()); + unreachable!(); + } + fn error(&self, kind: ErrorKind, message: Option<String>) -> Error { let frame = self.frames.last().unwrap(); Error { @@ -164,7 +184,7 @@ impl VM { } Op::Pop => { - self.stack.pop().unwrap(); + self.pop(); } Op::Tuple(size) => { @@ -173,11 +193,22 @@ impl VM { } Op::PopUpvalue => { - let value = self.stack.pop().unwrap(); + let value = self.pop(); let slot = self.stack.len(); self.drop_upvalue(slot, value); } + Op::Copy => { + let v = self.pop(); + self.push(v.clone()); + self.push(v); + } + + Op::Yield => { + self.frame_mut().ip += 1; + return Ok(OpResult::Yield); + } + Op::Constant(value) => { let offset = self.frame().stack_offset; let value = match value { @@ -200,7 +231,7 @@ impl VM { }, _ => value.clone(), }; - self.stack.push(value); + self.push(value); } Op::Index => { @@ -224,23 +255,23 @@ impl VM { } Op::Get(field) => { - let inst = self.stack.pop(); - if let Some(Value::BlobInstance(ty, values)) = inst { + let inst = self.pop(); + if let Value::BlobInstance(ty, values) = inst { let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; - self.stack.push(values.borrow()[slot].clone()); + self.push(values.borrow()[slot].clone()); } else { - error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst.unwrap()])); + error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); } } Op::Set(field) => { - let value = self.stack.pop().unwrap(); - let inst = self.stack.pop(); - if let Some(Value::BlobInstance(ty, values)) = inst { + let value = self.pop(); + let inst = self.pop(); + if let Value::BlobInstance(ty, values) = inst { let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; values.borrow_mut()[slot] = value; } else { - error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst.unwrap()])); + error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); } } @@ -272,17 +303,17 @@ impl VM { } Op::JmpFalse(line) => { - if matches!(self.stack.pop(), Some(Value::Bool(false))) { + if matches!(self.pop(), Value::Bool(false)) { self.frame_mut().ip = line; return Ok(OpResult::Continue); } } Op::Assert => { - if matches!(self.stack.pop(), Some(Value::Bool(false))) { + if matches!(self.pop(), Value::Bool(false)) { error!(self, ErrorKind::Assert); } - self.stack.push(Value::Bool(true)); + self.push(Value::Bool(true)); } Op::ReadUpvalue(slot) => { @@ -293,12 +324,12 @@ impl VM { } _ => unreachable!(), }; - self.stack.push(value); + self.push(value); } Op::AssignUpvalue(slot) => { let offset = self.frame().stack_offset; - let value = self.stack.pop().unwrap(); + let value = self.pop(); let slot = match &self.stack[offset] { Value::Function(ups, _) => Rc::clone(&ups[slot]), _ => unreachable!(), @@ -308,12 +339,12 @@ impl VM { Op::ReadLocal(slot) => { let slot = self.frame().stack_offset + slot; - self.stack.push(self.stack[slot].clone()); + self.push(self.stack[slot].clone()); } Op::AssignLocal(slot) => { let slot = self.frame().stack_offset + slot; - self.stack[slot] = self.stack.pop().unwrap(); + self.stack[slot] = self.pop(); } Op::Define(_) => {} @@ -329,8 +360,8 @@ impl VM { values.push(Value::Nil); } - self.stack.pop(); - self.stack.push(Value::BlobInstance(blob_id, Rc::new(RefCell::new(values)))); + self.pop(); + self.push(Value::BlobInstance(blob_id, Rc::new(RefCell::new(values)))); } Value::Function(_, block) => { let inner = block.borrow(); @@ -359,7 +390,7 @@ impl VM { Err(ek) => error!(self, ek, "Wrong arguments to external function".to_string()), }; self.stack.truncate(new_base); - self.stack.push(res); + self.push(res); } _ => { unreachable!() @@ -368,7 +399,7 @@ impl VM { } Op::Print => { - println!("PRINT: {:?}", self.stack.pop().unwrap()); + println!("PRINT: {:?}", self.pop()); } Op::Return => { @@ -376,7 +407,7 @@ impl VM { if self.frames.is_empty() { return Ok(OpResult::Done); } else { - self.stack[last.stack_offset] = self.stack.pop().unwrap(); + self.stack[last.stack_offset] = self.pop(); for slot in last.stack_offset+1..self.stack.len() { if self.upvalues.contains_key(&slot) { let value = self.stack[slot].clone(); @@ -408,20 +439,23 @@ impl VM { self.frame().block.borrow().ops[self.frame().ip]); } - pub fn run(&mut self, prog: &Prog) -> Result<(), Error>{ + pub fn init(&mut self, prog: &Prog) { let block = Rc::clone(&prog.blocks[0]); self.blobs = prog.blobs.clone(); self.extern_functions = prog.functions.clone(); self.stack.clear(); self.frames.clear(); - self.stack.push(Value::Function(Vec::new(), Rc::clone(&block))); + self.push(Value::Function(Vec::new(), Rc::clone(&block))); self.frames.push(Frame { stack_offset: 0, block, ip: 0 }); + } + + pub fn run(&mut self) -> Result<OpResult, Error> { if self.print_blocks { println!("\n [[{}]]\n", "RUNNING".red()); @@ -433,8 +467,9 @@ impl VM { self.print_stack() } - if matches!(self.eval_op(self.op())?, OpResult::Done) { - return Ok(()); + let op = self.eval_op(self.op())?; + if matches!(op, OpResult::Done | OpResult::Yield) { + return Ok(op); } } } @@ -445,10 +480,12 @@ impl VM { Op::Jmp(_line) => {} + Op::Yield => {} + Op::Constant(ref value) => { match value.clone() { Value::Function(_, block) => { - self.stack.push(Value::Function(Vec::new(), block.clone())); + self.push(Value::Function(Vec::new(), block.clone())); let mut types = Vec::new(); for (slot, is_up, ty) in block.borrow().ups.iter() { @@ -477,25 +514,26 @@ impl VM { }; }, _ => { - self.stack.push(value.clone()); + self.push(value.clone()); } } } Op::Get(field) => { - let inst = self.stack.pop(); - if let Some(Value::BlobInstance(ty, _)) = inst { + let inst = self.pop(); + if let Value::BlobInstance(ty, _) = inst { let value = self.blobs[ty].name_to_field.get(&field).unwrap().1.as_value(); - self.stack.push(value); + self.push(value); } else { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst.unwrap()])); + self.push(Value::Nil); + error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); } } Op::Set(field) => { - let value = self.stack.pop().unwrap(); - let inst = self.stack.pop().unwrap(); + let value = self.pop(); + let inst = self.pop(); + if let Value::BlobInstance(ty, _) = inst { let ty = &self.blobs[ty].name_to_field.get(&field).unwrap().1; if ty != &Type::from(&value) { @@ -507,17 +545,17 @@ impl VM { } Op::PopUpvalue => { - self.stack.pop().unwrap(); + self.pop(); } Op::ReadUpvalue(slot) => { let value = self.frame().block.borrow().ups[slot].2.as_value(); - self.stack.push(value); + self.push(value); } Op::AssignUpvalue(slot) => { let var = self.frame().block.borrow().ups[slot].2.clone(); - let up = self.stack.pop().unwrap().as_type(); + let up = self.pop().as_type(); if var != up { error!(self, ErrorKind::TypeError(op, vec![var, up]), "Incorrect type for upvalue.".to_string()); @@ -525,7 +563,7 @@ impl VM { } Op::Return => { - let a = self.stack.pop().unwrap(); + let a = self.pop(); let inner = self.frame().block.borrow(); let ret = inner.ret(); if a.as_type() != *ret { @@ -571,8 +609,8 @@ impl VM { values[*slot] = ty.as_value(); } - self.stack.pop(); - self.stack.push(Value::BlobInstance(blob_id, Rc::new(RefCell::new(values)))); + self.pop(); + self.push(Value::BlobInstance(blob_id, Rc::new(RefCell::new(values)))); } Value::Function(_, block) => { let inner = block.borrow(); @@ -603,12 +641,12 @@ impl VM { Ok(value) => value, Err(ek) => { self.stack.truncate(new_base); - self.stack.push(Value::Nil); + self.push(Value::Nil); error!(self, ek, "Wrong arguments to external function".to_string()) } }; self.stack.truncate(new_base); - self.stack.push(res); + self.push(res); } _ => { error!(self, @@ -637,9 +675,9 @@ impl VM { self.stack.clear(); self.frames.clear(); - self.stack.push(Value::Function(Vec::new(), Rc::clone(&block))); + self.push(Value::Function(Vec::new(), Rc::clone(&block))); for arg in block.borrow().args() { - self.stack.push(arg.as_value()); + self.push(arg.as_value()); } self.frames.push(Frame { @@ -670,8 +708,8 @@ impl VM { } if !self.stack.is_empty() { - let ident = self.stack.pop().unwrap().identity(); - self.stack.push(ident); + let ident = self.pop().identity(); + self.push(ident); } } errors |
