Skip to content

Commit fa151a4

Browse files
Merge pull request #2 from Rafael-Sapienza/feat/polymorphism_and_func_as_param
Feat/polymorphism and func as param
2 parents f6f4666 + c3aaa1f commit fa151a4

File tree

11 files changed

+408
-135
lines changed

11 files changed

+408
-135
lines changed

src/environment/environment.rs

Lines changed: 66 additions & 21 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,34 @@ 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 get_current_scope(&self) -> &Scope<A> {
87+
self.stack.front().unwrap_or(&self.globals)
88+
}
89+
90+
pub fn set_current_func(&mut self, func_signature: &FuncSignature) {
91+
self.current_func = func_signature.clone();
7592
}
7693

77-
pub fn set_global_functions(&mut self, global_functions: HashMap<Name, Function>) {
94+
pub fn set_global_functions(&mut self, global_functions: HashMap<FuncSignature, Function>) {
7895
self.globals.functions = global_functions;
7996
}
8097

@@ -108,13 +125,31 @@ impl<A: Clone> Environment<A> {
108125
self.globals.lookup_var(var)
109126
}
110127

111-
pub fn lookup_function(&self, name: &Name) -> Option<&Function> {
128+
pub fn lookup_function(&self, func_signature: &FuncSignature) -> Option<&Function> {
112129
for scope in self.stack.iter() {
113-
if let Some(func) = scope.lookup_function(name) {
130+
if let Some(func) = scope.lookup_function(func_signature) {
114131
return Some(func);
115132
}
116133
}
117-
self.globals.lookup_function(name)
134+
self.globals.lookup_function(func_signature)
135+
}
136+
137+
pub fn lookup_var_or_func(&self, name: &Name) -> Option<FuncOrVar<A>> {
138+
for scope in self.stack.iter() {
139+
if let Some(value) = scope.lookup_var(name) {
140+
return Some(FuncOrVar::Var(value));
141+
}
142+
if let Some(func) = scope.lookup_function_by_name(name) {
143+
return Some(FuncOrVar::Func(func.clone()));
144+
}
145+
}
146+
if let Some(value) = self.globals.lookup_var(name) {
147+
return Some(FuncOrVar::Var(value));
148+
}
149+
if let Some(func) = self.globals.lookup_function_by_name(name) {
150+
return Some(FuncOrVar::Func(func.clone()));
151+
}
152+
return None;
118153
}
119154

120155
pub fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
@@ -160,20 +195,29 @@ impl<A: Clone> Environment<A> {
160195
}
161196

162197
// The type checker ensures that each function is defined only once
163-
pub fn get_all_functions(&self) -> HashMap<Name, Function> {
198+
pub fn get_all_functions(&self) -> HashMap<FuncSignature, Function> {
164199
let mut all_functions = HashMap::new();
165-
for (name, func) in &self.globals.functions {
166-
all_functions.insert(name.clone(), func.clone());
200+
for (func_signature, func) in &self.globals.functions {
201+
all_functions.insert(func_signature.clone(), func.clone());
167202
}
168-
for scope in self.stack.iter() {
169-
for (name, func) in &scope.functions {
170-
all_functions.insert(name.clone(), func.clone());
203+
// It is necessary to traverse the scope stack from bottom to top
204+
// so that functions defined in inner scopes can shadow those
205+
// defined in outer scopes.
206+
for scope in self.stack.iter().rev() {
207+
for (func_signature, func) in &scope.functions {
208+
all_functions.insert(func_signature.clone(), func.clone());
171209
}
172210
}
173211
all_functions
174212
}
175213
}
176214

215+
pub enum FuncOrVar<A: Clone + Debug> {
216+
Func(Function),
217+
Var((bool, A)),
218+
}
219+
220+
/*
177221
#[cfg(test)]
178222
mod tests {
179223
use super::*;
@@ -245,3 +289,4 @@ mod tests {
245289
assert!(env.lookup_function(&"local".to_string()).is_none()); // local gone
246290
}
247291
}
292+
*/

src/interpreter/expression_eval.rs

Lines changed: 81 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,102 @@ 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();
393-
394-
if args.len() != function_definition.params.len() {
395-
return Err(format!(
396-
"[Runtime Error] Invalid number of arguments for '{}'.",
397-
name
398-
));
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+
Expression::Lambda(func) => {
411+
actual_arg_values.push(Expression::Lambda(func.clone()));
399412
}
413+
_ => match eval(arg.clone(), env)? {
414+
ExpressionResult::Value(expr) => {
415+
actual_arg_values.push(expr);
416+
}
417+
ExpressionResult::Propagate(expr) => {
418+
return Ok(ExpressionResult::Propagate(expr));
419+
}
420+
},
421+
}
422+
}
423+
for value in &actual_arg_values {
424+
actual_arg_types.push(check_expr(value.clone(), &Environment::<Type>::new())?);
425+
}
400426

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);
427+
let func_signature = FuncSignature {
428+
name: func_name.clone(),
429+
argument_types: actual_arg_types.clone(),
430+
};
431+
match env.lookup_function(&func_signature).cloned() {
432+
Some(func) => {
433+
434+
let mut new_env = Environment::new();
435+
436+
new_env.set_current_func(&func_signature);
405437
// Functions from the outer environment must be propagated to new_env to ensure access to external functions within the function body.
406438
// This also allows the function to reference itself, which enables recursion
407439
new_env.set_global_functions(env.get_all_functions());
408440

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))
441+
for (formal_arg, value) in func.params.iter().zip(actual_arg_values.iter()) {
442+
match formal_arg.argument_type {
443+
Type::TFunction(..) => {
444+
match value {
445+
Expression::Lambda(arg_func) => {
446+
let mut inner_func = arg_func.clone();
447+
inner_func.name = formal_arg.argument_name.clone();
448+
new_env.map_function(inner_func);
449+
}
450+
//This will never happen, but I need to cover all cases, otherwise it won't compile
451+
_ => {
452+
return Err(format!(
453+
"[Runtime Error] Function {:?} expected another function as argument, but received a non functional argument",
454+
func_signature
455+
));
456+
}
457+
}
458+
}
459+
_ => {
460+
new_env.map_variable(
461+
formal_arg.argument_name.clone(),
462+
false,
463+
value.clone(),
464+
);
414465
}
415-
};
416-
new_env.map_variable(formal.argument_name.clone(), false, value);
466+
}
417467
}
418468

419469
// 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-
) {
470+
match super::statement_execute::execute(*func.body.as_ref().unwrap().clone(), &new_env)
471+
{
424472
Ok(Computation::Continue(_)) => Err("Function did not return a value".to_string()),
425-
Ok(Computation::Return(value, _)) => Ok(ExpressionResult::Value(value)),
473+
Ok(Computation::Return(value, _final_env)) => {
474+
Ok(ExpressionResult::Value(value))
475+
}
426476
Ok(Computation::PropagateError(value, _)) => Ok(ExpressionResult::Propagate(value)),
427477
Err(e) => Err(e),
428478
}
429479
}
430-
_ => Err(format!("Function {} not found", name)),
480+
481+
_ => {
482+
Err(format!("Function '{}' not found", func_signature))
483+
}
431484
}
432485
}
433486

