Function application working again
This commit is contained in:
parent
16164c2235
commit
7282a38a08
@ -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
|
||||
},
|
||||
|
@ -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)]
|
||||
|
@ -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>;
|
||||
|
@ -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)),
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user