Created the foundation of an expression inverter. This is used to create a second *inverted* unit declaration, in order to cover both of the units.

This commit is contained in:
PaddiM8 2020-06-13 19:01:33 +02:00
parent eb20aae16f
commit bff785bc1e
4 changed files with 67 additions and 19 deletions

View File

@ -1,6 +1,4 @@
use crate::lexer::TokenKind;
use crate::parser::CalcError;
use crate::parser::Unit;
/// A tree structure of a statement.
#[derive(Debug, Clone, PartialEq)]
@ -23,20 +21,3 @@ pub enum Expr {
FnCall(String, Vec<Expr>),
Literal(String),
}
impl TokenKind {
pub fn is_unit(&self) -> bool {
match self {
TokenKind::Deg | TokenKind::Rad => true,
_ => false,
}
}
pub fn to_unit(&self) -> Result<Unit, CalcError> {
match self {
TokenKind::Deg => Ok(Unit::Degrees),
TokenKind::Rad => Ok(Unit::Radians),
_ => Err(CalcError::InvalidUnit),
}
}
}

52
kalk/src/inverter.rs Normal file
View File

@ -0,0 +1,52 @@
use crate::ast::Expr;
use crate::lexer::TokenKind;
impl Expr {
pub fn invert(&self) -> Self {
match self {
Expr::Binary(left, op, right) => invert_binary(&left, op, &right),
Expr::Unary(op, expr) => invert_unary(op, &expr),
Expr::Unit(identifier, expr) => invert_unit(&identifier, &expr),
Expr::Var(identifier) => invert_value(self),
Expr::Group(expr) => invert_group(&expr),
Expr::FnCall(identifier, expressions) => invert_fn_call(&identifier, expressions),
Expr::Literal(value) => invert_value(self),
}
}
}
fn invert_binary(left: &Expr, op: &TokenKind, right: &Expr) -> Expr {
let op_inv = match op {
TokenKind::Plus => TokenKind::Minus,
TokenKind::Minus => TokenKind::Plus,
TokenKind::Star => TokenKind::Slash,
TokenKind::Slash => TokenKind::Star,
_ => unreachable!(),
};
Expr::Binary(Box::new(right.invert()), op_inv, Box::new(left.invert()))
}
fn invert_unary(op: &TokenKind, expr: &Expr) -> Expr {
match op {
TokenKind::Minus => expr.clone(),
TokenKind::Exclamation => unimplemented!(),
_ => unreachable!(),
}
}
fn invert_unit(identifier: &str, expr: &Expr) -> Expr {
unimplemented!()
}
fn invert_group(expr: &Expr) -> Expr {
invert_value(expr)
}
fn invert_fn_call(identifier: &str, expressions: &Vec<Expr>) -> Expr {
unimplemented!()
}
fn invert_value(expr: &Expr) -> Expr {
Expr::Unary(TokenKind::Minus, Box::new(expr.clone()))
}

View File

@ -1,5 +1,6 @@
pub mod ast;
mod interpreter;
mod inverter;
mod lexer;
pub mod parser;
mod prelude;

View File

@ -19,7 +19,12 @@ pub struct Context {
pos: usize,
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.
/// Unit names are instead treated as variables.
parsing_unit_decl: bool,
/// When a unit declaration is being parsed, this value will be set
/// whenever a unit in the expression is found. Eg. unit a = 3b, it will be set to Some("b")
unit_decl_base_unit: Option<String>,
}
@ -176,9 +181,18 @@ fn parse_unit_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
return Err(CalcError::InvalidUnit);
};
// Automatically create a second unit decl with the expression inverted.
// This will turn eg. unit a = 3b, into unit b = a/3
// This is so that you only have to define `a`, and it will figure out the formula for `b` since it is used in the formula for `a`.
let stmt_inv = Stmt::UnitDecl(
base_unit.clone(),
identifier.value.clone(),
Box::new(def.invert()),
);
let stmt = Stmt::UnitDecl(identifier.value, base_unit, Box::new(def));
context.symbol_table.insert(stmt.clone());
context.symbol_table.insert(stmt_inv);
Ok(stmt)
}