From dda08ce1274a7ed016341a7586ceb8967a7db3cb Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Wed, 14 Aug 2024 22:33:08 -0500 Subject: [PATCH] for loop desugaring and loops in vm --- kabel/opcodes.txt | 3 +- kabel/src/codegen.rs | 30 +++++++++++++- kabel/src/debug.rs | 16 +++++++- kabel/src/main.rs | 14 +++---- kabel/src/opcodes.rs | 12 +++--- kabel/src/parser.rs | 93 ++++++++++++++++++++++++++++---------------- kabel/src/vm.rs | 7 +++- 7 files changed, 124 insertions(+), 51 deletions(-) diff --git a/kabel/opcodes.txt b/kabel/opcodes.txt index 52e942cfe82d198ede36d51937d1c06fce6aa102..dfaaee713d652403f802cb97dfd46dac6fbfa262 100644 --- a/kabel/opcodes.txt +++ b/kabel/opcodes.txt @@ -23,7 +23,8 @@ NOT ; 0x13 NEG ; 0x14 JMP LOC ; 0x15 -IF_NE ELSE ; 0x16 +JMP_UP LOC ; 0x16 +JNE ELSE ; 0x17 POP ; 0xFD PRINT ; 0xFE diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index b8241b4095f9057a0ed988d4e91f93a5a1ce35cf..057ffd4cf342e96ea8d98d23893a41b05e90ec32 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -21,6 +21,9 @@ impl Codegen { self.visit(ast); } } + While(condition, block) => { + self.visit_while(*condition, *block); + } If(condition, block, else_expr) => { self.visit_if(*condition, *block, *else_expr); } @@ -52,9 +55,34 @@ impl Codegen { _ => {} } } + pub fn visit_while(&mut self, condition: AST, block: AST) { + let end_jmp = self.vm.chunk.len(); + self.visit(condition.clone()); + self.vm.chunk.push(OpCode::JNE.into()); + self.vm.chunk.push(0xFF); // placeholder + self.vm.chunk.push(0xFF); // placeholder + let start_jmp_loc = self.vm.chunk.len()-2; + if self.vm.lines.last().unwrap().0 != condition.end_line { + self.vm.lines.push((condition.end_line, 3)); + } else { + self.vm.lines.last_mut().unwrap().1 += 3; + } + self.visit(block.clone()); + self.vm.chunk.push(OpCode::JMP_UP.into()); + let current = self.vm.chunk.len()+2; + let current_to_start = current - end_jmp; + self.vm.chunk.push(((current_to_start >> 8) & 0xFF) as u8); + self.vm.chunk.push((current_to_start & 0xFF) as u8); + if self.vm.lines.last().unwrap().0 != block.end_line { + self.vm.lines.push((block.end_line, 3)); + } else { + self.vm.lines.last_mut().unwrap().1 += 3; + } + self.patch_jump(start_jmp_loc); + } pub fn visit_if(&mut self, condition: AST, block: AST, else_expr: Option) { self.visit(condition.clone()); - self.vm.chunk.push(OpCode::IF_NE.into()); + self.vm.chunk.push(OpCode::JNE.into()); self.vm.chunk.push(0xFF); // placeholder self.vm.chunk.push(0xFF); // placeholder let start_jmp_loc = self.vm.chunk.len()-2; diff --git a/kabel/src/debug.rs b/kabel/src/debug.rs index 57edd16bfb8649f6771dcaad1b2cc021471f783a..481ef9bdb1117bcb3f84aa1e711f0fea611137bd 100644 --- a/kabel/src/debug.rs +++ b/kabel/src/debug.rs @@ -252,11 +252,23 @@ pub fn debug_bytecode(vm: &VM) -> String { output += &(byte_one | byte_two).to_string(); output += "\n"; } - IF_NE => { + JMP_UP => { output += &vm.ip.to_string(); output += " "; output += &vm.find_line().to_string(); - output += " IF_NE "; + output += " JMP_UP "; + vm.ip += 1; + let byte_one = (vm.chunk[vm.ip] as u16) << 8; + vm.ip += 1; + let byte_two = vm.chunk[vm.ip] as u16; + output += &(byte_one | byte_two).to_string(); + output += "\n"; + } + JNE => { + output += &vm.ip.to_string(); + output += " "; + output += &vm.find_line().to_string(); + output += " JNE "; vm.ip += 1; let byte_one = (vm.chunk[vm.ip] as u16) << 8; vm.ip += 1; diff --git a/kabel/src/main.rs b/kabel/src/main.rs index 7505556bc1399d606af411311682ca4a6073e940..7dbe4058ef88fb1545efcf072e7003485229ccd2 100644 --- a/kabel/src/main.rs +++ b/kabel/src/main.rs @@ -10,12 +10,13 @@ fn main() { fs::read_to_string(args[1].clone()).unwrap();*/ let program = -"var a = 2; -{ - var a = 3; - print a; +" +for(var i = 0; i < 5; i++) { + var j = 0; + print i; + print j; + j++; } -print a; ".to_string(); let mut output = "".to_string(); @@ -43,7 +44,7 @@ print a; println!("{}", output); return; } - //output += &debug_ast(ast.clone(), 0); + output += &debug_ast(ast.clone(), 0); output += "\n\n"; //output += &format!("{:#?}", ast); let (ast, analyzer) = run_semantic_analysis(program.to_string(), ast.clone()); @@ -63,7 +64,6 @@ print a; let mut vm = codegen.vm; output += &debug_bytecode(&vm); output += "\n"; - //output += &format!("{:?}", codegen.local); output += "\n"; match vm.run(&mut output) { diff --git a/kabel/src/opcodes.rs b/kabel/src/opcodes.rs index 1453d362c52d7866a734247634722de0d5f081a3..e4b74c37eec30db26e467bc9a1b6cda5ee8aa5be 100644 --- a/kabel/src/opcodes.rs +++ b/kabel/src/opcodes.rs @@ -27,7 +27,8 @@ pub enum OpCode { NEG, JMP, - IF_NE, + JMP_UP, + JNE, POP, PRINT, @@ -63,7 +64,8 @@ impl From for u8 { NEG => 0x14, JMP => 0x15, - IF_NE => 0x16, + JMP_UP => 0x16, + JNE => 0x17, POP => 0xFD, PRINT => 0xFE, @@ -73,8 +75,7 @@ impl From for u8 { } impl From for OpCode { fn from(value: u8) -> Self { - use OpCode::*; - match value { + use OpCode::*; match value { 0x00 => LOAD, 0x01 => VAR, 0x02 => ASSIGN, @@ -100,7 +101,8 @@ impl From for OpCode { 0x14 => NEG, 0x15 => JMP, - 0x16 => IF_NE, + 0x16 => JMP_UP, + 0x17 => JNE, 0xFD => POP, 0xFE => PRINT, diff --git a/kabel/src/parser.rs b/kabel/src/parser.rs index eda624974629f4bb30020ab7f23aa018b2fa8dfd..9448606cf2f0293f37250b0c46c745dcd81c3a93 100644 --- a/kabel/src/parser.rs +++ b/kabel/src/parser.rs @@ -167,50 +167,75 @@ impl Parser { if let TokenType::Semicolon = self.peek()?.token_type { expression1 = None; } else { - expression1 = Some(self.expression()?); - } - let semicolon = self.read_token()?; - if let TokenType::Semicolon = semicolon.token_type { - let expression2; - if let TokenType::Semicolon = self.peek()?.token_type { - expression2 = None; + if let TokenType::Var = self.peek()?.token_type { + expression1 = Some(self.declaration()?); } else { - expression2 = Some(self.expression()?); - } - let semicolon = self.read_token()?; - if let TokenType::Semicolon = semicolon.token_type { - let expression3; - if let TokenType::RightParen = self.peek()?.token_type { - expression3 = None; - } else { - expression3 = Some(self.expression()?); - } - let right_paren = self.read_token()?; - if let TokenType::RightParen = right_paren.token_type { - let block = self.block()?; - return Ok(ast_from_token_ast!( - ASTType::For( - Box::new(expression1), - Box::new(expression2), - Box::new(expression3), - Box::new(block.clone()) - ), - for_ident, - block - )); - } else { - return Err(unexpected_token!(self, "Expected ) found {}", right_paren)); + expression1 = Some(self.expression()?); + let semicolon = self.read_token()?; + if let TokenType::Semicolon = semicolon.token_type {} else { + self.current -= 1; + return Err(unexpected_token!(self, "Expected ; found {}", semicolon)); } + } + } + let expression2; + if let TokenType::Semicolon = self.peek()?.token_type { + expression2 = None; + } else { + expression2 = Some(self.expression()?); + } + let semicolon_2 = self.read_token()?; + if let TokenType::Semicolon = semicolon_2.token_type { + let expression3; + if let TokenType::RightParen = self.peek()?.token_type { + expression3 = None; } else { + expression3 = Some(self.expression()?); + } + let right_paren = self.read_token()?; + if let TokenType::RightParen = right_paren.token_type { + let block = self.block()?; + return Ok(Self::build_for(for_ident, semicolon_2, expression1, expression2, expression3, block)); + /*return Ok(ast_from_token_ast!( + ASTType::For( + Box::new(expression1), + Box::new(expression2), + Box::new(expression3), + Box::new(block.clone()) + ), + for_ident, + block + ));*/ } else { - return Err(unexpected_token!(self, "Expected ; found {}", semicolon)); + return Err(unexpected_token!(self, "Expected ) found {}", right_paren)); } } else { - return Err(unexpected_token!(self, "Expected ; found {}", semicolon)); + return Err(unexpected_token!(self, "Expected ; found {}", semicolon_2)); } } else { return Err(unexpected_token!(self, "Expected ( found {}", left_paren)); } } + fn build_for(for_ident: Token, semicolon_2: Token, expression1: Option, expression2: Option, expression3: Option, block: AST) -> AST { + let mut outer_block = Vec::new(); + if let Some(expression1) = expression1.clone() { + outer_block.push(expression1); + } + let mut new_block = block.clone(); + if let Some(expression3) = expression3 { + if let ASTType::Block(inner) = block.clone().ast_type { + let mut new_inner = inner; + new_inner.push(ast_from_ast!(ASTType::Expr(Box::new(expression3.clone())), expression3, expression3)); + new_block = ast_from_ast!(ASTType::Block(new_inner), block, block); + } + } + let condition = if let Some(expression2) = expression2 { + expression2 + } else { lit!(Bool, true, semicolon_2) }; + let while_ast = ast_from_ast!(ASTType::While(Box::new(condition.clone()), Box::new(new_block.clone())), condition, block); + outer_block.push(while_ast.clone()); + let outer_block = ast_from_token_ast!(ASTType::Block(outer_block), for_ident, new_block); + outer_block + } pub fn break_statement(&mut self) -> Result { let break_ident = self.read_token()?; diff --git a/kabel/src/vm.rs b/kabel/src/vm.rs index ef54c9a14b224af49c628d449fb8239e46d382ea..6537a9c815e292e47094fb9e787b564e3ba84c93 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -249,8 +249,13 @@ impl VM { let loc = self.read_u16(); self.ip += loc as usize; } - // IF_NE + // JMP_UP 0x16 => { + let loc = self.read_u16(); + self.ip -= loc as usize; + } + // JNE + 0x17 => { let condition = self.stack.pop().unwrap(); if let Value::Bool(condition) = condition { if !condition {