~starkingdoms/starkingdoms

1e504d7d6bd49ecb594ef9767800bac622c7161a — ghostly_zsh 1 year, 4 months ago 0349593
break and continue work?
4 files changed, 103 insertions(+), 10 deletions(-)

M kabel/src/codegen.rs
M kabel/src/name_resolution.rs
M kabel/src/parser.rs
M kabel/tmp.kab
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;
}