Skip to content

Commit c06fe60

Browse files
Refactor function resolution to support polymorphism and function arguments
Functions are now stored in the environment using their full signatures rather than just their names. This allows support for polymorphic functions and multiple overloads with different type parameters. Additionally, when evaluating a FuncCall whose target is an Expression::Var, the resolution process has changed. Instead of directly evaluating the variable and assuming it holds a value, we now perform a scoped lookup. In each environment scope, we first look for a variable with the given name; if not found, we then look for a function. This behavior ensures variables shadow functions of the same name in the same scope. This change allows function values to be passed as arguments and gives priority to local variables when both a function and variable share the same identifier, enabling more flexible and predictable behavior in higher-order and polymorphic scenarios
1 parent f6f4666 commit c06fe60

6 files changed

Lines changed: 301 additions & 79 deletions

File tree

src/environment/environment.rs

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
use crate::ir::ast::FuncSignature;
12
use crate::ir::ast::Function;
23
use crate::ir::ast::Name;
34
use crate::ir::ast::ValueConstructor;
45
use std::collections::HashMap;
56
use std::collections::LinkedList;
7+
use std::fmt::Debug;
68

79
#[derive(Clone)]
810
pub struct Scope<A> {
911
pub variables: HashMap<Name, (bool, A)>,
10-
pub functions: HashMap<Name, Function>,
12+
pub functions: HashMap<FuncSignature, Function>,
1113
pub adts: HashMap<Name, Vec<ValueConstructor>>,
1214
}
1315

@@ -26,7 +28,8 @@ impl<A: Clone> Scope<A> {
2628
}
2729

2830
fn map_function(&mut self, function: Function) -> () {
29-
self.functions.insert(function.name.clone(), function);
31+
let func_signature = FuncSignature::from_func(&function);
32+
self.functions.insert(func_signature, function);
3033
return ();
3134
}
3235

@@ -41,8 +44,18 @@ impl<A: Clone> Scope<A> {
4144
.map(|(mutable, value)| (*mutable, value.clone()))
4245
}
4346

