Made it possible for functions to call themselves

This commit is contained in:
bakk 2021-05-31 23:16:47 +02:00
parent 5b8ad2829c
commit 4da372aefe
2 changed files with 40 additions and 10 deletions

View File

@ -382,17 +382,45 @@ pub(crate) fn eval_fn_call_expr(
} }
// Initialise the arguments as their own variables. // Initialise the arguments as their own variables.
let mut new_argument_values = Vec::new();
for (i, argument) in arguments.iter().enumerate() { for (i, argument) in arguments.iter().enumerate() {
eval_stmt( let identifier_parts: Vec<&str> = argument.split('-').collect();
context, let var_decl = Stmt::VarDecl(
&Stmt::VarDecl( Identifier::parameter_from_name(identifier_parts[1], identifier_parts[0]),
Identifier::from_full_name(argument), Box::new(Expr::Literal(
Box::new(expressions[i].clone()), 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())), _ => Err(CalcError::UndefinedFn(identifier.full_name.clone())),
} }

View File

@ -574,6 +574,8 @@ fn parse_group_fn(context: &mut Context) -> Result<Expr, CalcError> {
fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> { fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
let identifier = Identifier::from_full_name(&advance(context).value); 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 // Eg. sqrt64
if match_token(context, TokenKind::Literal) if match_token(context, TokenKind::Literal)
@ -582,7 +584,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|| peek(context).value == "ϕ" || peek(context).value == "ϕ"
{ {
// If there is a function with this name, parse it as a function, with the next token as the argument. // 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 == "" { let parameter = if identifier.full_name == "" {
parse_exponent(context)? parse_exponent(context)?
} else { } else {
@ -594,7 +596,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
let parse_as_var_instead = match_token(context, TokenKind::OpenParenthesis) let parse_as_var_instead = match_token(context, TokenKind::OpenParenthesis)
&& !context.parsing_identifier_stmt && !context.parsing_identifier_stmt
&& !context.symbol_table.contains_fn(&identifier.pure_name); && !exists_as_fn;
// Eg. sqrt(64) // Eg. sqrt(64)
// If the function doesn't exist, parse it as a variable and multiplication instead. // If the function doesn't exist, parse it as a variable and multiplication instead.