From 3aca67bf85e575525eae5b36a391d269d9af46b3 Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Fri, 9 Aug 2024 08:39:40 -0500 Subject: [PATCH] run if statements --- kabel/opcodes.txt | 18 +++++++++++++ kabel/src/codegen.rs | 55 ++++++++++++++++++++++++++++++++++++++- kabel/src/debug.rs | 59 ++++++++++++++++++++++++++++++++++++++++++ kabel/src/opcodes.rs | 16 +++++++++++- kabel/src/parser.rs | 3 ++- kabel/src/vm.rs | 26 +++++++++++++++++++ kabel_test/src/main.rs | 18 ++++++++++--- 7 files changed, 189 insertions(+), 6 deletions(-) diff --git a/kabel/opcodes.txt b/kabel/opcodes.txt index b4e738d2978a7501008df8e890a0714268c6eb7c..05fa0a6378b382192099b261c09f00e2958b1af6 100644 --- a/kabel/opcodes.txt +++ b/kabel/opcodes.txt @@ -4,4 +4,22 @@ SUB ; 0x02 MUL ; 0x03 DIV ; 0x04 MOD ; 0x05 +BITAND ; 0x06 +BITXOR ; 0x07 +BITOR ; 0x08 +EQ ; 0x09 +NE ; 0x0A +GR ; 0x0B +GE ; 0x0C +LS ; 0x0D +LE ; 0x0E +OR ; 0x0F +AND ; 0x10 + +NOT ; 0x11 +NEG ; 0x12 + +JMP LOC ; 0x13 +IF_NE ELSE ; 0x14 + PRINT ; 0xFF diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index 7027e6ae754da260dcc0d4f87c20ae888dbdc2ae..6674af2fe2f0ade7a269cc239eb9856537890f55 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -1,4 +1,4 @@ -use crate::{codegen_binary, codegen_unary, opcodes::OpCode, parser::{BinOp, Lit, UnOp, AST}, vm::{Value, VM}}; +use crate::{codegen_binary, codegen_unary, opcodes::OpCode, parser::{ASTType, BinOp, Lit, UnOp, AST}, vm::{Value, VM}}; pub struct Codegen { pub vm: VM @@ -19,6 +19,12 @@ impl Codegen { self.visit(ast); } } + If(condition, block, else_expr) => { + self.visit_if(*condition, *block, *else_expr); + } + Block(stmts) => { + self.visit_block(stmts); + } // REMOVE LATER Print(ref expr) => { self.visit_print(&ast, *expr.clone()); @@ -35,6 +41,47 @@ impl Codegen { _ => {} } } + pub fn visit_if(&mut self, condition: AST, block: AST, else_expr: Option) { + self.visit(condition); + self.vm.chunk.push(OpCode::IF_NE.into()); + self.vm.chunk.push(0xFF); // placeholder + self.vm.chunk.push(0xFF); // placeholder + let start_jmp_loc = self.vm.chunk.len()-2; + self.visit(block); + if let Some(ast) = else_expr { + match ast.ast_type { + ASTType::If(_, _, _) => { + self.vm.chunk.push(OpCode::JMP.into()); + self.vm.chunk.push(0xFF); // placeholder + self.vm.chunk.push(0xFF); // placeholder + let end_jmp_loc = self.vm.chunk.len()-2; + + self.patch_jump(start_jmp_loc); + self.visit(ast); + self.patch_jump(end_jmp_loc); + } + ASTType::Block(_) => { + + self.vm.chunk.push(OpCode::JMP.into()); + self.vm.chunk.push(0xFF); // placeholder + self.vm.chunk.push(0xFF); // placeholder + + let end_jmp_loc = self.vm.chunk.len()-2; + self.patch_jump(start_jmp_loc); // jmp to else + self.visit(ast); + self.patch_jump(end_jmp_loc); // jmp to after else + } + _ => {} + } + } else { + self.patch_jump(start_jmp_loc); + } + } + pub fn visit_block(&mut self, stmts: Vec) { + for stmt in stmts { + self.visit(stmt); + } + } // REMOVE LATER pub fn visit_print(&mut self, ast: &AST, expr: AST) { self.visit(expr); @@ -90,4 +137,10 @@ impl Codegen { _ => {} } } + pub fn patch_jump(&mut self, loc: usize) { + let jump = self.vm.chunk.len() - loc - 2; + + self.vm.chunk[loc] = ((jump >> 8) & 0xFF) as u8; + self.vm.chunk[loc + 1] = (jump & 0xFF) as u8; + } } diff --git a/kabel/src/debug.rs b/kabel/src/debug.rs index 8fde8878d109ef44b8f2516668ff565b0fbb79b6..e8349a23bb5a8397f65fe9a7e22cbce3e60771f0 100644 --- a/kabel/src/debug.rs +++ b/kabel/src/debug.rs @@ -195,3 +195,62 @@ pub fn debug_ast(ast: AST, level: usize) -> String { } output } + +pub fn debug_bytecode(code: Vec) -> String { + use crate::opcodes::OpCode::*; + let mut ip = 0; + let mut output = "".to_string(); + while ip < code.len() { + match code[ip].into() { + CONSTANT => { + output += &ip.to_string(); + output += " CONSTANT "; + ip += 1; + output += &code[ip].to_string(); + output += "\n"; + } + ADD => { output += &ip.to_string(); output += " ADD\n" } + SUB => { output += &ip.to_string(); output += " SUB\n" } + MUL => { output += &ip.to_string(); output += " MUL\n" } + DIV => { output += &ip.to_string(); output += " DIV\n" } + MOD => { output += &ip.to_string(); output += " MOD\n" } + BITAND => { output += &ip.to_string(); output += " BITAND\n" } + BITXOR => { output += &ip.to_string(); output += " BITXOR\n" } + BITOR => { output += &ip.to_string(); output += " BITOR\n" } + EQ => { output += &ip.to_string(); output += " EQ\n" } + NE => { output += &ip.to_string(); output += " NE\n" } + GR => { output += &ip.to_string(); output += " GR\n" } + GE => { output += &ip.to_string(); output += " GE\n" } + LS => { output += &ip.to_string(); output += " LS\n" } + LE => { output += &ip.to_string(); output += " LE\n" } + OR => { output += &ip.to_string(); output += " OR\n" } + AND => { output += &ip.to_string(); output += " AND\n" } + NOT => { output += &ip.to_string(); output += " NOT\n" } + NEG => { output += &ip.to_string(); output += " NEG\n" } + JMP => { + output += &ip.to_string(); + output += " JMP "; + ip += 1; + let byte_one = (code[ip] as u16) << 8; + ip += 1; + let byte_two = code[ip] as u16; + output += &(byte_one | byte_two).to_string(); + output += "\n"; + } + IF_NE => { + output += &ip.to_string(); + output += " IF_NE "; + ip += 1; + let byte_one = (code[ip] as u16) << 8; + ip += 1; + let byte_two = code[ip] as u16; + output += &(byte_one | byte_two).to_string(); + output += "\n"; + } + PRINT => { output += &ip.to_string(); output += " PRINT\n" } + ERR => output += "ERR\n", + } + ip += 1; + } + output +} diff --git a/kabel/src/opcodes.rs b/kabel/src/opcodes.rs index b8d0c55f1e6ee78c66f2bc6d870b3e189f6f4ab7..ad547dfd93b35657ec73903ba1a2a135ab0a95e2 100644 --- a/kabel/src/opcodes.rs +++ b/kabel/src/opcodes.rs @@ -1,3 +1,5 @@ +#![allow(non_camel_case_types)] + pub enum OpCode { CONSTANT, @@ -20,6 +22,10 @@ pub enum OpCode { NOT, NEG, + + JMP, + IF_NE, + PRINT, ERR, } @@ -49,6 +55,10 @@ impl From for u8 { NOT => 0x11, NEG => 0x12, + + JMP => 0x13, + IF_NE => 0x14, + PRINT => 0xFE, ERR => 0xFF } @@ -79,7 +89,11 @@ impl From for OpCode { 0x11 => NOT, 0x12 => NEG, - 0x13 => PRINT, + + 0x13 => JMP, + 0x14 => IF_NE, + + 0xFE => PRINT, _ => ERR } } diff --git a/kabel/src/parser.rs b/kabel/src/parser.rs index dffb2588dfa1f38d67dc6ebceee72d9785fa9668..5305a165717666a98f83f9f9de83e22bcccab369 100644 --- a/kabel/src/parser.rs +++ b/kabel/src/parser.rs @@ -238,8 +238,9 @@ impl Parser { if let TokenType::RightParen = right_paren.token_type { let block = self.block()?; if self.current < self.input.len() { - let else_ident = self.read_token()?; + let else_ident = self.peek()?; if let TokenType::Else = else_ident.token_type { + self.read_token()?; if let TokenType::LeftBrace = self.peek()?.token_type { let else_block = self.block()?; return Ok(ast_from_token_ast!( diff --git a/kabel/src/vm.rs b/kabel/src/vm.rs index db5c1ec60a18e7cf39bcb7790c67795359b9f60a..62341098b2f92b3c34e23a4f23ba602181c6e7eb 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -229,6 +229,25 @@ impl VM { return Err(wrong_type!(self, "Cannot negate bools")) } } + // JMP + 0x13 => { + let loc = self.read_u16(); + self.ip += loc as usize; + } + // IF_NE + 0x14 => { + let condition = self.stack.pop().unwrap(); + if let Value::Bool(condition) = condition { + if !condition { + let loc = self.read_u16(); + self.ip += loc as usize; + } else { + self.read_u16(); + } + } else { + return Err(wrong_type!(self, "if must have condition of type boolean")) + } + } 0xFE => { // PRINT let value = self.stack.pop().unwrap(); @@ -249,6 +268,13 @@ impl VM { self.ip += 1; byte } + pub fn read_u16(&mut self) -> u16 { + let byte_one = (self.chunk[self.ip] as u16) << 0x08; + self.ip += 1; + let byte_two = self.chunk[self.ip] as u16; + self.ip += 1; + byte_one | byte_two + } pub fn find_line(&mut self) -> usize { // returns line # at ip let mut line_ip = 0; for (line, rep) in self.lines.clone() { diff --git a/kabel_test/src/main.rs b/kabel_test/src/main.rs index d9603948cfc2e49a405de5883cadd21abace9e58..d864c090f4c9e86c439e4b3339edd6bac9a0af95 100644 --- a/kabel_test/src/main.rs +++ b/kabel_test/src/main.rs @@ -1,13 +1,22 @@ //use std::{env, fs}; -use kabel::{debug::{debug_ast, debug_token_array}, run_codegen, run_lexer, run_parser, run_semantic_analysis}; +use kabel::{debug::{debug_ast, debug_bytecode, debug_token_array}, run_codegen, run_lexer, run_parser, run_semantic_analysis}; fn main() { /*let args: Vec = env::args().collect(); let program = fs::read_to_string(args[1].clone()).unwrap();*/ - let program = "print 4.1+5.3;".to_string(); + let program = +"if(true) { + print \"if\"; +} else if(true) { + print \"elseif\"; +} else { + print \"else\"; +} +print \"after\"; +".to_string(); let mut output = "".to_string(); @@ -34,7 +43,8 @@ fn main() { println!("{}", output); return; } - //output += &debug_ast(ast.clone(), 0); + output += &debug_ast(ast.clone(), 0); + output += "\n\n"; //output += &format!("{:#?}", ast); let analyzer = run_semantic_analysis(program.to_string(), ast.clone()); for error in analyzer.errors.clone() { @@ -45,6 +55,8 @@ fn main() { let codegen = run_codegen(program, ast); let mut vm = codegen.vm; + output += &debug_bytecode(vm.chunk.clone()); + output += "\n"; match vm.run(&mut output) { Ok(()) => {} Err(e) => output += &e.to_string(),