~starkingdoms/starkingdoms

dda08ce1274a7ed016341a7586ceb8967a7db3cb — ghostly_zsh 1 year, 4 months ago efcd9f2
for loop desugaring and loops in vm
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 {