Skip to content
Merged
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
29 changes: 28 additions & 1 deletion src/environment/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,32 @@ impl<A: Clone> Scope<A> {

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

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

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

pub fn set_current_func(&mut self, func_name: &str) {
self.current_func = func_name.to_string();
}

pub fn set_global_functions(&mut self, global_functions: HashMap<Name, 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 @@ -142,9 +156,22 @@ 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<Name, Function> {
let mut all_functions = HashMap::new();
for (name, func) in &self.globals.functions {
all_functions.insert(name.clone(), func.clone());
}
for scope in self.stack.iter() {
for (name, func) in &scope.functions {
all_functions.insert(name.clone(), func.clone());
}
}
all_functions
}
}

#[cfg(test)]
Expand Down
12 changes: 9 additions & 3 deletions src/interpreter/expression_eval.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::statement_execute::Computation;
use crate::environment::environment::Environment;
use crate::environment::environment::{Environment, Scope};
use crate::ir::ast::{Expression, Name};

#[derive(Debug, PartialEq, Clone)]
Expand Down Expand Up @@ -398,7 +398,13 @@ pub fn eval_function_call(
));
}

new_env.push();
// new_env.push(); <- Removed the push; parameters are now mapped directly to the global scope
//In this new environment, external functions and actual parameters are regarded as globally accessible
//This is justified, since their visibility extends across the entire function body
new_env.set_current_func(&name);
// 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, actual) in function_definition.params.iter().zip(args.iter()) {
let value = match eval(actual.clone(), env)? {
Expand All @@ -412,7 +418,7 @@ pub fn eval_function_call(

// Execute the body of the function.
match super::statement_execute::execute(
*function_definition.body.as_ref().unwrap().clone(),
*function_definition.body.as_ref().unwrap().clone(), //Push occurs here, because function body is a Statement::Block
&new_env,
) {
Ok(Computation::Continue(_)) => Err("Function did not return a value".to_string()),
Expand Down
44 changes: 37 additions & 7 deletions src/interpreter/statement_execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ pub fn execute(stmt: Statement, env: &Environment<Expression>) -> Result<Computa

match value {
Expression::CTrue => match *stmt_then {
Statement::Block(stmts) => execute_block(stmts, &new_env),
Statement::Block(stmts) => execute_if_block(stmts, &new_env),
_ => execute(*stmt_then, &new_env),
},
Expression::CFalse => match stmt_else {
Some(else_stmt) => match *else_stmt {
Statement::Block(stmts) => execute_block(stmts, &new_env),
Statement::Block(stmts) => execute_if_block(stmts, &new_env),
_ => execute(*else_stmt, &new_env),
},
None => Ok(Computation::Continue(new_env)),
Expand All @@ -94,9 +94,14 @@ pub fn execute(stmt: Statement, env: &Environment<Expression>) -> Result<Computa
}

Statement::Block(stmts) => {
new_env.push();
// new_env.push(); <- removing push()
let result = execute_block(stmts, &new_env);
new_env.pop();
// new_env.pop(); <- removing pop()
// `result` already encapsulates the updated environment,
// So popping would have no effect on the final outcome
// Therefore, push and pop operations will be handled in function 'execute_block'
// A new function `execute_if_block` will be created specifically for executing blocks
// without performing push/pop operations
result
}

Expand Down Expand Up @@ -201,13 +206,38 @@ pub fn execute_block(
env: &Environment<Expression>,
) -> Result<Computation, String> {
let mut current_env = env.clone();
current_env.push();

for stmt in stmts {
match execute(stmt, &current_env)? {
Computation::Continue(new_env) => current_env = new_env,
Computation::Return(expr, env) => return Ok(Computation::Return(expr, env)),
Computation::PropagateError(expr, env) => {
return Ok(Computation::PropagateError(expr, env))
Computation::Return(expr, mut new_env) => {
new_env.pop(); //expr has already been evaluated, so it is safe to pop here
return Ok(Computation::Return(expr, new_env));
}
Computation::PropagateError(expr, new_env) => {
return Ok(Computation::PropagateError(expr, new_env))
}
}
}
current_env.pop();
Ok(Computation::Continue(current_env))
}

pub fn execute_if_block(
stmts: Vec<Statement>,
env: &Environment<Expression>,
) -> Result<Computation, String> {
let mut current_env = env.clone();

for stmt in stmts {
match execute(stmt, &current_env)? {
Computation::Continue(new_env) => current_env = new_env,
Computation::Return(expr, new_env) => {
return Ok(Computation::Return(expr, new_env));
}
Computation::PropagateError(expr, new_env) => {
return Ok(Computation::PropagateError(expr, new_env))
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/ir/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ pub enum Expression {
IsNothing(Box<Expression>),
Propagate(Box<Expression>),

//Lambda expression
Lambda(Function),

// List value
ListValue(Vec<Expression>),

Expand Down
2 changes: 2 additions & 0 deletions src/parser/parser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub const ASSERT_KEYWORD: &str = "assert";
pub const VAR_KEYWORD: &str = "var";
pub const VAL_KEYWORD: &str = "val";
pub const DEF_KEYWORD: &str = "def";
pub const LAMBDA_KEYWORD: &str = "lambda";
pub const RET_KEYWORD: &str = "return";

// Operator and symbol constants
pub const FUNCTION_ARROW: &str = "->";
Expand Down
45 changes: 43 additions & 2 deletions src/parser/parser_expr.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use nom::{
branch::alt,
bytes::complete::{tag, take_while},
character::complete::{char, digit1, multispace0},
character::complete::{char, digit1, multispace0, multispace1},
combinator::{map, map_res, opt, value, verify},
error::Error,
multi::{fold_many0, separated_list0},
Expand All @@ -11,19 +11,26 @@ use nom::{

use std::str::FromStr;

use crate::ir::ast::Expression;
use crate::{ir::ast::Expression, parser::{parser_common::END_KEYWORD}};
use crate::parser::parser_common::{
identifier,
is_string_char,
keyword,
// Other character constants
COMMA_CHAR,
COLON_CHAR,
// Bracket and parentheses constants
LEFT_BRACKET,
LEFT_PAREN,
RIGHT_BRACKET,
RIGHT_PAREN,
FUNCTION_ARROW,
LAMBDA_KEYWORD,
};
use crate::parser::parser_stmt::{parse_formal_argument, parse_return_statement};
use crate::parser::parser_type::parse_type;
use crate::ir::ast::Function;
use crate::ir::ast::Statement;

pub fn parse_expression(input: &str) -> IResult<&str, Expression> {
parse_or(input)
Expand Down Expand Up @@ -117,6 +124,7 @@ fn parse_factor(input: &str) -> IResult<&str, Expression> {
parse_list,
parse_function_call,
parse_var,
parse_lambda,
delimited(
char::<&str, Error<&str>>(LEFT_PAREN),
parse_expression,
Expand All @@ -125,6 +133,39 @@ fn parse_factor(input: &str) -> IResult<&str, Expression> {
))(input)
}

fn parse_lambda(input: &str) -> IResult<&str, Expression> {
map(
tuple((
keyword(LAMBDA_KEYWORD),
preceded(multispace1, identifier),
delimited(
char::<&str, Error<&str>>(LEFT_PAREN),
separated_list0(
tuple((
multispace0,
char::<&str, Error<&str>>(COMMA_CHAR),
multispace0,
)),
parse_formal_argument,
),
char::<&str, Error<&str>>(RIGHT_PAREN),
),
preceded(multispace0, tag(FUNCTION_ARROW)),
delimited(multispace0, parse_type, char::<&str, Error<&str>>(COLON_CHAR)),
parse_return_statement,
keyword(END_KEYWORD)
)),
|(_, name, args, _, t, return_stmt, _)| {
Expression::Lambda(Function {
name: name.to_string(),
kind: t,
params: args,
body: Some(Box::new(Statement::Block(vec![return_stmt]))),
})
},
)(input)
}

fn parse_bool(input: &str) -> IResult<&str, Expression> {
alt((
value(Expression::CTrue, keyword("True")),
Expand Down
18 changes: 15 additions & 3 deletions src/parser/parser_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::ir::ast::{FormalArgument, Function, Statement};
use crate::parser::parser_common::{
identifier, keyword, ASSERT_KEYWORD, COLON_CHAR, COMMA_CHAR, DEF_KEYWORD, ELSE_KEYWORD,
END_KEYWORD, EQUALS_CHAR, FOR_KEYWORD, FUNCTION_ARROW, IF_KEYWORD, IN_KEYWORD, LEFT_PAREN,
RIGHT_PAREN, SEMICOLON_CHAR, VAL_KEYWORD, VAR_KEYWORD, WHILE_KEYWORD,
RIGHT_PAREN, SEMICOLON_CHAR, VAL_KEYWORD, VAR_KEYWORD, WHILE_KEYWORD, RET_KEYWORD
};
use crate::parser::parser_expr::parse_expression;
use crate::parser::parser_type::parse_type;
Expand All @@ -28,9 +28,21 @@ pub fn parse_statement(input: &str) -> IResult<&str, Statement> {
parse_for_statement,
parse_assert_statement,
parse_function_definition_statement,
parse_return_statement,
))(input)
}

pub fn parse_return_statement(input: &str) -> IResult<&str, Statement> {
map(
tuple((
keyword(RET_KEYWORD),
multispace0,
parse_expression,
)),
|(_, _, expr)| Statement::Return(Box::new(expr)),
)(input)
}

fn parse_var_declaration_statement(input: &str) -> IResult<&str, Statement> {
map(
tuple((
Expand Down Expand Up @@ -181,7 +193,7 @@ fn parse_function_definition_statement(input: &str) -> IResult<&str, Statement>
)(input)
}

fn parse_block(input: &str) -> IResult<&str, Statement> {
pub fn parse_block(input: &str) -> IResult<&str, Statement> {
map(
tuple((
char::<&str, Error<&str>>(COLON_CHAR),
Expand All @@ -204,7 +216,7 @@ fn parse_block(input: &str) -> IResult<&str, Statement> {
)(input)
}

fn parse_formal_argument(input: &str) -> IResult<&str, FormalArgument> {
pub fn parse_formal_argument(input: &str) -> IResult<&str, FormalArgument> {
map(
tuple((
preceded(multispace0, identifier),
Expand Down
45 changes: 45 additions & 0 deletions src/type_checker/expression_type_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub fn check_expr(exp: Expression, env: &Environment<Type>) -> Result<Type, Erro
Expression::Or(l, r) => check_bin_boolean_expression(*l, *r, env),
Expression::Not(e) => check_not_expression(*e, env),
Expression::EQ(l, r) => check_bin_relational_expression(*l, *r, env),
Expression::NEQ(l, r) => check_bin_relational_expression(*l, *r, env),
Expression::GT(l, r) => check_bin_relational_expression(*l, *r, env),
Expression::LT(l, r) => check_bin_relational_expression(*l, *r, env),
Expression::GTE(l, r) => check_bin_relational_expression(*l, *r, env),
Expand All @@ -34,11 +35,55 @@ pub fn check_expr(exp: Expression, env: &Environment<Type>) -> Result<Type, Erro
Expression::Propagate(e) => check_propagate_type(*e, env),
Expression::ListValue(elements) => check_list_value(&elements, env),
Expression::Constructor(name, args) => check_adt_constructor(name, args, env),
Expression::FuncCall(func_name, exp_vec) => {
check_func_call(func_name.clone(), exp_vec.clone(), env)
}

_ => Err("not implemented yet.".to_string()),
}
}

fn check_func_call(
func_name: Name,
exp_vector: Vec<Expression>,
env: &Environment<Type>,
) -> Result<Type, ErrorMessage> {
let func = env.lookup_function(&func_name);
if func.is_none() {
return Err(format!(
"Function {} was called but never declared",
func_name
));
}
let func = func.unwrap();
if func.params.len() != exp_vector.len() {
return Err(format!(
"Function {} receives {} arguments, but {} were given",
func_name,
func.params.len(),
exp_vector.len()
));
}
let mut formal_arg_types = Vec::new();
let mut actual_arg_types = Vec::new();
for (param, arg) in func.params.iter().zip(exp_vector.iter()) {
formal_arg_types.push(param.argument_type.clone());
let arg_type = check_expr(arg.clone(), env)?;
actual_arg_types.push(arg_type);
}
for (formal_type, actual_type) in formal_arg_types.iter().zip(actual_arg_types.iter()) {
if formal_type != actual_type {
return Err(format!(
"Mismatched types in function {} call \n
Expected:{:?}\n
Received: {:?}",
func_name, formal_arg_types, actual_arg_types
));
}
}
return Ok(func.kind.clone());
}

fn check_var_name(name: Name, env: &Environment<Type>) -> Result<Type, ErrorMessage> {
match env.lookup(&name) {
Some((_, t)) => Ok(t.clone()),
Expand Down
Loading