use std::rc::Rc; use std::str::FromStr; use lalrpop_util::ParseError; use assert::{relabel, grouping}; use rsprocess::{set, reaction, process, environment, system, label}; use rsprocess::element::IdType; use rsprocess::translator::Translator; use execution::presets; use rsprocess::graph; use crate::custom_error; grammar(translator: &mut Translator); extern { type Error = custom_error::UserError; } // ----------------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------------- // order match { "!", } else { r"[0-9]+" => NUMBER } else { r"([[:alpha:]])([[:word:]])*" => WORD // r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD, } else { r#""[^"]+""# => PATH, // " <- ignore comment, its for the linter in emacs } else { _ } // matches words (letter followed by numbers, letters or _) Literal: String = { WORD => <>.into(), }; Num: i64 = { =>? { if sign.is_some() { i64::from_str(n) .map(|n| -n) .map_err(|_| ParseError::User { error: custom_error::UserError { token: (start, n.into(), end), error: custom_error::UserErrorTypes::NumberTooBigi64 } }) } else { i64::from_str(n) .map_err(|_| ParseError::User { error: custom_error::UserError { token: (start, n.into(), end), error: custom_error::UserErrorTypes::NumberTooBigi64 } }) } } }; // macro for matching sequence of patterns with C as separator Separated: Vec = { C)+> => match e { None => v, Some(e) => { v.push(e); v } } }; Separated_Or: Vec = { => vec![v], > => v } Separated_Empty: Vec = { LP RP => vec![], LP RP => vec![v], LP > RP => v } // ----------------------------------------------------------------------------- // SetParser // ----------------------------------------------------------------------------- pub Set: set::Set = { > => set::Set::from(t.into_iter().map(|t| translator.encode(t)) .collect::>()) }; // ----------------------------------------------------------------------------- // LabelParser // ----------------------------------------------------------------------------- pub Label: label::Label = { "[" "Entities" ":" "," "Context" ":" "," "Reactants" ":" "," "ReactantsAbsent" ":" "," "Inhibitors" ":" "," "InhibitorsPresent" ":" "," "Products" ":" ","? "]" => label::Label::create(e, c, r, r_a, i, i_p, p) } // ----------------------------------------------------------------------------- // GroupingParser // ----------------------------------------------------------------------------- Group: Box = { ">" "node" "{" "}" => Box::new(grouping::Assert{tree: f}), }; GroupTree: grouping::Tree = { => grouping::Tree::Concat(Box::new(t1), Box::new(t2)), => t, } GroupTree2: grouping::Tree = { #[precedence(level="1")] "if" "then" "{" "}" ";"? => grouping::Tree::If(Box::new(e), Box::new(t)), #[precedence(level="0")] "if" "then" "{" "}" "else" "{" "}" ";"? => grouping::Tree::IfElse(Box::new(e), Box::new(t1), Box::new(t2)), "let" "=" ";" => grouping::Tree::Assignment(v, q, Box::new(e)), "return" ";" => grouping::Tree::Return(Box::new(e)), "for" "in" "{" "}" ";"? => grouping::Tree::For(v, r, Box::new(t)), } GroupVariable: grouping::Variable = { #[precedence(level="0")] "entities" => grouping::Variable::Special(grouping::Special::Entities), "node" => grouping::Variable::Special(grouping::Special::Node), #[precedence(level="1")] => grouping::Variable::Id(v), } GroupExpression: grouping::Expression = { #[precedence(level="100")] "(" ")" => grouping::Expression::Unary(unp, Box::new(e)), #[precedence(level="50")] "." => grouping::Expression::Unary(uns, Box::new(e)), #[precedence(level="100")] #[assoc(side="left")] => grouping::Expression::Binary(b, Box::new(e1), Box::new(e2)), #[precedence(level="100")] "(" "," ")" => grouping::Expression::Binary(b, Box::new(e1), Box::new(e2)), #[precedence(level="0")] => t, } GroupTerm: grouping::Expression = { "true" => grouping::Expression::True, "false" => grouping::Expression::False, => grouping::Expression::Var(v), // If changing IntegerType in assert.rs, also change from Num to another // similar parser with different return type => grouping::Expression::Integer(i), => grouping::Expression::Label(Box::new(lab)), => grouping::Expression::Set(set), "'" "'" => grouping::Expression::Element(translator.encode(el)), // strings PATH => grouping::Expression::String(<>.trim_end_matches("\"") .trim_start_matches("\"") .to_string()), // allow arbitrary parenthesis "(" ")" => e, } #[inline] GroupRange: grouping::Range = { "{" "}" => grouping::Range::IterateOverSet(Box::new(e)), "{" ".." "}" => grouping::Range::IterateInRange(Box::new(e1), Box::new(e2)), } #[inline] GroupUnaryPrefix: grouping::Unary = { "not" => grouping::Unary::Not, "rand" => grouping::Unary::Rand, } #[inline] GroupUnarySuffix: grouping::Unary = { #[precedence(level="0")] "empty" => grouping::Unary::Empty, "length" => grouping::Unary::Length, "tostr" => grouping::Unary::ToStr, "toel" => grouping::Unary::ToEl, #[precedence(level="1")] => grouping::Unary::Qualifier(q), } #[inline] GroupQualifierRestricted: grouping::QualifierRestricted = { "Entities" => grouping::QualifierRestricted::Entities, "Context" => grouping::QualifierRestricted::Context, "Reactants" => grouping::QualifierRestricted::Reactants, "ReactantsAbsent" => grouping::QualifierRestricted::ReactantsAbsent, "Inhibitors" => grouping::QualifierRestricted::Inhibitors, "InhibitorsPresent" => grouping::QualifierRestricted::InhibitorsPresent, "Products" => grouping::QualifierRestricted::Products, } #[inline] GroupQualifierLabel: grouping::QualifierLabel = { "AvailableEntities" => grouping::QualifierLabel::AvailableEntities, "AllReactants" => grouping::QualifierLabel::AllReactants, "AllInhibitors" => grouping::QualifierLabel::AllInhibitors, } #[inline] GroupQualifierSystem: grouping::QualifierSystem = { "SystemEntities" => grouping::QualifierSystem::Entities, "SystemContext" => grouping::QualifierSystem::Context, } #[inline] GroupQualifierEdge: grouping::QualifierEdge = { "source" => grouping::QualifierEdge::Source, "target" => grouping::QualifierEdge::Target, } #[inline] GroupQualifierNode: grouping::QualifierNode = { "neighbours" => grouping::QualifierNode::Neighbours, "system" => grouping::QualifierNode::System, } #[inline] GroupQualifier: grouping::Qualifier = { => grouping::Qualifier::System(q), => grouping::Qualifier::Label(q), => grouping::Qualifier::Restricted(q), => grouping::Qualifier::Edge(q), => grouping::Qualifier::Node(q), } #[inline] GroupBinary: grouping::Binary = { "&&" => grouping::Binary::And, "||" => grouping::Binary::Or, "^^" => grouping::Binary::Xor, "<" => grouping::Binary::Less, "<=" => grouping::Binary::LessEq, ">" => grouping::Binary::More, ">=" => grouping::Binary::MoreEq, "==" => grouping::Binary::Eq, "!=" => grouping::Binary::NotEq, "+" => grouping::Binary::Plus, "-" => grouping::Binary::Minus, "*" => grouping::Binary::Times, "^" => grouping::Binary::Exponential, "/" => grouping::Binary::Quotient, "%" => grouping::Binary::Reminder, "::" => grouping::Binary::Concat, } #[inline] GroupBinaryPrefix: grouping::Binary = { "substr" => grouping::Binary::SubStr, "min" => grouping::Binary::Min, "max" => grouping::Binary::Max, "commonsubstr" => grouping::Binary::CommonSubStr, }