From b1cbaea86da7a3d0362e02f4cf62e08f85c08b2a Mon Sep 17 00:00:00 2001 From: raffitz Date: Thu, 25 Mar 2021 00:00:18 +0000 Subject: [PATCH] Add AST data structures --- src/astree.rs | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 138 +++++++++++++++++++--------- 2 files changed, 344 insertions(+), 42 deletions(-) create mode 100644 src/astree.rs diff --git a/src/astree.rs b/src/astree.rs new file mode 100644 index 0000000..dbd1832 --- /dev/null +++ b/src/astree.rs @@ -0,0 +1,248 @@ +use std::collections::HashMap; + +#[derive(Debug, PartialEq)] +pub enum Error { + UnrecognisedBinaryOperator, + UnrecognisedCondition, + UnrecognisedJunction, + MissingVarValue, + MissingIdentAssignment, + MissingVarMap, + MissingIdentMap, +} + +#[derive(Debug, PartialEq)] +pub enum FunctionType { + Sin, + Cos, + Tan, + Asin, + Acos, + Atan, + Sign, + Abs, + Sqrt, + Exp, + Ln, + Log, +} + +#[derive(Debug)] +pub struct FunctionData { + kind: FunctionType, + arg: Box, +} + +impl FunctionData { + pub fn new(kind: FunctionType, arg_exp: Expression) -> Self { + let arg = Box::new(arg_exp); + FunctionData { kind, arg } + } + + pub fn eval( + &self, + idents: Option<&HashMap>, + vars: Option<&HashMap>, + ) -> Result { + let value = self.arg.eval(idents, vars)?; + + match self.kind { + FunctionType::Sin => Ok(value.sin()), + FunctionType::Cos => Ok(value.cos()), + FunctionType::Tan => Ok(value.tan()), + FunctionType::Asin => Ok(value.asin()), + FunctionType::Acos => Ok(value.acos()), + FunctionType::Atan => Ok(value.atan()), + FunctionType::Sign => Ok(value.signum()), + FunctionType::Abs => Ok(value.abs()), + FunctionType::Sqrt => Ok(value.sqrt()), + FunctionType::Exp => Ok(value.exp()), + FunctionType::Ln => Ok(value.ln()), + FunctionType::Log => Ok(value.log10()), + } + } +} + +#[derive(Debug)] +pub struct OperationData { + kind: char, + left: Box, + right: Box, +} + +impl OperationData { + pub fn new(kind: char, left_exp: Expression, right_exp: Expression) -> Self { + let left = Box::new(left_exp); + let right = Box::new(right_exp); + OperationData { kind, left, right } + } + + pub fn eval( + &self, + idents: Option<&HashMap>, + vars: Option<&HashMap>, + ) -> Result { + let left = self.left.eval(idents, vars)?; + let right = self.right.eval(idents, vars)?; + + match self.kind { + '+' => Ok(left + right), + '-' => Ok(left - right), + '*' => Ok(left * right), + '/' => Ok(left / right), + '^' => Ok(left.powf(right)), + _ => Err(Error::UnrecognisedBinaryOperator), + } + } +} + +#[derive(Debug)] +pub enum Expression { + Var(char), + Float(f64), + Ident(String), + Function(FunctionData), + Operation(OperationData), +} + +impl Expression { + pub fn var(c: char) -> Self { + Expression::Var(c) + } + + pub fn float(f: f64) -> Self { + Expression::Float(f) + } + + pub fn ident(s: String) -> Self { + Expression::Ident(s) + } + + pub fn function(f: FunctionType, arg: Expression) -> Self { + let data = FunctionData::new(f, arg); + Expression::Function(data) + } + + pub fn operation(kind: char, left: Expression, right: Expression) -> Self { + let data = OperationData::new(kind, left, right); + Expression::Operation(data) + } + + pub fn eval( + &self, + idents: Option<&HashMap>, + vars: Option<&HashMap>, + ) -> Result { + match self { + Expression::Float(f) => Ok(*f), + Expression::Function(f) => f.eval(idents, vars), + Expression::Operation(o) => o.eval(idents, vars), + Expression::Var(c) => { + let value = vars + .ok_or::(Error::MissingVarMap)? + .get(c) + .ok_or::(Error::MissingVarValue)?; + Ok(*value) + } + Expression::Ident(s) => { + let referred = idents + .ok_or::(Error::MissingIdentMap)? + .get(s) + .ok_or::(Error::MissingIdentAssignment)?; + referred.eval(idents, vars) + } + } + } +} + +#[derive(Debug)] +pub struct Condition { + kind: char, + left: Box, + right: Box, +} + +impl Condition { + pub fn new(kind: char, left_exp: Expression, right_exp: Expression) -> Self { + let left = Box::new(left_exp); + let right = Box::new(right_exp); + Condition { kind, left, right } + } + + pub fn eval( + &self, + idents: Option<&HashMap>, + vars: Option<&HashMap>, + ) -> Result { + let left_val = self.left.eval(idents, vars)?; + let right_val = self.right.eval(idents, vars)?; + match self.kind { + '=' => Ok((left_val - right_val).abs() < 100.0_f64 * f64::EPSILON), + '<' => Ok(left_val < right_val), + '>' => Ok(left_val > right_val), + '≤' => Ok(left_val <= right_val), + '≥' => Ok(left_val >= right_val), + _ => Err(Error::UnrecognisedCondition), + } + } +} + +#[derive(Debug)] +pub struct JunctionData { + kind: char, + left: Box, + right: Box, +} + +impl JunctionData { + pub fn new(kind: char, left_cond: Junction, right_cond: Junction) -> Self { + let left = Box::new(left_cond); + let right = Box::new(right_cond); + JunctionData { kind, left, right } + } + + pub fn eval( + &self, + idents: Option<&HashMap>, + vars: Option<&HashMap>, + ) -> Result { + let left_val = self.left.eval(idents, vars)?; + let right_val = self.right.eval(idents, vars)?; + match self.kind { + '⋀' => Ok(left_val & right_val), + '⋁' => Ok(left_val | right_val), + '⊻' => Ok(left_val ^ right_val), + '⊼' => Ok(!(left_val & right_val)), + '⊽' => Ok(!(left_val | right_val)), + _ => Err(Error::UnrecognisedJunction), + } + } +} + +#[derive(Debug)] +pub enum Junction { + Singleton(Condition), + Meta(JunctionData), +} + +impl Junction { + pub fn singleton(cond: Condition) -> Self { + Junction::Singleton(cond) + } + + pub fn meta(kind: char, left_cond: Junction, right_cond: Junction) -> Self { + let data = JunctionData::new(kind, left_cond, right_cond); + Junction::Meta(data) + } + + pub fn eval( + &self, + idents: Option<&HashMap>, + vars: Option<&HashMap>, + ) -> Result { + match self { + Junction::Meta(meta) => meta.eval(idents, vars), + Junction::Singleton(cond) => cond.eval(idents, vars), + } + } +} diff --git a/src/main.rs b/src/main.rs index 2e6d1cd..d41681a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ use pomelo::pomelo; use std::fs; use std::io::{Error, ErrorKind, Read}; +mod astree; + macro_rules! scale_message { ($n:ident) => { Err(format!("<{}> is not a positive integer", $n)) @@ -21,28 +23,55 @@ fn io_error(err: Error, path: &str) -> String { pomelo! { %include { use logos::{Lexer, Logos}; + use crate::astree::{Condition, Expression, FunctionType, Junction, Error}; + use std::collections::HashMap; + + #[derive(Debug)] + pub struct Limit{ + var: char, + min: Expression, + max: Expression, + } - #[derive(Debug, PartialEq)] - pub enum FunctionType{ - Sin, - Cos, - Tan, - Asin, - Acos, - Atan, - Sign, - Abs, - Sqrt, - Exp, - Log(f64), + impl Limit{ + pub fn new( + l: Expression, + lcond: char, + var: char, + rcond: char, + r: Expression, + ) -> Result { + if var != 'x' && var != 'y' && var != 'z' { + return Err(()); + } + if lcond == '<' || lcond == '≤' { + if rcond == '<' || rcond == '≤'{ + let min = l; + let max = r; + return Ok(Limit{var,min,max}); + } + return Err(()); + }else if lcond == '>' || lcond == '≥'{ + if rcond == '>' || rcond == '≥'{ + let min = r; + let max = l; + return Ok(Limit{var,min,max}); + } + return Err(()); + } + Err(()) + } } + type Limits = (Limit,Limit,Limit); + + type Return = (Option>,Limits,Junction); + fn read_var(lex: &mut Lexer) -> Option { lex.slice().chars().next() } } - %token #[derive(Logos, Debug, PartialEq)] pub enum Token {}; @@ -117,8 +146,8 @@ pomelo! { #[token("sqrt", |_| FunctionType::Sqrt)] #[token("√", |_| FunctionType::Sqrt)] #[token("exp", |_| FunctionType::Exp)] - #[token("ln", |_| FunctionType::Log(1.0))] - #[token("log", |_| FunctionType::Log(std::f64::consts::LN_10))] + #[token("ln", |_| FunctionType::Ln)] + #[token("log", |_| FunctionType::Log)] Function FunctionType; %type #[token("(")] LParen; @@ -144,32 +173,57 @@ pomelo! { %right Function; %left LineEnd; - input ::= limits metajuncture; - input ::= limits assignments metajuncture; - limit ::= expr Qualifier Var Qualifier expr; - limits ::= limit LineEnd limit LineEnd limit LineEnd; - limits ::= LineEnd limits; - assignment ::= Assign Ident expr; - assignments ::= assignment LineEnd; - assignments ::= assignment LineEnd assignments; - quality ::= expr Qualifier expr; - juncture ::= quality; - juncture ::= juncture Junction juncture; - juncture ::= LBrace juncture RBrace; - metajuncture ::= juncture; - metajuncture ::= metajuncture LineEnd; - metajuncture ::= metajuncture LineEnd metajuncture; - - expr ::= expr Sum expr; - expr ::= expr Subtraction expr; - expr ::= expr Product expr; - expr ::= expr Quotient expr; - expr ::= expr Power expr; - expr ::= Function expr; - expr ::= LParen expr RParen; - expr ::= Var; - expr ::= Float; - expr ::= Ident; + %type input Return; + input ::= limits(L) metajuncture(J) { (None,L,J) } + input ::= LineEnd limits(L) metajuncture(J) { (None,L,J) } + input ::= assignments(A) limits(L) metajuncture(J) { (Some(A),L,J) } + input ::= LineEnd assignments(A) limits(L) metajuncture(J) { (Some(A),L,J) } + + %type limit Limit; + limit ::= expr(L) Qualifier(F) Var(V) Qualifier(S) expr(R) { Limit::new(L,F,V,S,R)? } + + %type limits Limits; + limits ::= limit(A) LineEnd limit(B) LineEnd limit(C) LineEnd { (A,B,C) } + + %type assignment (String,Expression); + assignment ::= Assign Ident(S) expr(E) { (S,E) } + + %type assignments HashMap; + assignments ::= assignment(A) LineEnd { + let (k,v) = A; + let mut m = HashMap::new(); + m.insert(k,v); + m + } + assignments ::= assignment(A) LineEnd assignments(mut M){ + let (k,v) = A; + M.insert(k,v); + M + } + %type quality Condition; + quality ::= expr(L) Qualifier(Q) expr (R) { Condition::new(Q,L,R) } + + %type juncture Junction; + juncture ::= quality(Q) { Junction::singleton(Q) } + juncture ::= juncture(L) Junction(J) juncture(R) { Junction::meta(J,L,R) } + juncture ::= LBrace juncture(J) RBrace { J } + + %type metajuncture Junction; + metajuncture ::= juncture(J) { J } + metajuncture ::= metajuncture(M) LineEnd { M } + metajuncture ::= metajuncture(L) LineEnd metajuncture(R) { Junction::meta('⋀',L,R) } + + %type expr Expression; + expr ::= expr(L) Sum expr(R) { Expression::operation('+',L,R) } + expr ::= expr(L) Subtraction expr(R) { Expression::operation('-',L,R) } + expr ::= expr(L) Product expr(R) { Expression::operation('*',L,R) } + expr ::= expr(L) Quotient expr(R) { Expression::operation('/',L,R) } + expr ::= expr(L) Power expr(R) { Expression::operation('^',L,R) } + expr ::= Function(F) expr(A) { Expression::function(F,A) } + expr ::= LParen expr(E) RParen { E } + expr ::= Var(V) { Expression::var(V) } + expr ::= Float(F) { Expression::float(F) } + expr ::= Ident(S) { Expression::ident(S) } } fn main() -> Result<(), ()> {