use std::str::FromStr; use lalrpop_util::ParseError; use rsprocess::set; use rsprocess::translator::Translator; use rsprocess::graph; use crate::custom_error; grammar(translator: &mut Translator); extern { type Error = custom_error::UserError; } // ----------------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------------- // order match { "!", "(", ")", ",", "<", "<=", "=", "==", ">", ">=", "?", "AbsentReactants", "Context", "Context.EntitySet", "Context.Nill", "Context.NonDeterministicChoice", "Context.RecursiveIdentifier", "Context.Summation", "Context.WaitEntity", "Difference", "Entities", "EntitiesAdded", "EntitiesDeleted", "ExcludeEntities", "Hide", "Inhibitors", "MaskContext", "MaskDifference", "MaskEntities", "MaskEntitiesAdded", "MaskEntitiesDeleted", "MaskProducts", "MaskUncommonEntities", "MaskUnion", "PresentInhibitors", "Products", "Reactants", "T", "UncommonContext", "UncommonDifference", "UncommonEntities", "UncommonEntitiesAdded", "UncommonEntitiesDeleted", "UncommonMaskContext", "UncommonMaskDifference", "UncommonMaskEntities", "UncommonMaskEntitiesAdded", "UncommonMaskEntitiesDeleted", "UncommonMaskProducts", "UncommonMaskUnion", "UncommonProducts", "UncommonUnion", "Union", "\"", "{", "||", "}", "⊂", "⊃", "⊆", "⊇", } 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(), "Context" => <>.into(), "Context.EntitySet" => <>.into(), "Context.Nill" => <>.into(), "Context.NonDeterministicChoice" => <>.into(), "Context.RecursiveIdentifier" => <>.into(), "Context.Summation" => <>.into(), "Context.WaitEntity" => <>.into(), "Difference" => <>.into(), "Entities" => <>.into(), "EntitiesAdded" => <>.into(), "EntitiesDeleted" => <>.into(), "ExcludeEntities" => <>.into(), "Hide" => <>.into(), "Inhibitors" => <>.into(), "MaskContext" => <>.into(), "MaskDifference" => <>.into(), "MaskEntities" => <>.into(), "MaskEntitiesAdded" => <>.into(), "MaskEntitiesDeleted" => <>.into(), "MaskProducts" => <>.into(), "MaskUncommonEntities" => <>.into(), "MaskUnion" => <>.into(), "PresentInhibitors" => <>.into(), "Products" => <>.into(), "Reactants" => <>.into(), "T" => <>.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(), }; 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::>()) }; // ~~~~~~~~~~~~~~~~~~~ // Instruction Parsing // ~~~~~~~~~~~~~~~~~~~ /// Match for strings between nodes formatters LiteralSeparatorNode: graph::NodeDisplayBase = { PATH => graph::NodeDisplayBase::String { string: <>.trim_end_matches("\"") .trim_start_matches("\"") .to_string() } }; /// Match for strings between edge formatters LiteralSeparatorEdge: graph::EdgeDisplayBase = { PATH => graph::EdgeDisplayBase::String { string: <>.trim_end_matches("\"") .trim_start_matches("\"") .to_string() } }; NodeDisplayBase: graph::NodeDisplayBase = { "Hide" => graph::NodeDisplayBase::Hide, "Entities" => graph::NodeDisplayBase::Entities, "MaskEntities" => graph::NodeDisplayBase::MaskEntities{mask}, "ExcludeEntities" => graph::NodeDisplayBase::ExcludeEntities{mask}, "Context" => graph::NodeDisplayBase::Context, "UncommonEntities" => graph::NodeDisplayBase::UncommonEntities, "MaskUncommonEntities" => graph::NodeDisplayBase::MaskUncommonEntities{mask}, } /// Node display formatters separated by arbitrary strings in quotes pub SeparatorNode: graph::NodeDisplay = { => graph::NodeDisplay {base: vec![v]}, )+> => match e { None => graph::NodeDisplay { base: 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); graph::NodeDisplay { base: v } } } } // ----------------------------------------------------------------------------- EdgeDisplay: graph::EdgeDisplayBase = { "Hide" => graph::EdgeDisplayBase::Hide, "Products" => graph::EdgeDisplayBase::Products { mask: None, filter_common: false }, "MaskProducts" => graph::EdgeDisplayBase::Entities { mask: Some(mask), filter_common: false }, "UncommonProducts" => graph::EdgeDisplayBase::Products { mask: None, filter_common: true }, "UncommonMaskProducts" => graph::EdgeDisplayBase::Entities { mask: Some(mask), filter_common: true }, "Entities" => graph::EdgeDisplayBase::Entities { mask: None, filter_common: false }, "MaskEntities" => graph::EdgeDisplayBase::Entities { mask: Some(mask), filter_common: false }, "UncommonEntities" => graph::EdgeDisplayBase::Entities { mask: None, filter_common: true }, "UncommonMaskEntities" => graph::EdgeDisplayBase::Entities { mask: Some(mask), filter_common: true }, "Context" => graph::EdgeDisplayBase::Context { mask: None, filter_common: false }, "MaskContext" => graph::EdgeDisplayBase::Context { mask: Some(mask), filter_common: false }, "UncommonContext" => graph::EdgeDisplayBase::Context { mask: None, filter_common: true }, "UncommonMaskContext" => graph::EdgeDisplayBase::Context { mask: Some(mask), filter_common: true }, "Union" => graph::EdgeDisplayBase::Union { mask: None, filter_common: false }, "MaskUnion" => graph::EdgeDisplayBase::Union { mask: Some(mask), filter_common: false }, "UncommonUnion" => graph::EdgeDisplayBase::Union { mask: None, filter_common: true }, "UncommonMaskUnion" => graph::EdgeDisplayBase::Union { mask: Some(mask), filter_common: true }, "Difference" => graph::EdgeDisplayBase::Difference { mask: None, filter_common: false }, "MaskDifference" => graph::EdgeDisplayBase::Difference { mask: Some(mask), filter_common: false }, "UncommonDifference" => graph::EdgeDisplayBase::Difference { mask: None, filter_common: true }, "UncommonMaskDifference" => graph::EdgeDisplayBase::Difference { mask: Some(mask), filter_common: true }, "EntitiesDeleted" => graph::EdgeDisplayBase::EntitiesDeleted { mask: None, filter_common: false }, "MaskEntitiesDeleted" => graph::EdgeDisplayBase::EntitiesDeleted { mask: Some(mask), filter_common: false }, "UncommonEntitiesDeleted" => graph::EdgeDisplayBase::EntitiesDeleted { mask: None, filter_common: true }, "UncommonMaskEntitiesDeleted" => graph::EdgeDisplayBase::EntitiesDeleted { mask: Some(mask), filter_common: true }, "EntitiesAdded" => graph::EdgeDisplayBase::EntitiesAdded { mask: None, filter_common: false }, "MaskEntitiesAdded" => graph::EdgeDisplayBase::EntitiesAdded { mask: Some(mask), filter_common: false }, "UncommonEntitiesAdded" => graph::EdgeDisplayBase::EntitiesAdded { mask: None, filter_common: true }, "UncommonMaskEntitiesAdded" => graph::EdgeDisplayBase::EntitiesAdded { mask: Some(mask), filter_common: true }, } /// Edge display formatters separated by arbitrary strings in quotes pub SeparatorEdge: graph::EdgeDisplay = { => graph::EdgeDisplay{ base: vec![v] }, )+> => match e { None => graph::EdgeDisplay{ base: 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); graph::EdgeDisplay{ base: 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 pub 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()), } pub ColorEdge: graph::EdgeColor = { > "!" => graph::EdgeColor { conditionals, base_color: base_color.to_string() }, "!" => graph::EdgeColor { conditionals: vec![], base_color: base_color.to_string() }, } // ----------------------------------------------------------------------------- // pub 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 }, // }