diff --git a/src/rsprocess/assert.rs b/src/rsprocess/assert.rs index 0c50ef9..eb9b75c 100644 --- a/src/rsprocess/assert.rs +++ b/src/rsprocess/assert.rs @@ -20,7 +20,11 @@ pub enum Tree { For(Variable, Range, Box), } -pub type Variable = String; +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Variable { + Id(String), + Label +} #[derive(Debug, Clone)] pub enum AssignmentVariable { @@ -28,15 +32,6 @@ pub enum AssignmentVariable { QualifiedVar(Variable, QualifierRestricted) } -impl fmt::Display for AssignmentVariable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Var(v) => write!(f, "{v}"), - Self::QualifiedVar(v, q) => write!(f, "{v}.{q}"), - } - } -} - #[derive(Debug, Clone)] pub enum Expression { True, @@ -67,9 +62,26 @@ pub enum Unary { Length, ToStr, Qualifier(Qualifier), + ToEl } impl Unary { + fn is_prefix(&self) -> bool { + match self { + Self::Not | + Self::Rand => {true}, + Self::Empty | + Self::Length | + Self::ToStr | + Self::Qualifier(_) | + Self::ToEl => {false} + } + } + + fn is_suffix(&self) -> bool { + !self.is_prefix() + } + fn associated_types_unary(&self) -> Vec { match self { Unary::Not => vec![AssertionTypes::Boolean], @@ -80,25 +92,12 @@ impl Unary { Unary::ToStr => vec![AssertionTypes::Boolean, AssertionTypes::Integer, AssertionTypes::Element], - Unary::Qualifier(_) => vec![AssertionTypes::Set] + Unary::Qualifier(_) => vec![AssertionTypes::Set], + Unary::ToEl => vec![AssertionTypes::String] } } } -impl fmt::Display for Unary { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Unary::Not => write!(f, "not"), - Unary::Rand => write!(f, "rand"), - Unary::Empty => write!(f, ".empty"), - Unary::Length => write!(f, ".length"), - Unary::ToStr => write!(f, ".tostr"), - Unary::Qualifier(q) => write!(f, ".{q}"), - } - } -} - - #[derive(Debug, Clone, Copy)] pub enum QualifierRestricted { Entities, @@ -110,27 +109,6 @@ pub enum QualifierRestricted { Products, } -impl fmt::Display for QualifierRestricted { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - QualifierRestricted::Entities => - write!(f, "Entities"), - QualifierRestricted::Context => - write!(f, "Context"), - QualifierRestricted::Reactants => - write!(f, "Reactants"), - QualifierRestricted::ReactantsAbsent => - write!(f, "ReactantsAbsent"), - QualifierRestricted::Inhibitors => - write!(f, "Inhibitors"), - QualifierRestricted::InhibitorsPresent => - write!(f, "InhibitorsPresent"), - QualifierRestricted::Products => - write!(f, "Products"), - } - } -} - #[derive(Debug, Clone, Copy)] pub enum Qualifier { AvailableEntities, @@ -139,18 +117,6 @@ pub enum Qualifier { Restricted(QualifierRestricted), } -impl fmt::Display for Qualifier { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::AvailableEntities => write!(f, "AvailableEntities"), - Self::AllReactants => write!(f, "AllReactants"), - Self::AllInhibitors => write!(f, "AllInhibitors"), - Self::Restricted(q) => write!(f, "{q}"), - } - } -} - - #[derive(Debug, Clone, Copy)] pub enum Binary { And, @@ -177,6 +143,60 @@ pub enum Binary { } impl Binary { + fn is_prefix(&self) -> bool { + match self { + Self::And | + Self::Or | + Self::Xor | + Self::Less | + Self::LessEq | + Self::More | + Self::MoreEq | + Self::Eq | + Self::NotEq | + Self::Plus | + Self::Minus | + Self::Times | + Self::Exponential | + Self::Quotient | + Self::Reminder | + Self::Concat => false, + Self::SubStr | + Self::Min | + Self::Max | + Self::CommonSubStr => true, + } + } + + fn is_suffix(&self) -> bool { + false + } + + fn is_infix(&self) -> bool { + match self { + Self::And | + Self::Or | + Self::Xor | + Self::Less | + Self::LessEq | + Self::More | + Self::MoreEq | + Self::Eq | + Self::NotEq | + Self::Plus | + Self::Minus | + Self::Times | + Self::Exponential | + Self::Quotient | + Self::Reminder | + Self::Concat => true, + Self::SubStr | + Self::Min | + Self::Max | + Self::CommonSubStr => false, + } + } + fn associate( &self, t1: &AssertionTypes, @@ -274,40 +294,13 @@ impl Binary { } } -impl fmt::Display for Binary { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::And => write!(f, "&&"), - Self::Or => write!(f, "||"), - Self::Xor => write!(f, "^^"), - Self::Less => write!(f, "<"), - Self::LessEq => write!(f, "<="), - Self::More => write!(f, ">"), - Self::MoreEq => write!(f, ">="), - Self::Eq => write!(f, "=="), - Self::NotEq => write!(f, "!="), - Self::Plus => write!(f, "+"), - Self::Minus => write!(f, "-"), - Self::Times => write!(f, "*"), - Self::Exponential => write!(f, "^"), - Self::Quotient => write!(f, "/"), - Self::Reminder => write!(f, "%"), - Self::Concat => write!(f, "::"), - Self::SubStr => write!(f, "substr"), - Self::Min => write!(f, "min"), - Self::Max => write!(f, "max"), - Self::CommonSubStr => write!(f, "commonsubstr"), - } - } -} - use core::fmt; // ----------------------------------------------------------------------------- use std::collections::HashMap; struct Context { - data: HashMap, + data: HashMap, ty_return: Option } @@ -326,10 +319,13 @@ impl Context { ) -> Result<(), String> { match v { AssignmentVariable::Var(v) => { - self.data.insert(v.clone(), ty); + if let Variable::Id(v) = v { + self.data.insert(v.clone(), ty); + } Ok(()) }, - AssignmentVariable::QualifiedVar(v, q) => { + AssignmentVariable::QualifiedVar(Variable::Label, _) => Ok(()), + AssignmentVariable::QualifiedVar(Variable::Id(v), q) => { if let Some(AssertionTypes::Label) = self.data.get(v) { Ok(()) } else { @@ -362,6 +358,11 @@ impl Context { v: &Variable, ty: AssertionTypes ) -> Result<(), String> { + let v = match v { + Variable::Label => return Err("Protected word label used in for \ + assignment.".into()), + Variable::Id(v) => v + }; match ty { AssertionTypes::RangeSet => { self.data.insert(v.clone(), AssertionTypes::Element); @@ -383,13 +384,22 @@ impl Context { ) -> Result { match v { AssignmentVariable::Var(v) => { - if let Some(ty) = self.data.get(v) { - Ok(*ty) - } else { - Err(format!("Could not find variable {v}.")) + match v { + Variable::Label => Ok(AssertionTypes::Label), + Variable::Id(v) => { + if let Some(ty) = self.data.get(v) { + Ok(*ty) + } else { + Err(format!("Could not find variable {v}.")) + } + } } }, AssignmentVariable::QualifiedVar(var, _) => { + let var = match var { + Variable::Id(v) => v, + Variable::Label => return Ok(AssertionTypes::Set), + }; if let Some(ty) = self.data.get(var) { if *ty == AssertionTypes::Label { Ok(AssertionTypes::Set) @@ -559,3 +569,164 @@ impl RSassert { Ok(()) } } + + +// ----------------------------------------------------------------------------- +// Display Implementation for all types +// ----------------------------------------------------------------------------- + +impl fmt::Display for RSassert { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "label {{\n{}\n}}", self.tree) + } +} + +impl fmt::Display for Tree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Concat(t1, t2) => {write!(f, "{t1};\n{t2}")}, + Self::If(exp, t) => {write!(f, "if {exp} {{\n{t}\n}}")}, + Self::IfElse(exp, t1, t2) => { + write!(f, "if {exp} {{\n{t1}\n}} else {{\n{t2}\n}}") + }, + Self::Assignment(v, exp) => {write!(f, "{v} = {exp}")}, + Self::Return(exp) => {write!(f, "return {exp}")}, + Self::For(v, r, t) => {write!(f, "for {v} in {r} {{\n{t}\n}}")}, + } + } +} + +impl fmt::Display for Variable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Label => {write!(f, "label")}, + Self::Id(s) => {write!(f, "{s}")} + } + } +} + +impl fmt::Display for AssignmentVariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Var(v) => write!(f, "{v}"), + Self::QualifiedVar(v, q) => write!(f, "{v}.{q}"), + } + } +} + +impl fmt::Display for Expression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::True => {write!(f, "True")}, + Self::False => {write!(f, "False")}, + Self::Integer(i) => {write!(f, "{i}")}, + Self::Label(rslabel) => {write!(f, "{rslabel:?}")}, + Self::Set(set) => {write!(f, "{set:?}")}, + Self::Element(el) => {write!(f, "'{el}'")}, + Self::String(s) => {write!(f, r#""{s}""#)}, + Self::Var(v) => {write!(f, "{v}")}, + Self::Unary(u, exp) => { + if u.is_prefix() { + write!(f, "{u}({exp})") + } else if u.is_suffix() { + write!(f, "{exp}{u}") + } else { + unreachable!() + } + }, + Self::Binary(b, exp1, exp2) => { + if b.is_prefix() { + write!(f, "{b}({exp1}, {exp2})") + } else if b.is_suffix() { + write!(f, "({exp1}, {exp2}){b}") + } else if b.is_infix() { + write!(f, "({exp1} {b} {exp2})") + } else { + unreachable!() + } + }, + } + } +} + +impl fmt::Display for Range { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::IterateOverSet(exp) => {write!(f, "{{{exp}}}")}, + Self::IterateInRange(exp1, exp2) => {write!(f, "{exp1}..{exp2}")} + } + } +} + +impl fmt::Display for Unary { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Unary::Not => write!(f, "not"), + Unary::Rand => write!(f, "rand"), + Unary::Empty => write!(f, ".empty"), + Unary::Length => write!(f, ".length"), + Unary::ToStr => write!(f, ".tostr"), + Unary::Qualifier(q) => write!(f, ".{q}"), + Unary::ToEl => write!(f, ".toel") + } + } +} + +impl fmt::Display for QualifierRestricted { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + QualifierRestricted::Entities => + write!(f, "Entities"), + QualifierRestricted::Context => + write!(f, "Context"), + QualifierRestricted::Reactants => + write!(f, "Reactants"), + QualifierRestricted::ReactantsAbsent => + write!(f, "ReactantsAbsent"), + QualifierRestricted::Inhibitors => + write!(f, "Inhibitors"), + QualifierRestricted::InhibitorsPresent => + write!(f, "InhibitorsPresent"), + QualifierRestricted::Products => + write!(f, "Products"), + } + } +} + +impl fmt::Display for Qualifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::AvailableEntities => write!(f, "AvailableEntities"), + Self::AllReactants => write!(f, "AllReactants"), + Self::AllInhibitors => write!(f, "AllInhibitors"), + Self::Restricted(q) => write!(f, "{q}"), + } + } +} + +impl fmt::Display for Binary { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::And => write!(f, "&&"), + Self::Or => write!(f, "||"), + Self::Xor => write!(f, "^^"), + Self::Less => write!(f, "<"), + Self::LessEq => write!(f, "<="), + Self::More => write!(f, ">"), + Self::MoreEq => write!(f, ">="), + Self::Eq => write!(f, "=="), + Self::NotEq => write!(f, "!="), + Self::Plus => write!(f, "+"), + Self::Minus => write!(f, "-"), + Self::Times => write!(f, "*"), + Self::Exponential => write!(f, "^"), + Self::Quotient => write!(f, "/"), + Self::Reminder => write!(f, "%"), + Self::Concat => write!(f, "::"), + Self::SubStr => write!(f, "substr"), + Self::Min => write!(f, "min"), + Self::Max => write!(f, "max"), + Self::CommonSubStr => write!(f, "commonsubstr"), + } + } +} diff --git a/src/rsprocess/grammar.lalrpop b/src/rsprocess/grammar.lalrpop index 01679c9..2e66bce 100644 --- a/src/rsprocess/grammar.lalrpop +++ b/src/rsprocess/grammar.lalrpop @@ -30,7 +30,6 @@ match { "r:", "i:", "p:", "-", "^", "true", "false", - "inW", "inR", "inI", "inP", "Environment", "Initial Entities", "Context", "Reactions", "Weights", "Sets", "Print", "Save", @@ -38,6 +37,7 @@ match { "Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency", "FastFrequency", "Digraph", "Bisimilarity", "Deserialize", + "?", "Hide", "Entities", "MaskEntities", "UncommonEntities", "UncommonMaskEntities", "MaskContext", "UncommonContext", "UncommonMaskContext", @@ -49,6 +49,11 @@ match { "UncommonEntitiesDeleted", "UncommonMaskEntitiesDeleted", "EntitiesAdded", "MaskEntitiesAdded", "UncommonEntitiesAdded", "UncommonMaskEntitiesAdded", + "label", "if", "then", "else", "let", "=", "return", "for", "in", + "not", "rand", ".empty", ".length", ".tostr", + "&&", "||", "^^", "<=", ">=", "==", "!=", "+", "*", "/", "%", + "::", "substr", "min", "max", "commonsubstr", + "AvailableEntities", "AllReactants", "AllInhibitors", } else { r"[0-9]+" => NUMBER } else { @@ -174,7 +179,7 @@ Env_term: (IdType, RSprocess) = { // AssertParser // ----------------------------------------------------------------------------- pub Assert: Box = { - "fn" "{" "}" => + "label" "{" "}" => Box::new(assert::RSassert{tree: f}), }; @@ -211,13 +216,27 @@ AssertAssignmentVar: assert::AssignmentVariable = { } AssertVariable: assert::Variable = { - => v + "label" => assert::Variable::Label, + => assert::Variable::Id(v), } AssertExpression: assert::Expression = { + => + assert::Expression::Unary(unp, Box::new(e)), + "(" ")" => + assert::Expression::Unary(uns, Box::new(e)), + + "(" ")" => + assert::Expression::Binary(b, Box::new(e1), Box::new(e2)), + + "(" "," ")" => + assert::Expression::Binary(b, Box::new(e1), Box::new(e2)), + "(" ")" => e, - "True" => assert::Expression::True, - "False" => assert::Expression::False, + "true" => assert::Expression::True, + "false" => assert::Expression::False, + + => assert::Expression::Var(v), // If changing IntegerType in assert.rs, also change from Num to another // similar parser with different return type @@ -231,17 +250,6 @@ AssertExpression: assert::Expression = { PATH => assert::Expression::String(<>.trim_end_matches("\"") .trim_start_matches("\"") .to_string()), - - => - assert::Expression::Unary(unp, Box::new(e)), - "(" ")" => - assert::Expression::Unary(uns, Box::new(e)), - - "(" ")" => - assert::Expression::Binary(b, Box::new(e1), Box::new(e2)), - - "(" "," ")" => - assert::Expression::Binary(b, Box::new(e1), Box::new(e2)), } AssertUnaryPrefix: assert::Unary = {