44-
fn lookup_function(&self, name: &Name) -> Option<&Function> {
45-
self.functions.get(name)
47+
fn lookup_function(&self, func_signature: &FuncSignature) -> Option<&Function> {
48+
self.functions.get(func_signature)
49+
}
50+
51+
fn lookup_function_by_name(&self, name: &Name) -> Option<&Function> {
52+
self.functions.iter().find_map(|(signature, function)| {
53+
if &signature.name == name {
54+
Some(function)
55+
} else {
56+
None
57+
}
58+
})
4659
}
4760

4861
fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
@@ -51,30 +64,30 @@ impl<A: Clone> Scope<A> {
5164
}
5265

5366
#[derive(Clone)]
54-
pub struct Environment<A> {
55-
pub current_func: String,
67+
pub struct Environment<A: Clone + Debug> {
68+
pub current_func: FuncSignature,
5669
pub globals: Scope<A>,
5770
pub stack: LinkedList<Scope<A>>,
5871
}
5972

60-
impl<A: Clone> Environment<A> {
73+
impl<A: Clone + Debug> Environment<A> {
6174
pub fn new() -> Environment<A> {
6275
Environment {
63-
current_func: String::new(),
76+
current_func: FuncSignature::new(),
6477
globals: Scope::new(),
6578
stack: LinkedList::new(),
6679
}
6780
}
6881

69-
pub fn get_current_func(&self) -> String {
82+
pub fn get_current_func(&self) -> FuncSignature {
7083
return self.current_func.clone();
7184
}
7285

73-
pub fn set_current_func(&mut self, func_name: &str) {
74-
self.current_func = func_name.to_string();
86+
pub fn set_current_func(&mut self, func_signature: &FuncSignature) {
87+
self.current_func = func_signature.clone();
7588
}
7689

77-
pub fn set_global_functions(&mut self, global_functions: HashMap<Name, Function>) {
90+
pub fn set_global_functions(&mut self, global_functions: HashMap<FuncSignature, Function>) {
7891
self.globals.functions = global_functions;
7992
}
8093

@@ -108,13 +121,31 @@ impl<A: Clone> Environment<A> {
108121
self.globals.lookup_var(var)
109122
}
110123

111-
pub fn lookup_function(&self, name: &Name) -> Option<&Function> {
124+
pub fn lookup_function(&self, func_signature: &FuncSignature) -> Option<&Function> {
112125
for scope in self.stack.iter() {
113-
if let Some(func) = scope.lookup_function(name) {
126+
if let Some(func) = scope.lookup_function(func_signature) {
114127
return Some(func);
115128
}
116129
}
117-
self.globals.lookup_function(name)
130+
self.globals.lookup_function(func_signature)
131+
}
132+
133+
pub fn lookup_var_or_func(&self, name: &Name) -> Option<FuncOrVar<A>> {
134+
for scope in self.stack.iter() {
135+
if let Some(value) = scope.lookup_var(name) {
136+
return Some(FuncOrVar::Var(value));
137+
}
138+
if let Some(func) = scope.lookup_function_by_name(name) {
139+
return Some(FuncOrVar::Func(func.clone()));
140+
}
141+
}
142+
if let Some(value) = self.globals.lookup_var(name) {
143+
return Some(FuncOrVar::Var(value));
144+
}
145+
if let Some(func) = self.globals.lookup_function_by_name(name) {
146+
return Some(FuncOrVar::Func(func.clone()));
147+
}
148+
return None;
118149
}
119150

120151
pub fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
@@ -160,20 +191,26 @@ impl<A: Clone> Environment<A> {
160191
}
161192

162193
// The type checker ensures that each function is defined only once
163-
pub fn get_all_functions(&self) -> HashMap<Name, Function> {
194+
pub fn get_all_functions(&self) -> HashMap<FuncSignature, Function> {
164195
let mut all_functions = HashMap::new();
165-
for (name, func) in &self.globals.functions {
166-
all_functions.insert(name.clone(), func.clone());
196+
for (func_signature, func) in &self.globals.functions {
197+
all_functions.insert(func_signature.clone(), func.clone());
167198
}
168199
for scope in self.stack.iter() {
169-
for (name, func) in &scope.functions {
170-
all_functions.insert(name.clone(), func.clone());
200+
for (func_signature, func) in &scope.functions {
201+
all_functions.insert(func_signature.clone(), func.clone());
171202
}
172203
}
173204
all_functions
174205
}
175206
}
176207

208+
pub enum FuncOrVar<A: Clone + Debug> {
209+
Func(Function),
210+
Var((bool, A)),
211+
}
212+
213+
/*
177214
#[cfg(test)]
178215
mod tests {
179216
use super::*;
@@ -245,3 +282,4 @@ mod tests {
245282
assert!(env.lookup_function(&"local".to_string()).is_none()); // local gone
246283
}
247284
}
285+
*/

src/interpreter/expression_eval.rs

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use super::statement_execute::Computation;
2-
use crate::environment::environment::{Environment, Scope};
2+
use crate::environment::environment::{Environment, FuncOrVar};
33
use crate::ir::ast::{Expression, Name};
4+
use crate::ir::ast::{FuncSignature, Type};
5+
use crate::type_checker::check_expr;
46

57
#[derive(Debug, PartialEq, Clone)]
68
pub enum ExpressionResult {
@@ -383,51 +385,99 @@ pub fn eval_lookup(
383385

384386
// Function call
385387
pub fn eval_function_call(
386-
name: Name,
388+
func_name: Name,
387389
args: Vec<Expression>,
388390
env: &Environment<Expression>,
389391
) -> Result<ExpressionResult, String> {
390-
match env.lookup_function(&name) {
391-
Some(function_definition) => {
392-
let mut new_env = Environment::new();
392+
let mut actual_arg_values = Vec::new();
393+
let mut actual_arg_types = Vec::new();
394+
for arg in args.iter() {
395+
match arg {
396+
Expression::Var(name) => match env.lookup_var_or_func(name) {
397+
Some(FuncOrVar::Var((_, _var_exp))) => match eval_lookup(name.to_string(), env)? {
398+
ExpressionResult::Propagate(expr) => {
399+
return Ok(ExpressionResult::Propagate(expr));
400+
}
401+
ExpressionResult::Value(expr) => {
402+
actual_arg_values.push(expr);
403+
}
404+
},
405+
Some(FuncOrVar::Func(func)) => {
406+
actual_arg_values.push(Expression::Lambda(func));
407+
}
408+
None => return Err(format!("Identifier '{}' was never declared", name)),
409+
},
410+
_ => match eval(arg.clone(), env)? {
411+
ExpressionResult::Value(expr) => {
412+
actual_arg_values.push(expr);
413+
}
414+
ExpressionResult::Propagate(expr) => {
415+
return Ok(ExpressionResult::Propagate(expr));
416+
}
417+
},
418+
}
419+
}
420+
for value in &actual_arg_values {
421+
actual_arg_types.push(check_expr(value.clone(), &Environment::<Type>::new())?);
422+
}
393423

394-
if args.len() != function_definition.params.len() {
395-
return Err(format!(
396-
"[Runtime Error] Invalid number of arguments for '{}'.",
397-
name
398-
));
399-
}
424+
let func_signature = FuncSignature {
425+
name: func_name.clone(),
426+
argument_types: actual_arg_types.clone(),
427+
};
428+
match env.lookup_function(&func_signature).cloned() {
429+
Some(func) => {
430+
431+
let mut new_env = Environment::new();
400432

401-
// new_env.push(); <- Removed the push; parameters are now mapped directly to the global scope
402-
//In this new environment, external functions and actual parameters are regarded as globally accessible
403-
//This is justified, since their visibility extends across the entire function body
404-
new_env.set_current_func(&name);
433+
new_env.set_current_func(&func_signature);
405434
// Functions from the outer environment must be propagated to new_env to ensure access to external functions within the function body.
406435
// This also allows the function to reference itself, which enables recursion
407436
new_env.set_global_functions(env.get_all_functions());
408437

409-
for (formal, actual) in function_definition.params.iter().zip(args.iter()) {
410-
let value = match eval(actual.clone(), env)? {
411-
ExpressionResult::Value(expr) => expr,
412-
ExpressionResult::Propagate(expr) => {
413-
return Ok(ExpressionResult::Propagate(expr))
438+
for (formal_arg, value) in func.params.iter().zip(actual_arg_values.iter()) {
439+
match formal_arg.argument_type {
440+
Type::TFunction(..) => {
441+
match value {
442+
Expression::Lambda(arg_func) => {
443+
let mut inner_func = arg_func.clone();
444+
inner_func.name = formal_arg.argument_name.clone();
445+
new_env.map_function(inner_func);
446+
}
447+
//This will never happen, but I need to cover all cases, otherwise it won't compile
448+
_ => {
449+
return Err(format!(
450+
"[Runtime Error] Function {} expected another function as argument, but received a non functional argument",
451+
func_name
452+
));
453+
}
454+
}
414455
}
415-
};
416-
new_env.map_variable(formal.argument_name.clone(), false, value);
456+
_ => {
457+
new_env.map_variable(
458+
formal_arg.argument_name.clone(),
459+
false,
460+
value.clone(),
461+
);
462+
}
463+
}
417464
}
418465

419466
// Execute the body of the function.
420-
match super::statement_execute::execute(
421-
*function_definition.body.as_ref().unwrap().clone(), //Push occurs here, because function body is a Statement::Block
422-
&new_env,
423-
) {
467+
match super::statement_execute::execute(*func.body.as_ref().unwrap().clone(), &new_env)
468+
{
424469
Ok(Computation::Continue(_)) => Err("Function did not return a value".to_string()),
425-
Ok(Computation::Return(value, _)) => Ok(ExpressionResult::Value(value)),
470+
Ok(Computation::Return(value, _final_env)) => {
471+
Ok(ExpressionResult::Value(value))
472+
}
426473
Ok(Computation::PropagateError(value, _)) => Ok(ExpressionResult::Propagate(value)),
427474
Err(e) => Err(e),
428475
}
429476
}
430-
_ => Err(format!("Function {} not found", name)),
477+
478+
_ => {
479+
Err(format!("Function '{}' not found", func_signature))
480+
}
431481
}
432482
}
433483

0 commit comments

Comments
 (0)