diff options
| -rw-r--r-- | src/compiler.rs | 8 | ||||
| -rw-r--r-- | src/error.rs | 5 | ||||
| -rw-r--r-- | src/vm.rs | 35 |
3 files changed, 45 insertions, 3 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index f691922..8275618 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -380,6 +380,14 @@ impl Compiler { self.assign(&name, block); } + (Token::If, _, _, _) => { + self.eat(); + self.expression(block); + let jump = block.add(Op::Illegal, self.line()); + self.scope(block); + block.patch(Op::JmpFalse(block.curr()), jump); + } + (Token::LeftBrace, _, _, _) => { self.scope(block); } diff --git a/src/error.rs b/src/error.rs index 22e0d1a..d79a5fb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,6 +7,8 @@ use crate::tokenizer::Token; pub enum ErrorKind { TypeError(Op, Vec<Value>), AssertFailed(Value, Value), + InvalidProgram, + SyntaxError(usize, Token), } @@ -33,6 +35,9 @@ impl fmt::Display for ErrorKind { ErrorKind::SyntaxError(line, token) => { write!(f, "Syntax error on line {} at token {:?}", line, token) } + ErrorKind::InvalidProgram => { + write!(f, "[!!!] Invalid program") + } } } } @@ -21,6 +21,8 @@ pub enum Value { #[derive(Debug, Clone, Copy)] pub enum Op { + Illegal, + Pop, Constant(Value), @@ -34,6 +36,9 @@ pub enum Op { Or, Not, + Jmp(usize), + JmpFalse(usize), + Equal, // == Less, // < Greater, // > @@ -69,7 +74,7 @@ impl Block { } pub fn add(&mut self, op: Op, token_position: usize) -> usize { - let len = self.ops.len(); + let len = self.curr(); if token_position != self.last_line_offset { self.line_offsets.insert(len, token_position); self.last_line_offset = token_position; @@ -79,12 +84,20 @@ impl Block { } pub fn add_from(&mut self, ops: &[Op], token_position: usize) -> usize { - let len = self.ops.len(); + let len = self.curr(); for op in ops { self.add(*op, token_position); } len } + + pub fn curr(&self) -> usize { + self.ops.len() + } + + pub fn patch(&mut self, op: Op, pos: usize) { + self.ops[pos] = op; + } } #[derive(Debug)] @@ -135,7 +148,7 @@ impl VM { } pub fn run(&mut self) -> Result<(), Error>{ - const PRINT_WHILE_RUNNING: bool = false; + const PRINT_WHILE_RUNNING: bool = true; const PRINT_BLOCK: bool = true; if PRINT_BLOCK { @@ -159,6 +172,10 @@ impl VM { let op = self.block.ops[self.ip]; match op { + Op::Illegal => { + error!(self, ErrorKind::InvalidProgram); + } + Op::Pop => { self.stack.pop(); } @@ -243,6 +260,18 @@ impl VM { } } + Op::Jmp(line) => { + self.ip = line; + continue; + } + + Op::JmpFalse(line) => { + if Some(Value::Bool(false)) == self.stack.pop() { + self.ip = line; + continue; + } + } + Op::AssertEqual => { let (a, b) = self.pop_twice(); if a != b { |
