M kabel/opcodes.txt => kabel/opcodes.txt +2 -1
@@ 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
M kabel/src/codegen.rs => kabel/src/codegen.rs +29 -1
@@ 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<AST>) {
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;
M kabel/src/debug.rs => kabel/src/debug.rs +14 -2
@@ 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;
M kabel/src/main.rs => kabel/src/main.rs +7 -7
@@ 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) {
M kabel/src/opcodes.rs => kabel/src/opcodes.rs +7 -5
@@ 27,7 27,8 @@ pub enum OpCode {
NEG,
JMP,
- IF_NE,
+ JMP_UP,
+ JNE,
POP,
PRINT,
@@ 63,7 64,8 @@ impl From<OpCode> for u8 {
NEG => 0x14,
JMP => 0x15,
- IF_NE => 0x16,
+ JMP_UP => 0x16,
+ JNE => 0x17,
POP => 0xFD,
PRINT => 0xFE,
@@ 73,8 75,7 @@ impl From<OpCode> for u8 {
}
impl From<u8> 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<u8> for OpCode {
0x14 => NEG,
0x15 => JMP,
- 0x16 => IF_NE,
+ 0x16 => JMP_UP,
+ 0x17 => JNE,
0xFD => POP,
0xFE => PRINT,
M kabel/src/parser.rs => kabel/src/parser.rs +59 -34
@@ 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<AST>, expression2: Option<AST>, expression3: Option<AST>, 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<AST, KabelError> {
let break_ident = self.read_token()?;
M kabel/src/vm.rs => kabel/src/vm.rs +6 -1
@@ 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 {