WIP evaluating self in method call

This commit is contained in:
Greg Shuflin 2021-12-08 16:18:27 -08:00
parent b5ec8116a2
commit d913443e97
4 changed files with 52 additions and 11 deletions

View File

@ -127,7 +127,7 @@ impl<'a, 'b> Reducer<'a, 'b> {
use crate::ast::ExpressionKind::*;
match &expr.kind {
SelfValue => panic!(),
SelfValue => Expression::Lookup(Lookup::SelfParam),
NatLiteral(n) => Expression::Literal(Literal::Nat(*n)),
FloatLiteral(f) => Expression::Literal(Literal::Float(*f)),
//TODO implement handling string literal prefixes
@ -136,10 +136,19 @@ impl<'a, 'b> Reducer<'a, 'b> {
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 } => Expression::Call {
f: Box::new(self.expression(f)),
args: arguments.iter().map(|arg| self.invocation_argument(arg)).collect(),
},
Call { f, arguments } => {
let f = self.expression(f);
let args = arguments.iter().map(|arg| self.invocation_argument(arg)).collect();
//TODO need to have full type availability at this point to do this method lookup
//correctly
if let Expression::Access { name, expr } = f {
let def_id = unimplemented!();
let method = Expression::Lookup(Lookup::Function(def_id));
Expression::CallMethod { f: Box::new(method), args, self_expr: expr }
} else {
Expression::Call { f: Box::new(f), args }
}
}
TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
IfExpression { discriminator, body } =>
self.reduce_if_expression(discriminator.as_ref().map(|x| x.as_ref()), body),

View File

@ -57,6 +57,7 @@ pub enum Expression {
Access { name: String, expr: Box<Expression> },
Callable(Callable),
Call { f: Box<Expression>, args: Vec<Expression> },
CallMethod { f: Box<Expression>, args: Vec<Expression>, self_expr: Box<Expression> },
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> },
Loop { cond: Box<Expression>, statements: Vec<Statement> },
@ -90,6 +91,7 @@ pub enum Lookup {
GlobalVar(DefId),
Function(DefId),
Param(u8),
SelfParam,
}
#[derive(Debug, Clone, PartialEq)]

View File

@ -133,6 +133,13 @@ impl<'a, 'b> Evaluator<'a, 'b> {
e => return Err(format!("Param lookup error, got {:?}", e).into()),
}
}
Lookup::SelfParam => {
let mem = Memory::self_param();
match self.state.environments.lookup(&mem) {
Some(MemoryValue::Primitive(prim)) => prim.clone(),
e => return Err(format!("SelfParam lookup error, got {:?}", e).into()),
}
}
Lookup::LocalVar(ref id) | Lookup::GlobalVar(ref id) => {
let mem = id.into();
match self.state.environments.lookup(&mem) {
@ -151,7 +158,9 @@ impl<'a, 'b> Evaluator<'a, 'b> {
self.state.environments.insert(mem, MemoryValue::Primitive(evaluated));
Primitive::unit()
}
Expression::Call { box f, args } => self.call_expression(f, args)?,
Expression::Call { box f, args } => self.call_expression(f, args, None)?,
Expression::CallMethod { box f, args, box self_expr } =>
self.call_expression(f, args, Some(self_expr))?,
Expression::Callable(Callable::DataConstructor { type_id, tag }) => {
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
if arity == 0 {
@ -314,7 +323,13 @@ impl<'a, 'b> Evaluator<'a, 'b> {
Err("No valid match in match expression".into())
}
fn call_expression(&mut self, f: Expression, args: Vec<Expression>) -> EvalResult<Primitive> {
//TODO need to do something with self_expr to make method invocations actually work
fn call_expression(
&mut self,
f: Expression,
args: Vec<Expression>,
self_expr: Option<Expression>,
) -> EvalResult<Primitive> {
let func = match self.expression(f)? {
Primitive::Callable(func) => func,
other => return Err(format!("Trying to call non-function value: {:?}", other).into()),
@ -326,7 +341,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
match self.state.environments.lookup(&mem) {
Some(MemoryValue::Function(FunctionDefinition { body })) => {
let body = body.clone(); //TODO ideally this clone would not happen
self.apply_function(body, args)
self.apply_function(body, args, self_expr)
}
e => Err(format!("Error looking up function with id {}: {:?}", def_id, e).into()),
}
@ -340,7 +355,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
)
.into());
}
self.apply_function(body, args)
self.apply_function(body, args, None)
}
Callable::DataConstructor { type_id, tag } => {
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
@ -469,7 +484,13 @@ impl<'a, 'b> Evaluator<'a, 'b> {
})
}
fn apply_function(&mut self, body: Vec<Statement>, args: Vec<Expression>) -> EvalResult<Primitive> {
fn apply_function(
&mut self,
body: Vec<Statement>,
args: Vec<Expression>,
self_expr: Option<Expression>,
) -> EvalResult<Primitive> {
let self_expr = if let Some(expr) = self_expr { Some(self.expression(expr)?) } else { None };
let mut evaluated_args: Vec<Primitive> = vec![];
for arg in args.into_iter() {
evaluated_args.push(self.expression(arg)?);
@ -478,12 +499,15 @@ impl<'a, 'b> Evaluator<'a, 'b> {
let mut frame_state = State { environments: self.state.environments.new_scope(None) };
let mut evaluator = Evaluator::new(&mut frame_state, self.type_context);
if let Some(evaled) = self_expr {
let mem = Memory::self_param();
evaluator.state.environments.insert(mem, MemoryValue::Primitive(evaled));
}
for (n, evaled) in evaluated_args.into_iter().enumerate() {
let n = n as u8;
let mem = n.into();
evaluator.state.environments.insert(mem, MemoryValue::Primitive(evaled));
}
evaluator.block(body)
}
}

View File

@ -24,6 +24,12 @@ enum Memory {
Index(u32),
}
impl Memory {
fn self_param() -> Self {
Memory::Index(3_999_999)
}
}
// This is for function param lookups, and is a hack
impl From<u8> for Memory {
fn from(n: u8) -> Self {