Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 82 additions & 10 deletions src/environment/environment.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use crate::ir::ast::FuncSignature;
use crate::ir::ast::Function;
use crate::ir::ast::Name;
use crate::ir::ast::ValueConstructor;
use std::collections::HashMap;
use std::collections::LinkedList;
use std::fmt::Debug;

#[derive(Clone)]
pub struct Scope<A> {
pub variables: HashMap<Name, (bool, A)>,
pub functions: HashMap<Name, Function>,
pub functions: HashMap<FuncSignature, Function>,
pub adts: HashMap<Name, Vec<ValueConstructor>>,
}

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

fn map_function(&mut self, function: Function) -> () {
self.functions.insert(function.name.clone(), function);
let func_signature = FuncSignature::from_func(&function);
self.functions.insert(func_signature, function);
return ();
}

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

fn lookup_function(&self, name: &Name) -> Option<&Function> {
self.functions.get(name)
fn lookup_function(&self, func_signature: &FuncSignature) -> Option<&Function> {
self.functions.get(func_signature)
}

fn lookup_function_by_name(&self, name: &Name) -> Option<&Function> {
self.functions.iter().find_map(|(signature, function)| {
if &signature.name == name {
Some(function)
} else {
None
}
})
}

fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
Expand All @@ -51,19 +64,37 @@ impl<A: Clone> Scope<A> {
}

#[derive(Clone)]
pub struct Environment<A> {
pub struct Environment<A: Clone + Debug> {
pub current_func: FuncSignature,
pub globals: Scope<A>,
pub stack: LinkedList<Scope<A>>,
}

impl<A: Clone> Environment<A> {
impl<A: Clone + Debug> Environment<A> {
pub fn new() -> Environment<A> {
Environment {
current_func: FuncSignature::new(),
globals: Scope::new(),
stack: LinkedList::new(),
}
}

pub fn get_current_func(&self) -> FuncSignature {
return self.current_func.clone();
}

pub fn get_current_scope(&self) -> &Scope<A> {
self.stack.front().unwrap_or(&self.globals)
}

pub fn set_current_func(&mut self, func_signature: &FuncSignature) {
self.current_func = func_signature.clone();
}

pub fn set_global_functions(&mut self, global_functions: HashMap<FuncSignature, Function>) {
self.globals.functions = global_functions;
}

pub fn map_variable(&mut self, var: Name, mutable: bool, value: A) -> () {
match self.stack.front_mut() {
None => self.globals.map_variable(var, mutable, value),
Expand Down Expand Up @@ -94,13 +125,31 @@ impl<A: Clone> Environment<A> {
self.globals.lookup_var(var)
}

pub fn lookup_function(&self, name: &Name) -> Option<&Function> {
pub fn lookup_function(&self, func_signature: &FuncSignature) -> Option<&Function> {
for scope in self.stack.iter() {
if let Some(func) = scope.lookup_function(name) {
if let Some(func) = scope.lookup_function(func_signature) {
return Some(func);
}
}
self.globals.lookup_function(name)
self.globals.lookup_function(func_signature)
}

pub fn lookup_var_or_func(&self, name: &Name) -> Option<FuncOrVar<A>> {
for scope in self.stack.iter() {
if let Some(value) = scope.lookup_var(name) {
return Some(FuncOrVar::Var(value));
}
if let Some(func) = scope.lookup_function_by_name(name) {
return Some(FuncOrVar::Func(func.clone()));
}
}
if let Some(value) = self.globals.lookup_var(name) {
return Some(FuncOrVar::Var(value));
}
if let Some(func) = self.globals.lookup_function_by_name(name) {
return Some(FuncOrVar::Func(func.clone()));
}
return None;
}

pub fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
Expand Down Expand Up @@ -142,11 +191,33 @@ impl<A: Clone> Environment<A> {
vars.push((name.clone(), value.clone()));
}
}

vars
}

// The type checker ensures that each function is defined only once
pub fn get_all_functions(&self) -> HashMap<FuncSignature, Function> {
let mut all_functions = HashMap::new();
for (func_signature, func) in &self.globals.functions {
all_functions.insert(func_signature.clone(), func.clone());
}
// It is necessary to traverse the scope stack from bottom to top
// so that functions defined in inner scopes can shadow those
// defined in outer scopes.
for scope in self.stack.iter().rev() {
for (func_signature, func) in &scope.functions {
all_functions.insert(func_signature.clone(), func.clone());
}
}
all_functions
}
}

pub enum FuncOrVar<A: Clone + Debug> {
Func(Function),
Var((bool, A)),
}

/*
#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -218,3 +289,4 @@ mod tests {
assert!(env.lookup_function(&"local".to_string()).is_none()); // local gone
}
}
*/
109 changes: 84 additions & 25 deletions src/interpreter/expression_eval.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::statement_execute::Computation;
use crate::environment::environment::Environment;
use crate::environment::environment::{Environment, FuncOrVar};
use crate::ir::ast::{Expression, Name};
use crate::ir::ast::{FuncSignature, Type};
use crate::type_checker::check_expr;

#[derive(Debug, PartialEq, Clone)]
pub enum ExpressionResult {
Expand Down Expand Up @@ -383,45 +385,102 @@ pub fn eval_lookup(

// Function call
pub fn eval_function_call(
name: Name,
func_name: Name,
args: Vec<Expression>,
env: &Environment<Expression>,
) -> Result<ExpressionResult, String> {
match env.lookup_function(&name) {
Some(function_definition) => {
let mut new_env = Environment::new();

if args.len() != function_definition.params.len() {
return Err(format!(
"[Runtime Error] Invalid number of arguments for '{}'.",
name
));
let mut actual_arg_values = Vec::new();
let mut actual_arg_types = Vec::new();
for arg in args.iter() {
match arg {
Expression::Var(name) => match env.lookup_var_or_func(name) {
Some(FuncOrVar::Var((_, _var_exp))) => match eval_lookup(name.to_string(), env)? {
ExpressionResult::Propagate(expr) => {
return Ok(ExpressionResult::Propagate(expr));
}
ExpressionResult::Value(expr) => {
actual_arg_values.push(expr);
}
},
Some(FuncOrVar::Func(func)) => {
actual_arg_values.push(Expression::Lambda(func));
}
None => return Err(format!("Identifier '{}' was never declared", name)),
},
Expression::Lambda(func) => {
actual_arg_values.push(Expression::Lambda(func.clone()));
}
_ => match eval(arg.clone(), env)? {
ExpressionResult::Value(expr) => {
actual_arg_values.push(expr);
}
ExpressionResult::Propagate(expr) => {
return Ok(ExpressionResult::Propagate(expr));
}
},
}
}
for value in &actual_arg_values {
actual_arg_types.push(check_expr(value.clone(), &Environment::<Type>::new())?);
}

new_env.push();
let func_signature = FuncSignature {
name: func_name.clone(),
argument_types: actual_arg_types.clone(),
};
match env.lookup_function(&func_signature).cloned() {
Some(func) => {

for (formal, actual) in function_definition.params.iter().zip(args.iter()) {
let value = match eval(actual.clone(), env)? {
ExpressionResult::Value(expr) => expr,
ExpressionResult::Propagate(expr) => {
return Ok(ExpressionResult::Propagate(expr))
let mut new_env = Environment::new();

new_env.set_current_func(&func_signature);
// Functions from the outer environment must be propagated to new_env to ensure access to external functions within the function body.
// This also allows the function to reference itself, which enables recursion
new_env.set_global_functions(env.get_all_functions());

for (formal_arg, value) in func.params.iter().zip(actual_arg_values.iter()) {
match formal_arg.argument_type {
Type::TFunction(..) => {
match value {
Expression::Lambda(arg_func) => {
let mut inner_func = arg_func.clone();
inner_func.name = formal_arg.argument_name.clone();
new_env.map_function(inner_func);
}
//This will never happen, but I need to cover all cases, otherwise it won't compile
_ => {
return Err(format!(
"[Runtime Error] Function {:?} expected another function as argument, but received a non functional argument",
func_signature
));
}
}
}
};
new_env.map_variable(formal.argument_name.clone(), false, value);
_ => {
new_env.map_variable(
formal_arg.argument_name.clone(),
false,
value.clone(),
);
}
}
}

// Execute the body of the function.
match super::statement_execute::execute(
*function_definition.body.as_ref().unwrap().clone(),
&new_env,
) {
match super::statement_execute::execute(*func.body.as_ref().unwrap().clone(), &new_env)
{
Ok(Computation::Continue(_)) => Err("Function did not return a value".to_string()),
Ok(Computation::Return(value, _)) => Ok(ExpressionResult::Value(value)),
Ok(Computation::Return(value, _final_env)) => {
Ok(ExpressionResult::Value(value))
}
Ok(Computation::PropagateError(value, _)) => Ok(ExpressionResult::Propagate(value)),
Err(e) => Err(e),
}
}
_ => Err(format!("Function {} not found", name)),

_ => {
Err(format!("Function '{}' not found", func_signature))
}
}
}

Expand Down
Loading