~starkingdoms/starkingdoms

2ee9958ed9779739e20afab5f3d127a43d1eb651 — ghostly_zsh 1 year, 3 months ago 364d4a8
first draft of functions and calls
M kabel/opcodes.txt => kabel/opcodes.txt +1 -1
@@ 1,4 1,4 @@
CONSTANT VAL    ; 0x00
LOAD VAL        ; 0x00
VAR STACKPTR    ; 0x01
ASSIGN PTR      ; 0x02


M kabel/src/codegen.rs => kabel/src/codegen.rs +39 -7
@@ 28,6 28,9 @@ impl Codegen {
            Function(name, args, block) => {
                self.visit_function(name, args, *block);
            }
            Return(ref expr) => {
                self.visit_return(&ast, *expr.clone());
            }
            While(condition, block) => {
                self.visit_while(*condition, *block);
            }


@@ 88,27 91,56 @@ impl Codegen {
        }
        match self.vm.units[self.vm.unit_ptr].code.last() {
            Some(instr) => {
                if *instr != OpCode::RET.into() {
                if *instr != <OpCode as Into<u8>>::into(OpCode::RET) {
                    self.vm.units[self.vm.unit_ptr].pool.push(Value::Null);
                    self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
                    let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
                    self.vm.units[self.vm.unit_ptr].code.push(loc);
                    self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
                    if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
                        self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 1));
                        self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3));
                    } else {
                        self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
                        self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
                    }
                }
            }
            None => {
                self.vm.units[self.vm.unit_ptr].pool.push(Value::Null);
                self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
                let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
                self.vm.units[self.vm.unit_ptr].code.push(loc);
                self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
                if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
                    self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 1));
                    self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3));
                } else {
                    self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
                    self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
                }
            }
        };
        self.vm.unit_ptr = old_unit_ptr;
        self.vm.ip = old_ip;
    }
    pub fn visit_return(&mut self, ast: &AST, expr: Option<AST>) {
        if let Some(expr) = expr {
            self.visit(expr);
        } else {
            self.vm.units[self.vm.unit_ptr].pool.push(Value::Null);
            self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
            let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
            self.vm.units[self.vm.unit_ptr].code.push(loc);
            if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
                self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
            } else {
                self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
            }
        }
        self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
        if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
            self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 1));
        } else {
            self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
        }
    }
    pub fn visit_while(&mut self, condition: AST, block: AST) {
        self.break_stack.push(Vec::new());
        self.continue_stack.push(Vec::new());


@@ 459,8 491,8 @@ impl Codegen {
        }
    }
    pub fn visit_call(&mut self, ast: &AST, _name: Name, args: Vec<AST>) {
        for arg in args.clone() {
            self.visit(arg);
        for arg in args.iter().rev() {
            self.visit(arg.clone());
        }
        self.vm.units[self.vm.unit_ptr].code.push(OpCode::CALL.into());
        self.vm.units[self.vm.unit_ptr].code.push(args.len() as u8);

M kabel/src/debug.rs => kabel/src/debug.rs +12 -0
@@ 286,6 286,18 @@ pub fn debug_bytecode(vm: &VM) -> String {
                output += &(byte_one | byte_two).to_string();
                output += "\n";
            }
            CALL => {
                output += &vm.ip.to_string();
                output += " ";
                output += &vm.find_line().to_string();
                output += " CALL ";
                vm.ip += 1;
                output += &(vm.units[vm.unit_ptr].code[vm.ip]).to_string();
                output += " ";
                vm.ip += 1;
                output += &(vm.units[vm.unit_ptr].code[vm.ip]).to_string();
                output += "\n";
            }
            RET => {
                output += &vm.ip.to_string();
                output += " ";

M kabel/src/macros.rs => kabel/src/macros.rs +24 -9
@@ 276,8 276,8 @@ macro_rules! codegen_unary {
        match $match_to {
            $( $oper => {
                $self.visit($right);
                $self.vm.units[0].code.push(OpCode::$code.into());
                $self.vm.units[0].lines.last_mut().unwrap().1 += 1;
                $self.vm.units[$self.vm.unit_ptr].code.push(OpCode::$code.into());
                $self.vm.units[$self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
            } )*
        }
    };


@@ 298,16 298,31 @@ macro_rules! push_codegen {
        }
    };
}
#[macro_export]
macro_rules! vm_boolean_equality {
    ($self:expr, $oper:tt) => {
        match ($self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
                $self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
            (Num(v1), Num(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
            (Str(v1), Str(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
            (Bool(v1), Bool(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
            (Null, Null) => $self.units[$self.unit_ptr].stack.push(Bool(true)),
            (_v1, _v2) => $self.units[$self.unit_ptr].stack.push(Bool(false)),
        }
    };
}

#[macro_export]
macro_rules! vm_boolean_binary {
macro_rules! vm_boolean_comparison {
    ($self:expr, $oper:tt) => {
        match ($self.units[0].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
                $self.units[0].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
            (Num(v1), Num(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
            (Str(v1), Str(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
            (Bool(v1), Bool(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
            (_v1, _v2) => $self.units[0].stack.push(Bool(false)),
        match ($self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
                $self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
            (Num(v1), Num(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
            (Str(v1), Str(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
            (Bool(v1), Bool(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
            (Null, _) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))),
            (_, Null) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))),
            (_v1, _v2) => $self.units[$self.unit_ptr].stack.push(Bool(false)),
        }
    };
}

M kabel/src/main.rs => kabel/src/main.rs +1 -0
@@ 61,6 61,7 @@ fn main() {
        output += "\n";
    }
    vm.unit_ptr = 0;
    println!("{}", output);

    output += "\n";
    match vm.run(&mut output) {

M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +1 -1
@@ 287,7 287,7 @@ impl Resolver {
                }
                return AST {
                    ast_type: Call(ident, n_args),
                    extensions: vec![Extension::Resolution(self.scope, place)],
                    extensions: vec![Extension::Resolution(self.scope, place+1)],
                    start_line: ast.start_line,
                    end_line: ast.end_line,
                    start_column: ast.start_column,

M kabel/src/vm.rs => kabel/src/vm.rs +36 -19
@@ 1,5 1,5 @@

use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_binary};
use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_comparison, vm_boolean_equality};
use crate::vm_error;

#[derive(Debug, Clone)]


@@ 213,26 213,28 @@ impl VM {
                    }
                }
                // EQ
                0x0b => vm_boolean_binary!(self, ==),
                0x0b => vm_boolean_equality!(self, ==),
                // NE
                0x0C => vm_boolean_binary!(self, !=),
                0x0C => vm_boolean_equality!(self, !=),
                // GR
                0x0D => vm_boolean_binary!(self, >),
                0x0D => vm_boolean_comparison!(self, >),
                // GE
                0x0E => vm_boolean_binary!(self, >=),
                0x0E => vm_boolean_comparison!(self, >=),
                // LS
                0x0F => vm_boolean_binary!(self, <),
                0x0F => vm_boolean_comparison!(self, <),
                // LE
                0x10 => vm_boolean_binary!(self, <=),
                0x10 => vm_boolean_comparison!(self, <=),
                // OR
                0x11 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
                    (Num(_v1), Num(_v2)) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical OR on numbers"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean numbers"))
                    }
                    (Str(_v1), Str(_v2)) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical OR on strings"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean strings"))
                    },
                    (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 || v2)),
                    (Null, _) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean value null")),
                    (_, Null) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean value null")),
                    (v1, v2) => {
                        return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
                    }


@@ 240,34 242,38 @@ impl VM {
                // AND
                0x12 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
                    (Num(_v1), Num(_v2)) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical AND on numbers"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean numbers"))
                    }
                    (Str(_v1), Str(_v2)) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical AND on strings"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean strings"))
                    },
                    (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 && v2)),
                    (Null, _) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean value null")),
                    (_, Null) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean value null")),
                    (v1, v2) => {
                        return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
                    }
                }
                // NOT
                0x13 => match self.units[self.unit_ptr].stack.pop().unwrap() {
                    Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean value null")) }
                    Num(_v1) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on numbers"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean number"))
                    }
                    Str(_v1) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on strings"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean string"))
                    }
                    Bool(v1) => self.units[self.unit_ptr].stack.push(Bool(!v1)),
                }
                // NEG
                0x14 => match self.units[self.unit_ptr].stack.pop().unwrap() {
                    Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number value null")) }
                    Num(v1) => self.units[self.unit_ptr].stack.push(Num(-v1)),
                    Str(_v1) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate strings"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number string"))
                    }
                    Bool(_v1) => {
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate bools"))
                        return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number boolean"))
                    }
                }
                // JMP


