mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-08 14:38:50 +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
6e81ea5ae1
commit
4c34908368
@ -2,6 +2,7 @@ use crate::ast::{Expr, Stmt};
|
|||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
use crate::parser::CalcError;
|
use crate::parser::CalcError;
|
||||||
use crate::parser::Unit;
|
use crate::parser::Unit;
|
||||||
|
use crate::parser::DECL_UNIT;
|
||||||
use crate::prelude;
|
use crate::prelude;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use rug::ops::Pow;
|
use rug::ops::Pow;
|
||||||
@ -128,11 +129,11 @@ fn convert_unit(
|
|||||||
to_unit: &str,
|
to_unit: &str,
|
||||||
) -> Result<Float, CalcError> {
|
) -> Result<Float, CalcError> {
|
||||||
if let Some(Stmt::UnitDecl(_, _, unit_def)) =
|
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
|
context
|
||||||
.symbol_table
|
.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)
|
eval_expr(context, &unit_def)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,67 +1,114 @@
|
|||||||
use crate::ast::{Expr, Stmt};
|
use crate::ast::{Expr, Stmt};
|
||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
use crate::parser::CalcError;
|
use crate::parser::CalcError;
|
||||||
|
use crate::parser::DECL_UNIT;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
pub fn invert(&self, symbol_table: &mut SymbolTable) -> Result<Self, CalcError> {
|
pub fn invert(&self, symbol_table: &mut SymbolTable) -> Result<Self, CalcError> {
|
||||||
match self {
|
let target_expr = Expr::Var(DECL_UNIT.into());
|
||||||
Expr::Binary(left, op, right) => invert_binary(symbol_table, &left, op, &right),
|
let result = invert(target_expr, symbol_table, self);
|
||||||
Expr::Unary(op, expr) => invert_unary(op, &expr),
|
Ok(result?.0)
|
||||||
Expr::Unit(identifier, expr) => invert_unit(&identifier, &expr),
|
}
|
||||||
Expr::Var(_) => invert_value(self),
|
}
|
||||||
Expr::Group(expr) => invert_group(&expr),
|
|
||||||
Expr::FnCall(identifier, arguments) => {
|
fn invert(
|
||||||
invert_fn_call(symbol_table, &identifier, arguments)
|
target_expr: Expr,
|
||||||
}
|
symbol_table: &mut SymbolTable,
|
||||||
Expr::Literal(_) => invert_value(self),
|
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(target_expr, symbol_table, &identifier, arguments)
|
||||||
|
}
|
||||||
|
Expr::Literal(_) => Ok((target_expr, expr.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invert_binary(
|
fn invert_binary(
|
||||||
|
target_expr: Expr,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
left: &Expr,
|
left: &Expr,
|
||||||
op: &TokenKind,
|
op: &TokenKind,
|
||||||
right: &Expr,
|
right: &Expr,
|
||||||
) -> Result<Expr, CalcError> {
|
) -> Result<(Expr, Expr), CalcError> {
|
||||||
let op_inv = match op {
|
let op_inv = match op {
|
||||||
TokenKind::Plus => TokenKind::Minus,
|
TokenKind::Plus => TokenKind::Minus,
|
||||||
TokenKind::Minus => TokenKind::Plus,
|
TokenKind::Minus => TokenKind::Plus,
|
||||||
TokenKind::Star => TokenKind::Slash,
|
TokenKind::Star => {
|
||||||
TokenKind::Slash => 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!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Expr::Binary(
|
if contains_the_unit(left) {
|
||||||
Box::new(right.invert(symbol_table)?),
|
return Ok(invert(
|
||||||
op_inv,
|
Expr::Binary(Box::new(target_expr), op_inv, Box::new(right.clone())),
|
||||||
Box::new(left.invert(symbol_table)?),
|
symbol_table,
|
||||||
))
|
left,
|
||||||
}
|
)?);
|
||||||
|
}
|
||||||
|
|
||||||
fn invert_unary(op: &TokenKind, expr: &Expr) -> Result<Expr, CalcError> {
|
Ok(invert(
|
||||||
Ok(match op {
|
Expr::Binary(Box::new(target_expr), op_inv, Box::new(left.clone())),
|
||||||
TokenKind::Minus => expr.clone(),
|
symbol_table,
|
||||||
TokenKind::Exclamation => unimplemented!(),
|
right,
|
||||||
_ => unreachable!(),
|
)?)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not necessary yet
|
// 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!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invert_group(expr: &Expr) -> Result<Expr, CalcError> {
|
|
||||||
invert_value(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invert_fn_call(
|
fn invert_fn_call(
|
||||||
|
target_expr: Expr,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
arguments: &Vec<Expr>,
|
arguments: &Vec<Expr>,
|
||||||
) -> Result<Expr, CalcError> {
|
) -> Result<(Expr, Expr), CalcError> {
|
||||||
let (parameters, body) =
|
let (parameters, body) =
|
||||||
if let Some(Stmt::FnDecl(_, parameters, body)) = symbol_table.get_fn(identifier).cloned() {
|
if let Some(Stmt::FnDecl(_, parameters, body)) = symbol_table.get_fn(identifier).cloned() {
|
||||||
(parameters, body)
|
(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> {
|
fn contains_the_unit(expr: &Expr) -> bool {
|
||||||
Ok(Expr::Unary(TokenKind::Minus, Box::new(expr.clone())))
|
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;
|
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.
|
/// Struct containing the current state of the parser. It stores user-defined functions and variables.
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
@ -20,7 +22,7 @@ pub struct Context {
|
|||||||
symbol_table: SymbolTable,
|
symbol_table: SymbolTable,
|
||||||
angle_unit: Unit,
|
angle_unit: Unit,
|
||||||
/// This is true whenever the parser is currently parsing a unit declaration.
|
/// 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.
|
/// Unit names are instead treated as variables.
|
||||||
parsing_unit_decl: bool,
|
parsing_unit_decl: bool,
|
||||||
/// When a unit declaration is being parsed, this value will be set
|
/// 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
|
// Eg. x
|
||||||
if context.parsing_unit_decl {
|
if context.symbol_table.contains_var(&identifier.value) {
|
||||||
context.unit_decl_base_unit = Some(identifier.value);
|
|
||||||
Ok(Expr::Var(String::from("u")))
|
|
||||||
} else if context.symbol_table.contains_var(&identifier.value) {
|
|
||||||
Ok(Expr::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 {
|
} else {
|
||||||
let mut chars = identifier.value.chars();
|
let mut chars = identifier.value.chars();
|
||||||
let mut left = Expr::Var(chars.next().unwrap().to_string());
|
let mut left = Expr::Var(chars.next().unwrap().to_string());
|
||||||
|
Loading…
Reference in New Issue
Block a user