Fixed recursion not working

This commit is contained in:
PaddiM8 2022-03-26 19:44:26 +01:00
parent 3f4cfd9359
commit f78794f073
5 changed files with 72 additions and 11 deletions

View File

@ -51,6 +51,7 @@ mod tests {
#[test_case("matrices/operations")]
#[test_case("matrices/transpose")]
#[test_case("radix")]
#[test_case("recursion")]
#[test_case("redefining")]
#[test_case("sum")]
#[test_case("variables")]

View File

@ -156,7 +156,7 @@ fn equivalent_fraction(value: f64) -> Option<String> {
numer = numer.trunc();
denom = denom.trunc();
if denom <= 1f64 || denom >= 100f64 || denom == 10f64 {
if denom <= 1f64 || denom >= 100f64 || denom as i64 == 10 {
return None;
}

View File

@ -1,4 +1,5 @@
#![allow(clippy::unused_unit)]
#![allow(clippy::float_cmp)]
mod analysis;
pub mod ast;
pub mod calculation_result;

View File

@ -212,16 +212,11 @@ pub fn parse(context: &mut Context, input: &str) -> Result<Vec<Stmt>, CalcError>
}
fn parse_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
if match_token(context, TokenKind::Identifier) {
return Ok(match peek_next(context).kind {
//TokenKind::Equals => parse_var_decl_stmt(context)?,
_ => Stmt::Expr(Box::new(parse_expr(context)?)),
});
} else if match_token(context, TokenKind::UnitKeyword) {
return parse_unit_decl_stmt(context);
if match_token(context, TokenKind::UnitKeyword) {
parse_unit_decl_stmt(context)
} else {
Ok(Stmt::Expr(Box::new(parse_expr(context)?)))
}
Ok(Stmt::Expr(Box::new(parse_expr(context)?)))
}
fn parse_piecewise(context: &mut Context) -> Result<Expr, CalcError> {
@ -376,6 +371,57 @@ fn parse_comparison(context: &mut Context) -> Result<Expr, CalcError> {
{
let op = peek(context).kind;
advance(context);
// If it's potentially a function declaration, run it through
// the analysis phase to ensure it gets added to the symbol
// table before parsing the right side. This is necessary for
// recursion to work.
if let (TokenKind::Equals, Expr::Binary(_, TokenKind::Star, _)) = (TokenKind::Equals, &left)
{
let analysed = analysis::analyse_stmt(
context.symbol_table.get_mut(),
Stmt::Expr(Box::new(Expr::Binary(
Box::new(left),
op,
Box::new(Expr::Literal(0f64)),
))),
)?;
left = match analysed {
// Reconstruct function declarations into what they were originally parsed as
Stmt::FnDecl(identifier, parameters, _) => {
let mut parameter_vars: Vec<Expr> = parameters
.into_iter()
.map(|x| {
Expr::Var(Identifier::from_full_name(
// Parameters will come back as eg. f-x,
// therefore the function name needs to be removed
&x[identifier.full_name.len() + 1..],
))
})
.collect();
Expr::Binary(
Box::new(Expr::Var(identifier)),
TokenKind::Star,
Box::new(if parameter_vars.len() > 1 {
Expr::Vector(parameter_vars)
} else {
Expr::Group(Box::new(parameter_vars.pop().unwrap()))
}),
)
}
Stmt::Expr(analysed_expr) => {
if let Expr::Binary(analysed_left, TokenKind::Equals, _) = *analysed_expr {
*analysed_left
} else {
unreachable!()
}
}
_ => unreachable!(),
};
}
let right = if op == TokenKind::Equals && match_token(context, TokenKind::OpenBrace) {
parse_piecewise(context)?
} else {
@ -385,7 +431,9 @@ fn parse_comparison(context: &mut Context) -> Result<Expr, CalcError> {
left = match right {
Expr::Binary(
inner_left,
inner_op @ (TokenKind::Equals
inner_op
@
(TokenKind::Equals
| TokenKind::NotEquals
| TokenKind::GreaterThan
| TokenKind::LessThan

11
tests/recursion.kalker Normal file
View File

@ -0,0 +1,11 @@
f(x) = {
f(x - 1) if x >= 1
x otherwise
}
g(x, y) = {
g(x - 1, y + 1) if x >= 1
y otherwise
}
f(5) = 0 and g(5, 0) = 5