More examples, better defaults
grammar_separated is grammar but with all functions exposed
This commit is contained in:
481
grammar_separated/src/instructions.lalrpop
Normal file
481
grammar_separated/src/instructions.lalrpop
Normal file
@ -0,0 +1,481 @@
|
||||
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 = {
|
||||
<sign: "-"?> <start: @L> <n: NUMBER> <end: @R> =>? {
|
||||
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 = {
|
||||
<start: @L> <n: NUMBER> <end: @R> =>? 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<T, C>: Vec<T> = {
|
||||
<mut v:(<T> C)+> <e:T?> => match e {
|
||||
None => v,
|
||||
Some(e) => {
|
||||
v.push(e);
|
||||
v
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Separated_Or<T, C>: Vec<T> = {
|
||||
<v: T> => vec![v],
|
||||
<v: Separated<T, C>> => v
|
||||
}
|
||||
|
||||
Separated_Empty<LP, T, C, RP>: Vec<T> = {
|
||||
LP RP => vec![],
|
||||
LP <v: T> RP => vec![v],
|
||||
LP <v: Separated<T, C>> RP => v
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SetParser
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
pub Set: set::Set = {
|
||||
<s: Separated_Empty<"{", Literal, ",", "}">> =>
|
||||
set::Set::from(s.into_iter().map(|t| translator.encode(t))
|
||||
.collect::<Vec<_>>())
|
||||
};
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
// 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" <mask: Set> =>
|
||||
graph::NodeDisplayBase::MaskEntities{mask},
|
||||
"ExcludeEntities" <mask: Set> =>
|
||||
graph::NodeDisplayBase::ExcludeEntities{mask},
|
||||
"Context" =>
|
||||
graph::NodeDisplayBase::Context,
|
||||
"UncommonEntities" =>
|
||||
graph::NodeDisplayBase::UncommonEntities,
|
||||
"MaskUncommonEntities" <mask: Set> =>
|
||||
graph::NodeDisplayBase::MaskUncommonEntities{mask},
|
||||
}
|
||||
|
||||
/// Node display formatters separated by arbitrary strings in quotes
|
||||
pub SeparatorNode: graph::NodeDisplay = {
|
||||
<v: NodeDisplayBase> => graph::NodeDisplay {base: vec![v]},
|
||||
<v:(<NodeDisplayBase> <LiteralSeparatorNode>)+> <e: NodeDisplayBase?> =>
|
||||
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" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Entities
|
||||
{ mask: Some(mask), filter_common: false },
|
||||
"UncommonProducts" =>
|
||||
graph::EdgeDisplayBase::Products
|
||||
{ mask: None, filter_common: true },
|
||||
"UncommonMaskProducts" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Entities
|
||||
{ mask: Some(mask), filter_common: true },
|
||||
|
||||
"Entities" =>
|
||||
graph::EdgeDisplayBase::Entities
|
||||
{ mask: None, filter_common: false },
|
||||
"MaskEntities" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Entities
|
||||
{ mask: Some(mask), filter_common: false },
|
||||
"UncommonEntities" =>
|
||||
graph::EdgeDisplayBase::Entities
|
||||
{ mask: None, filter_common: true },
|
||||
"UncommonMaskEntities" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Entities
|
||||
{ mask: Some(mask), filter_common: true },
|
||||
|
||||
"Context" =>
|
||||
graph::EdgeDisplayBase::Context
|
||||
{ mask: None, filter_common: false },
|
||||
"MaskContext" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Context
|
||||
{ mask: Some(mask), filter_common: false },
|
||||
"UncommonContext" =>
|
||||
graph::EdgeDisplayBase::Context
|
||||
{ mask: None, filter_common: true },
|
||||
"UncommonMaskContext" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Context
|
||||
{ mask: Some(mask), filter_common: true },
|
||||
|
||||
"Union" =>
|
||||
graph::EdgeDisplayBase::Union
|
||||
{ mask: None, filter_common: false },
|
||||
"MaskUnion" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Union
|
||||
{ mask: Some(mask), filter_common: false },
|
||||
"UncommonUnion" =>
|
||||
graph::EdgeDisplayBase::Union
|
||||
{ mask: None, filter_common: true },
|
||||
"UncommonMaskUnion" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Union
|
||||
{ mask: Some(mask), filter_common: true },
|
||||
|
||||
"Difference" =>
|
||||
graph::EdgeDisplayBase::Difference
|
||||
{ mask: None, filter_common: false },
|
||||
"MaskDifference" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Difference
|
||||
{ mask: Some(mask), filter_common: false },
|
||||
"UncommonDifference" =>
|
||||
graph::EdgeDisplayBase::Difference
|
||||
{ mask: None, filter_common: true },
|
||||
"UncommonMaskDifference" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::Difference
|
||||
{ mask: Some(mask), filter_common: true },
|
||||
|
||||
"EntitiesDeleted" =>
|
||||
graph::EdgeDisplayBase::EntitiesDeleted
|
||||
{ mask: None, filter_common: false },
|
||||
"MaskEntitiesDeleted" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::EntitiesDeleted
|
||||
{ mask: Some(mask), filter_common: false },
|
||||
"UncommonEntitiesDeleted" =>
|
||||
graph::EdgeDisplayBase::EntitiesDeleted
|
||||
{ mask: None, filter_common: true },
|
||||
"UncommonMaskEntitiesDeleted" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::EntitiesDeleted
|
||||
{ mask: Some(mask), filter_common: true },
|
||||
|
||||
"EntitiesAdded" =>
|
||||
graph::EdgeDisplayBase::EntitiesAdded
|
||||
{ mask: None, filter_common: false },
|
||||
"MaskEntitiesAdded" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::EntitiesAdded
|
||||
{ mask: Some(mask), filter_common: false },
|
||||
"UncommonEntitiesAdded" =>
|
||||
graph::EdgeDisplayBase::EntitiesAdded
|
||||
{ mask: None, filter_common: true },
|
||||
"UncommonMaskEntitiesAdded" <mask: Set> =>
|
||||
graph::EdgeDisplayBase::EntitiesAdded
|
||||
{ mask: Some(mask), filter_common: true },
|
||||
}
|
||||
|
||||
/// Edge display formatters separated by arbitrary strings in quotes
|
||||
pub SeparatorEdge: graph::EdgeDisplay = {
|
||||
<v: EdgeDisplay> => graph::EdgeDisplay{ base: vec![v] },
|
||||
<v:(<EdgeDisplay> <LiteralSeparatorEdge>)+> <e: EdgeDisplay?> =>
|
||||
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" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::NodeColorConditional::EntitiesConditional(op, set),
|
||||
color.to_string()),
|
||||
"Context.Nill" "?" <color: PATH> =>
|
||||
(graph::NodeColorConditional::ContextConditional(
|
||||
graph::ContextColorConditional::Nill),
|
||||
color.to_string()),
|
||||
"Context.RecursiveIdentifier" "(" <x: Literal> ")" "?" <color: PATH> =>
|
||||
(graph::NodeColorConditional::ContextConditional(
|
||||
graph::ContextColorConditional::RecursiveIdentifier(
|
||||
translator.encode(x)
|
||||
)),
|
||||
color.to_string()),
|
||||
"Context.EntitySet" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::NodeColorConditional::ContextConditional(
|
||||
graph::ContextColorConditional::EntitySet(op, set)),
|
||||
color.to_string()),
|
||||
"Context.NonDeterministicChoice" "?" <color: PATH> =>
|
||||
(graph::NodeColorConditional::ContextConditional(
|
||||
graph::ContextColorConditional::NonDeterministicChoice),
|
||||
color.to_string()),
|
||||
"Context.Summation" "?" <color: PATH> =>
|
||||
(graph::NodeColorConditional::ContextConditional(
|
||||
graph::ContextColorConditional::Summation),
|
||||
color.to_string()),
|
||||
"Context.WaitEntity" "?" <color: PATH> =>
|
||||
(graph::NodeColorConditional::ContextConditional(
|
||||
graph::ContextColorConditional::WaitEntity),
|
||||
color.to_string()),
|
||||
}
|
||||
|
||||
/// Node color formatter
|
||||
pub ColorNode: graph::NodeColor = {
|
||||
<conditionals: Separated_Or<NodeColorConditional, "||">>
|
||||
"!" <base_color: PATH> =>
|
||||
graph::NodeColor { conditionals,
|
||||
base_color: base_color.to_string() },
|
||||
|
||||
"!" <base_color: PATH> =>
|
||||
graph::NodeColor { conditionals: vec![],
|
||||
base_color: base_color.to_string() },
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
EdgeColorConditional: (graph::EdgeColorConditional, String) = {
|
||||
"Entities" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::Entities(op, set),
|
||||
color.to_string()),
|
||||
"Context" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::Context(op, set),
|
||||
color.to_string()),
|
||||
"T" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::T(op, set),
|
||||
color.to_string()),
|
||||
"Reactants" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::Reactants(op, set),
|
||||
color.to_string()),
|
||||
"AbsentReactants" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::ReactantsAbsent(op, set),
|
||||
color.to_string()),
|
||||
"Inhibitors" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::Inhibitors(op, set),
|
||||
color.to_string()),
|
||||
"PresentInhibitors" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::InhibitorsPresent(op, set),
|
||||
color.to_string()),
|
||||
"Products" <op: Operation> <set: Set> "?" <color: PATH> =>
|
||||
(graph::EdgeColorConditional::Products(op, set),
|
||||
color.to_string()),
|
||||
}
|
||||
|
||||
pub ColorEdge: graph::EdgeColor = {
|
||||
<conditionals: Separated_Or<EdgeColorConditional, "||">>
|
||||
"!" <base_color: PATH> =>
|
||||
graph::EdgeColor { conditionals,
|
||||
base_color: base_color.to_string() },
|
||||
|
||||
"!" <base_color: PATH> =>
|
||||
graph::EdgeColor { conditionals: vec![],
|
||||
base_color: base_color.to_string() },
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// pub GraphSaveOptions: presets::GraphSaveOptions = {
|
||||
// "Dot"
|
||||
// "|"? <s_node: SeparatorNode>
|
||||
// "|" <s_edge: SeparatorEdge>
|
||||
// "|" <c_node: ColorNode>
|
||||
// "|" <c_edge: ColorEdge>
|
||||
// ">" <so: SaveOptions> =>
|
||||
// presets::GraphSaveOptions::Dot { node_display: s_node,
|
||||
// edge_display: s_edge,
|
||||
// node_color: c_node,
|
||||
// edge_color: c_edge,
|
||||
// so },
|
||||
// "GraphML"
|
||||
// "|"? <s_node: SeparatorNode>
|
||||
// "|" <s_edge: SeparatorEdge>
|
||||
// ">" <so: SaveOptions> =>
|
||||
// presets::GraphSaveOptions::GraphML { node_display: s_node,
|
||||
// edge_display: s_edge,
|
||||
// so },
|
||||
// "Serialize" "(" <path: Path> ")" =>
|
||||
// presets::GraphSaveOptions::Serialize { path },
|
||||
// }
|
||||
Reference in New Issue
Block a user