Skip to content

Commit

Permalink
fix: recursion
Browse files Browse the repository at this point in the history
  • Loading branch information
fcoury committed Jul 14, 2024
1 parent b7d13e3 commit 28189ab
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 9 deletions.
36 changes: 27 additions & 9 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,25 @@ use crate::{

pub struct Interpreter {
environment: IndexMap<String, Value>,
global_environment: IndexMap<String, Value>,
}

impl Interpreter {
pub fn new() -> Self {
let mut interpreter = Interpreter {
environment: IndexMap::new(),
global_environment: IndexMap::new(),
};
interpreter.init_standard_library();
interpreter
}

fn init_standard_library(&mut self) {
self.environment.insert(
self.global_environment.insert(
"print".to_string(),
Value::Function(Function::BuiltIn(stdlib_print)),
);
self.environment.insert(
self.global_environment.insert(
"println".to_string(),
Value::Function(Function::BuiltIn(stdlib_println)),
);
Expand Down Expand Up @@ -76,6 +78,7 @@ impl Interpreter {
for method in methods {
if let Stmt::Function(name, params, _, body, _) = method {
let func = Value::Function(Function::UserDefined(
name.clone(),
params.clone(),
body.clone(),
self.environment.clone(),
Expand Down Expand Up @@ -107,6 +110,7 @@ impl Interpreter {
}
Stmt::Function(name, params, _, body, _) => {
let func = Value::Function(Function::UserDefined(
name.clone(),
params.clone(),
body.clone(),
self.environment.clone(),
Expand Down Expand Up @@ -264,6 +268,7 @@ impl Interpreter {
// Execute the matched arm with the new environment
let mut arm_interpreter = Interpreter {
environment: new_env,
global_environment: self.global_environment.clone(),
};
return arm_interpreter.execute_statements(body);
}
Expand Down Expand Up @@ -409,32 +414,40 @@ impl Interpreter {
name.to_string()
};

let func = self.environment.get(&name).cloned().ok_or_else(|| {
Error::new_runtime(format!("Undefined function: {}", name), *span)
})?;
let func = self
.environment
.get(&name)
.cloned()
.or_else(|| self.global_environment.get(&name).cloned())
.ok_or_else(|| {
Error::new_runtime(format!("Undefined function: {}", name), *span)
})?;

match func {
match &func {
Value::Function(Function::BuiltIn(func)) => {
let evaluated_args: Result<Vec<Value>> =
args.iter().map(|arg| self.evaluate_expr(arg)).collect();
func(&evaluated_args?)
}
Value::Function(Function::UserDefined(params, body, func_env)) => {
Value::Function(Function::UserDefined(func_name, params, body, func_env)) => {
if args.len() != params.len() {
return Err(Error::new_runtime(
format!("Function {} called with wrong number of arguments", name),
*span,
));
}

let mut local_env = func_env;
let mut local_env = func_env.clone();
local_env.insert(func_name.clone(), func.clone());

for ((param_name, _), arg_expr) in params.iter().zip(args.iter()) {
let arg_value = self.evaluate_expr(arg_expr)?;
local_env.insert(param_name.clone(), arg_value);
}

let mut interpreter = Interpreter {
environment: local_env,
global_environment: self.global_environment.clone(),
};

let mut result = Value::Unit;
Expand Down Expand Up @@ -833,7 +846,12 @@ impl PartialEq for Value {

#[derive(Clone, Debug)]
pub enum Function {
UserDefined(Vec<(String, String)>, Vec<Stmt>, IndexMap<String, Value>),
UserDefined(
String,
Vec<(String, String)>,
Vec<Stmt>,
IndexMap<String, Value>,
),
BuiltIn(fn(&[Value]) -> Result<Value>),
}

Expand Down
12 changes: 12 additions & 0 deletions tests/scripts/factorial.hk
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

fn factorial(n: int) -> int {
if n == 0 {
1
} else {
n * factorial(n - 1)
}
}

for i in 0..10 {
println(i, " factorial is ", factorial(i))
}
Empty file added tests/scripts/factorial.hk.err
Empty file.
10 changes: 10 additions & 0 deletions tests/scripts/factorial.hk.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
0 factorial is 1
1 factorial is 1
2 factorial is 2
3 factorial is 6
4 factorial is 24
5 factorial is 120
6 factorial is 720
7 factorial is 5040
8 factorial is 40320
9 factorial is 362880
Empty file.
10 changes: 10 additions & 0 deletions tests/scripts/factorial.hk.tr.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
0 factorial is 1
1 factorial is 1
2 factorial is 2
3 factorial is 6
4 factorial is 24
5 factorial is 120
6 factorial is 720
7 factorial is 5040
8 factorial is 40320
9 factorial is 362880

0 comments on commit 28189ab

Please sign in to comment.