Function application working again

This commit is contained in:
Greg Shuflin 2021-10-24 17:57:56 -07:00
parent 16164c2235
commit 7282a38a08
4 changed files with 84 additions and 16 deletions

View File

@ -118,7 +118,13 @@ impl<'a> Reducer<'a> {
BinExp(binop, lhs, rhs) => self.binop(binop, lhs, rhs),
PrefixExp(op, arg) => self.prefix(op, arg),
Value(qualified_name) => self.value(qualified_name),
Call { f, arguments } => Unimplemented, // self.reduce_call_expression(f, arguments),
Call { f, arguments } => Expression::Call {
f: Box::new(self.expression(f)),
args: arguments
.iter()
.map(|arg| self.invocation_argument(arg))
.collect(),
},
TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
IfExpression {
discriminator,
@ -133,6 +139,15 @@ impl<'a> Reducer<'a> {
}
}
fn invocation_argument(&mut self, invoc: &ast::InvocationArgument) -> Expression {
use crate::ast::InvocationArgument::*;
match invoc {
Positional(ex) => self.expression(ex),
Keyword { .. } => Expression::ReductionError("Keyword arguments not supported".to_string()),
Ignored => Expression::ReductionError("Ignored arguments not supported".to_string()),
}
}
fn function(&mut self, statements: &ast::Block) -> Vec<Statement> {
statements.iter().filter_map(|stmt| self.function_internal_statement(stmt)).collect()
}
@ -201,7 +216,7 @@ impl<'a> Reducer<'a> {
Func(_) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Function },
GlobalBinding => Expression::Lookup { id: def_id.clone(), kind: Lookup::GlobalVar },
LocalVariable => Expression::Lookup { id: def_id.clone(), kind: Lookup::LocalVar },
FunctionParam(_) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Param },
FunctionParam(n) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Param(*n) },
DataConstructor { index, arity, .. } => {
Expression::Unimplemented
},

View File

@ -2,7 +2,10 @@ use std::collections::HashMap;
use std::rc::Rc;
use crate::builtin::Builtin;
use crate::symbol_table::{DefId, Symbol, SymbolSpec, SymbolTable};
use crate::symbol_table::{DefId, SymbolTable};
//TODO most of these Clone impls only exist to support function application, because the
//tree-walking evaluator moves the reduced IR members.
/// The reduced intermediate representation consists of a list of function definitions, and a block
/// of entrypoint statements. In a repl or script context this can be an arbitrary list of
@ -14,7 +17,7 @@ pub struct ReducedIR {
}
impl ReducedIR {
fn debug(&self, symbol_table: &SymbolTable) {
pub fn debug(&self, symbol_table: &SymbolTable) {
println!("Reduced IR:");
println!("Functions:");
println!("-----------");
@ -32,7 +35,7 @@ impl ReducedIR {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Statement {
Expression(Expression),
Binding {
@ -42,7 +45,7 @@ pub enum Statement {
},
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Expression {
Literal(Literal),
Tuple(Vec<Expression>),
@ -80,12 +83,12 @@ pub enum Function {
UserDefined(DefId)
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Lookup {
LocalVar,
GlobalVar,
Function,
Param,
Param(u8),
}
#[derive(Debug, Clone)]

View File

@ -1,7 +1,7 @@
use std::rc::Rc;
use crate::ast::*;
use crate::symbol_table::{Fqsn, Scope, SymbolTable, Symbol, SymbolSpec, DefId};
use crate::symbol_table::{Fqsn, Scope, SymbolTable, SymbolSpec};
use crate::util::ScopeStack;
type FqsnPrefix = Vec<Scope>;

View File

@ -21,6 +21,13 @@ enum Memory {
Index(u32)
}
// This is for function param lookups, and is a hack
impl From<u8> for Memory {
fn from(n: u8) -> Self {
Memory::Index(4_000_000 + (n as u32))
}
}
impl From<&DefId> for Memory {
fn from(id: &DefId) -> Self {
Self::Index(id.as_u32())
@ -159,6 +166,21 @@ impl<'a> State<'a> {
acc
}
fn block(&mut self, statements: Vec<Statement>) -> EvalResult<Primitive> {
//TODO need to handle breaks, returns, etc.
let mut ret = None;
for stmt in statements.into_iter() {
if let Some(RuntimeValue::Primitive(prim)) = self.statement(stmt)? {
ret = Some(prim);
}
}
Ok(if let Some(ret) = ret {
ret
} else {
self.expression(Expression::unit())?
})
}
fn statement(&mut self, stmt: Statement) -> EvalResult<Option<RuntimeValue>> {
match stmt {
Statement::Binding { ref id, expr, constant } => {
@ -179,14 +201,25 @@ impl<'a> State<'a> {
Expression::Literal(lit) => Primitive::Literal(lit),
Expression::Tuple(items) => Primitive::Tuple(items.into_iter().map(|expr| self.expression(expr)).collect::<EvalResult<Vec<Primitive>>>()?),
Expression::Lookup { ref id, kind } => {
let mem = id.into();
match kind {
Lookup::Function => match self.environments.lookup(&mem) {
//TODO is this right? not sure
Some(RuntimeValue::Primitive(prim)) => prim.clone(),
_ => return Err(format!("Function not found for id: {}", id)),
Lookup::Function => {
let mem = id.into();
match self.environments.lookup(&mem) {
// This just checks that the function exists in "memory" by ID, we don't
// actually retrieve it until `apply_function()`
Some(RuntimeValue::Function(_)) => Primitive::Callable(Function::UserDefined(id.clone())),
x => return Err(format!("Function not found for id: {} : {:?}", id, x)),
}
},
kind @ Lookup::LocalVar | kind @ Lookup::GlobalVar | kind @ Lookup::Param => {
Lookup::Param(n) => {
let mem = n.into();
match self.environments.lookup(&mem) {
Some(RuntimeValue::Primitive(prim)) => prim.clone(),
e => return Err(format!("Param lookup error, got {:?}", e)),
}
},
kind @ Lookup::LocalVar | kind @ Lookup::GlobalVar => {
let mem = id.into();
match self.environments.lookup(&mem) {
Some(RuntimeValue::Primitive(expr)) => expr.clone(),
_ => return Err(format!("Nothing found for variable lookup {} of kind {:?}", id, kind)),
@ -302,7 +335,24 @@ impl<'a> State<'a> {
let mem = (&def_id).into();
Ok(match self.environments.lookup(&mem) {
Some(RuntimeValue::Function(FunctionDefinition { body })) => {
return Err("unimplemented apply-function".to_string());
let body = body.clone(); //TODO ideally this clone would not happen
let mut evaluated_args: Vec<Primitive> = vec![];
for arg in args.into_iter() {
evaluated_args.push(self.expression(arg)?);
}
let mut frame_state = State {
environments: self.environments.new_scope(None)
};
for (n, evaled) in evaluated_args.into_iter().enumerate() {
let n = n as u8;
let mem = n.into();
frame_state.environments.insert(mem, RuntimeValue::Primitive(evaled));
}
frame_state.block(body)?
},
e => return Err(format!("Error looking up function with id {}: {:?}", def_id, e)),
})