use std::rc::Rc; use std::str::FromStr; use lalrpop_util::ParseError; use rsprocess::{set, reaction, process, environment, system, label}; use rsprocess::element::{self, IdType}; use rsprocess::translator::Translator; use crate::custom_error; grammar(translator: &mut Translator); extern { type Error = custom_error::UserError; } // ----------------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------------- // order match { "!", "(", ")", "+", ",", "-", ".", ":", ";", "<", "<=", "=", "==", ">", ">=", "?", "AbsentReactants", "Bisimilarity", "Context", "Context.EntitySet", "Context.Nill", "Context.NonDeterministicChoice", "Context.RecursiveIdentifier", "Context.Summation", "Context.WaitEntity", "Deserialize", "Difference", "Digraph", "Dot", "Entities", "EntitiesAdded", "EntitiesDeleted", "Environment", "ExcludeEntities", "FastFrequency", "GraphML", "Grequency", "Hide", "Inhibitors", "InhibitorsPresent", "Initial Entities", "Limit", "LimitFrequency", "Loop", "MaskContext", "MaskDifference", "MaskEntities", "MaskEntitiesAdded", "MaskEntitiesDeleted", "MaskProducts", "MaskUncommonEntities", "MaskUnion", "PresentInhibitors", "Print", "Products", "Reactants", "ReactantsAbsent", "Reactions", "Run", "Save", "Serialize", "Sets", "Stats", "T", "Target", "UncommonContext", "UncommonDifference", "UncommonEntities", "UncommonEntitiesAdded", "UncommonEntitiesDeleted", "UncommonMaskContext", "UncommonMaskDifference", "UncommonMaskEntities", "UncommonMaskEntitiesAdded", "UncommonMaskEntitiesDeleted", "UncommonMaskProducts", "UncommonMaskUnion", "UncommonProducts", "UncommonUnion", "Union", "Weights", "[", "]", "i:", "nill", "p:", "r:", "relabel", "{", "|", "}", "⊂", "⊃", "⊆", "⊇", } 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(), }; LiteralProcess: String = { Literal => <>, "AbsentReactants" => <>.into(), "Bisimilarity" => <>.into(), "Context" => <>.into(), "Context.EntitySet" => <>.into(), "Context.Nill" => <>.into(), "Context.NonDeterministicChoice" => <>.into(), "Context.RecursiveIdentifier" => <>.into(), "Context.Summation" => <>.into(), "Context.WaitEntity" => <>.into(), "Deserialize" => <>.into(), "Difference" => <>.into(), "Digraph" => <>.into(), "Dot" => <>.into(), "Entities" => <>.into(), "EntitiesAdded" => <>.into(), "EntitiesDeleted" => <>.into(), "Environment" => <>.into(), "ExcludeEntities" => <>.into(), "FastFrequency" => <>.into(), "GraphML" => <>.into(), "Grequency" => <>.into(), "Hide" => <>.into(), "Inhibitors" => <>.into(), "InhibitorsPresent" => <>.into(), "Initial" => <>.into(), "Limit" => <>.into(), "LimitFrequency" => <>.into(), "Loop" => <>.into(), "MaskContext" => <>.into(), "MaskDifference" => <>.into(), "MaskEntities" => <>.into(), "MaskEntitiesAdded" => <>.into(), "MaskEntitiesDeleted" => <>.into(), "MaskProducts" => <>.into(), "MaskUncommonEntities" => <>.into(), "MaskUnion" => <>.into(), "PresentInhibitors" => <>.into(), "Print" => <>.into(), "Products" => <>.into(), "Reactants" => <>.into(), "ReactantsAbsent" => <>.into(), "Reactions" => <>.into(), "Run" => <>.into(), "Save" => <>.into(), "Serialize" => <>.into(), "Sets" => <>.into(), "Stats" => <>.into(), "T" => <>.into(), "Target" => <>.into(), "UncommonContext" => <>.into(), "UncommonDifference" => <>.into(), "UncommonEntities" => <>.into(), "UncommonEntitiesAdded" => <>.into(), "UncommonEntitiesDeleted" => <>.into(), "UncommonMaskContext" => <>.into(), "UncommonMaskDifference" => <>.into(), "UncommonMaskEntities" => <>.into(), "UncommonMaskEntitiesAdded" => <>.into(), "UncommonMaskEntitiesDeleted" => <>.into(), "UncommonMaskProducts" => <>.into(), "UncommonMaskUnion" => <>.into(), "UncommonProducts" => <>.into(), "UncommonUnion" => <>.into(), "Union" => <>.into(), "Weights" => <>.into(), "relabel" => <>.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 } }) } } }; NumUsize: usize = { =>? usize::from_str(n) .map_err(|_| ParseError::User { error: custom_error::UserError { token: (start, n.into(), end), error: custom_error::UserErrorTypes::NumberTooBigUsize } }) }; Path: String = { PATH => <>.trim_end_matches("\"").trim_start_matches("\"").to_string() }; // 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(s.into_iter().map(|t| translator.encode(t)) .collect::>()) }; pub PositiveSet: set::PositiveSet = { > => set::PositiveSet::from(s) }; PositiveLiteral: (element::IdType, element::IdState) = { "+" => (translator.encode(t), element::IdState::Positive), "-" => (translator.encode(t), element::IdState::Negative), } // ----------------------------------------------------------------------------- // ReactionParser // ----------------------------------------------------------------------------- pub Reactions: Vec = { > => s } Reaction: reaction::Reaction = { #[precedence(level="1")] "[" "," "," "]" => reaction::Reaction::from(r, i, p), #[precedence(level="0")] "[" "r:" "," "i:" "," "p:" "]" => reaction::Reaction::from(r, i, p), } pub PositiveReactions: Vec = { > => s } PositiveReaction: reaction::PositiveReaction = { #[precedence(level="1")] "[" "," "]" => reaction::PositiveReaction::from(r, p), #[precedence(level="0")] "[" "r:" "," "p:" "]" => reaction::PositiveReaction::from(r, p), } // ----------------------------------------------------------------------------- // ContextParser // ----------------------------------------------------------------------------- pub Context: process::Process = { > => process::Process::NondeterministicChoice{ children: t.into_iter().map(Rc::new).collect::>() } }; ContextProcess: process::Process = { "nill" => process::Process::Nill, "." => process::Process::EntitySet{ entities: c, next_process: Rc::new(k) }, "(" ")" => k, "(" > ")" => process::Process::Summation{ children: k.into_iter().map(Rc::new).collect::>() }, "?" "?" "." => process::Process::Guarded{ reaction: r, next_process: Rc::new(k) }, "<" "," ">" "." => process::Process::WaitEntity{ repeat: n, repeated_process: Rc::new(k1), next_process: Rc::new(k) }, => process::Process::RecursiveIdentifier{ identifier: translator.encode(identifier) } }; pub PositiveContext: process::PositiveProcess = { > => process::PositiveProcess::NondeterministicChoice{ children: t.into_iter().map(Rc::new).collect::>() } }; PositiveContextProcess: process::PositiveProcess = { "nill" => process::PositiveProcess::Nill, "." => process::PositiveProcess::EntitySet{ entities: c, next_process: Rc::new(k) }, "(" ")" => k, "(" > ")" => process::PositiveProcess::Summation{ children: k.into_iter().map(Rc::new).collect::>() }, "?" "?" "." => process::PositiveProcess::Guarded{ reaction: r, next_process: Rc::new(k) }, "<" "," ">" "." => process::PositiveProcess::WaitEntity{ repeat: n, repeated_process: Rc::new(k1), next_process: Rc::new(k) }, => process::PositiveProcess::RecursiveIdentifier{ identifier: translator.encode(identifier) } }; // ----------------------------------------------------------------------------- // EnvironmentParser // ----------------------------------------------------------------------------- pub Environment: Box = { > => Box::new(environment::Environment::from(t)) }; Env_term: (IdType, process::Process) = { "=" => (translator.encode(identifier), k) }; pub PositiveEnvironment: Box = { > => Box::new(environment::PositiveEnvironment::from(t)) }; PositiveEnv_term: (IdType, process::PositiveProcess) = { "=" => (translator.encode(identifier), k) }; // ----------------------------------------------------------------------------- // LabelParser // ----------------------------------------------------------------------------- pub Label: label::Label = { "[" "Entities" ":" "," "Context" ":" "," "Reactants" ":" "," "ReactantsAbsent" ":" "," "Inhibitors" ":" "," "InhibitorsPresent" ":" "," "Products" ":" ","? "]" => label::Label::create(e, c, r, r_a, i, i_p, p) } // ---------------------------------------------------------------------------- // File Parsing // ---------------------------------------------------------------------------- // system // a system is an environment, a set of entities as initial state, a context and // a set of reaction rules. pub System: system::System = { "Environment" ":" "Initial Entities" ":" "Context" ":" "Reactions" ":" => system::System::from(delta.into(), available_entities, context_process, Rc::new(reaction_rules)) } // experiment // an experiment is composed by a sequence of weights and a sequence of sets of // entities of equal length. pub Experiment: (Vec, Vec) = { "Weights" ":" > "Sets" ":" > => (w.into_iter().map(|x| x as u32).collect::>(), s), }