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), BinExp(binop, lhs, rhs) => self.binop(binop, lhs, rhs),
PrefixExp(op, arg) => self.prefix(op, arg), PrefixExp(op, arg) => self.prefix(op, arg),
Value(qualified_name) => self.value(qualified_name), 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()), TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
IfExpression { IfExpression {
discriminator, 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> { fn function(&mut self, statements: &ast::Block) -> Vec<Statement> {
statements.iter().filter_map(|stmt| self.function_internal_statement(stmt)).collect() 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 }, Func(_) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Function },
GlobalBinding => Expression::Lookup { id: def_id.clone(), kind: Lookup::GlobalVar }, GlobalBinding => Expression::Lookup { id: def_id.clone(), kind: Lookup::GlobalVar },
LocalVariable => Expression::Lookup { id: def_id.clone(), kind: Lookup::LocalVar }, 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, .. } => { DataConstructor { index, arity, .. } => {
Expression::Unimplemented Expression::Unimplemented
}, },

View File

@ -2,7 +2,10 @@ use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use crate::builtin::Builtin; 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 /// 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 /// 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 { impl ReducedIR {
fn debug(&self, symbol_table: &SymbolTable) { pub fn debug(&self, symbol_table: &SymbolTable) {
println!("Reduced IR:"); println!("Reduced IR:");
println!("Functions:"); println!("Functions:");
println!("-----------"); println!("-----------");
@ -32,7 +35,7 @@ impl ReducedIR {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Statement { pub enum Statement {
Expression(Expression), Expression(Expression),
Binding { Binding {
@ -42,7 +45,7 @@ pub enum Statement {
}, },
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Expression { pub enum Expression {
Literal(Literal), Literal(Literal),
Tuple(Vec<Expression>), Tuple(Vec<Expression>),
@ -80,12 +83,12 @@ pub enum Function {
UserDefined(DefId) UserDefined(DefId)
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Lookup { pub enum Lookup {
LocalVar, LocalVar,
GlobalVar, GlobalVar,
Function, Function,
Param, Param(u8),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -1,7 +1,7 @@
use std::rc::Rc; use std::rc::Rc;
use crate::ast::*; 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; use crate::util::ScopeStack;
type FqsnPrefix = Vec<Scope>; type FqsnPrefix = Vec<Scope>;

View File

@ -21,6 +21,13 @@ enum Memory {
Index(u32) 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 { impl From<&DefId> for Memory {
fn from(id: &DefId) -> Self { fn from(id: &DefId) -> Self {
Self::Index(id.as_u32()) Self::Index(id.as_u32())
@ -159,6 +166,21 @@ impl<'a> State<'a> {
acc 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>> { fn statement(&mut self, stmt: Statement) -> EvalResult<Option<RuntimeValue>> {
match stmt { match stmt {
Statement::Binding { ref id, expr, constant } => { Statement::Binding { ref id, expr, constant } => {
@ -179,14 +201,25 @@ impl<'a> State<'a> {
Expression::Literal(lit) => Primitive::Literal(lit), Expression::Literal(lit) => Primitive::Literal(lit),
Expression::Tuple(items) => Primitive::Tuple(items.into_iter().map(|expr| self.expression(expr)).collect::<EvalResult<Vec<Primitive>>>()?), Expression::Tuple(items) => Primitive::Tuple(items.into_iter().map(|expr| self.expression(expr)).collect::<EvalResult<Vec<Primitive>>>()?),
Expression::Lookup { ref id, kind } => { Expression::Lookup { ref id, kind } => {
let mem = id.into();
match kind { match kind {
Lookup::Function => match self.environments.lookup(&mem) { Lookup::Function => {
//TODO is this right? not sure let mem = id.into();
Some(RuntimeValue::Primitive(prim)) => prim.clone(), match self.environments.lookup(&mem) {
_ => return Err(format!("Function not found for id: {}", id)), // 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) { match self.environments.lookup(&mem) {
Some(RuntimeValue::Primitive(expr)) => expr.clone(), Some(RuntimeValue::Primitive(expr)) => expr.clone(),
_ => return Err(format!("Nothing found for variable lookup {} of kind {:?}", id, kind)), _ => 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(); let mem = (&def_id).into();
Ok(match self.environments.lookup(&mem) { Ok(match self.environments.lookup(&mem) {
Some(RuntimeValue::Function(FunctionDefinition { body })) => { 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)), e => return Err(format!("Error looking up function with id {}: {:?}", def_id, e)),
}) })