mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-07 22:19:24 +01:00
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:
parent
45adb1b526
commit
71df9f5454
@ -1,6 +1,4 @@
|
|||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
use crate::parser::CalcError;
|
|
||||||
use crate::parser::Unit;
|
|
||||||
|
|
||||||
/// A tree structure of a statement.
|
/// A tree structure of a statement.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -23,20 +21,3 @@ pub enum Expr {
|
|||||||
FnCall(String, Vec<Expr>),
|
FnCall(String, Vec<Expr>),
|
||||||
Literal(String),
|
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
52
kalk/src/inverter.rs
Normal 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()))
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
mod interpreter;
|
mod interpreter;
|
||||||
|
mod inverter;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
mod prelude;
|
mod prelude;
|
||||||
|
@ -19,7 +19,12 @@ pub struct Context {
|
|||||||
pos: usize,
|
pos: usize,
|
||||||
symbol_table: SymbolTable,
|
symbol_table: SymbolTable,
|
||||||
angle_unit: Unit,
|
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,
|
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>,
|
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);
|
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));
|
let stmt = Stmt::UnitDecl(identifier.value, base_unit, Box::new(def));
|
||||||
|
|
||||||
context.symbol_table.insert(stmt.clone());
|
context.symbol_table.insert(stmt.clone());
|
||||||
|
context.symbol_table.insert(stmt_inv);
|
||||||
|
|
||||||
Ok(stmt)
|
Ok(stmt)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user