diff --git a/schala-lang/src/reduced_ir/mod.rs b/schala-lang/src/reduced_ir/mod.rs index 53bdbba..e4f0fe6 100644 --- a/schala-lang/src/reduced_ir/mod.rs +++ b/schala-lang/src/reduced_ir/mod.rs @@ -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), diff --git a/schala-lang/src/reduced_ir/types.rs b/schala-lang/src/reduced_ir/types.rs index b6fd275..f5ac67d 100644 --- a/schala-lang/src/reduced_ir/types.rs +++ b/schala-lang/src/reduced_ir/types.rs @@ -57,6 +57,7 @@ pub enum Expression { Access { name: String, expr: Box }, Callable(Callable), Call { f: Box, args: Vec }, + CallMethod { f: Box, args: Vec, self_expr: Box }, Conditional { cond: Box, then_clause: Vec, else_clause: Vec }, CaseMatch { cond: Box, alternatives: Vec }, Loop { cond: Box, statements: Vec }, @@ -90,6 +91,7 @@ pub enum Lookup { GlobalVar(DefId), Function(DefId), Param(u8), + SelfParam, } #[derive(Debug, Clone, PartialEq)] diff --git a/schala-lang/src/tree_walk_eval/evaluator.rs b/schala-lang/src/tree_walk_eval/evaluator.rs index 843b5a7..91a4442 100644 --- a/schala-lang/src/tree_walk_eval/evaluator.rs +++ b/schala-lang/src/tree_walk_eval/evaluator.rs @@ -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) -> EvalResult { + //TODO need to do something with self_expr to make method invocations actually work + fn call_expression( + &mut self, + f: Expression, + args: Vec, + self_expr: Option, + ) -> EvalResult { 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, args: Vec) -> EvalResult { + fn apply_function( + &mut self, + body: Vec, + args: Vec, + self_expr: Option, + ) -> EvalResult { + let self_expr = if let Some(expr) = self_expr { Some(self.expression(expr)?) } else { None }; let mut evaluated_args: Vec = 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) } } diff --git a/schala-lang/src/tree_walk_eval/mod.rs b/schala-lang/src/tree_walk_eval/mod.rs index 60ecd7f..c575d51 100644 --- a/schala-lang/src/tree_walk_eval/mod.rs +++ b/schala-lang/src/tree_walk_eval/mod.rs @@ -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 for Memory { fn from(n: u8) -> Self {