~starkingdoms/starkingdoms

73a203ce8ed8742d653a87a08f51e6739984d5e9 — ghostly_zsh 1 year, 4 months ago 5d800d4
break works, continue works-ish
2 files changed, 58 insertions(+), 20 deletions(-)

M kabel/src/codegen.rs
M kabel/src/main.rs
M kabel/src/codegen.rs => kabel/src/codegen.rs +57 -17
@@ 2,7 2,7 @@ use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen

pub struct Codegen {
    pub vm: VM,
    pub scopes: Vec<usize>, // number of variables declared in the scope
    pub scopes: Vec<(ScopeType, usize)>, // number of variables declared in the scope
    break_stack: Vec<Vec<usize>>,
    continue_stack: Vec<Vec<usize>>,
}


@@ 12,7 12,7 @@ impl Codegen {
        Codegen {
            vm: VM::new(Vec::new(), Vec::new(),
                Vec::new(), text),
            scopes: vec![0],
            scopes: vec![(ScopeType::Main, 0)],
            break_stack: Vec::new(),
            continue_stack: Vec::new(),
        }


@@ 38,7 38,7 @@ impl Codegen {
                self.visit_if(*condition, *block, *else_expr);
            }
            Block(ref stmts) => {
                self.visit_block(&ast, stmts.clone());
                self.visit_block(&ast, stmts.clone(), ScopeType::Other);
            }
            Decl(ref name, ref expr) => {
                self.visit_decl(&ast, name.clone(), *expr.clone());


@@ 80,7 80,9 @@ impl Codegen {
        } else {
            self.vm.lines.last_mut().unwrap().1 += 3;
        }
        self.visit(block.clone());
        if let ASTType::Block(ref stmts) = block.ast_type {
            self.visit_block(&block, stmts.clone(), ScopeType::Loop);
        }
        self.vm.chunk.push(OpCode::JMP_UP.into());
        let current = self.vm.chunk.len()+2;
        let current_to_start = current - end_jmp;


@@ 107,24 109,51 @@ impl Codegen {
        }
    }
    pub fn visit_break(&mut self, ast: &AST) {
        let mut scopes = self.scopes.clone();
        let mut pop_count = 0;
        loop {
            let (scope_type, scope) = scopes.pop().expect("scopes empty in break");
            pop_count += scope;
            if scope_type == ScopeType::Loop {
                break;
            }
        }
        self.vm.chunk.push(OpCode::POP.into());
        self.vm.chunk.push(pop_count as u8);

        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 {
            self.vm.lines.push((ast.end_line, 3));
            self.vm.lines.push((ast.end_line, 5));
        } else {
            self.vm.lines.last_mut().unwrap().1 += 3;
            self.vm.lines.last_mut().unwrap().1 += 5;
        }
        self.break_stack.last_mut().expect("break not in a loop").push(self.vm.chunk.len()-2);
    }
    // ======================================================================
    //          CONTINUE IS BROKEN AND HANGS IN FOR LOOPS, FIX LATER
    // ======================================================================
    pub fn visit_continue(&mut self, ast: &AST) {
        let mut scopes = self.scopes.clone();
        let mut pop_count = 0;
        loop {
            let (scope_type, scope) = scopes.pop().expect("scopes empty in break");
            pop_count += scope;
            if scope_type == ScopeType::Loop {
                break;
            }
        }
        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(0xFF);
        self.vm.chunk.push(0xFF);
        if self.vm.lines.last().unwrap().0 != ast.end_line {
            self.vm.lines.push((ast.end_line, 3));
            self.vm.lines.push((ast.end_line, 5));
        } else {
            self.vm.lines.last_mut().unwrap().1 += 3;
            self.vm.lines.last_mut().unwrap().1 += 5;
        }
        self.continue_stack.last_mut().expect("continue not in a loop").push(self.vm.chunk.len()-2);
    }


@@ 135,11 164,13 @@ impl Codegen {
        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));
            self.vm.lines.push((condition.end_line, 5));
        } else {
            self.vm.lines.last_mut().unwrap().1 += 3;
            self.vm.lines.last_mut().unwrap().1 += 5;
        }
        if let ASTType::Block(ref stmts) = block.ast_type {
            self.visit_block(&block, stmts.clone(), ScopeType::If);
        }
        self.visit(block);
        if let Some(ast) = else_expr {
            match ast.ast_type {
                ASTType::If(_, _, _) => {


@@ 154,7 185,9 @@ impl Codegen {
                    }
                    
                    self.patch_jump(start_jmp_loc, 0);
                    self.visit(ast);
                    if let ASTType::Block(ref stmts) = ast.ast_type {
                        self.visit_block(&ast, stmts.clone(), ScopeType::If);
                    }
                    self.patch_jump(end_jmp_loc, 0);
                }
                ASTType::Block(_) => {


@@ 170,7 203,9 @@ impl Codegen {
                    
                    let end_jmp_loc = self.vm.chunk.len()-2;
                    self.patch_jump(start_jmp_loc, 0); // jmp to else
                    self.visit(ast);
                    if let ASTType::Block(ref stmts) = ast.ast_type {
                        self.visit_block(&ast, stmts.clone(), ScopeType::If);
                    }
                    self.patch_jump(end_jmp_loc, 0); // jmp to after else
                }
                _ => { println!("unimplemented"); }


@@ 179,12 214,12 @@ impl Codegen {
            self.patch_jump(start_jmp_loc, 0);
        }
    }
    pub fn visit_block(&mut self, ast: &AST, stmts: Vec<AST>) {
        self.scopes.push(0);
    pub fn visit_block(&mut self, ast: &AST, stmts: Vec<AST>, scope_type: ScopeType) {
        self.scopes.push((scope_type, 0));
        for stmt in stmts {
            self.visit(stmt);
        }
        let variables = self.scopes.pop().expect("popped scope in block");
        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 != ast.end_line {


@@ 197,7 232,7 @@ impl Codegen {
        self.visit(expr);
        #[allow(irrefutable_let_patterns)]
        if let Extension::Resolution(_scope, _ptr) = ast.extensions[0] {
            *self.scopes.last_mut().expect("codegen scopes vec was empty") += 1;
            self.scopes.last_mut().expect("codegen scopes vec was empty").1 += 1;
        }
    }
    pub fn visit_expr_stmt(&mut self, ast: &AST, expr: AST) {


@@ 307,3 342,8 @@ impl Codegen {
        self.vm.chunk[loc + 1] = (jump & 0xFF) as u8;
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScopeType {
    Main, Loop, If, Other,
}

M kabel/src/main.rs => kabel/src/main.rs +1 -3
@@ 11,10 11,8 @@ fn main() {

    let program =
"
var i = 0;
while(i < 5) {
for(var i = 0; i < 5; i++) {
    print i;
    i += 1;
    continue;
}
".to_string();