Finish up function call implementation, it appears to be working

Functions are downcasted to a `Fun` trait, which will construct the
appropriate stack frame.

A few other things have been shifted around that affect internal APIs
while things are still under construction.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-10-07 15:48:24 -07:00
parent 0ca8dc64b2
commit dd7cd04b39
9 changed files with 286 additions and 164 deletions

View File

@@ -23,10 +23,14 @@ impl Compile {
/// Compiles the given AST body.
pub fn compile(mut self, body: &Body) -> error::Result<(ConstPool, UserFunRef)> {
self.push_scope_layer();
let main = thunk::CompileBody::new(&mut self)
let mut main = thunk::CompileBody::new(&mut self)
.compile(body)?
.flatten()
.to_vec();
// XXX TODO(compile)
// remove this when we get returns implemented
main.push(crate::vm::inst::Inst::PushSym(crate::obj::reserved::NIL_NAME.sym));
main.push(crate::vm::inst::Inst::Return);
let globals_syms: std::collections::BTreeMap<_, _> = self.pop_scope_layer().unwrap()
.into_iter()
.map(|(sym, name)| (name, sym))

View File

@@ -1,17 +1,10 @@
use crate::obj::prelude::*;
use std::collections::BTreeMap;
// current TODO/problem: How should locals work?
//
// * I think we should have a global/local dichotomy in the VM. You can only look up the local
// scope in the VM; inner functions that have captures should be created on the fly and detected
// by the compiler. I.E. any lookups that are not local or global should be captured dynamically.
// * Need to differentiate between locals collected on the compilation side vs. locals on the
// object/vm side
pub type ScopeLocalSyms = BTreeMap<Sym, Name>;
pub type ScopeLocals = Vec<Sym>;
#[derive(Debug, Default)]
pub struct Scope {
scope: Vec<ScopeLocalSyms>,
}
@@ -77,10 +70,3 @@ impl Scope {
self.scope.first_mut()
}
}
impl Default for Scope {
fn default() -> Self {
// empty global scope
Self { scope: vec![Default::default()] }
}
}

View File

@@ -382,9 +382,13 @@ impl Visit for CompileBody<'_> {
})
.collect();
let code = self.visit_body(&expr.body)?
let mut code = self.visit_body(&expr.body)?
.flatten()
.to_vec();
// XXX TODO(compile)
// remove this when we get returns implemented
code.push(Inst::PushSym(crate::obj::reserved::NIL_NAME.sym));
code.push(Inst::Return);
let (hdl, _fun) = self.compile.push_const(UserFun::new_obj(code, locals));
// TODO(compile) : determine return value at the end of the body (preferably at parse-time)
@@ -397,6 +401,7 @@ impl Visit for CompileBody<'_> {
let thunk = match atom {
Atom::Ident(ident) => {
let sym = global_sym(ident.to_string());
// TODO : use "LOAD_GLOBAL" instead of "LOAD_LOCAL" when inside a user function
if let Some(local) = self.compile.lookup_local(sym) {
// get local
Inst::LoadLocal(local).into()