use std::str::FromStr; use lalrpop_util::ParseError; use assert::grouping; use rsprocess::{set, label}; use rsprocess::translator::Translator; use crate::custom_error; grammar(translator: &mut Translator); extern { type Error = custom_error::UserError; } // ----------------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------------- // order match { "!", "!=", "%", "&&", "'", "(", ")", "*", "+", ",", "-", "..", "/", ":", "::", ";", "<", "<=", "=", "==", ">", ">=", "AllInhibitors", "AllReactants", "AvailableEntities", "Context", "Entities", "getGuardInhibitors", "getGuardProducts", "getGuardReactants", "getIdentifier", "getNextProcesses", "getRepeatedCounter", "getRepeatedProcess", "getSet", "Inhibitors", "InhibitorsPresent", "isGuarded", "isIdentifier", "isNill", "isNondeterministicChoice", "isRepeated", "isSet", "isSummation", "Products", "Reactants", "ReactantsAbsent", "SystemContext", "SystemEntities", "[", "\"", "]", "^", "^^", "edge", "else", "empty", "entities", "false", "for", "if", "in", "label", "length", "let", "neighbours", "node", "not", "rand", "return", "source", "system", "target", "then", "toel", "tostr", "true", "{", "||", "}", } 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 // ----------------------------------------------------------------------------- Set: set::Set = { > => set::Set::from(s.into_iter().map(|t| translator.encode(t)) .collect::>()) }; // ----------------------------------------------------------------------------- // LabelParser // ----------------------------------------------------------------------------- Label: label::Label = { "[" "Entities" ":" "," "Context" ":" "," "Reactants" ":" "," "ReactantsAbsent" ":" "," "Inhibitors" ":" "," "InhibitorsPresent" ":" "," "Products" ":" ","? "]" => label::Label::create(e, c, r, r_a, i, i_p, p) } // ----------------------------------------------------------------------------- // GroupingParser // ----------------------------------------------------------------------------- pub 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, } GroupRange: grouping::Range = { "{" "}" => grouping::Range::IterateOverSet(Box::new(e)), "{" ".." "}" => grouping::Range::IterateInRange(Box::new(e1), Box::new(e2)), } GroupUnaryPrefix: grouping::Unary = { "not" => grouping::Unary::Not, "rand" => grouping::Unary::Rand, } 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), } 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, } GroupQualifierLabel: grouping::QualifierLabel = { "AvailableEntities" => grouping::QualifierLabel::AvailableEntities, "AllReactants" => grouping::QualifierLabel::AllReactants, "AllInhibitors" => grouping::QualifierLabel::AllInhibitors, } GroupQualifierSystem: grouping::QualifierSystem = { "SystemEntities" => grouping::QualifierSystem::Entities, "SystemContext" => grouping::QualifierSystem::Context, } GroupQualifierContext: grouping::QualifierContext = { "isNill" => grouping::QualifierContext::IsNill, "isIdentifier" => grouping::QualifierContext::IsIdentifier, "isSet" => grouping::QualifierContext::IsSet, "isGuarded" => grouping::QualifierContext::IsGuarded, "isRepeated" => grouping::QualifierContext::IsRepeated, "isSummation" => grouping::QualifierContext::IsSummation, "isNondeterministicChoice" => grouping::QualifierContext::IsNondeterministicChoice, "getIdentifier" => grouping::QualifierContext::GetIdentifier, "getSet" => grouping::QualifierContext::GetSet, "getGuardReactants" => grouping::QualifierContext::GetGuardReactants, "getGuardInhibitors" => grouping::QualifierContext::GetGuardInhibitors, "getGuardProducts" => grouping::QualifierContext::GetGuardProducts, "getRepeatedCounter" => grouping::QualifierContext::GetRepeatedCounter, "getRepeatedProcess" => grouping::QualifierContext::GetRepeatedProcess, "getNextProcesses" => grouping::QualifierContext::GetNextProcesses, } GroupQualifierEdge: grouping::QualifierEdge = { "source" => grouping::QualifierEdge::Source, "target" => grouping::QualifierEdge::Target, "label" => grouping::QualifierEdge::Label, } GroupQualifierNode: grouping::QualifierNode = { "neighbours" => grouping::QualifierNode::Neighbours, "system" => grouping::QualifierNode::System, } GroupQualifier: grouping::Qualifier = { => grouping::Qualifier::System(q), => grouping::Qualifier::Context(q), => grouping::Qualifier::Label(q), => grouping::Qualifier::Restricted(q), => grouping::Qualifier::Edge(q), => grouping::Qualifier::Node(q), } 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, } GroupBinaryPrefix: grouping::Binary = { "substr" => grouping::Binary::SubStr, "min" => grouping::Binary::Min, "max" => grouping::Binary::Max, "commonsubstr" => grouping::Binary::CommonSubStr, }