~starkingdoms/starkingdoms

3aca67bf85e575525eae5b36a391d269d9af46b3 — ghostly_zsh 1 year, 4 months ago 3eaea37
run if statements
M kabel/opcodes.txt => kabel/opcodes.txt +18 -0
@@ 4,4 4,22 @@ SUB ; 0x02
MUL ; 0x03
DIV ; 0x04
MOD ; 0x05
BITAND ; 0x06
BITXOR ; 0x07
BITOR ; 0x08
EQ ; 0x09
NE ; 0x0A
GR ; 0x0B
GE ; 0x0C
LS ; 0x0D
LE ; 0x0E
OR ; 0x0F
AND ; 0x10

NOT ; 0x11
NEG ; 0x12

JMP LOC ; 0x13
IF_NE ELSE ; 0x14

PRINT ; 0xFF

M kabel/src/codegen.rs => kabel/src/codegen.rs +54 -1
@@ 1,4 1,4 @@
use crate::{codegen_binary, codegen_unary, opcodes::OpCode, parser::{BinOp, Lit, UnOp, AST}, vm::{Value, VM}};
use crate::{codegen_binary, codegen_unary, opcodes::OpCode, parser::{ASTType, BinOp, Lit, UnOp, AST}, vm::{Value, VM}};

pub struct Codegen {
    pub vm: VM


@@ 19,6 19,12 @@ impl Codegen {
                    self.visit(ast);
                }
            }
            If(condition, block, else_expr) => {
                self.visit_if(*condition, *block, *else_expr);
            }
            Block(stmts) => {
                self.visit_block(stmts);
            }
            // REMOVE LATER
            Print(ref expr) => {
                self.visit_print(&ast, *expr.clone());


@@ 35,6 41,47 @@ impl Codegen {
            _ => {}
        }
    }
    pub fn visit_if(&mut self, condition: AST, block: AST, else_expr: Option<AST>) {
        self.visit(condition);
        self.vm.chunk.push(OpCode::IF_NE.into());
        self.vm.chunk.push(0xFF); // placeholder
        self.vm.chunk.push(0xFF); // placeholder
        let start_jmp_loc = self.vm.chunk.len()-2;
        self.visit(block);
        if let Some(ast) = else_expr {
            match ast.ast_type {
                ASTType::If(_, _, _) => {
                    self.vm.chunk.push(OpCode::JMP.into());
                    self.vm.chunk.push(0xFF); // placeholder
                    self.vm.chunk.push(0xFF); // placeholder
                    let end_jmp_loc = self.vm.chunk.len()-2;
                    
                    self.patch_jump(start_jmp_loc);
                    self.visit(ast);
                    self.patch_jump(end_jmp_loc);
                }
                ASTType::Block(_) => {

                    self.vm.chunk.push(OpCode::JMP.into());
                    self.vm.chunk.push(0xFF); // placeholder
                    self.vm.chunk.push(0xFF); // placeholder
                    
                    let end_jmp_loc = self.vm.chunk.len()-2;
                    self.patch_jump(start_jmp_loc); // jmp to else
                    self.visit(ast);
                    self.patch_jump(end_jmp_loc); // jmp to after else
                }
                _ => {}
            }
        } else {
            self.patch_jump(start_jmp_loc);
        }
    }
    pub fn visit_block(&mut self, stmts: Vec<AST>) {
        for stmt in stmts {
            self.visit(stmt);
        }
    }
    // REMOVE LATER
    pub fn visit_print(&mut self, ast: &AST, expr: AST) {
        self.visit(expr);


@@ 90,4 137,10 @@ impl Codegen {
            _ => {}
        }
    }
    pub fn patch_jump(&mut self, loc: usize) {
        let jump = self.vm.chunk.len() - loc - 2;

        self.vm.chunk[loc] = ((jump >> 8) & 0xFF) as u8;
        self.vm.chunk[loc + 1] = (jump & 0xFF) as u8;
    }
}

M kabel/src/debug.rs => kabel/src/debug.rs +59 -0
@@ 195,3 195,62 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
    }
    output
}

pub fn debug_bytecode(code: Vec<u8>) -> String {
    use crate::opcodes::OpCode::*;
    let mut ip = 0;
    let mut output = "".to_string();
    while ip < code.len() {
        match code[ip].into() {
            CONSTANT => {
                output += &ip.to_string();
                output += " CONSTANT ";
                ip += 1;
                output += &code[ip].to_string();
                output += "\n";
            }
            ADD => { output += &ip.to_string(); output += " ADD\n" }
            SUB => { output += &ip.to_string(); output += " SUB\n" }
            MUL => { output += &ip.to_string(); output += " MUL\n" }
            DIV => { output += &ip.to_string(); output += " DIV\n" }
            MOD => { output += &ip.to_string(); output += " MOD\n" }
            BITAND => { output += &ip.to_string(); output += " BITAND\n" }
            BITXOR => { output += &ip.to_string(); output += " BITXOR\n" }
            BITOR => { output += &ip.to_string(); output += " BITOR\n" }
            EQ => { output += &ip.to_string(); output += " EQ\n" }
            NE => { output += &ip.to_string(); output += " NE\n" }
            GR => { output += &ip.to_string(); output += " GR\n" }
            GE => { output += &ip.to_string(); output += " GE\n" }
            LS => { output += &ip.to_string(); output += " LS\n" }
            LE => { output += &ip.to_string(); output += " LE\n" }
            OR => { output += &ip.to_string(); output += " OR\n" }
            AND => { output += &ip.to_string(); output += " AND\n" }
            NOT => { output += &ip.to_string(); output += " NOT\n" }
            NEG => { output += &ip.to_string(); output += " NEG\n" }
            JMP => {
                output += &ip.to_string();
                output += " JMP ";
                ip += 1;
                let byte_one = (code[ip] as u16) << 8;
                ip += 1;
                let byte_two = code[ip] as u16;
                output += &(byte_one | byte_two).to_string();
                output += "\n";
            }
            IF_NE => {
                output += &ip.to_string();
                output += " IF_NE ";
                ip += 1;
                let byte_one = (code[ip] as u16) << 8;
                ip += 1;
                let byte_two = code[ip] as u16;
                output += &(byte_one | byte_two).to_string();
                output += "\n";
            }
            PRINT => { output += &ip.to_string(); output += " PRINT\n" }
            ERR => output += "ERR\n",
        }
        ip += 1;
    }
    output
}