src/interpreter/statement_execute.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,23 @@ pub fn execute(stmt: Statement, env: &Environment<Expression>) -> Result<Computa
5959
}
6060

6161
Statement::Assignment(name, exp) => {
62-
let value = match eval(*exp, &new_env)? {
63-
ExpressionResult::Value(expr) => expr,
64-
ExpressionResult::Propagate(expr) => {
65-
return Ok(Computation::PropagateError(expr, new_env))
62+
match *exp {
63+
Expression::Lambda(mut func) => {
64+
func.name = name;
65+
new_env.map_function(func);
66+
return Ok(Computation::Continue(new_env));
6667
}
67-
};
68-
new_env.map_variable(name, true, value);
69-
Ok(Computation::Continue(new_env))
68+
_ => {
69+
let value = match eval(*exp, &mut new_env)? {
70+
ExpressionResult::Value(expr) => expr,
71+
ExpressionResult::Propagate(expr) => {
72+
return Ok(Computation::PropagateError(expr, new_env));
73+
}
74+
};
75+
new_env.map_variable(name, true,value);
76+
return Ok(Computation::Continue(new_env));
77+
}
78+
}
7079
}
7180

7281
Statement::IfThenElse(cond, stmt_then, stmt_else) => {

0 commit comments

Comments
 (0)