Browse Source

Add AST data structures

main
raffitz 3 years ago
parent
commit
b1cbaea86d
Signed by: raffitz
GPG Key ID: BB3596BD0A31252D
  1. 248
      src/astree.rs
  2. 138
      src/main.rs

248
src/astree.rs

@ -0,0 +1,248 @@ @@ -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<Expression>,
}
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<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
) -> Result<f64, Error> {
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<Expression>,
right: Box<Expression>,
}
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<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
) -> Result<f64, Error> {
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<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
) -> Result<f64, Error> {
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>(Error::MissingVarMap)?
.get(c)
.ok_or::<Error>(Error::MissingVarValue)?;
Ok(*value)
}
Expression::Ident(s) => {
let referred = idents
.ok_or::<Error>(Error::MissingIdentMap)?
.get(s)
.ok_or::<Error>(Error::MissingIdentAssignment)?;
referred.eval(idents, vars)
}
}
}
}
#[derive(Debug)]
pub struct Condition {
kind: char,
left: Box<Expression>,
right: Box<Expression>,
}
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<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
) -> Result<bool, Error> {
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<Junction>,
right: Box<Junction>,
}
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<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
) -> Result<bool, Error> {
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<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
) -> Result<bool, Error> {
match self {
Junction::Meta(meta) => meta.eval(idents, vars),
Junction::Singleton(cond) => cond.eval(idents, vars),
}
}
}

138
src/main.rs

@ -4,6 +4,8 @@ use pomelo::pomelo; @@ -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 { @@ -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<Self,()> {
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<HashMap<String,Expression>>,Limits,Junction);
fn read_var(lex: &mut Lexer<Token>) -> Option<char> {
lex.slice().chars().next()
}
}
%token #[derive(Logos, Debug, PartialEq)]
pub enum Token {};
@ -117,8 +146,8 @@ pomelo! { @@ -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! { @@ -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<String,Expression>;
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<(), ()> {

Loading…
Cancel
Save