use std::rc::Rc; use std::str::FromStr; use lalrpop_util::ParseError; use crate::rsprocess::structure::{RSset, RSprocess, RSenvironment, RSassert, RSassertOp, RSBHML, RSsystem, RSreaction}; use crate::rsprocess::translator::{Translator, IdType}; use crate::rsprocess::presets::Instructions; use crate::rsprocess::presets; use crate::rsprocess::graph; grammar(translator: &mut Translator); // ----------------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------------- // order match { ".", ",", ";", "nill", "{", "}", "[", "]", "(", ")", "<", ">", "r:", "i:", "p:", "-", "^", "true", "false", "inW", "inR", "inI", "inP", "Environment", "Initial Entities", "Context", "Reactions", "Weights", "Sets", "Print", "Save", "Dot", "GraphML", "Serialize", "Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency", "FastFrequency", "Digraph", "Bisimilarity", "Deserialize", "Hide", "Entities", "MaskEntities", "MaskContext", "Products", "MaskProducts", "Union", "MaskUnion", "Difference", "MaskDifference", "EntitiesDeleted", "MaskEntitiesDeleted", "EntitiesAdded", "MaskEntitiesAdded" } 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 => <>.to_string() }; // all numbers are i64 Num: i64 = { NUMBER =>? i64::from_str(<>) .map_err(|_| ParseError::User { error: "Number is too big" }) }; 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 } // ----------------------------------------------------------------------------- // SetParser // ----------------------------------------------------------------------------- pub Set: RSset = { => s }; Set_of_entities: RSset = { "{" "}" => RSset::from(vec![]), "{" > "}" => RSset::from(t.into_iter().map(|t| translator.encode(t)) .collect::>()) }; // ----------------------------------------------------------------------------- // ReactionParser // ----------------------------------------------------------------------------- pub Reactions: Vec = { "(" ")" => vec![], "(" > ")" => s } Reaction: RSreaction = { "[" "," "," "]" => RSreaction::from(r, i, p), "[" "r:" "," "i:" "," "p:" "]" => RSreaction::from(r, i, p), } // ----------------------------------------------------------------------------- // ContextParser // ----------------------------------------------------------------------------- pub Context: RSprocess = { "[" "]" => RSprocess::NondeterministicChoice{ children: vec![] }, "[" > "]" => RSprocess::NondeterministicChoice{ children: t } }; Boxed_CTX_process: Rc = { => Rc::new(t) } CTX_process: RSprocess = { "nill" => RSprocess::Nill, "." => RSprocess::EntitySet{ entities: c, next_process: Rc::new(k) }, "(" ")" => k, "(" > ")" => RSprocess::Summation{ children: k.into_iter().map(Rc::new).collect::>() }, "<" ">" "." => RSprocess::WaitEntity{ repeat: n, repeated_process: Rc::new(k1), next_process: Rc::new(k) }, => RSprocess::RecursiveIdentifier{ identifier: translator.encode(identifier) } }; // ----------------------------------------------------------------------------- // EnvironmentParser // ----------------------------------------------------------------------------- pub Environment: Box = { "[" "]" => Box::new(RSenvironment::new()), "[" > "]" => Box::new(RSenvironment::from(t)) }; Env_term: (IdType, RSprocess) = { "=" => (translator.encode(identifier), k) }; // ----------------------------------------------------------------------------- // AssertParser // ----------------------------------------------------------------------------- pub Assert: Box = { => Box::new(f) }; Formula_Assert: RSassert = { "-" => RSassert::Not(Box::new(f)), "(" "^" ")" => RSassert::Xor(Box::new(f1), Box::new(f2)), "(" > ")" => RSassert::Or(f), "(" > ")" => RSassert::And(f), "inW" => RSassert::Sub(c, RSassertOp::InW), "inR" => RSassert::Sub(c, RSassertOp::InR), "inI" => RSassert::Sub(c, RSassertOp::InI), "inP" => RSassert::Sub(c, RSassertOp::InP), "?" "inW" => RSassert::NonEmpty(RSassertOp::InW), "?" "inR" => RSassert::NonEmpty(RSassertOp::InR), "?" "inI" => RSassert::NonEmpty(RSassertOp::InI), "?" "inP" => RSassert::NonEmpty(RSassertOp::InP), }; // ----------------------------------------------------------------------------- // BHMLParser // ----------------------------------------------------------------------------- pub BHML: Box = { => Box::new(g) }; Formula_BHML: RSBHML = { "true" => RSBHML::True, "false" => RSBHML::False, "(" > ")" => RSBHML::Or(g), "(" > ")" => RSBHML::And(g), "<" ">" => RSBHML::Diamond(Box::new(f), Box::new(g)), "[" "]" => RSBHML::Box(Box::new(f), Box::new(g)), }; // ---------------------------------------------------------------------------- // 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: RSsystem = { "Environment" ":" "Initial Entities" ":" "Context" ":" "Reactions" ":" => RSsystem::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), } // ~~~~~~~~~~~~~~~~~~~ // Instruction Parsing // ~~~~~~~~~~~~~~~~~~~ /// Decides whetherer to print to stdout or to save to file Helper_SO: presets::SaveOptions = { "Print" => presets::SaveOptions {print: true, save: None}, "Save" "(" ")" => presets::SaveOptions {print: false, save: Some(vec![p])} } /// we could need to save to multiple files SaveOptions: presets::SaveOptions = { > => { p.into_iter() .reduce(|mut acc, mut e| {acc.combine(&mut e); acc}) .unwrap_or_default() } } /// Match for strings between nodes formatters LiteralSeparatorNode: presets::NodeDisplay = { PATH => presets::NodeDisplay::Separator( <>.trim_end_matches("\"").trim_start_matches("\"").to_string() ) }; /// Match for strings between edge formatters LiteralSeparatorEdge: presets::EdgeDisplay = { PATH => presets::EdgeDisplay::Separator( <>.trim_end_matches("\"").trim_start_matches("\"").to_string() ) }; NodeDisplay: presets::NodeDisplay = { "Hide" => presets::NodeDisplay::Display(graph::GraphMapNodes::Hide), "Entities" => presets::NodeDisplay::Display(graph::GraphMapNodes::Entities), "MaskEntities" => presets::NodeDisplay::Display(graph::GraphMapNodes::MaskEntities{mask}), "Context" => presets::NodeDisplay::Display(graph::GraphMapNodes::Context), "UncommonEntities" => presets::NodeDisplay::UncommonEntities, "MaskUncommonentities" => presets::NodeDisplay::MaskUncommonEntities(mask), "ExcludeEntities" => presets::NodeDisplay::Display(graph::GraphMapNodes::ExcludeEntities{mask}) } /// Node display formatters separated by arbitrary strings in quotes SeparatorNode: Vec = { => vec![v], )+> => match e { None => v.iter().fold(vec![], |mut acc, (a, b)| { acc.push(a.clone()); acc.push(b.clone()); acc.clone() }), Some(e) => { let mut v = v.iter().fold(vec![], |mut acc, (a, b)| { acc.push(a.clone()); acc.push(b.clone()); acc.clone() }); v.push(e); v } } } EdgeDisplay: presets::EdgeDisplay = { "Hide" => presets::EdgeDisplay::Display( graph::GraphMapEdges::Hide ), "Products" => presets::EdgeDisplay::Display( graph::GraphMapEdges::Products ), "MaskProducts" => presets::EdgeDisplay::Display( graph::GraphMapEdges::MaskEntities{ mask } ), "Entities" => presets::EdgeDisplay::Display( graph::GraphMapEdges::Entities ), "MaskEntities" => presets::EdgeDisplay::Display( graph::GraphMapEdges::MaskEntities{ mask } ), "Context" => presets::EdgeDisplay::Display( graph::GraphMapEdges::Context ), "MaskContext" => presets::EdgeDisplay::Display( graph::GraphMapEdges::MaskContext{ mask } ), "Union" => presets::EdgeDisplay::Display( graph::GraphMapEdges::Union ), "MaskUnion" => presets::EdgeDisplay::Display( graph::GraphMapEdges::MaskUnion{ mask } ), "Difference" => presets::EdgeDisplay::Display( graph::GraphMapEdges::Difference ), "MaskDifference" => presets::EdgeDisplay::Display( graph::GraphMapEdges::MaskDifference{ mask } ), "EntitiesDeleted" => presets::EdgeDisplay::Display( graph::GraphMapEdges::EntitiesDeleted ), "MaskEntitiesDeleted" => presets::EdgeDisplay::Display( graph::GraphMapEdges::MaskEntitiesDeleted{ mask } ), "EntitiesAdded" => presets::EdgeDisplay::Display( graph::GraphMapEdges::EntitiesAdded ), "MaskEntitiesAdded" => presets::EdgeDisplay::Display( graph::GraphMapEdges::MaskEntitiesAdded{ mask } ), } /// Edge display formatters separated by arbitrary strings in quotes SeparatorEdge: Vec = { => vec![v], )+> => match e { None => v.iter().fold(vec![], |mut acc, (a, b)| { acc.push(a.clone()); acc.push(b.clone()); acc.clone() }), Some(e) => { let mut v = v.iter().fold(vec![], |mut acc, (a, b)| { acc.push(a.clone()); acc.push(b.clone()); acc.clone() }); v.push(e); v } } } Operation: graph::OperationType = { "==" => graph::OperationType::Equals, "=" => graph::OperationType::Equals, "<" => graph::OperationType::Subset, "⊂" => graph::OperationType::Subset, "<=" => graph::OperationType::SubsetEqual, "⊆" => graph::OperationType::SubsetEqual, ">" => graph::OperationType::Superset, "⊃" => graph::OperationType::Superset, ">=" => graph::OperationType::SupersetEqual, "⊇" => graph::OperationType::SupersetEqual } NodeColorConditional: (graph::NodeColorConditional, String) = { "Entities" "?" => (graph::NodeColorConditional::EntitiesConditional(op, set), color.to_string()), "Context.Nill" "?" => (graph::NodeColorConditional::ContextConditional( graph::ContextColorConditional::Nill), color.to_string()), "Context.RecursiveIdentifier" "(" ")" "?" => (graph::NodeColorConditional::ContextConditional( graph::ContextColorConditional::RecursiveIdentifier( translator.encode(x) )), color.to_string()), "Context.EntitySet" "?" => (graph::NodeColorConditional::ContextConditional( graph::ContextColorConditional::EntitySet(op, set)), color.to_string()), "Context.NonDeterministicChoice" "?" => (graph::NodeColorConditional::ContextConditional( graph::ContextColorConditional::NonDeterministicChoice), color.to_string()), "Context.Summation" "?" => (graph::NodeColorConditional::ContextConditional( graph::ContextColorConditional::Summation), color.to_string()), "Context.WaitEntity" "?" => (graph::NodeColorConditional::ContextConditional( graph::ContextColorConditional::WaitEntity), color.to_string()), } /// Node color formatter ColorNode: graph::NodeColor = { > "!" => graph::NodeColor { conditionals, base_color: base_color.to_string() }, "!" => graph::NodeColor { conditionals: vec![], base_color: base_color.to_string() }, } EdgeColorConditional: (graph::EdgeColorConditional, String) = { "Entities" "?" => (graph::EdgeColorConditional::Entities(op, set), color.to_string()), "Context" "?" => (graph::EdgeColorConditional::Context(op, set), color.to_string()), "T" "?" => (graph::EdgeColorConditional::T(op, set), color.to_string()), "Reactants" "?" => (graph::EdgeColorConditional::Reactants(op, set), color.to_string()), "AbsentReactants" "?" => (graph::EdgeColorConditional::ReactantsAbsent(op, set), color.to_string()), "Inhibitors" "?" => (graph::EdgeColorConditional::Inhibitors(op, set), color.to_string()), "PresentInhibitors" "?" => (graph::EdgeColorConditional::InhibitorsPresent(op, set), color.to_string()), "Products" "?" => (graph::EdgeColorConditional::Products(op, set), color.to_string()), } ColorEdge: graph::EdgeColor = { > "!" => graph::EdgeColor { conditionals, base_color: base_color.to_string() }, "!" => graph::EdgeColor { conditionals: vec![], base_color: base_color.to_string() }, } GraphSaveOptions: presets::GraphSaveOptions = { "Dot" "|"? "|" "|" "|" ">" => presets::GraphSaveOptions::Dot { node_display: s_node, edge_display: s_edge, node_color: c_node, edge_color: c_edge, so }, "GraphML" "|"? "|" ">" => presets::GraphSaveOptions::GraphML { node_display: s_node, edge_display: s_edge, so }, "Serialize" "(" ")" => presets::GraphSaveOptions::Serialize { path }, } Instruction: presets::Instruction = { "Stats" ">" => presets::Instruction::Stats { so }, "Target" ">" => presets::Instruction::Target { so }, "Run" ">" => presets::Instruction::Run { so }, "Loop" "(" ")" ">" => presets::Instruction::Loop { symbol, so }, "Frequency" ">" => presets::Instruction::Frequency { so }, "LimitFrequency" "(" ")" ">" => presets::Instruction::LimitFrequency { experiment: p, so }, "FastFrequency" "(" ")" ">" => presets::Instruction::FastFrequency { experiment: p, so }, "Digraph" ">" > => presets::Instruction::Digraph { gso }, "Bisimilarity" "(" ")" ">" => presets::Instruction::Bisimilarity { system_b: p, so }, } pub Run: presets::Instructions = { > => Instructions { system: presets::System::RSsystem { sys }, instructions: instr }, => Instructions { system: presets::System::RSsystem { sys }, instructions: vec![] }, "Deserialize" "(" ")" > => Instructions { system: presets::System::Deserialize { path }, instructions: instr }, }