~starkingdoms/starkingdoms

fb87d2ae4d216d82afd37a99baec64f034d87f69 — ghostly_zsh 1 year, 3 months ago 3cad7d7
anonymous functions
M .gitignore => .gitignore +2 -1
@@ 13,4 13,5 @@ starkingdoms-client/node_modules
starkingdoms-client/dist
client/node_modules
starkingdoms-backplane/config.toml
starkingdoms-api/config.toml
\ No newline at end of file
starkingdoms-api/config.toml
kabel/tmp.kab

M kabel/grammar.ebnf => kabel/grammar.ebnf +7 -5
@@ 1,7 1,7 @@
program = { statement } ;

statement = function | return | loop | while | for | break | continue
                | if | block | expression_statement ;
                | if | block | declaration | expression_statement ;

function = "function" , identifier , "(" , { identifier , "," , } ")" , block ;
return = "return" , expression , ";" ;


@@ 16,14 16,16 @@ if = "if" , "(" , expression , ")" , block [ , "else" , ( if | block ) ] ;

block = "{" , { statement } , "}" ;

expression_statement = expression , ";" ;
declaration = "var" , identifier , "=" , expression , ";" ;

expression = assignment | declaration ;
expression_statement = expression , ";" ;

declaration = "var" , identifier , "=" , expression ;
expression = assignment ;

assignment = ( identifier , ( "=" | "+=" | "-=" | "*="
    | "/=" | "%=" | "&=" | "^=" | "|=" ) , assignment ) | ternary ;
    | "/=" | "%=" | "&=" | "^=" | "|=" ) , assignment ) | anonymous_function ;

anonymous_function = ( "(" , { identifier , "," , } ")" , "=>" , block ) | ternary ;

ternary = logical_or [ , "?" , expression , ":" , expression ] ;


M kabel/opcodes.txt => kabel/opcodes.txt +1 -1
@@ 26,7 26,7 @@ JMP LOC         ; 0x15
JMP_UP LOC      ; 0x16
JNE ELSE        ; 0x17

CALL NUMARGS    ; 0x18
CALL ARITY      ; 0x18
RET             ; 0x19

LIST LEN        ; 0x1A

