DEV: Function calls work. Also wired up some of the bang opcode.

This commit is contained in:
Jeremy Wall 2019-08-14 19:52:41 -05:00
parent f9c3ebeb50
commit e998e582ae
4 changed files with 54 additions and 20 deletions

View File

@ -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,

View File

@ -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)),
];
}

View File

@ -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"),
}

View File

@ -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<P: Into<PathBuf>>(
@ -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()?;