M kabel/grammar.ebnf => kabel/grammar.ebnf +1 -1
@@ 53,7 53,7 @@ array = "[" , { expression , "," ? } , "]" ;
member = identifier , "." , { ( identifier | call ) , "." ? } ;
-call = ( identifier , "(" , { expression, "," ? } , ")" ) ;
+call = identifier , "(" , { expression, "," ? } , ")" ;
incdec = identifier , [ "++" , "--" ] ;
M kabel/opcodes.txt => kabel/opcodes.txt +2 -2
@@ 26,8 26,8 @@ JMP LOC ; 0x15
JMP_UP LOC ; 0x16
JNE ELSE ; 0x17
-CALL NUMARGS UNIT_PTR ; 0x18
-RET ; 0x19
+CALL NUMARGS ; 0x18
+RET ; 0x19
POP COUNT ; 0xFD
PRINT ; 0xFE
M kabel/src/ast.rs => kabel/src/ast.rs +1 -1
@@ 43,7 43,7 @@ pub enum ASTType {
// primary
Lit(Lit),
- Call(Name, Vec<AST>),
+ Call(Box<AST>, Vec<AST>),
Member(Box<AST>, Box<AST>),
}
M kabel/src/codegen.rs => kabel/src/codegen.rs +28 -18
@@ 1,4 1,4 @@
-use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Unit, Value, VM}};
+use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Function, Unit, Value, VM}};
pub struct Codegen {
pub vm: VM,
@@ 72,18 72,34 @@ impl Codegen {
self.visit_lit(&ast, lit.clone());
}
Call(ref name, ref args) => {
- self.visit_call(&ast, name.clone(), args.clone());
+ self.visit_call(&ast, *name.clone(), args.clone());
}
_ => {}
}
}
- pub fn visit_function(&mut self, _name: Name, _args: Vec<Name>, block: AST) {
- let old_unit_ptr = self.vm.unit_ptr;
- let old_ip = self.vm.ip;
+ pub fn visit_function(&mut self, _name: Name, args: Vec<Name>, block: AST) {
// create new compilation unit
self.vm.units.push(Unit::new_empty());
+
+ // add function to constant pool and add a load expression in its place
+ 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: args.len(),
+ }));
+ 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;
+ }
+
+ let old_unit_ptr = self.vm.unit_ptr;
+ let old_ip = self.vm.ip;
// set unit to write to
- self.vm.unit_ptr = self.vm.units.len()-1;
+ self.vm.unit_ptr = new_unit_ptr;
self.vm.ip = 0;
if let ASTType::Block(ref stmts) = block.ast_type {
@@ 282,9 298,6 @@ impl Codegen {
}
self.break_stack.last_mut().expect("break not in a loop").push(self.vm.units[self.vm.unit_ptr].code.len()-2);
}
- // ======================================================================
- // CONTINUE IS BROKEN AND HANGS IN FOR LOOPS, FIX LATER
- // ======================================================================
pub fn visit_continue(&mut self, ast: &AST) {
let mut scopes = self.scopes.clone();
let mut pop_count = 0;
@@ 490,20 503,17 @@ impl Codegen {
_ => {}
}
}
- pub fn visit_call(&mut self, ast: &AST, _name: Name, args: Vec<AST>) {
+ pub fn visit_call(&mut self, ast: &AST, ident: AST, args: Vec<AST>) {
for arg in args.iter().rev() {
self.visit(arg.clone());
}
+ self.visit(ident);
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);
- #[allow(irrefutable_let_patterns)]
- if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
- self.vm.units[self.vm.unit_ptr].code.push(ptr as u8);
- if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || 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, 3));
- } else {
- self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
- }
+ if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || 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;
}
}
pub fn patch_jump(&mut self, loc: usize, offset: i32) {
M kabel/src/debug.rs => kabel/src/debug.rs +3 -6
@@ 1,4 1,4 @@
-use crate::{ast::AST, extension::Extension, lexer::Token, push_codegen, push_output, vm::{Value, VM}};
+use crate::{ast::AST, lexer::Token, push_codegen, push_output, vm::{Value, VM}};
pub fn debug_token_array(tokens: Vec<Token>) -> String {
let mut output = "".to_string();
@@ 193,8 193,8 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
}
Call(name, args) => {
output += &"| ".repeat(level);
- output += "Call ";
- output += &name.name;
+ output += "Call\n";
+ output += &debug_ast(*name, level+1);
for arg in args {
output += "\n";
output += &debug_ast(arg, level+1);
@@ 293,9 293,6 @@ pub fn debug_bytecode(vm: &VM) -> 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 => {
M kabel/src/main.rs => kabel/src/main.rs +2 -2
@@ 52,6 52,7 @@ fn main() {
let codegen = run_codegen(program.to_string(), ast);
let mut vm = codegen.vm;
+ output += &debug_stack(&vm.units[0].stack);
for (index, _) in vm.units.iter().enumerate() {
vm.unit_ptr = index;
output += "unit ptr: ";
@@ 61,14 62,13 @@ fn main() {
output += "\n";
}
vm.unit_ptr = 0;
- println!("{}", output);
output += "\n";
match vm.run(&mut output) {
Ok(()) => {}
Err(e) => output += &e.to_string(),
}
- output += &debug_stack(&vm.units[0].stack);
+ //output += &debug_stack(&vm.units[0].stack);
println!("{}", output);
}
M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +5 -25
@@ 1,6 1,6 @@
use std::collections::HashMap;
-use crate::{ast::{ASTType, AST}, ast_error, ast_from_ast, collect_lines, error::{ErrorKind, KabelError}, extension::Extension, out_of_scope_var};
+use crate::{ast::{ASTType, AST}, ast_error, ast_from_ast, error::{ErrorKind, KabelError}, extension::Extension, out_of_scope_var};
pub struct Resolver {
text: Vec<String>,
@@ 260,34 260,14 @@ impl Resolver {
ast_from_ast!(Lit(lit), ast, ast)
}
Call(ident, args) => {
- let resolution = self.resolve_function(&ident.name, args.len());
- let place = match resolution {
- Ok(place) => place,
- Err(e) => match e {
- (ErrorKind::OutOfScope, _, _) => { self.errors.push(ast_error!(self, ErrorKind::OutOfScope, ast, "Function \"{}\" not in scope", ident.name)); 0 },
- (ErrorKind::IncorrectArity, Some(f_arity), Some(arity)) => {
- self.errors.push(
- KabelError::new(
- ErrorKind::IncorrectArity,
- format!("Function {} has {} argument, provided {}", ident.name, f_arity, arity),
- None,
- ast.start_line,
- ast.start_column,
- collect_lines!(self.text[ast.start_line-1..ast.end_line-1]),
- )
- );
- 0
- }
- _ => { panic!("Returned invalid ErrorKind from resolve_function") },
- }
- };
+ let ident = self.visit(*ident.clone());
let mut n_args = Vec::new();
for arg in args {
n_args.push(self.visit(arg));
}
return AST {
- ast_type: Call(ident, n_args),
- extensions: vec![Extension::Resolution(self.scope, place+1)],
+ ast_type: Call(Box::new(ident), n_args),
+ extensions: Vec::new(),
start_line: ast.start_line,
end_line: ast.end_line,
start_column: ast.start_column,
@@ 307,7 287,7 @@ impl Resolver {
}*/
fn resolve_var(&self, name: &String) -> (bool, usize) {
for scope in self.symbol_table.iter().rev() {
- if let Some((Symbol::Var, place)) = scope.get(name) {
+ if let Some((Symbol::Var, place)) | Some((Symbol::Function(_), place)) = scope.get(name) {
return (true, *place);
}
}
M kabel/src/parser.rs => kabel/src/parser.rs +1 -1
@@ 978,7 978,7 @@ impl Parser {
let right_paren = self.read_token()?;
if let TokenType::Ident(name) = ident.token_type {
return Ok(ast_from_token!(
- ASTType::Call(name!(name, ident), expressions),
+ ASTType::Call(Box::new(lit!(Ident, name, ident)), expressions),
ident,
right_paren
));
M kabel/src/runtime_error.rs => kabel/src/runtime_error.rs +4 -1
@@ 42,6 42,7 @@ impl std::error::Error for KabelRuntimeError {}
pub enum RuntimeErrorKind {
MismatchedTypes,
WrongType,
+ IncorrectArity,
}
impl std::fmt::Display for RuntimeErrorKind {
@@ 49,7 50,8 @@ impl std::fmt::Display for RuntimeErrorKind {
use RuntimeErrorKind::*;
match self {
MismatchedTypes => f.write_str("Mismatched types"),
- WrongType => f.write_str("WrongType"),
+ WrongType => f.write_str("Wrong type"),
+ IncorrectArity => f.write_str("Incorrect arity"),
}
}
}
@@ 60,6 62,7 @@ impl From<RuntimeErrorKind> for usize {
match value {
MismatchedTypes => 0x00,
WrongType => 0x01,
+ IncorrectArity => 0x02,
}
}
}
M kabel/src/vm.rs => kabel/src/vm.rs +29 -8
@@ 264,6 264,9 @@ impl VM {
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)),
+ Fun(_v1) => {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean function"))
+ }
}
// NEG
0x14 => match self.units[self.unit_ptr].stack.pop().unwrap() {
@@ 275,6 278,9 @@ impl VM {
Bool(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number boolean"))
}
+ Fun(_v1) => {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number function"))
+ }
}
// JMP
0x15 => {
@@ 304,14 310,21 @@ impl VM {
// CALL
0x18 => {
let num_args = self.read();
- let unit_ptr = self.read();
- self.call_stack.push((self.unit_ptr, self.ip));
- 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);
+ let function = self.units[self.unit_ptr].stack.pop().expect("Stack was empty in call");
+ if let Value::Fun(function) = function {
+ if num_args as usize != function.arity {
+ return Err(vm_error!(self, RuntimeErrorKind::IncorrectArity, "Function has {} arguments, {} provided", function.arity, num_args))
+ }
+ self.call_stack.push((self.unit_ptr, self.ip));
+ for _ in 0..num_args {
+ let arg = self.units[self.unit_ptr].stack.pop().expect("Missing arguments in call");
+ self.units[function.unit_ptr as usize].stack.push(arg);
+ }
+ self.ip = 0;
+ self.unit_ptr = function.unit_ptr as usize;
+ } else {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to call non-function type {}", function.type_str()))
}
- self.ip = 0;
- self.unit_ptr = unit_ptr as usize;
}
// RET
0x19 => {
@@ 337,6 350,7 @@ impl VM {
Num(v) => *output += &v.to_string(),
Str(v) => *output += &v,
Bool(v) => *output += &v.to_string(),
+ Fun(v) => *output += &format!("<function {}>", v.unit_ptr),
}
*output += "\n";
}
@@ 372,7 386,7 @@ impl VM {
#[derive(Debug, Clone)]
pub enum Value {
- Null, Num(f32), Str(String), Bool(bool),
+ Null, Num(f32), Str(String), Bool(bool), Fun(Function)
}
impl Value {
@@ 382,6 396,13 @@ impl Value {
Value::Num(_) => "number".to_string(),
Value::Str(_) => "string".to_string(),
Value::Bool(_) => "bool".to_string(),
+ Value::Fun(_) => "function".to_string(),
}
}
}
+
+#[derive(Debug, Clone)]
+pub struct Function {
+ pub unit_ptr: usize,
+ pub arity: usize,
+}
M kabel/tmp.kab => kabel/tmp.kab +1 -1
@@ 5,4 5,4 @@ function bar(i) {
function foo(i) {
return i+1;
}
-print foo(2);
+print foo(bar(k));