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() + ¶m.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() + ¶m.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);