@@ 300,13 306,22 @@ impl VM {
                    let num_args = self.read();
                    let unit_ptr = self.read();
                    self.call_stack.push((self.unit_ptr, self.ip));
                    for i in 0..num_args {

                    for _ in 0..num_args {
                        let arg = self.units[self.unit_ptr].stack.pop().expect("Missing arguments in call");
                        self.units[unit_ptr as usize].stack.push(arg);
                    }
                    self.ip = 0;
                    self.unit_ptr = unit_ptr as usize;
                }
                // RET
                0x19 => {

                    let (unit_ptr, ip) = self.call_stack.pop().expect("Call stack empty on RET");
                    let ret = self.units[self.unit_ptr].stack.pop().expect("Missing return value");
                    self.units[self.unit_ptr].stack.clear();
                    self.unit_ptr = unit_ptr;
                    self.ip = ip;
                    // returned to code
                    self.units[self.unit_ptr].stack.push(ret);
                }

                0xFD => { // POP


@@ 318,6 333,7 @@ impl VM {
                0xFE => { // PRINT
                    let value = self.units[self.unit_ptr].stack.pop().unwrap();
                    match value {
                        Null => *output += "null",
                        Num(v) => *output += &v.to_string(),
                        Str(v) => *output += &v,
                        Bool(v) => *output += &v.to_string(),


@@ 356,12 372,13 @@ impl VM {

#[derive(Debug, Clone)]
pub enum Value {
    Num(f32), Str(String), Bool(bool),
    Null, Num(f32), Str(String), Bool(bool),
}

impl Value {
    pub fn type_str(&self) -> String {
        match self {
            Value::Null => "null".to_string(),
            Value::Num(_) => "number".to_string(),
            Value::Str(_) => "string".to_string(),
            Value::Bool(_) => "bool".to_string(),

M kabel/tmp.kab => kabel/tmp.kab +7 -3
@@ 1,4 1,8 @@
function i(j) {
    j+1;
var k = 0;
function bar(i) {
    return i+2;
}
print i(2);
function foo(i) {
    return i+1;
}
print foo(2);