From 4da372aefe8f9ecf6151a939325fa4915fe49bcc Mon Sep 17 00:00:00 2001 From: bakk Date: Mon, 31 May 2021 23:16:47 +0200 Subject: [PATCH] Made it possible for functions to call themselves --- kalk/src/interpreter.rs | 44 +++++++++++++++++++++++++++++++++-------- kalk/src/parser.rs | 6 ++++-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/kalk/src/interpreter.rs b/kalk/src/interpreter.rs index 5455fbc..4afac65 100644 --- a/kalk/src/interpreter.rs +++ b/kalk/src/interpreter.rs @@ -382,17 +382,45 @@ pub(crate) fn eval_fn_call_expr( } // Initialise the arguments as their own variables. + let mut new_argument_values = Vec::new(); for (i, argument) in arguments.iter().enumerate() { - eval_stmt( - context, - &Stmt::VarDecl( - Identifier::from_full_name(argument), - Box::new(expressions[i].clone()), - ), - )?; + let identifier_parts: Vec<&str> = argument.split('-').collect(); + let var_decl = Stmt::VarDecl( + Identifier::parameter_from_name(identifier_parts[1], identifier_parts[0]), + Box::new(Expr::Literal( + eval_expr(context, &expressions[i], "")?.to_f64(), + )), + ); + + // Don't set these values just yet, since + // to avoid affecting the value of arguments + // during recursion. + new_argument_values.push((argument, var_decl)); } - eval_expr(context, &fn_body, unit) + let mut old_argument_values = Vec::new(); + for (name, value) in new_argument_values { + // Save the original argument values, + // so that they can be reverted to after + // the function call is evaluated. + // This is necessary since recursive + // function calls have the same argument names. + old_argument_values.push(context.symbol_table.get_and_remove_var(name)); + + // Now set the new variable value + eval_stmt(context, &value)?; + } + + let fn_value = eval_expr(context, &fn_body, unit); + + // Revert to original argument values + for old_argument_value in old_argument_values { + if let Some(old_argument_value) = old_argument_value { + context.symbol_table.insert(old_argument_value); + } + } + + fn_value } _ => Err(CalcError::UndefinedFn(identifier.full_name.clone())), } diff --git a/kalk/src/parser.rs b/kalk/src/parser.rs index 65bac59..f932ccc 100644 --- a/kalk/src/parser.rs +++ b/kalk/src/parser.rs @@ -574,6 +574,8 @@ fn parse_group_fn(context: &mut Context) -> Result { fn parse_identifier(context: &mut Context) -> Result { let identifier = Identifier::from_full_name(&advance(context).value); + let exists_as_fn = context.symbol_table.contains_fn(&identifier.pure_name) + || context.current_function.as_ref() == Some(&identifier.pure_name); // Eg. sqrt64 if match_token(context, TokenKind::Literal) @@ -582,7 +584,7 @@ fn parse_identifier(context: &mut Context) -> Result { || peek(context).value == "ϕ" { // If there is a function with this name, parse it as a function, with the next token as the argument. - if context.symbol_table.contains_fn(&identifier.pure_name) { + if exists_as_fn { let parameter = if identifier.full_name == "√" { parse_exponent(context)? } else { @@ -594,7 +596,7 @@ fn parse_identifier(context: &mut Context) -> Result { let parse_as_var_instead = match_token(context, TokenKind::OpenParenthesis) && !context.parsing_identifier_stmt - && !context.symbol_table.contains_fn(&identifier.pure_name); + && !exists_as_fn; // Eg. sqrt(64) // If the function doesn't exist, parse it as a variable and multiplication instead.