M kabel/src/opcodes.rs => kabel/src/opcodes.rs +15 -1
@@ 1,3 1,5 @@
#![allow(non_camel_case_types)]

pub enum OpCode {
    CONSTANT,



@@ 20,6 22,10 @@ pub enum OpCode {

    NOT,
    NEG,

    JMP,
    IF_NE,

    PRINT,
    ERR,
}


@@ 49,6 55,10 @@ impl From<OpCode> for u8 {

            NOT => 0x11,
            NEG => 0x12,

            JMP => 0x13,
            IF_NE => 0x14,

            PRINT => 0xFE,
            ERR => 0xFF
        }


@@ 79,7 89,11 @@ impl From<u8> for OpCode {

            0x11 => NOT,
            0x12 => NEG,
            0x13 => PRINT,

            0x13 => JMP,
            0x14 => IF_NE,

            0xFE => PRINT,
            _ => ERR
        }
    }

M kabel/src/parser.rs => kabel/src/parser.rs +2 -1
@@ 238,8 238,9 @@ impl Parser {
            if let TokenType::RightParen = right_paren.token_type {
                let block = self.block()?;
                if self.current < self.input.len() {
                    let else_ident = self.read_token()?;
                    let else_ident = self.peek()?;
                    if let TokenType::Else = else_ident.token_type {
                        self.read_token()?;
                        if let TokenType::LeftBrace = self.peek()?.token_type {
                            let else_block = self.block()?;
                            return Ok(ast_from_token_ast!(

M kabel/src/vm.rs => kabel/src/vm.rs +26 -0
@@ 229,6 229,25 @@ impl VM {
                        return Err(wrong_type!(self, "Cannot negate bools"))
                    }
                }
                // JMP
                0x13 => {
                    let loc = self.read_u16();
                    self.ip += loc as usize;
                }
                // IF_NE
                0x14 => {
                    let condition = self.stack.pop().unwrap();
                    if let Value::Bool(condition) = condition {
                        if !condition {
                            let loc = self.read_u16();
                            self.ip += loc as usize;
                        } else {
                            self.read_u16();
                        }
                    } else {
                        return Err(wrong_type!(self, "if must have condition of type boolean"))
                    }
                }

                0xFE => { // PRINT
                    let value = self.stack.pop().unwrap();


@@ 249,6 268,13 @@ impl VM {
        self.ip += 1;
        byte
    }
    pub fn read_u16(&mut self) -> u16 {
        let byte_one = (self.chunk[self.ip] as u16) << 0x08;
        self.ip += 1;
        let byte_two = self.chunk[self.ip] as u16;
        self.ip += 1;
        byte_one | byte_two
    }
    pub fn find_line(&mut self) -> usize { // returns line # at ip
        let mut line_ip = 0;
        for (line, rep) in self.lines.clone() {

M kabel_test/src/main.rs => kabel_test/src/main.rs +15 -3
@@ 1,13 1,22 @@
//use std::{env, fs};

use kabel::{debug::{debug_ast, debug_token_array}, run_codegen, run_lexer, run_parser, run_semantic_analysis};
use kabel::{debug::{debug_ast, debug_bytecode, debug_token_array}, run_codegen, run_lexer, run_parser, run_semantic_analysis};

fn main() {
    /*let args: Vec<String> = env::args().collect();
    let program =
        fs::read_to_string(args[1].clone()).unwrap();*/

    let program = "print 4.1+5.3;".to_string();
    let program =
"if(true) {
    print \"if\";
} else if(true) {
    print \"elseif\";
} else {
    print \"else\";
}
print \"after\";
".to_string();

    let mut output = "".to_string();



@@ 34,7 43,8 @@ fn main() {
        println!("{}", output);
        return;
    }
    //output += &debug_ast(ast.clone(), 0);
    output += &debug_ast(ast.clone(), 0);
    output += "\n\n";
    //output += &format!("{:#?}", ast);
    let analyzer = run_semantic_analysis(program.to_string(), ast.clone());
    for error in analyzer.errors.clone() {


@@ 45,6 55,8 @@ fn main() {
    let codegen = run_codegen(program, ast);

    let mut vm = codegen.vm;
    output += &debug_bytecode(vm.chunk.clone());
    output += "\n";
    match vm.run(&mut output) {
        Ok(()) => {}
        Err(e) => output += &e.to_string(),