M kabel/src/ast.rs => kabel/src/ast.rs +1 -0
@@ 36,6 36,7 @@ pub enum ASTType {

    // expressions
    Assign(Name, Box<AST>),
    Anonymous(Vec<Name>, Box<AST>),
    Ternary(Box<AST>, Box<AST>, Box<AST>),
    Subscript(Box<AST>, Box<AST>),
    Binary(Box<AST>, BinOp, Box<AST>),

M kabel/src/codegen.rs => kabel/src/codegen.rs +67 -0
@@ 62,6 62,9 @@ impl Codegen {
            Assign(ref name, ref expr) => {
                self.visit_assign(&ast, name.clone(), *expr.clone());
            }
            Anonymous(params, block) => {
                self.visit_anonymous(params, *block);
            }
            Subscript(ref left, ref right) => {
                self.visit_subscript(&ast, *left.clone(), *right.clone());
            }


@@ 448,6 451,70 @@ impl Codegen {
            self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
        }
    }
    pub fn visit_anonymous(&mut self, params: Vec<Name>, block: AST) {
        self.vm.units.push(Unit::new_empty());

        let new_unit_ptr = self.vm.units.len()-1;
        self.vm.units[self.vm.unit_ptr].pool.push(Value::Fun(Function {
            unit_ptr: new_unit_ptr,
            arity: params.len(),
        }));
        // load function to stack
        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.len() == 0 || 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, 2));
        } else {
            self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
        }
        self.scopes.last_mut().expect("codegen scopes vec was empty").1 += 1;

        // enter function unit
        let old_unit_ptr = self.vm.unit_ptr;
        let old_ip = self.vm.ip;
        self.vm.unit_ptr = new_unit_ptr;
        self.vm.ip = 0;

        // update scopes with number of parameters
        self.scopes.last_mut().expect("codegen scopes vec was empty").1 += params.len();
        
        if let ASTType::Block(ref stmts) = block.ast_type {
            self.visit_block(&block, stmts.clone(), ScopeType::Function);
        }
        // add implicit RET
        match self.vm.units[self.vm.unit_ptr].code.last() {
            Some(instr) => {
                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, 3));
                    } else {
                        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, 3));
                } else {
                    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_subscript(&mut self, ast: &AST, left: AST, right: AST) {
        self.visit(left);
        self.visit(right);

M kabel/src/debug.rs => kabel/src/debug.rs +12 -3
@@ 23,12 23,12 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
                output += &debug_ast(ast, level+1);
            }
        }
        Function(name, args, block) => {
        Function(name, params, block) => {
            output += &"| ".repeat(level);
            output += "Function";
            output += &(" ".to_string() + &name.name);
            for arg in args {
                output += &(" ".to_string() + &arg.name);
            for param in params {
                output += &(" ".to_string() + &param.name);
            }
            output += &format!(" {:?}", ast.extensions);
            output += "\n";


@@ 131,6 131,15 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
            output += "\n";
            output += &debug_ast(*expr, level+1);
        }
        Anonymous(params, block) => {
            output += &"| ".repeat(level);
            output += "Anonymous ";
            for param in params {
                output += &(" ".to_string() + &param.name);
            }
            output += "\n";
            output += &debug_ast(*block, level+1);
        }
        Ternary(condition, true_expr, false_expr) => {
            output += &"| ".repeat(level);
            output += "Ternary\n";

M kabel/src/lexer.rs => kabel/src/lexer.rs +6 -1
@@ 213,6 213,10 @@ impl Lexer {
                    self.read_char("Kabel broke")?;
                    self.output.push(token!(self, TokenType::EqualEqual));
                    self.start = self.line_current;
                } else if self.peek("").unwrap_or(' ') == '>' {
                    self.read_char("Kabel broke")?;
                    self.output.push(token!(self, TokenType::Arrow));
                    self.start = self.line_current;
                } else {
                    self.output.push(token!(self, TokenType::Equal));
                    self.start = self.line_current;


@@ 415,6 419,7 @@ pub enum TokenType {
    Semicolon,
    Colon,
    Question,
    Arrow,

    Ident(String),
    Str(String),


@@ 432,7 437,7 @@ impl Display for TokenType {
            LeftSquare, RightSquare, Equal, EqualEqual,
            Bang, BangEqual, Greater, GreaterEqual, Less,
            LessEqual, And, AndEqual, AndAnd, Or, OrEqual, OrOr,
            Caret, CaretEqual, Period, Comma, Semicolon, Colon, Question);
            Caret, CaretEqual, Period, Comma, Semicolon, Colon, Question, Arrow);
        match *self {
            Ident(ref name) => {
                f.write_str("Ident ")?;

M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +14 -0
@@ 223,6 223,19 @@ impl Resolver {
                    end_column: ast.end_column,
                }
            }
            Anonymous(params, block) => {
                self.locals.push(Vec::new());
                self.symbol_table.push(HashMap::new());
                self.locals.last_mut().expect("locals last in anonymous self-reference push").push(self.scope);
                for param in params.clone() {
                    self.locals.last_mut().expect("locals last in anonymous param push").push(self.scope+1);
                    self.symbol_table.last_mut().unwrap().insert(param.name, (Symbol::Var,self.locals.last().expect("locals last in anonymous param len").len()-1));
                }
                let block = self.visit(*block);
                self.symbol_table.pop();
                self.locals.pop();
                ast_from_ast!(Anonymous(params, Box::new(block)), ast, ast)
            }
            Ternary(condition, true_expr, false_expr) => {
                let condition = self.visit(*condition);
                let true_expr = self.visit(*true_expr);


@@ 317,4 330,5 @@ impl Resolver {
pub enum Symbol {
    Var,
    Function(usize),
    Anonymous(usize),
}

M kabel/src/parser.rs => kabel/src/parser.rs +76 -2
@@ 398,7 398,7 @@ impl Parser {
            let ident = self.read_token()?;
            if self.current >= self.input.len() {
                self.current -= 1;
                return self.logical_or();
                return self.ternary();
            }
            if let TokenType::Equal
            | TokenType::PlusEqual


@@ 584,9 584,83 @@ impl Parser {
                }
            }
            self.current -= 1;
            return self.ternary();
            return self.anonymous_function();
        }

        return self.anonymous_function();
    }

    pub fn anonymous_function(&mut self) -> Result<AST, KabelError> {
        if let TokenType::LeftParen = self.peek()?.token_type {
            let left_paren = self.read_token()?;
            match self.peek()?.token_type {
                TokenType::Ident(name) => {
                    let param = self.read_token()?;
                    if matches!(self.peek()?.token_type, TokenType::Comma) {
                        self.read_token()?;
                        let mut params = vec![name!(name, param)];
                        while self.peek()?.token_type != TokenType::RightParen {
                            let ident = self.read_token()?;
                            if let TokenType::Ident(name) = ident.token_type {
                                params.push(name!(name, ident));
                            } else {
                                return Err(unexpected_token!(self, "Expected identifier but found {}", ident));
                            }
                            if let TokenType::Comma = self.peek()?.token_type {
                                self.read_token()?;
                            }
                        }
                        self.read_token()?; // right paren
                        if let TokenType::Arrow = self.peek()?.token_type {
                            self.read_token()?;
                            if let TokenType::LeftBrace = self.peek()?.token_type {
                                let block = self.block()?;
                                return Ok(ast_from_token_ast!(ASTType::Anonymous(params, Box::new(block.clone())), left_paren, block));
                            } else {
                                let left_brace = self.read_token()?;
                                return Err(unexpected_token!(self, "Expected {{ but found {}", left_brace));
                            }
                        } else {
                            let arrow = self.read_token()?;
                            return Err(unexpected_token!(self, "Expected => but found {}", arrow));
                        }
                    } else if matches!(self.peek()?.token_type, TokenType::RightParen) {
                        self.read_token()?; // right paren
                        let params = vec![name!(name, param)];
                        if let TokenType::Arrow = self.peek()?.token_type {
                            self.read_token()?;
                            if let TokenType::LeftBrace = self.peek()?.token_type {
                                let block = self.block()?;
                                return Ok(ast_from_token_ast!(ASTType::Anonymous(params, Box::new(block.clone())), left_paren, block));
                            } else {
                                let left_brace = self.read_token()?;
                                return Err(unexpected_token!(self, "Expected {{ but found {}", left_brace));
                            }
                        } else {
                            let arrow = self.read_token()?;
                            return Err(unexpected_token!(self, "Expected => but found {}", arrow));
                        }
                    } else {
                        self.current -= 1;
                        return self.group(left_paren);
                    }
                }
                TokenType::RightParen => {
                    self.read_token()?; // right paren
                    if let TokenType::Arrow = self.peek()?.token_type {
                        self.read_token()?;
                        let block = self.block()?;
                        return Ok(ast_from_token_ast!(ASTType::Anonymous(Vec::new(), Box::new(block.clone())), left_paren, block));
                    } else {
                        let arrow = self.read_token()?;
                        return Err(unexpected_token!(self, "Expected => but found {}", arrow));
                    }
                }
                _ => {
                    return self.group(left_paren);
                }
            }
        }
        return self.ternary();
    }


M kabel/src/vm.rs => kabel/src/vm.rs +1 -6
@@ 29,7 29,6 @@ impl Unit {
pub struct VM {
    pub ip: usize,
    pub unit_ptr: usize,
    pub stack_ptr: usize,
    pub call_stack: Vec<(usize, usize, usize)>, // (unit_ptr, ip, stack_offset)
    pub units: Vec<Unit>,
    pub stack: Vec<Value>,


@@ 43,7 42,6 @@ impl VM {
        Self {
            ip: 0,
            unit_ptr: 0,
            stack_ptr: 0,
            call_stack: vec![(0, 0, 0)],
            units: vec![Unit::new(bytecode, pool, lines)],
            stack: Vec::new(),


@@ 334,8 332,6 @@ impl VM {
                            self.stack.push(arg);
                        }
                        self.stack.insert(self.stack.len()-num_args as usize, Value::Fun(function));
                        //println!("stack call {:?}", self.stack);
                        self.stack_ptr += 1;
                        self.ip = 0;
                        self.unit_ptr = function.unit_ptr as usize;
                    } else {


@@ 351,9 347,9 @@ impl VM {
                    self.unit_ptr = unit_ptr;
                    self.ip = ip;
                    // returned to code
                    self.stack_ptr -= 1;
                    self.stack.push(ret);
                }

                // LIST
                0x1A => {
                    let len = self.read();


@@ 432,7 428,6 @@ impl VM {
            }
            line_ip += rep;
        }
        println!("{} {}", line_ip, self.ip);
        panic!("Something went wrong in finding line for error")
    }
}

M kabel/tmp.kab => kabel/tmp.kab +7 -7
@@ 1,8 1,8 @@
function foo(bar) {
    bar();
var add_one = (num) => {
    return num + 1;
};
function add_two(num) {
    return num + 2;
}
function bar() {
    print 3;
}

foo(bar);
print add_one(1);
print add_two(2);