diff --git a/src/build/opcode/mod.rs b/src/build/opcode/mod.rs index 442ef25..3215448 100644 --- a/src/build/opcode/mod.rs +++ b/src/build/opcode/mod.rs @@ -195,8 +195,8 @@ pub enum Op { Noop, // Pending Computation InitThunk(i32), // Basically just used for module return expressions - Module(usize), - Func(usize), + Module(i32), + Func(i32), Return, // Calls FCall, diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index 050b324..6cd47d6 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -346,7 +346,7 @@ fn function_definition_and_call() { InitList, // 1 Sym("arg".to_owned()), // 2 Element, // 3 - Func(6), // 4 + Func(2), // 4 DeRef("arg".to_owned()), // 5 Return, // 6 Bind, // 7 @@ -362,7 +362,7 @@ fn function_definition_and_call() { InitList, // 4 Sym("arg".to_owned()), // 5 Element, // 6 - Func(11), // 7 + Func(4), // 7 DeRef("arg".to_owned()), // 8 DeRef("closed".to_owned()), // 9 Add, // 10 @@ -391,7 +391,7 @@ fn module_call() { Sym("two".to_owned()), // 9 Val(Int(2)), // 10 Field, // 11 - Module(17), // 12 // Module body definition + Module(5), // 12 // Module body definition Bind, // 13 // bind the mod tuple Sym("foo".to_owned()), // 14 DeRef("mod".to_owned()), // 15 @@ -425,7 +425,7 @@ fn module_call() { InitThunk(2), // 12 // Module Return expression Val(Int(1)), // 13 Return, // 14 - Module(20), // 15 // Module definition + Module(5), // 15 // Module definition Bind, // 16 Sym("foo".to_owned()), // 17 DeRef("mod".to_owned()), // 18 @@ -708,3 +708,11 @@ fn simple_format_expressions() { "\"@{item.num}\" % {num=1};" => P(Str("1".to_owned())), ]; } + +#[test] +fn simple_functions() { + assert_parse_cases![ + "let f = func(val) => val; f(1);" => P(Int(1)), + "let f = func(val1, val2) => val1 + val2; f(1, 1);" => P(Int(2)), + ]; +} diff --git a/src/build/opcode/translate.rs b/src/build/opcode/translate.rs index 10a08bd..2d6d3ca 100644 --- a/src/build/opcode/translate.rs +++ b/src/build/opcode/translate.rs @@ -15,8 +15,7 @@ use crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value}; use crate::ast::{Position, TemplatePart}; use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser}; use crate::build::opcode::Primitive; -use crate::build::opcode::Value::{C, F, M, P, T}; -use crate::build::opcode::{Hook, Op}; +use crate::build::opcode::{Func, Hook, Op}; pub struct AST(); @@ -252,7 +251,19 @@ impl AST { } } } - Expression::Func(_) => unimplemented!("Func expressions are not implmented yet"), + Expression::Func(def) => { + ops.push(Op::InitList); + for b in def.argdefs { + ops.push(Op::Sym(b.val)); + ops.push(Op::Element); + } + ops.push(Op::Noop); + let idx = ops.len() - 1; + Self::translate_expr(*def.fields, &mut ops); + ops.push(Op::Return); + let jptr = ops.len() - 1 - idx; + ops[idx] = Op::Func(jptr as i32); + } Expression::FuncOp(_) => unimplemented!("FuncOp expressions are not implmented yet"), Expression::Import(_) => unimplemented!("Import expressions are not implmented yet"), Expression::Include(_) => unimplemented!("Include expressions are not implmented yet"), @@ -263,7 +274,16 @@ impl AST { } Expression::Range(_) => unimplemented!("Range expressions are not implmented yet"), Expression::Select(_) => unimplemented!("Select expressions are not implmented yet"), - Expression::Call(_) => unimplemented!("Call expressions are not implmented yet"), + Expression::Call(def) => { + // first push our arguments. + for e in def.arglist { + Self::translate_expr(e, &mut ops); + } + // then push the func reference + Self::translate_value(def.funcref, &mut ops); + ops.push(Op::FCall); + dbg!(ops); + } Expression::Copy(_) => unimplemented!("Copy expressions are not implmented yet"), Expression::Debug(_) => unimplemented!("Debug expressions are not implmented yet"), } diff --git a/src/build/opcode/vm.rs b/src/build/opcode/vm.rs index fa034af..a0b424a 100644 --- a/src/build/opcode/vm.rs +++ b/src/build/opcode/vm.rs @@ -104,7 +104,7 @@ impl<'a> VM { Op::SafeIndex => self.op_index(true)?, Op::Cp => self.op_copy()?, //TODO(jwall): Should this take a user provided message? - Op::Bang => return dbg!(Err(Error {})), + Op::Bang => self.op_bang()?, Op::InitThunk(jp) => self.op_thunk(idx, jp)?, Op::Noop => { // Do nothing @@ -234,7 +234,7 @@ impl<'a> VM { Ok(()) } - fn op_module(&'a mut self, idx: usize, jptr: usize) -> Result<(), Error> { + fn op_module(&'a mut self, idx: usize, jptr: i32) -> Result<(), Error> { let mod_val = self.pop()?; let (result_ptr, flds) = match mod_val.as_ref() { &C(Tuple(ref flds)) => (None, flds.clone()), @@ -257,10 +257,10 @@ impl<'a> VM { result_ptr: result_ptr, flds: flds, })))?; - self.ops.jump(jptr) + self.op_jump(jptr) } - fn op_func(&mut self, idx: usize, jptr: usize) -> Result<(), Error> { + fn op_func(&mut self, idx: usize, jptr: i32) -> Result<(), Error> { // get arity from stack let mut scope_snapshot = self.symbols.snapshot(); scope_snapshot.push(); @@ -289,7 +289,7 @@ impl<'a> VM { snapshot: scope_snapshot, })))?; eprintln!("Jumping to {} past the function body", jptr); - self.ops.jump(jptr) + self.op_jump(jptr) } pub fn fcall_impl>( @@ -329,10 +329,10 @@ impl<'a> VM { } fn op_fcall(&mut self) -> Result<(), Error> { - let f = self.pop()?; + let f = dbg!(self.pop())?; if let &F(ref f) = f.as_ref() { let val = Self::fcall_impl(&self.path, f, &mut self.stack)?; - self.push(val)?; + self.push(dbg!(val))?; } Ok(()) } @@ -505,10 +505,10 @@ impl<'a> VM { fn op_element(&mut self) -> Result<(), Error> { // get element from stack. - let val = self.pop()?; + let val = dbg!(self.pop()?); // get next value. It should be a Composite list. - let tpl = self.pop()?; - if let &C(List(ref elems)) = tpl.as_ref() { + let list = dbg!(self.pop()?); + if let &C(List(ref elems)) = list.as_ref() { // add value to list // TODO(jwall): This is probably memory inefficient and we should // optimize it a bit. @@ -559,6 +559,12 @@ impl<'a> VM { } } + fn op_bang(&mut self) -> Result<(), Error> { + let msg = self.pop()?; + // TODO(jwall): record an error here. + Ok(()) + } + fn op_index(&mut self, safe: bool) -> Result<(), Error> { // left and then right let right = self.pop()?;