mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-12-13 10:00:51 +01:00
Fixed recursion not working
This commit is contained in:
parent
1b35a2ab42
commit
3009ad2ee1
@ -51,6 +51,7 @@ mod tests {
|
|||||||
#[test_case("matrices/operations")]
|
#[test_case("matrices/operations")]
|
||||||
#[test_case("matrices/transpose")]
|
#[test_case("matrices/transpose")]
|
||||||
#[test_case("radix")]
|
#[test_case("radix")]
|
||||||
|
#[test_case("recursion")]
|
||||||
#[test_case("redefining")]
|
#[test_case("redefining")]
|
||||||
#[test_case("sum")]
|
#[test_case("sum")]
|
||||||
#[test_case("variables")]
|
#[test_case("variables")]
|
||||||
|
@ -156,7 +156,7 @@ fn equivalent_fraction(value: f64) -> Option<String> {
|
|||||||
numer = numer.trunc();
|
numer = numer.trunc();
|
||||||
denom = denom.trunc();
|
denom = denom.trunc();
|
||||||
|
|
||||||
if denom <= 1f64 || denom >= 100f64 || denom == 10f64 {
|
if denom <= 1f64 || denom >= 100f64 || denom as i64 == 10 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![allow(clippy::unused_unit)]
|
#![allow(clippy::unused_unit)]
|
||||||
|
#![allow(clippy::float_cmp)]
|
||||||
mod analysis;
|
mod analysis;
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod calculation_result;
|
pub mod calculation_result;
|
||||||
|
@ -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> {
|
fn parse_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||||
if match_token(context, TokenKind::Identifier) {
|
if match_token(context, TokenKind::UnitKeyword) {
|
||||||
return Ok(match peek_next(context).kind {
|
parse_unit_decl_stmt(context)
|
||||||
//TokenKind::Equals => parse_var_decl_stmt(context)?,
|
} else {
|
||||||
_ => Stmt::Expr(Box::new(parse_expr(context)?)),
|
Ok(Stmt::Expr(Box::new(parse_expr(context)?)))
|
||||||
});
|
|
||||||
} else if match_token(context, TokenKind::UnitKeyword) {
|
|
||||||
return parse_unit_decl_stmt(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Stmt::Expr(Box::new(parse_expr(context)?)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_piecewise(context: &mut Context) -> Result<Expr, CalcError> {
|
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;
|
let op = peek(context).kind;
|
||||||
advance(context);
|
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) {
|
let right = if op == TokenKind::Equals && match_token(context, TokenKind::OpenBrace) {
|
||||||
parse_piecewise(context)?
|
parse_piecewise(context)?
|
||||||
} else {
|
} else {
|
||||||
@ -385,7 +431,9 @@ fn parse_comparison(context: &mut Context) -> Result<Expr, CalcError> {
|
|||||||
left = match right {
|
left = match right {
|
||||||
Expr::Binary(
|
Expr::Binary(
|
||||||
inner_left,
|
inner_left,
|
||||||
inner_op @ (TokenKind::Equals
|
inner_op
|
||||||
|
@
|
||||||
|
(TokenKind::Equals
|
||||||
| TokenKind::NotEquals
|
| TokenKind::NotEquals
|
||||||
| TokenKind::GreaterThan
|
| TokenKind::GreaterThan
|
||||||
| TokenKind::LessThan
|
| TokenKind::LessThan
|
||||||
|
11
tests/recursion.kalker
Normal file
11
tests/recursion.kalker
Normal 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
|
Loading…
Reference in New Issue
Block a user