Made recursion possible

This commit is contained in:
bakk 2021-05-24 21:32:58 +02:00
parent d1365b5982
commit c4c768374f
3 changed files with 159 additions and 99 deletions

View File

@ -26,6 +26,7 @@ pub enum Expr {
pub struct Identifier { pub struct Identifier {
pub full_name: String, pub full_name: String,
pub pure_name: String, pub pure_name: String,
pub parameter_of_function: Option<String>,
pub prime_count: u32, pub prime_count: u32,
} }
@ -36,6 +37,7 @@ impl Identifier {
Identifier { Identifier {
full_name: full_name.to_string(), full_name: full_name.to_string(),
pure_name, pure_name,
parameter_of_function: None,
prime_count, prime_count,
} }
} }
@ -44,9 +46,19 @@ impl Identifier {
Identifier { Identifier {
full_name: format!("{}{}", pure_name, "'".repeat(prime_count as usize)), full_name: format!("{}{}", pure_name, "'".repeat(prime_count as usize)),
pure_name: pure_name.into(), pure_name: pure_name.into(),
parameter_of_function: None,
prime_count, prime_count,
} }
} }
pub fn parameter_from_name(name: &str, function: &str) -> Self {
Identifier {
full_name: format!("{}-{}", function, name),
pure_name: name.into(),
parameter_of_function: Some(function.into()),
prime_count: 0u32,
}
}
} }
pub fn build_literal_ast(kalk_num: &crate::kalk_num::KalkNum) -> Expr { pub fn build_literal_ast(kalk_num: &crate::kalk_num::KalkNum) -> Expr {

View File

@ -29,8 +29,10 @@ pub struct Context {
unit_decl_base_unit: Option<String>, unit_decl_base_unit: Option<String>,
parsing_identifier_stmt: bool, parsing_identifier_stmt: bool,
equation_variable: Option<String>, equation_variable: Option<String>,
contains_equal_sign: bool, contains_equation_equal_sign: bool,
is_in_integral: bool, is_in_integral: bool,
current_function: Option<String>,
current_function_parameters: Option<Vec<String>>,
} }
#[wasm_bindgen] #[wasm_bindgen]
@ -47,8 +49,10 @@ impl Context {
unit_decl_base_unit: None, unit_decl_base_unit: None,
parsing_identifier_stmt: false, parsing_identifier_stmt: false,
equation_variable: None, equation_variable: None,
contains_equal_sign: false, contains_equation_equal_sign: false,
is_in_integral: false, is_in_integral: false,
current_function: None,
current_function_parameters: None,
}; };
parse(&mut context, crate::prelude::INIT).unwrap(); parse(&mut context, crate::prelude::INIT).unwrap();
@ -143,7 +147,9 @@ pub fn eval(
input: &str, input: &str,
#[cfg(feature = "rug")] precision: u32, #[cfg(feature = "rug")] precision: u32,
) -> Result<Option<KalkNum>, CalcError> { ) -> Result<Option<KalkNum>, CalcError> {
context.contains_equal_sign = input.contains("="); // Variable and function declaration parsers will set this to false
// if the equal sign is for one of those instead.
context.contains_equation_equal_sign = input.contains("=");
let statements = parse(context, input)?; let statements = parse(context, input)?;
let mut interpreter = interpreter::Context::new( let mut interpreter = interpreter::Context::new(
@ -208,20 +214,28 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
if let Expr::FnCall(identifier, parameters) = primary { if let Expr::FnCall(identifier, parameters) = primary {
if !prelude::is_prelude_func(&identifier.full_name) { if !prelude::is_prelude_func(&identifier.full_name) {
advance(context); advance(context);
let expr = parse_expr(context)?;
let mut parameter_identifiers = Vec::new();
// All the "arguments" are expected to be parsed as variables, // All the "arguments" are expected to be parsed as variables,
// since parameter definitions look the same as variable references. // since parameter definitions look the same as variable references.
// Extract these. // Extract these.
let mut parameter_identifiers = Vec::new();
for parameter in parameters { for parameter in parameters {
if let Expr::Var(parameter_identifier) = parameter { if let Expr::Var(parameter_identifier) = parameter {
parameter_identifiers.push(parameter_identifier.full_name); parameter_identifiers.push(format!(
"{}-{}",
&identifier.pure_name, &parameter_identifier.full_name
));
} }
} }
let fn_decl = context.current_function = Some(identifier.pure_name.clone());
Stmt::FnDecl(identifier.clone(), parameter_identifiers, Box::new(expr)); context.current_function_parameters = Some(parameter_identifiers.clone());
context.contains_equation_equal_sign = false;
context.equation_variable = None;
let expr = parse_expr(context)?;
let fn_decl = Stmt::FnDecl(identifier, parameter_identifiers, Box::new(expr));
context.current_function = None;
context.current_function_parameters = None;
// Insert the function declaration into the symbol table during parsing // Insert the function declaration into the symbol table during parsing
// so that the parser can find out if particular functions exist. // so that the parser can find out if particular functions exist.
@ -241,6 +255,8 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> { fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
let identifier = advance(context).clone(); let identifier = advance(context).clone();
advance(context); // Equal sign advance(context); // Equal sign
context.contains_equation_equal_sign = false;
context.equation_variable = None;
let expr = parse_expr(context)?; let expr = parse_expr(context)?;
if inverter::contains_var(&context.symbol_table, &expr, &identifier.value) { if inverter::contains_var(&context.symbol_table, &expr, &identifier.value) {
return Err(CalcError::VariableReferencesItself); return Err(CalcError::VariableReferencesItself);
@ -528,6 +544,27 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
return Ok(Expr::FnCall(identifier, parameters)); return Ok(Expr::FnCall(identifier, parameters));
} }
// Eg. x
if parse_as_var_instead || context.symbol_table.contains_var(&identifier.pure_name) {
Ok(Expr::Var(identifier))
} else if context.parsing_unit_decl {
context.unit_decl_base_unit = Some(identifier.full_name);
Ok(Expr::Var(Identifier::from_full_name(DECL_UNIT)))
} else {
if let Some(equation_var) = &context.equation_variable {
if &identifier.full_name == equation_var {
return Ok(build_var(context, &identifier.full_name));
}
}
if context.contains_equation_equal_sign {
context.equation_variable = Some(identifier.full_name.clone());
return Ok(build_var(context, &identifier.full_name));
}
if identifier.pure_name.len() == 1 {
return Ok(build_var(context, &identifier.full_name));
}
// Eg. dx inside an integral, should be parsed as *one* identifier // Eg. dx inside an integral, should be parsed as *one* identifier
// Reverse the identifier and take two. This gets the last two characters (in reversed order). // Reverse the identifier and take two. This gets the last two characters (in reversed order).
// Now reverse this to finally get the last two characters in correct order. // Now reverse this to finally get the last two characters in correct order.
@ -547,22 +584,15 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
} }
} }
// Eg. x split_into_variables(context, &identifier, dx)
if parse_as_var_instead || context.symbol_table.contains_var(&identifier.pure_name) {
Ok(Expr::Var(identifier))
} else if context.parsing_unit_decl {
context.unit_decl_base_unit = Some(identifier.full_name);
Ok(Expr::Var(Identifier::from_full_name(DECL_UNIT)))
} else {
if let Some(equation_var) = &context.equation_variable {
if &identifier.full_name == equation_var {
return Ok(Expr::Var(identifier));
}
} else if context.contains_equal_sign {
context.equation_variable = Some(identifier.full_name.clone());
return Ok(Expr::Var(identifier));
} }
}
fn split_into_variables(
context: &mut Context,
identifier: &Identifier,
dx: Option<String>,
) -> Result<Expr, CalcError> {
let mut chars: Vec<char> = identifier.pure_name.chars().collect(); let mut chars: Vec<char> = identifier.pure_name.chars().collect();
let mut left = Expr::Var(Identifier::from_full_name(&chars[0].to_string())); let mut left = Expr::Var(Identifier::from_full_name(&chars[0].to_string()));
@ -621,7 +651,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
last_var last_var
} else { } else {
Expr::Var(Identifier::from_full_name(&c.to_string())) build_var(context, &c.to_string())
}; };
left = Expr::Binary(Box::new(left), TokenKind::Star, Box::new(right)); left = Expr::Binary(Box::new(left), TokenKind::Star, Box::new(right));
@ -636,7 +666,19 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
} }
Ok(left) Ok(left)
}
fn build_var(context: &Context, name: &str) -> Expr {
if let (Some(function_name), Some(params)) = (
context.current_function.as_ref(),
context.current_function_parameters.as_ref(),
) {
let identifier = Identifier::parameter_from_name(name, &function_name);
if params.contains(&identifier.full_name) {
return Expr::Var(identifier);
} }
}
return Expr::Var(Identifier::from_full_name(name));
} }
fn peek(context: &Context) -> &Token { fn peek(context: &Context) -> &Token {
@ -889,7 +931,7 @@ mod tests {
token(Equals, ""), token(Equals, ""),
token(Literal, "1"), token(Literal, "1"),
token(Plus, ""), token(Plus, ""),
token(Literal, "2"), token(Identifier, "x"),
token(EOF, ""), token(EOF, ""),
]; ];
@ -897,8 +939,8 @@ mod tests {
parse(tokens).unwrap(), parse(tokens).unwrap(),
Stmt::FnDecl( Stmt::FnDecl(
Identifier::from_full_name("f"), Identifier::from_full_name("f"),
vec![String::from("x")], vec![String::from("f-x")],
binary(literal(1f64), Plus, literal(2f64)) binary(literal(1f64), Plus, param_var("f", "x"))
) )
); );
} }

View File

@ -21,6 +21,12 @@ pub fn var(identifier: &str) -> Box<Expr> {
Box::new(Expr::Var(Identifier::from_full_name(identifier))) Box::new(Expr::Var(Identifier::from_full_name(identifier)))
} }
pub fn param_var(function: &str, identifier: &str) -> Box<Expr> {
Box::new(Expr::Var(Identifier::parameter_from_name(
identifier, function,
)))
}
pub fn fn_call(identifier: &str, arguments: Vec<Expr>) -> Box<Expr> { pub fn fn_call(identifier: &str, arguments: Vec<Expr>) -> Box<Expr> {
Box::new(Expr::FnCall( Box::new(Expr::FnCall(
Identifier::from_full_name(identifier), Identifier::from_full_name(identifier),