mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-11-08 00:44:40 +01:00
Changed inverter to instead move expressions to the LHS, like done when equations are solved in maths. Also made it multiply into parenthesis.
This commit is contained in:
parent
1edec7d16e
commit
24771b3a5a
@ -2,6 +2,7 @@ use crate::ast::{Expr, Stmt};
|
||||
use crate::lexer::TokenKind;
|
||||
use crate::parser::CalcError;
|
||||
use crate::parser::Unit;
|
||||
use crate::parser::DECL_UNIT;
|
||||
use crate::prelude;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use rug::ops::Pow;
|
||||
@ -128,11 +129,11 @@ fn convert_unit(
|
||||
to_unit: &str,
|
||||
) -> Result<Float, CalcError> {
|
||||
if let Some(Stmt::UnitDecl(_, _, unit_def)) =
|
||||
context.symbol_table.get_unit(from_unit, to_unit).cloned()
|
||||
context.symbol_table.get_unit(to_unit, from_unit).cloned()
|
||||
{
|
||||
context
|
||||
.symbol_table
|
||||
.insert(Stmt::VarDecl(String::from("u"), Box::new(expr.clone())));
|
||||
.insert(Stmt::VarDecl(DECL_UNIT.into(), Box::new(expr.clone())));
|
||||
|
||||
eval_expr(context, &unit_def)
|
||||
} else {
|
||||
|
@ -1,67 +1,114 @@
|
||||
use crate::ast::{Expr, Stmt};
|
||||
use crate::lexer::TokenKind;
|
||||
use crate::parser::CalcError;
|
||||
use crate::parser::DECL_UNIT;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
|
||||
impl Expr {
|
||||
pub fn invert(&self, symbol_table: &mut SymbolTable) -> Result<Self, CalcError> {
|
||||
match self {
|
||||
Expr::Binary(left, op, right) => invert_binary(symbol_table, &left, op, &right),
|
||||
Expr::Unary(op, expr) => invert_unary(op, &expr),
|
||||
Expr::Unit(identifier, expr) => invert_unit(&identifier, &expr),
|
||||
Expr::Var(_) => invert_value(self),
|
||||
Expr::Group(expr) => invert_group(&expr),
|
||||
let target_expr = Expr::Var(DECL_UNIT.into());
|
||||
let result = invert(target_expr, symbol_table, self);
|
||||
Ok(result?.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn invert(
|
||||
target_expr: Expr,
|
||||
symbol_table: &mut SymbolTable,
|
||||
expr: &Expr,
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
match expr {
|
||||
Expr::Binary(left, op, right) => {
|
||||
invert_binary(target_expr, symbol_table, &left, op, &right)
|
||||
}
|
||||
Expr::Unary(_, _) => Ok((target_expr, expr.clone())),
|
||||
Expr::Unit(identifier, expr) => invert_unit(target_expr, &identifier, &expr),
|
||||
Expr::Var(_) => Ok((target_expr, expr.clone())),
|
||||
Expr::Group(expr) => Ok((target_expr, *expr.clone())),
|
||||
Expr::FnCall(identifier, arguments) => {
|
||||
invert_fn_call(symbol_table, &identifier, arguments)
|
||||
}
|
||||
Expr::Literal(_) => invert_value(self),
|
||||
invert_fn_call(target_expr, symbol_table, &identifier, arguments)
|
||||
}
|
||||
Expr::Literal(_) => Ok((target_expr, expr.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
fn invert_binary(
|
||||
target_expr: Expr,
|
||||
symbol_table: &mut SymbolTable,
|
||||
left: &Expr,
|
||||
op: &TokenKind,
|
||||
right: &Expr,
|
||||
) -> Result<Expr, CalcError> {
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
let op_inv = match op {
|
||||
TokenKind::Plus => TokenKind::Minus,
|
||||
TokenKind::Minus => TokenKind::Plus,
|
||||
TokenKind::Star => TokenKind::Slash,
|
||||
TokenKind::Slash => TokenKind::Star,
|
||||
TokenKind::Star => {
|
||||
if let Expr::Group(inside_group) = left {
|
||||
return invert(
|
||||
target_expr,
|
||||
symbol_table,
|
||||
&multiply_in(right, inside_group)?,
|
||||
);
|
||||
}
|
||||
|
||||
if let Expr::Group(inside_group) = right {
|
||||
return invert(target_expr, symbol_table, &multiply_in(left, inside_group)?);
|
||||
}
|
||||
|
||||
TokenKind::Slash
|
||||
}
|
||||
TokenKind::Slash => {
|
||||
if let Expr::Group(inside_group) = left {
|
||||
return invert(
|
||||
target_expr,
|
||||
symbol_table,
|
||||
&Expr::Binary(inside_group.clone(), op.clone(), Box::new(right.clone())),
|
||||
);
|
||||
}
|
||||
|
||||
if let Expr::Group(inside_group) = right {
|
||||
return invert(
|
||||
target_expr,
|
||||
symbol_table,
|
||||
&Expr::Binary(Box::new(left.clone()), op.clone(), inside_group.clone()),
|
||||
);
|
||||
}
|
||||
|
||||
TokenKind::Star
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(Expr::Binary(
|
||||
Box::new(right.invert(symbol_table)?),
|
||||
op_inv,
|
||||
Box::new(left.invert(symbol_table)?),
|
||||
))
|
||||
if contains_the_unit(left) {
|
||||
return Ok(invert(
|
||||
Expr::Binary(Box::new(target_expr), op_inv, Box::new(right.clone())),
|
||||
symbol_table,
|
||||
left,
|
||||
)?);
|
||||
}
|
||||
|
||||
fn invert_unary(op: &TokenKind, expr: &Expr) -> Result<Expr, CalcError> {
|
||||
Ok(match op {
|
||||
TokenKind::Minus => expr.clone(),
|
||||
TokenKind::Exclamation => unimplemented!(),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
Ok(invert(
|
||||
Expr::Binary(Box::new(target_expr), op_inv, Box::new(left.clone())),
|
||||
symbol_table,
|
||||
right,
|
||||
)?)
|
||||
}
|
||||
|
||||
// Not necessary yet
|
||||
fn invert_unit(_identifier: &str, _expr: &Expr) -> Result<Expr, CalcError> {
|
||||
fn invert_unit(
|
||||
_target_expr: Expr,
|
||||
_identifier: &str,
|
||||
_expr: &Expr,
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn invert_group(expr: &Expr) -> Result<Expr, CalcError> {
|
||||
invert_value(expr)
|
||||
}
|
||||
|
||||
fn invert_fn_call(
|
||||
target_expr: Expr,
|
||||
symbol_table: &mut SymbolTable,
|
||||
identifier: &str,
|
||||
arguments: &Vec<Expr>,
|
||||
) -> Result<Expr, CalcError> {
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
let (parameters, body) =
|
||||
if let Some(Stmt::FnDecl(_, parameters, body)) = symbol_table.get_fn(identifier).cloned() {
|
||||
(parameters, body)
|
||||
@ -85,9 +132,49 @@ fn invert_fn_call(
|
||||
));
|
||||
}
|
||||
|
||||
body.invert(symbol_table)
|
||||
invert(target_expr, symbol_table, &body)
|
||||
}
|
||||
|
||||
fn invert_value(expr: &Expr) -> Result<Expr, CalcError> {
|
||||
Ok(Expr::Unary(TokenKind::Minus, Box::new(expr.clone())))
|
||||
fn contains_the_unit(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::Binary(left, _, right) => contains_the_unit(left) || contains_the_unit(right),
|
||||
Expr::Unary(_, expr) => contains_the_unit(expr),
|
||||
Expr::Unit(_, expr) => contains_the_unit(expr),
|
||||
Expr::Var(identifier) => identifier == DECL_UNIT,
|
||||
Expr::Group(expr) => contains_the_unit(expr),
|
||||
Expr::FnCall(_, args) => {
|
||||
for arg in args {
|
||||
if contains_the_unit(arg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
Expr::Literal(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn multiply_in(expr: &Expr, base_expr: &Expr) -> Result<Expr, CalcError> {
|
||||
match base_expr {
|
||||
Expr::Binary(left, op, right) => match op {
|
||||
TokenKind::Plus | TokenKind::Minus => Ok(Expr::Binary(
|
||||
Box::new(multiply_in(expr, &left)?),
|
||||
op.clone(),
|
||||
Box::new(multiply_in(expr, &right)?),
|
||||
)),
|
||||
TokenKind::Star | TokenKind::Slash => Ok(Expr::Binary(
|
||||
Box::new(multiply_in(expr, &left)?),
|
||||
op.clone(),
|
||||
right.clone(),
|
||||
)),
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
Expr::Literal(_) | Expr::Var(_) => Ok(Expr::Binary(
|
||||
Box::new(expr.clone()),
|
||||
TokenKind::Star,
|
||||
Box::new(base_expr.clone()),
|
||||
)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ use crate::{
|
||||
};
|
||||
use rug::Float;
|
||||
|
||||
pub const DECL_UNIT: &'static str = ".u";
|
||||
|
||||
/// Struct containing the current state of the parser. It stores user-defined functions and variables.
|
||||
/// # Examples
|
||||
/// ```
|
||||
@ -20,7 +22,7 @@ pub struct Context {
|
||||
symbol_table: SymbolTable,
|
||||
angle_unit: Unit,
|
||||
/// This is true whenever the parser is currently parsing a unit declaration.
|
||||
/// It is necessary to keep track of this since you cannot use variables in unit declarations.
|
||||
/// It is necessary to keep track of this in order to know when to find (figure out) units that haven't been defined yet.
|
||||
/// Unit names are instead treated as variables.
|
||||
parsing_unit_decl: bool,
|
||||
/// When a unit declaration is being parsed, this value will be set
|
||||
@ -346,11 +348,11 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
}
|
||||
|
||||
// Eg. x
|
||||
if context.parsing_unit_decl {
|
||||
context.unit_decl_base_unit = Some(identifier.value);
|
||||
Ok(Expr::Var(String::from("u")))
|
||||
} else if context.symbol_table.contains_var(&identifier.value) {
|
||||
if context.symbol_table.contains_var(&identifier.value) {
|
||||
Ok(Expr::Var(identifier.value))
|
||||
} else if context.parsing_unit_decl {
|
||||
context.unit_decl_base_unit = Some(identifier.value);
|
||||
Ok(Expr::Var(DECL_UNIT.into()))
|
||||
} else {
|
||||
let mut chars = identifier.value.chars();
|
||||
let mut left = Expr::Var(chars.next().unwrap().to_string());
|
||||
|
Loading…
Reference in New Issue
Block a user