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", "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#"'([^']+)'"# => SEPARATOR, } else { r#""[^"]+""# => PATH, // " } 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) } /// 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 } } } GraphSaveOptions: presets::GraphSaveOptions = { "Dot" "|" ">" => presets::GraphSaveOptions::Dot { node_display: s_node, edge_display: s_edge, node_color: graph::NodeColor { conditionals: vec![], base_color: "white".into() }, 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 }, } pub Run: presets::Instructions = { > => Instructions { system: presets::System::RSsystem { sys }, instructions: instr }, "Deserialize" "(" ")" > => Instructions { system: presets::System::Deserialize { path }, instructions: instr }, }