mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-12-04 13:43:49 +01:00
Fixed precedence problems for multiplication following function calls
This commit is contained in:
parent
b4e2667f16
commit
39cbbb607d
@ -197,14 +197,7 @@ fn analyse_expr(context: &mut Context, expr: Expr) -> Result<Expr, CalcError> {
|
||||
Expr::Unit(name, value) => Expr::Unit(name, Box::new(analyse_expr(context, *value)?)),
|
||||
Expr::Var(identifier) => analyse_var(context, identifier, None, None)?,
|
||||
Expr::Group(value) => Expr::Group(Box::new(analyse_expr(context, *value)?)),
|
||||
Expr::FnCall(identifier, arguments) => {
|
||||
let mut analysed_arguments = Vec::new();
|
||||
for argument in arguments {
|
||||
analysed_arguments.push(analyse_expr(context, argument)?);
|
||||
}
|
||||
|
||||
Expr::FnCall(identifier, analysed_arguments)
|
||||
}
|
||||
Expr::FnCall(identifier, arguments) => analyse_fn(context, identifier, arguments)?,
|
||||
Expr::Literal(_) => expr,
|
||||
Expr::Piecewise(pieces) => {
|
||||
let mut analysed_pieces = Vec::new();
|
||||
@ -472,29 +465,6 @@ fn analyse_var(
|
||||
adjacent_factor: Option<Expr>,
|
||||
adjacent_exponent: Option<Expr>,
|
||||
) -> Result<Expr, CalcError> {
|
||||
let mut log_base = None;
|
||||
if identifier.full_name.starts_with("log") {
|
||||
if let Some(lowered) = identifier.get_lowered_part() {
|
||||
if let Ok(lowered_float) = lowered.parse::<f64>() {
|
||||
log_base = Some(Expr::Literal(lowered_float));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eg. f(1, 2, 3), f(3) or f3
|
||||
let exists_as_fn = context.symbol_table.contains_fn(&identifier.pure_name)
|
||||
|| context.current_function_name.as_ref() == Some(&identifier.pure_name)
|
||||
|| log_base.is_some();
|
||||
if exists_as_fn {
|
||||
if let Some(adjacent_expr) = adjacent_factor {
|
||||
return with_adjacent(
|
||||
build_fn_call(context, identifier, adjacent_expr, log_base)?,
|
||||
None,
|
||||
adjacent_exponent,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let adjacent_factor = if let Some(adjacent_factor) = adjacent_factor {
|
||||
Some(analyse_expr(context, adjacent_factor)?)
|
||||
} else {
|
||||
@ -591,86 +561,6 @@ fn with_adjacent(
|
||||
}
|
||||
}
|
||||
|
||||
fn build_fn_call(
|
||||
context: &mut Context,
|
||||
identifier: Identifier,
|
||||
adjacent_expr: Expr,
|
||||
log_base: Option<Expr>,
|
||||
) -> Result<Expr, CalcError> {
|
||||
let is_integral = identifier.pure_name == "integrate";
|
||||
let prev_in_integral = context.in_integral;
|
||||
if is_integral {
|
||||
context.in_integral = true;
|
||||
}
|
||||
|
||||
let prev_in_sum_prod = context.in_sum_prod;
|
||||
let is_sum_prod = identifier.pure_name == "sum" || identifier.pure_name == "prod";
|
||||
if is_sum_prod {
|
||||
context.in_sum_prod = true;
|
||||
if context.sum_variable_names.is_none() {
|
||||
context.sum_variable_names = Some(Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
// Don't perform equation solving on special functions
|
||||
if is_integral || is_sum_prod {
|
||||
context.in_equation = false;
|
||||
}
|
||||
|
||||
let arguments = match adjacent_expr {
|
||||
Expr::Vector(arguments) => {
|
||||
let mut new_arguments = Vec::new();
|
||||
for (i, argument) in arguments.iter().enumerate() {
|
||||
if i == 0 && context.in_sum_prod {
|
||||
context.in_conditional = true;
|
||||
let vars = context.sum_variable_names.as_mut().unwrap();
|
||||
if let Expr::Binary(left, TokenKind::Equals, _) = argument {
|
||||
if let Expr::Var(var_identifier) = &**left {
|
||||
vars.push(var_identifier.pure_name.clone());
|
||||
} else {
|
||||
vars.push(String::from("n"));
|
||||
}
|
||||
} else {
|
||||
vars.push(String::from("n"));
|
||||
}
|
||||
}
|
||||
|
||||
new_arguments.push(analyse_expr(context, argument.to_owned())?);
|
||||
context.in_conditional = false;
|
||||
}
|
||||
|
||||
new_arguments
|
||||
}
|
||||
_ => {
|
||||
let argument = if let Expr::Group(argument) = adjacent_expr {
|
||||
*argument
|
||||
} else {
|
||||
adjacent_expr
|
||||
};
|
||||
if let Some(log_base) = log_base {
|
||||
return Ok(Expr::FnCall(
|
||||
Identifier::from_full_name("log"),
|
||||
vec![analyse_expr(context, argument)?, log_base],
|
||||
));
|
||||
} else {
|
||||
vec![analyse_expr(context, argument)?]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if is_integral {
|
||||
context.in_integral = prev_in_integral;
|
||||
}
|
||||
|
||||
if is_sum_prod {
|
||||
context.in_sum_prod = prev_in_sum_prod;
|
||||
let vars = context.sum_variable_names.as_mut().unwrap();
|
||||
vars.pop();
|
||||
}
|
||||
|
||||
Ok(Expr::FnCall(identifier, arguments))
|
||||
}
|
||||
|
||||
fn build_indexed_var(context: &mut Context, identifier: Identifier) -> Result<Expr, CalcError> {
|
||||
let underscore_pos = identifier.pure_name.find('_').unwrap();
|
||||
let var_name = &identifier.pure_name[0..underscore_pos];
|
||||
@ -803,3 +693,59 @@ fn build_var(context: &mut Context, name: &str) -> Expr {
|
||||
|
||||
Expr::Var(Identifier::from_full_name(name))
|
||||
}
|
||||
|
||||
fn analyse_fn(
|
||||
context: &mut Context,
|
||||
identifier: Identifier,
|
||||
arguments: Vec<Expr>,
|
||||
) -> Result<Expr, CalcError> {
|
||||
let is_integral = identifier.pure_name == "integrate";
|
||||
let prev_in_integral = context.in_integral;
|
||||
if is_integral {
|
||||
context.in_integral = true;
|
||||
}
|
||||
|
||||
let prev_in_sum_prod = context.in_sum_prod;
|
||||
let is_sum_prod = identifier.pure_name == "sum" || identifier.pure_name == "prod";
|
||||
if is_sum_prod {
|
||||
context.in_sum_prod = true;
|
||||
if context.sum_variable_names.is_none() {
|
||||
context.sum_variable_names = Some(Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
// Don't perform equation solving on special functions
|
||||
if is_integral || is_sum_prod {
|
||||
context.in_equation = false;
|
||||
}
|
||||
|
||||
let mut analysed_arguments = Vec::new();
|
||||
for (i, argument) in arguments.iter().enumerate() {
|
||||
if i == 0 && context.in_sum_prod {
|
||||
context.in_conditional = true;
|
||||
let vars = context.sum_variable_names.as_mut().unwrap();
|
||||
if let Expr::Binary(left, TokenKind::Equals, _) = argument {
|
||||
if let Expr::Var(var_identifier) = &**left {
|
||||
vars.push(var_identifier.pure_name.clone());
|
||||
} else {
|
||||
vars.push(String::from("n"));
|
||||
}
|
||||
} else {
|
||||
vars.push(String::from("n"));
|
||||
}
|
||||
}
|
||||
|
||||
analysed_arguments.push(analyse_expr(context, argument.to_owned())?);
|
||||
context.in_conditional = false;
|
||||
}
|
||||
|
||||
context.in_integral = prev_in_integral;
|
||||
|
||||
if is_sum_prod {
|
||||
context.in_sum_prod = prev_in_sum_prod;
|
||||
let vars = context.sum_variable_names.as_mut().unwrap();
|
||||
vars.pop();
|
||||
}
|
||||
|
||||
Ok(Expr::FnCall(identifier, analysed_arguments))
|
||||
}
|
||||
|
@ -252,7 +252,9 @@ fn eval_var_expr(
|
||||
}
|
||||
|
||||
if let Some(sum_variables) = &context.sum_variables {
|
||||
let sum_variable = sum_variables.iter().find(|x| x.name == identifier.full_name);
|
||||
let sum_variable = sum_variables
|
||||
.iter()
|
||||
.find(|x| x.name == identifier.full_name);
|
||||
if let Some(sum_variable) = sum_variable {
|
||||
return Ok(KalkValue::from(sum_variable.value));
|
||||
}
|
||||
@ -428,15 +430,16 @@ pub(crate) fn eval_fn_call_expr(
|
||||
));
|
||||
}
|
||||
|
||||
let (var_name, start_expr) = if let Expr::Binary(left, TokenKind::Equals, right) = &expressions[0] {
|
||||
if let Expr::Var(var_identifier) = &**left {
|
||||
(var_identifier.pure_name.as_ref(), &**right)
|
||||
let (var_name, start_expr) =
|
||||
if let Expr::Binary(left, TokenKind::Equals, right) = &expressions[0] {
|
||||
if let Expr::Var(var_identifier) = &**left {
|
||||
(var_identifier.pure_name.as_ref(), &**right)
|
||||
} else {
|
||||
("n", &**right)
|
||||
}
|
||||
} else {
|
||||
("n", &**right)
|
||||
}
|
||||
} else {
|
||||
("n", &expressions[0])
|
||||
};
|
||||
("n", &expressions[0])
|
||||
};
|
||||
|
||||
if context.sum_variables.is_none() {
|
||||
context.sum_variables = Some(Vec::new());
|
||||
@ -444,7 +447,10 @@ pub(crate) fn eval_fn_call_expr(
|
||||
|
||||
{
|
||||
let sum_variables = context.sum_variables.as_mut().unwrap();
|
||||
sum_variables.push(SumVar { name: var_name.into(), value: 0 });
|
||||
sum_variables.push(SumVar {
|
||||
name: var_name.into(),
|
||||
value: 0,
|
||||
});
|
||||
}
|
||||
|
||||
let start = eval_expr(context, start_expr, "")?.to_f64() as i128;
|
||||
@ -636,6 +642,15 @@ fn eval_indexer(
|
||||
}
|
||||
}
|
||||
KalkValue::Matrix(rows) => {
|
||||
if indexes.len() == 1 {
|
||||
let row_index = eval_expr(context, &indexes[0], unit)?.to_f64() as usize;
|
||||
return if let Some(row) = rows.get(row_index - 1) {
|
||||
Ok(KalkValue::Vector(row.clone()))
|
||||
} else {
|
||||
Err(CalcError::ItemOfIndexDoesNotExist(vec![row_index]))
|
||||
};
|
||||
}
|
||||
|
||||
if indexes.len() != 2 {
|
||||
return Err(CalcError::IncorrectAmountOfIndexes(indexes.len(), 2));
|
||||
}
|
||||
@ -660,7 +675,7 @@ fn eval_indexer(
|
||||
column_index,
|
||||
]))
|
||||
}
|
||||
_ => Err(CalcError::CanOnlyIndexVectors),
|
||||
_ => Err(CalcError::CanOnlyIndexX),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ impl Default for Context {
|
||||
/// Error that occured during parsing or evaluation.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CalcError {
|
||||
CanOnlyIndexVectors,
|
||||
CanOnlyIndexX,
|
||||
Expected(String),
|
||||
ExpectedDx,
|
||||
ExpectedIf,
|
||||
@ -118,7 +118,7 @@ pub enum CalcError {
|
||||
impl ToString for CalcError {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
CalcError::CanOnlyIndexVectors => String::from("Indexing (getting an item with a specific index) is only possible on vectors."),
|
||||
CalcError::CanOnlyIndexX => String::from("Indexing (getting an item with a specific index) is only possible on vectors and matrices."),
|
||||
CalcError::Expected(description) => format!("Expected: {}", description),
|
||||
CalcError::ExpectedDx => String::from("Expected eg. dx, to specify for which variable the operation is being done to. Example with integration: ∫(0, 1, x dx) or ∫(0, 1, x, dx). You may need to put parenthesis around the expression before dx/dy/du/etc."),
|
||||
CalcError::ExpectedIf => String::from("Expected 'if', with a condition after it."),
|
||||
@ -411,7 +411,7 @@ fn parse_comparison(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
}
|
||||
|
||||
fn parse_to(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
let left = parse_sum(context)?;
|
||||
let left = parse_term(context)?;
|
||||
|
||||
if match_token(context, TokenKind::ToKeyword) {
|
||||
advance(context);
|
||||
@ -427,13 +427,13 @@ fn parse_to(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
Ok(left)
|
||||
}
|
||||
|
||||
fn parse_sum(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
fn parse_term(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
let mut left = parse_factor(context)?;
|
||||
|
||||
while match_token(context, TokenKind::Plus) || match_token(context, TokenKind::Minus) {
|
||||
let op = peek(context).kind;
|
||||
advance(context);
|
||||
let right = parse_sum(context)?;
|
||||
let right = parse_factor(context)?;
|
||||
|
||||
left = Expr::Binary(Box::new(left), op, Box::new(right));
|
||||
}
|
||||
@ -445,7 +445,7 @@ fn parse_factor(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
let mut left = parse_unit(context)?;
|
||||
|
||||
if let Expr::Unary(TokenKind::Percent, percent_left) = left.clone() {
|
||||
let try_parse = parse_factor(context);
|
||||
let try_parse = parse_unit(context);
|
||||
if try_parse.is_ok() {
|
||||
left = Expr::Binary(percent_left, TokenKind::Percent, Box::new(try_parse?));
|
||||
}
|
||||
@ -473,7 +473,8 @@ fn parse_factor(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
_ => advance(context).kind,
|
||||
};
|
||||
|
||||
let right = parse_factor(context)?;
|
||||
let right = parse_unit(context)?;
|
||||
|
||||
left = Expr::Binary(Box::new(left), op, Box::new(right));
|
||||
}
|
||||
|
||||
@ -650,6 +651,16 @@ fn parse_vector(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 mut log_base = None;
|
||||
if identifier.full_name.starts_with("log") {
|
||||
if let Some(lowered) = identifier.get_lowered_part() {
|
||||
if let Ok(lowered_float) = lowered.parse::<f64>() {
|
||||
log_base = Some(Expr::Literal(lowered_float));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if context.parsing_unit_decl
|
||||
&& !context
|
||||
.symbol_table
|
||||
@ -658,6 +669,28 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
{
|
||||
context.unit_decl_base_unit = Some(identifier.full_name);
|
||||
Ok(Expr::Var(Identifier::from_full_name(DECL_UNIT)))
|
||||
} else if log_base.is_some()
|
||||
|| context
|
||||
.symbol_table
|
||||
.get_mut()
|
||||
.contains_fn(&identifier.pure_name)
|
||||
{
|
||||
// Function call
|
||||
let mut arguments = match parse_vector(context)? {
|
||||
Expr::Vector(arguments) => arguments,
|
||||
Expr::Group(argument) => vec![*argument],
|
||||
argument => vec![argument],
|
||||
};
|
||||
|
||||
if let Some(log_base) = log_base {
|
||||
let log_arg = arguments.remove(0);
|
||||
Ok(Expr::FnCall(
|
||||
Identifier::from_full_name("log"),
|
||||
vec![log_arg, log_base],
|
||||
))
|
||||
} else {
|
||||
Ok(Expr::FnCall(identifier, arguments))
|
||||
}
|
||||
} else {
|
||||
Ok(Expr::Var(identifier))
|
||||
}
|
||||
|
@ -2,4 +2,4 @@ x = 2
|
||||
y = 3
|
||||
f(x) = 2x(x - 3)(y + 2)
|
||||
|
||||
2f(f(x) + y) = 6800
|
||||
2f(f(x) + y) * 2 = 13600
|
4
tests/precedence.kalker
Normal file
4
tests/precedence.kalker
Normal file
@ -0,0 +1,4 @@
|
||||
x = 3
|
||||
2sqrt(64)3x + 2 = 146 and
|
||||
2/sqrt(64)3x + 2 = 4.25 and
|
||||
2sqrt(64)/3x + 2 = 18
|
5
tests/unicode.kalker
Normal file
5
tests/unicode.kalker
Normal file
@ -0,0 +1,5 @@
|
||||
x₂₃ = 3
|
||||
|
||||
π + ϕ + τ + √(64) = 19.0428119495 and
|
||||
log₁₀(100) = 2 and
|
||||
1 + x₂₃ = 4
|
Loading…
Reference in New Issue
Block a user