M kabel/src/codegen.rs => kabel/src/codegen.rs +81 -1
@@ 28,6 28,9 @@ impl Codegen {
While(condition, block) => {
self.visit_while(*condition, *block);
}
+ For(expr1, expr2, expr3, block) => {
+ self.visit_for(*expr1, *expr2, *expr3, *block);
+ }
Break => {
self.visit_break(&ast);
}
@@ 106,6 109,83 @@ impl Codegen {
self.vm.chunk[loc + 1] = (jump & 0xFF) as u8;
}
}
+ pub fn visit_for(&mut self, expr1: Option<AST>, expr2: Option<AST>,
+ expr3: Option<AST>, block: AST) {
+ self.scopes.push((ScopeType::Other, 0));
+
+ self.break_stack.push(Vec::new());
+ self.continue_stack.push(Vec::new());
+
+ if let Some(expr1) = expr1 {
+ self.visit(expr1);
+ }
+ let end_jmp = self.vm.chunk.len();
+ let mut start_jmp_loc = None;
+ if let Some(expr2) = expr2 {
+ self.visit(expr2.clone());
+ self.vm.chunk.push(OpCode::JNE.into());
+ self.vm.chunk.push(0xFF); // placeholder
+ self.vm.chunk.push(0xFF); // placeholder
+ start_jmp_loc = Some(self.vm.chunk.len()-2);
+ if self.vm.lines.last().unwrap().0 != expr2.end_line {
+ self.vm.lines.push((expr2.end_line, 3));
+ } else {
+ self.vm.lines.last_mut().unwrap().1 += 3;
+ }
+ }
+ if let ASTType::Block(ref stmts) = block.ast_type {
+ self.visit_block(&block, stmts.clone(), ScopeType::Loop);
+ }
+ let continues = self.continue_stack.pop().expect("continue stack empty on pop");
+ for loc in continues {
+ /*let jump = loc - end_jmp + 2;
+ self.vm.chunk[loc] = ((jump >> 8) & 0xFF) as u8;
+ self.vm.chunk[loc + 1] = (jump & 0xFF) as u8;*/
+ self.patch_jump(loc, 0);
+ }
+ if let Some(expr3) = expr3 {
+ self.visit(expr3);
+ self.vm.chunk.push(OpCode::POP.into());
+ self.vm.chunk.push(0x01);
+ if self.vm.lines.last().unwrap().0 != block.end_line {
+ self.vm.lines.push((block.end_line, 2));
+ } else {
+ self.vm.lines.last_mut().unwrap().1 += 2;
+ }
+ }
+
+ // write instruction to loop
+ 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;
+ }
+
+ let breaks = self.break_stack.pop().expect("break stack empty on pop");
+ for loc in breaks {
+ self.patch_jump(loc, 0);
+ }
+
+
+ if let Some(loc) = start_jmp_loc {
+ self.patch_jump(loc, 0);
+ }
+
+ let (_scope_type, variables) = self.scopes.pop().expect("popped scope in block");
+ self.vm.chunk.push(OpCode::POP.into());
+ self.vm.chunk.push(variables as u8);
+ if self.vm.lines.last().unwrap().0 != block.end_line {
+ self.vm.lines.push((block.end_line, 2));
+ } else {
+ self.vm.lines.last_mut().unwrap().1 += 2;
+ }
+
+ }
pub fn visit_break(&mut self, ast: &AST) {
let mut scopes = self.scopes.clone();
let mut pop_count = 0;
@@ 145,7 225,7 @@ impl Codegen {
self.vm.chunk.push(OpCode::POP.into());
self.vm.chunk.push(pop_count as u8);
- self.vm.chunk.push(OpCode::JMP_UP.into());
+ self.vm.chunk.push(OpCode::JMP.into());
self.vm.chunk.push(0xFF);
self.vm.chunk.push(0xFF);
if self.vm.lines.last().unwrap().0 != ast.end_line {
M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +11 -0
@@ 67,6 67,8 @@ impl Resolver {
Break => { ast_from_ast!(Break, ast, ast) }
Continue => { ast_from_ast!(Continue, ast, ast) }
For(expr1, expr2, expr3, block) => {
+ self.symbol_table.push(HashMap::new());
+ self.scope += 1;
let mut n_expr1 = None;
let mut n_expr2 = None;
let mut n_expr3 = None;
@@ 80,6 82,15 @@ impl Resolver {
n_expr3 = Some(self.visit(expr));
}
let block = self.visit(*block);
+ while let Some(scope) = self.locals.last() {
+ if self.scope == *scope {
+ self.locals.pop();
+ } else {
+ break;
+ }
+ }
+ self.scope -= 1;
+ self.symbol_table.pop();
ast_from_ast!(For(Box::new(n_expr1), Box::new(n_expr2), Box::new(n_expr3), Box::new(block)), ast, ast)
}
If(condition, block, else_expr) => {
M kabel/src/parser.rs => kabel/src/parser.rs +5 -5
@@ 194,8 194,8 @@ impl Parser {
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!(
+ //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),
@@ 204,7 204,7 @@ impl Parser {
),
for_ident,
block
- ));*/
+ ));
} else {
return Err(unexpected_token!(self, "Expected ) but found {}", right_paren));
}
@@ 215,7 215,7 @@ impl Parser {
return Err(unexpected_token!(self, "Expected ( but found {}", left_paren));
}
}
- fn build_for(for_ident: Token, semicolon_2: Token, expression1: Option<AST>, expression2: Option<AST>, expression3: Option<AST>, block: AST) -> AST {
+ /*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);
@@ 235,7 235,7 @@ impl Parser {
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/tmp.kab => kabel/tmp.kab +6 -4
@@ 1,6 1,8 @@
for (var i = 1; i < 101; i++) {
- if (i % 3 != 0 && i % 5 != 0) { print i; }
- else if (i % 3 == 0 && i % 5 != 0) { print "Fizz"; }
- else if (i % 3 != 0 && i % 5 == 0) { print "Buzz"; }
- else if (i % 3 == 0 && i % 5 == 0) { print "FizzBuzz"; }
+ //if (i % 3 != 0 && i % 5 != 0) { print i; }
+ //else if (i % 3 == 0 && i % 5 != 0) { print "Fizz"; }
+ //else if (i % 3 != 0 && i % 5 == 0) { print "Buzz"; }
+ //else if (i % 3 == 0 && i % 5 == 0) { print "FizzBuzz"; }
+ print i;
+ break;
}