2025-05-21 00:03:36 +02:00
|
|
|
use std::rc::Rc;
|
2025-05-14 11:42:19 +02:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
use lalrpop_util::ParseError;
|
2025-08-18 20:39:43 +02:00
|
|
|
use crate::rsprocess::structure::{ RSset,
|
|
|
|
|
RSprocess,
|
|
|
|
|
RSenvironment,
|
|
|
|
|
RSsystem,
|
|
|
|
|
RSlabel,
|
|
|
|
|
RSreaction };
|
|
|
|
|
use crate::rsprocess::structure::rsassert;
|
|
|
|
|
use crate::rsprocess::translator::{ Translator, IdType };
|
2025-07-11 23:49:59 +02:00
|
|
|
use crate::rsprocess::presets::Instructions;
|
|
|
|
|
use crate::rsprocess::presets;
|
2025-07-12 15:32:21 +02:00
|
|
|
use crate::rsprocess::graph;
|
2025-05-14 11:42:19 +02:00
|
|
|
|
2025-06-16 14:46:04 +02:00
|
|
|
grammar(translator: &mut Translator);
|
2025-05-14 11:42:19 +02:00
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Helpers
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2025-07-03 16:28:28 +02:00
|
|
|
// order
|
|
|
|
|
match {
|
2025-07-11 23:49:59 +02:00
|
|
|
".", ",", ";",
|
2025-07-03 23:44:10 +02:00
|
|
|
"nill",
|
|
|
|
|
"{", "}",
|
|
|
|
|
"[", "]",
|
|
|
|
|
"(", ")",
|
|
|
|
|
"<", ">",
|
|
|
|
|
"r:", "i:", "p:",
|
|
|
|
|
"-", "^",
|
|
|
|
|
"true", "false",
|
2025-07-11 23:49:59 +02:00
|
|
|
"Environment", "Initial Entities", "Context", "Reactions",
|
|
|
|
|
"Weights", "Sets",
|
|
|
|
|
"Print", "Save",
|
|
|
|
|
"Dot", "GraphML", "Serialize",
|
|
|
|
|
"Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency",
|
2025-07-16 00:05:14 +02:00
|
|
|
"FastFrequency", "Digraph", "Bisimilarity",
|
2025-07-12 15:32:21 +02:00
|
|
|
"Deserialize",
|
2025-07-30 18:05:55 +02:00
|
|
|
"?",
|
2025-07-27 19:08:27 +02:00
|
|
|
"Hide",
|
|
|
|
|
"Entities", "MaskEntities", "UncommonEntities", "UncommonMaskEntities",
|
|
|
|
|
"MaskContext", "UncommonContext", "UncommonMaskContext",
|
|
|
|
|
"Products", "MaskProducts", "UncommonProducts", "UncommonMaskProducts",
|
|
|
|
|
"Union", "MaskUnion", "UncommonUnion", "UncommonMaskUnion",
|
2025-07-12 15:32:21 +02:00
|
|
|
"Difference", "MaskDifference",
|
2025-08-20 19:51:03 +02:00
|
|
|
"UncommonDifference", "UncommonMaskDifference",
|
2025-07-12 15:32:21 +02:00
|
|
|
"EntitiesDeleted", "MaskEntitiesDeleted",
|
2025-07-27 19:08:27 +02:00
|
|
|
"UncommonEntitiesDeleted", "UncommonMaskEntitiesDeleted",
|
|
|
|
|
"EntitiesAdded", "MaskEntitiesAdded",
|
|
|
|
|
"UncommonEntitiesAdded", "UncommonMaskEntitiesAdded",
|
2025-08-14 02:47:12 +02:00
|
|
|
"label", "edge", "if", "then", "else", "let", "=", "return", "for", "in",
|
2025-08-20 19:51:03 +02:00
|
|
|
"not", "rand", "empty", "length", "tostr", "source", "target",
|
2025-07-30 18:05:55 +02:00
|
|
|
"&&", "||", "^^", "<=", ">=", "==", "!=", "+", "*", "/", "%",
|
2025-08-20 19:51:03 +02:00
|
|
|
"::",
|
|
|
|
|
"substr", "min", "max", "commonsubstr",
|
2025-08-14 21:20:10 +02:00
|
|
|
"SystemEntities", "SystemContext",
|
2025-07-30 18:05:55 +02:00
|
|
|
"AvailableEntities", "AllReactants", "AllInhibitors",
|
2025-08-15 00:32:58 +02:00
|
|
|
"relabel",
|
2025-07-03 23:44:10 +02:00
|
|
|
} else {
|
2025-07-03 16:28:28 +02:00
|
|
|
r"[0-9]+" => NUMBER
|
|
|
|
|
} else {
|
2025-07-12 15:32:21 +02:00
|
|
|
r"([[:alpha:]])([[:word:]])*" => WORD
|
|
|
|
|
// r"(\p{L}|\p{Emoji})(\p{L}|\p{Emoji}|\p{Dash}|\p{N})*" => WORD,
|
2025-07-11 23:49:59 +02:00
|
|
|
} else {
|
2025-07-13 18:14:35 +02:00
|
|
|
r#""[^"]+""# => PATH, // " <- ignore comment, its for the linter in emacs
|
2025-07-03 16:28:28 +02:00
|
|
|
} else {
|
|
|
|
|
_
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 12:14:13 +02:00
|
|
|
// matches words (letter followed by numbers, letters or _)
|
2025-07-03 16:28:28 +02:00
|
|
|
Literal: String = {
|
2025-08-20 19:51:03 +02:00
|
|
|
WORD => <>.into(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LiteralProcess: String = {
|
|
|
|
|
Literal => <>,
|
|
|
|
|
"true" => <>.into(),
|
|
|
|
|
"false" => <>.into(),
|
|
|
|
|
"Environment" => <>.into(),
|
|
|
|
|
"Initial" => <>.into(),
|
|
|
|
|
"Context" => <>.into(),
|
|
|
|
|
"Reactions" => <>.into(),
|
|
|
|
|
"Weights" => <>.into(),
|
|
|
|
|
"Sets" => <>.into(),
|
|
|
|
|
"Print" => <>.into(),
|
|
|
|
|
"Save" => <>.into(),
|
|
|
|
|
"Dot" => <>.into(),
|
|
|
|
|
"GraphML" => <>.into(),
|
|
|
|
|
"Serialize" => <>.into(),
|
|
|
|
|
"Stats" => <>.into(),
|
|
|
|
|
"Target" => <>.into(),
|
|
|
|
|
"Run" => <>.into(),
|
|
|
|
|
"Loop" => <>.into(),
|
|
|
|
|
"Frequency" => <>.into(),
|
|
|
|
|
"LimitFrequency" => <>.into(),
|
|
|
|
|
"FastFrequency" => <>.into(),
|
|
|
|
|
"Digraph" => <>.into(),
|
|
|
|
|
"Bisimilarity" => <>.into(),
|
|
|
|
|
"Deserialize" => <>.into(),
|
|
|
|
|
"Hide" => <>.into(),
|
|
|
|
|
"Entities" => <>.into(),
|
|
|
|
|
"MaskEntities" => <>.into(),
|
|
|
|
|
"UncommonEntities" => <>.into(),
|
|
|
|
|
"UncommonMaskEntities" => <>.into(),
|
|
|
|
|
"MaskContext" => <>.into(),
|
|
|
|
|
"UncommonContext" => <>.into(),
|
|
|
|
|
"UncommonMaskContext" => <>.into(),
|
|
|
|
|
"Products" => <>.into(),
|
|
|
|
|
"MaskProducts" => <>.into(),
|
|
|
|
|
"UncommonProducts" => <>.into(),
|
|
|
|
|
"UncommonMaskProducts" => <>.into(),
|
|
|
|
|
"Union" => <>.into(),
|
|
|
|
|
"MaskUnion" => <>.into(),
|
|
|
|
|
"UncommonUnion" => <>.into(),
|
|
|
|
|
"UncommonMaskUnion" => <>.into(),
|
|
|
|
|
"Difference" => <>.into(),
|
|
|
|
|
"MaskDifference" => <>.into(),
|
|
|
|
|
"UncommonDifference" => <>.into(),
|
|
|
|
|
"UncommonMaskDifference" => <>.into(),
|
|
|
|
|
"EntitiesDeleted" => <>.into(),
|
|
|
|
|
"MaskEntitiesDeleted" => <>.into(),
|
|
|
|
|
"UncommonEntitiesDeleted" => <>.into(),
|
|
|
|
|
"UncommonMaskEntitiesDeleted" => <>.into(),
|
|
|
|
|
"EntitiesAdded" => <>.into(),
|
|
|
|
|
"MaskEntitiesAdded" => <>.into(),
|
|
|
|
|
"UncommonEntitiesAdded" => <>.into(),
|
|
|
|
|
"UncommonMaskEntitiesAdded" => <>.into(),
|
|
|
|
|
"label" => <>.into(),
|
|
|
|
|
"edge" => <>.into(),
|
|
|
|
|
"if" => <>.into(),
|
|
|
|
|
"then" => <>.into(),
|
|
|
|
|
"else" => <>.into(),
|
|
|
|
|
"let" => <>.into(),
|
|
|
|
|
"return" => <>.into(),
|
|
|
|
|
"for" => <>.into(),
|
|
|
|
|
"in" => <>.into(),
|
|
|
|
|
"not" => <>.into(),
|
|
|
|
|
"rand" => <>.into(),
|
|
|
|
|
"empty" => <>.into(),
|
|
|
|
|
"length" => <>.into(),
|
|
|
|
|
"tostr" => <>.into(),
|
|
|
|
|
"source" => <>.into(),
|
|
|
|
|
"target" => <>.into(),
|
|
|
|
|
"substr" => <>.into(),
|
|
|
|
|
"min" => <>.into(),
|
|
|
|
|
"max" => <>.into(),
|
|
|
|
|
"commonsubstr" => <>.into(),
|
|
|
|
|
"SystemEntities" => <>.into(),
|
|
|
|
|
"SystemContext" => <>.into(),
|
|
|
|
|
"AvailableEntities" => <>.into(),
|
|
|
|
|
"AllReactants" => <>.into(),
|
|
|
|
|
"AllInhibitors" => <>.into(),
|
|
|
|
|
"relabel" => <>.into(),
|
2025-07-03 16:28:28 +02:00
|
|
|
};
|
2025-05-14 11:42:19 +02:00
|
|
|
|
2025-05-14 12:14:13 +02:00
|
|
|
// all numbers are i64
|
2025-05-14 11:42:19 +02:00
|
|
|
Num: i64 = {
|
2025-07-03 16:28:28 +02:00
|
|
|
NUMBER =>? i64::from_str(<>)
|
2025-08-20 19:51:03 +02:00
|
|
|
.map_err(|_| ParseError::User { error: "Number is too big" })
|
2025-05-14 11:42:19 +02:00
|
|
|
};
|
|
|
|
|
|
2025-07-11 23:49:59 +02:00
|
|
|
Path: String = {
|
|
|
|
|
PATH => <>.trim_end_matches("\"").trim_start_matches("\"").to_string()
|
|
|
|
|
};
|
|
|
|
|
|
2025-05-14 12:14:13 +02:00
|
|
|
// macro for matching sequence of patterns with C as separator
|
2025-07-02 17:27:36 +02:00
|
|
|
Separated<T, C>: Vec<T> = {
|
2025-05-14 11:42:19 +02:00
|
|
|
<mut v:(<T> C)+> <e:T?> => match e {
|
|
|
|
|
None => v,
|
|
|
|
|
Some(e) => {
|
|
|
|
|
v.push(e);
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-03 11:09:58 +02:00
|
|
|
Separated_Or<T, C>: Vec<T> = {
|
|
|
|
|
<v: T> => vec![v],
|
|
|
|
|
<v: Separated<T, C>> => v
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// SetParser
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2025-06-16 14:46:04 +02:00
|
|
|
pub Set: RSset = {
|
2025-05-14 11:42:19 +02:00
|
|
|
<s: Set_of_entities> => s
|
|
|
|
|
};
|
|
|
|
|
|
2025-06-16 14:46:04 +02:00
|
|
|
Set_of_entities: RSset = {
|
2025-05-19 00:10:23 +02:00
|
|
|
"{" "}" => RSset::from(vec![]),
|
2025-07-03 11:09:58 +02:00
|
|
|
"{" <t: Separated_Or<Literal, ",">> "}" =>
|
2025-07-13 18:14:35 +02:00
|
|
|
RSset::from(t.into_iter().map(|t| translator.encode(t))
|
|
|
|
|
.collect::<Vec<_>>())
|
2025-05-19 00:10:23 +02:00
|
|
|
};
|
|
|
|
|
|
2025-06-12 16:23:39 +02:00
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// ReactionParser
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
pub Reactions: Vec<RSreaction> = {
|
|
|
|
|
"(" ")" => vec![],
|
2025-07-03 11:09:58 +02:00
|
|
|
"(" <s: Separated_Or<Reaction, ";">> ")" => s
|
2025-07-01 04:04:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Reaction: RSreaction = {
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="1")]
|
2025-07-01 04:04:13 +02:00
|
|
|
"[" <r: Set> "," <i: Set> "," <p: Set> "]" => RSreaction::from(r, i, p),
|
2025-08-20 19:51:03 +02:00
|
|
|
|
|
|
|
|
#[precedence(level="0")]
|
2025-07-01 19:22:50 +02:00
|
|
|
"[" "r:" <r: Set> "," "i:" <i: Set> "," "p:" <p: Set> "]" =>
|
|
|
|
|
RSreaction::from(r, i, p),
|
2025-07-01 04:04:13 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-29 22:56:32 +02:00
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// ContextParser
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
pub Context: RSprocess = {
|
|
|
|
|
"[" "]" => RSprocess::NondeterministicChoice{ children: vec![] },
|
2025-07-03 11:09:58 +02:00
|
|
|
"[" <t: Separated_Or<Boxed_CTX_process, ",">> "]" =>
|
2025-07-01 04:04:13 +02:00
|
|
|
RSprocess::NondeterministicChoice{ children: t }
|
2025-05-14 11:42:19 +02:00
|
|
|
};
|
|
|
|
|
|
2025-06-16 14:46:04 +02:00
|
|
|
Boxed_CTX_process: Rc<RSprocess> = {
|
2025-05-21 00:03:36 +02:00
|
|
|
<t: CTX_process> => Rc::new(t)
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-16 14:46:04 +02:00
|
|
|
CTX_process: RSprocess = {
|
2025-07-03 23:44:10 +02:00
|
|
|
"nill" => RSprocess::Nill,
|
2025-08-20 19:51:03 +02:00
|
|
|
|
2025-05-19 00:10:23 +02:00
|
|
|
<c: Set_of_entities> "." <k: CTX_process> =>
|
2025-05-21 00:03:36 +02:00
|
|
|
RSprocess::EntitySet{ entities: c, next_process: Rc::new(k) },
|
2025-08-20 19:51:03 +02:00
|
|
|
|
2025-05-14 11:42:19 +02:00
|
|
|
"(" <k: CTX_process> ")" => k,
|
2025-08-20 19:51:03 +02:00
|
|
|
|
2025-07-02 17:27:36 +02:00
|
|
|
"(" <k: Separated<CTX_process, "+">> ")" =>
|
2025-07-01 19:22:50 +02:00
|
|
|
RSprocess::Summation{
|
|
|
|
|
children: k.into_iter().map(Rc::new).collect::<Vec<_>>()
|
|
|
|
|
},
|
2025-08-20 19:51:03 +02:00
|
|
|
|
|
|
|
|
"?" <r: Reaction> "?" "." <k: CTX_process> =>
|
|
|
|
|
RSprocess::Guarded{ reaction: r, next_process: Rc::new(k) },
|
|
|
|
|
|
|
|
|
|
"<" <n: Num> "," <k1: CTX_process> ">" "." <k: CTX_process> =>
|
2025-05-19 00:10:23 +02:00
|
|
|
RSprocess::WaitEntity{ repeat: n,
|
2025-05-21 00:03:36 +02:00
|
|
|
repeated_process: Rc::new(k1),
|
2025-07-01 19:22:50 +02:00
|
|
|
next_process: Rc::new(k) },
|
2025-08-20 19:51:03 +02:00
|
|
|
|
|
|
|
|
<identifier: LiteralProcess> =>
|
2025-07-01 19:22:50 +02:00
|
|
|
RSprocess::RecursiveIdentifier{
|
|
|
|
|
identifier: translator.encode(identifier)
|
|
|
|
|
}
|
2025-05-14 11:42:19 +02:00
|
|
|
};
|
|
|
|
|
|
2025-07-29 22:56:32 +02:00
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// EnvironmentParser
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2025-06-16 14:46:04 +02:00
|
|
|
pub Environment: Box<RSenvironment> = {
|
2025-05-14 11:42:19 +02:00
|
|
|
"[" "]" => Box::new(RSenvironment::new()),
|
2025-07-03 11:09:58 +02:00
|
|
|
"[" <t: Separated_Or<Env_term, ",">> "]" => Box::new(RSenvironment::from(t))
|
2025-05-14 11:42:19 +02:00
|
|
|
};
|
|
|
|
|
|
2025-06-16 14:46:04 +02:00
|
|
|
Env_term: (IdType, RSprocess) = {
|
2025-08-20 19:51:03 +02:00
|
|
|
<identifier: LiteralProcess> "=" <k: CTX_process> =>
|
2025-06-18 11:28:04 +02:00
|
|
|
(translator.encode(identifier), k)
|
2025-05-14 11:42:19 +02:00
|
|
|
};
|
|
|
|
|
|
2025-07-29 22:56:32 +02:00
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// AssertParser
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2025-08-18 20:39:43 +02:00
|
|
|
pub Assert: Box<rsassert::RSassert> = {
|
|
|
|
|
"label" "{" <f: AssertTree> "}" =>
|
|
|
|
|
Box::new(rsassert::RSassert{tree: f}),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
AssertTree: rsassert::Tree = {
|
|
|
|
|
<t1: AssertTree2> ";" <t2: AssertTree> =>
|
|
|
|
|
rsassert::Tree::Concat(Box::new(t1), Box::new(t2)),
|
|
|
|
|
<t: AssertTree2> => t,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertTree2: rsassert::Tree = {
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="1")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"if" <e: AssertExpression>
|
|
|
|
|
"then" "{" <t: AssertTree> "}" =>
|
|
|
|
|
rsassert::Tree::If(Box::new(e), Box::new(t)),
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="0")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"if" <e: AssertExpression>
|
|
|
|
|
"then" "{" <t1: AssertTree> "}"
|
|
|
|
|
"else" "{" <t2: AssertTree> "}" =>
|
|
|
|
|
rsassert::Tree::IfElse(Box::new(e), Box::new(t1), Box::new(t2)),
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="2")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"let" <v: AssertVariable> <q: AssertQualifier?> "=" <e: AssertExpression> =>
|
|
|
|
|
rsassert::Tree::Assignment(v, q, Box::new(e)),
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="3")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"return" <e: AssertExpression> =>
|
|
|
|
|
rsassert::Tree::Return(Box::new(e)),
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="4")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"for" <v: AssertVariable> "in" <r: AssertRange> "{" <t: AssertTree> "}" =>
|
|
|
|
|
rsassert::Tree::For(v, r, Box::new(t)),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertVariable: rsassert::Variable = {
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="0")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"label" => rsassert::Variable::Special(rsassert::Special::Label),
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="1")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"edge" => rsassert::Variable::Special(rsassert::Special::Edge),
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="2")]
|
2025-08-18 20:39:43 +02:00
|
|
|
<v: Literal> => rsassert::Variable::Id(v),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AssertExpression: rsassert::Expression = {
|
|
|
|
|
// Unary
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="0")]
|
2025-08-18 20:39:43 +02:00
|
|
|
<unp: AssertUnaryPrefix> <e: AssertExpression> =>
|
|
|
|
|
rsassert::Expression::Unary(unp, Box::new(e)),
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="2")]
|
|
|
|
|
<e: AssertExpression> <uns: AssertUnarySuffix> =>
|
2025-08-18 20:39:43 +02:00
|
|
|
rsassert::Expression::Unary(uns, Box::new(e)),
|
|
|
|
|
|
|
|
|
|
// binary
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="3")] #[assoc(side="left")]
|
|
|
|
|
<e1: AssertExpression> <b: AssertBinary> <e2: AssertExpression> =>
|
2025-08-18 20:39:43 +02:00
|
|
|
rsassert::Expression::Binary(b, Box::new(e1), Box::new(e2)),
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="1")]
|
2025-08-18 20:39:43 +02:00
|
|
|
<b: AssertBinaryPrefix>
|
|
|
|
|
"(" <e1: AssertExpression> "," <e2: AssertExpression> ")" =>
|
|
|
|
|
rsassert::Expression::Binary(b, Box::new(e1), Box::new(e2)),
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="4")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"(" <e: AssertExpression> ")" => e,
|
|
|
|
|
"true" => rsassert::Expression::True,
|
|
|
|
|
"false" => rsassert::Expression::False,
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="5")]
|
2025-08-18 20:39:43 +02:00
|
|
|
<v: AssertVariable> => rsassert::Expression::Var(v),
|
|
|
|
|
|
|
|
|
|
// If changing IntegerType in assert.rs, also change from Num to another
|
|
|
|
|
// similar parser with different return type
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="6")]
|
2025-08-18 20:39:43 +02:00
|
|
|
<i: Num> => rsassert::Expression::Integer(i),
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="7")]
|
2025-08-18 20:39:43 +02:00
|
|
|
<lab: AssertLabel> => rsassert::Expression::Label(Box::new(lab)),
|
|
|
|
|
<set: Set_of_entities> => rsassert::Expression::Set(set),
|
|
|
|
|
"'" <el: Literal> "'" => rsassert::Expression::Element(translator.encode(el)),
|
|
|
|
|
|
|
|
|
|
// strings
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="8")]
|
2025-08-18 20:39:43 +02:00
|
|
|
PATH => rsassert::Expression::String(<>.trim_end_matches("\"")
|
|
|
|
|
.trim_start_matches("\"")
|
|
|
|
|
.to_string()),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertRange: rsassert::Range = {
|
|
|
|
|
"{" <e: AssertExpression> "}" => rsassert::Range::IterateOverSet(Box::new(e)),
|
|
|
|
|
"{" <e1: AssertExpression> ".." <e2: AssertExpression> "}" =>
|
|
|
|
|
rsassert::Range::IterateInRange(Box::new(e1), Box::new(e2)),
|
|
|
|
|
}
|
2025-07-29 22:56:32 +02:00
|
|
|
|
2025-08-18 20:39:43 +02:00
|
|
|
AssertUnaryPrefix: rsassert::Unary = {
|
|
|
|
|
"not" => rsassert::Unary::Not,
|
|
|
|
|
"rand" => rsassert::Unary::Rand,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertUnarySuffix: rsassert::Unary = {
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="0")]
|
|
|
|
|
"." "empty" => rsassert::Unary::Empty,
|
|
|
|
|
"." "length" => rsassert::Unary::Length,
|
|
|
|
|
"." "tostr" => rsassert::Unary::ToStr,
|
|
|
|
|
"." "toel" => rsassert::Unary::ToEl,
|
2025-08-18 20:39:43 +02:00
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="1")]
|
2025-08-18 20:39:43 +02:00
|
|
|
"." <q: AssertQualifier> => rsassert::Unary::Qualifier(q),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertQualifierRestricted: rsassert::QualifierRestricted = {
|
|
|
|
|
"Entities" => rsassert::QualifierRestricted::Entities,
|
|
|
|
|
"Context" => rsassert::QualifierRestricted::Context,
|
|
|
|
|
"Reactants" => rsassert::QualifierRestricted::Reactants,
|
|
|
|
|
"ReactantsAbsent" => rsassert::QualifierRestricted::ReactantsAbsent,
|
|
|
|
|
"Inhibitors" => rsassert::QualifierRestricted::Inhibitors,
|
|
|
|
|
"InhibitorsPresent" => rsassert::QualifierRestricted::InhibitorsPresent,
|
|
|
|
|
"Products" => rsassert::QualifierRestricted::Products,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertQualifierLabel: rsassert::QualifierLabel = {
|
|
|
|
|
"AvailableEntities" => rsassert::QualifierLabel::AvailableEntities,
|
|
|
|
|
"AllReactants" => rsassert::QualifierLabel::AllReactants,
|
|
|
|
|
"AllInhibitors" => rsassert::QualifierLabel::AllInhibitors,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertQualifierSystem: rsassert::QualifierSystem = {
|
|
|
|
|
"SystemEntities" => rsassert::QualifierSystem::Entities,
|
|
|
|
|
"SystemContext" => rsassert::QualifierSystem::Context,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertQualifierEdge: rsassert::QualifierEdge = {
|
|
|
|
|
"source" => rsassert::QualifierEdge::Source,
|
|
|
|
|
"target" => rsassert::QualifierEdge::Target,
|
|
|
|
|
}
|
2025-07-29 19:35:25 +02:00
|
|
|
|
2025-08-18 20:39:43 +02:00
|
|
|
AssertQualifierNode: rsassert::QualifierNode = {
|
|
|
|
|
"neighbours" => rsassert::QualifierNode::Neighbours,
|
|
|
|
|
"system" => rsassert::QualifierNode::System,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertQualifier: rsassert::Qualifier = {
|
|
|
|
|
<q: AssertQualifierSystem> => rsassert::Qualifier::System(q),
|
|
|
|
|
<q: AssertQualifierLabel> => rsassert::Qualifier::Label(q),
|
|
|
|
|
<q: AssertQualifierRestricted> => rsassert::Qualifier::Restricted(q),
|
|
|
|
|
<q: AssertQualifierEdge> => rsassert::Qualifier::Edge(q),
|
|
|
|
|
<q: AssertQualifierNode> => rsassert::Qualifier::Node(q),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AssertBinary: rsassert::Binary = {
|
|
|
|
|
"&&" => rsassert::Binary::And,
|
|
|
|
|
"||" => rsassert::Binary::Or,
|
|
|
|
|
"^^" => rsassert::Binary::Xor,
|
|
|
|
|
"<" => rsassert::Binary::Less,
|
|
|
|
|
"<=" => rsassert::Binary::LessEq,
|
|
|
|
|
">" => rsassert::Binary::More,
|
|
|
|
|
">=" => rsassert::Binary::MoreEq,
|
|
|
|
|
"==" => rsassert::Binary::Eq,
|
|
|
|
|
"!=" => rsassert::Binary::NotEq,
|
|
|
|
|
"+" => rsassert::Binary::Plus,
|
|
|
|
|
"-" => rsassert::Binary::Minus,
|
|
|
|
|
"*" => rsassert::Binary::Times,
|
|
|
|
|
"^" => rsassert::Binary::Exponential,
|
|
|
|
|
"/" => rsassert::Binary::Quotient,
|
|
|
|
|
"%" => rsassert::Binary::Reminder,
|
|
|
|
|
"::" => rsassert::Binary::Concat,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AssertBinaryPrefix: rsassert::Binary = {
|
|
|
|
|
"substr" => rsassert::Binary::SubStr,
|
|
|
|
|
"min" => rsassert::Binary::Min,
|
|
|
|
|
"max" => rsassert::Binary::Max,
|
|
|
|
|
"commonsubstr" => rsassert::Binary::CommonSubStr,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AssertLabel: RSlabel = {
|
|
|
|
|
"["
|
|
|
|
|
"Entities" ":" <e: Set_of_entities> ","
|
|
|
|
|
"Context" ":" <c: Set_of_entities> ","
|
|
|
|
|
"Reactants" ":" <r: Set_of_entities> ","
|
|
|
|
|
"ReactantsAbsent" ":" <r_a: Set_of_entities> ","
|
|
|
|
|
"Inhibitors" ":" <i: Set_of_entities> ","
|
|
|
|
|
"InhibitorsPresent" ":" <i_p: Set_of_entities> ","
|
|
|
|
|
"Products" ":" <p: Set_of_entities> ","
|
|
|
|
|
"]" => RSlabel::create(e, c, r, r_a, i, i_p, p)
|
|
|
|
|
}
|
2025-05-14 11:42:19 +02:00
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// BHMLParser
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2025-07-29 19:35:25 +02:00
|
|
|
// pub BHML: Box<RSBHML> = {
|
|
|
|
|
// <g: Formula_BHML> => Box::new(g)
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// Formula_BHML: RSBHML = {
|
|
|
|
|
// "true" => RSBHML::True,
|
|
|
|
|
// "false" => RSBHML::False,
|
|
|
|
|
// "(" <g: Separated<Formula_BHML, "\\/">> ")" => RSBHML::Or(g),
|
|
|
|
|
// "(" <g: Separated<Formula_BHML, "/\\">> ")" => RSBHML::And(g),
|
|
|
|
|
// "<" <f: Formula_Assert> ">" <g: Formula_BHML> =>
|
|
|
|
|
// RSBHML::Diamond(Box::new(f), Box::new(g)),
|
|
|
|
|
// "[" <f: Formula_Assert> "]" <g: Formula_BHML> =>
|
|
|
|
|
// RSBHML::Box(Box::new(f), Box::new(g)),
|
|
|
|
|
// };
|
2025-07-01 04:04:13 +02:00
|
|
|
|
|
|
|
|
|
2025-07-11 23:49:59 +02:00
|
|
|
// ----------------------------------------------------------------------------
|
2025-07-01 04:04:13 +02:00
|
|
|
// File Parsing
|
2025-07-11 23:49:59 +02:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2025-07-01 04:04:13 +02:00
|
|
|
// system
|
|
|
|
|
// a system is an environment, a set of entities as initial state, a context and
|
|
|
|
|
// a set of reaction rules.
|
|
|
|
|
pub System: RSsystem = {
|
2025-07-11 23:49:59 +02:00
|
|
|
"Environment" ":" <delta: Environment>
|
|
|
|
|
"Initial Entities" ":" <available_entities: Set>
|
|
|
|
|
"Context" ":" <context_process: Context>
|
|
|
|
|
"Reactions" ":" <reaction_rules: Reactions>
|
2025-07-01 19:22:50 +02:00
|
|
|
=> RSsystem::from(delta.into(),
|
|
|
|
|
available_entities,
|
|
|
|
|
context_process,
|
|
|
|
|
Rc::new(reaction_rules))
|
2025-07-01 04:04:13 +02:00
|
|
|
}
|
2025-07-02 17:27:36 +02:00
|
|
|
|
|
|
|
|
// experiment
|
|
|
|
|
// an experiment is composed by a sequence of weights and a sequence of sets of
|
|
|
|
|
// entities of equal length.
|
|
|
|
|
pub Experiment: (Vec<u32>, Vec<RSset>) = {
|
2025-07-11 23:49:59 +02:00
|
|
|
"Weights" ":" <w: Separated_Or<Num, ",">>
|
|
|
|
|
"Sets" ":" <s: Separated_Or<Set_of_entities, ",">>
|
2025-07-03 11:09:58 +02:00
|
|
|
=> (w.into_iter().map(|x| x as u32).collect::<Vec<_>>(), s),
|
2025-07-02 17:27:36 +02:00
|
|
|
}
|
2025-07-11 23:49:59 +02:00
|
|
|
|
|
|
|
|
|
2025-07-13 17:28:13 +02:00
|
|
|
// ~~~~~~~~~~~~~~~~~~~
|
2025-07-11 23:49:59 +02:00
|
|
|
// Instruction Parsing
|
2025-07-13 17:28:13 +02:00
|
|
|
// ~~~~~~~~~~~~~~~~~~~
|
2025-07-11 23:49:59 +02:00
|
|
|
|
2025-07-13 17:28:13 +02:00
|
|
|
/// Decides whetherer to print to stdout or to save to file
|
2025-07-11 23:49:59 +02:00
|
|
|
Helper_SO: presets::SaveOptions = {
|
|
|
|
|
"Print" =>
|
|
|
|
|
presets::SaveOptions {print: true, save: None},
|
|
|
|
|
"Save" "(" <p: Path> ")" =>
|
|
|
|
|
presets::SaveOptions {print: false, save: Some(vec![p])}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-13 17:28:13 +02:00
|
|
|
/// we could need to save to multiple files
|
2025-07-11 23:49:59 +02:00
|
|
|
SaveOptions: presets::SaveOptions = {
|
|
|
|
|
<p: Separated_Or<Helper_SO, ";">> => {
|
2025-07-12 02:42:28 +02:00
|
|
|
p.into_iter()
|
|
|
|
|
.reduce(|mut acc, mut e| {acc.combine(&mut e); acc})
|
|
|
|
|
.unwrap_or_default()
|
2025-07-11 23:49:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-13 17:28:13 +02:00
|
|
|
/// Match for strings between nodes formatters
|
2025-07-26 22:46:10 +02:00
|
|
|
LiteralSeparatorNode: graph::NodeDisplayBase = {
|
2025-07-12 15:32:21 +02:00
|
|
|
PATH =>
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplayBase::String {
|
|
|
|
|
string: <>.trim_end_matches("\"")
|
|
|
|
|
.trim_start_matches("\"")
|
|
|
|
|
.to_string()
|
|
|
|
|
}
|
2025-07-12 15:32:21 +02:00
|
|
|
};
|
|
|
|
|
|
2025-07-13 17:28:13 +02:00
|
|
|
/// Match for strings between edge formatters
|
2025-07-27 14:59:35 +02:00
|
|
|
LiteralSeparatorEdge: graph::EdgeDisplayBase = {
|
2025-07-12 15:32:21 +02:00
|
|
|
PATH =>
|
2025-07-27 14:59:35 +02:00
|
|
|
graph::EdgeDisplayBase::String {
|
2025-07-29 22:56:32 +02:00
|
|
|
string: <>.trim_end_matches("\"")
|
|
|
|
|
.trim_start_matches("\"")
|
|
|
|
|
.to_string()
|
2025-07-27 14:59:35 +02:00
|
|
|
}
|
2025-07-12 15:32:21 +02:00
|
|
|
};
|
|
|
|
|
|
2025-07-26 22:46:10 +02:00
|
|
|
NodeDisplayBase: graph::NodeDisplayBase = {
|
2025-07-16 16:20:29 +02:00
|
|
|
"Hide" =>
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplayBase::Hide,
|
2025-07-16 16:20:29 +02:00
|
|
|
"Entities" =>
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplayBase::Entities,
|
2025-07-12 15:32:21 +02:00
|
|
|
"MaskEntities" <mask: Set> =>
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplayBase::MaskEntities{mask},
|
|
|
|
|
"ExcludeEntities" <mask: Set> =>
|
|
|
|
|
graph::NodeDisplayBase::ExcludeEntities{mask},
|
2025-07-16 16:20:29 +02:00
|
|
|
"Context" =>
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplayBase::Context,
|
2025-07-16 16:20:29 +02:00
|
|
|
"UncommonEntities" =>
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplayBase::UncommonEntities,
|
2025-07-16 16:20:29 +02:00
|
|
|
"MaskUncommonentities" <mask: Set> =>
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplayBase::MaskUncommonEntities{mask},
|
2025-07-12 15:32:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-13 17:28:13 +02:00
|
|
|
/// Node display formatters separated by arbitrary strings in quotes
|
2025-07-26 22:46:10 +02:00
|
|
|
SeparatorNode: graph::NodeDisplay = {
|
|
|
|
|
<v: NodeDisplayBase> => graph::NodeDisplay {base: vec![v]},
|
|
|
|
|
<v:(<NodeDisplayBase> <LiteralSeparatorNode>)+> <e: NodeDisplayBase?> =>
|
2025-07-12 15:32:21 +02:00
|
|
|
match e {
|
2025-07-26 22:46:10 +02:00
|
|
|
None => graph::NodeDisplay {
|
|
|
|
|
base:
|
|
|
|
|
v.iter().fold(vec![],
|
|
|
|
|
|mut acc, (a, b)| {
|
|
|
|
|
acc.push(a.clone());
|
|
|
|
|
acc.push(b.clone());
|
|
|
|
|
acc.clone()
|
|
|
|
|
})
|
|
|
|
|
},
|
2025-07-12 15:32:21 +02:00
|
|
|
Some(e) => {
|
2025-07-13 18:14:35 +02:00
|
|
|
let mut v = v.iter().fold(vec![],
|
|
|
|
|
|mut acc, (a, b)| {
|
|
|
|
|
acc.push(a.clone());
|
|
|
|
|
acc.push(b.clone());
|
|
|
|
|
acc.clone()
|
|
|
|
|
});
|
2025-07-12 15:32:21 +02:00
|
|
|
v.push(e);
|
2025-07-26 22:46:10 +02:00
|
|
|
graph::NodeDisplay { base: v }
|
2025-07-12 15:32:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-27 14:59:35 +02:00
|
|
|
EdgeDisplay: graph::EdgeDisplayBase = {
|
2025-07-13 18:14:35 +02:00
|
|
|
"Hide" =>
|
2025-07-27 14:59:35 +02:00
|
|
|
graph::EdgeDisplayBase::Hide,
|
2025-07-27 19:08:27 +02:00
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
"Products" =>
|
2025-07-27 19:08:27 +02:00
|
|
|
graph::EdgeDisplayBase::Products
|
|
|
|
|
{ mask: None, filter_common: false },
|
2025-07-12 15:32:21 +02:00
|
|
|
"MaskProducts" <mask: Set> =>
|
2025-07-27 19:08:27 +02:00
|
|
|
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 },
|
|
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
"Entities" =>
|
2025-07-27 19:08:27 +02:00
|
|
|
graph::EdgeDisplayBase::Entities
|
|
|
|
|
{ mask: None, filter_common: false },
|
2025-07-13 18:14:35 +02:00
|
|
|
"MaskEntities" <mask: Set> =>
|
2025-07-27 19:08:27 +02:00
|
|
|
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 },
|
|
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
"Context" =>
|
2025-07-27 19:08:27 +02:00
|
|
|
graph::EdgeDisplayBase::Context
|
|
|
|
|
{ mask: None, filter_common: false },
|
2025-07-13 18:14:35 +02:00
|
|
|
"MaskContext" <mask: Set> =>
|
2025-07-27 19:08:27 +02:00
|
|
|
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 },
|
|
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
"Union" =>
|
2025-07-27 19:08:27 +02:00
|
|
|
graph::EdgeDisplayBase::Union
|
|
|
|
|
{ mask: None, filter_common: false },
|
2025-07-13 18:14:35 +02:00
|
|
|
"MaskUnion" <mask: Set> =>
|
2025-07-27 19:08:27 +02:00
|
|
|
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 },
|
|
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
"Difference" =>
|
2025-07-27 19:08:27 +02:00
|
|
|
graph::EdgeDisplayBase::Difference
|
|
|
|
|
{ mask: None, filter_common: false },
|
2025-07-13 18:14:35 +02:00
|
|
|
"MaskDifference" <mask: Set> =>
|
2025-07-27 19:08:27 +02:00
|
|
|
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 },
|
|
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
"EntitiesDeleted" =>
|
2025-07-27 19:08:27 +02:00
|
|
|
graph::EdgeDisplayBase::EntitiesDeleted
|
|
|
|
|
{ mask: None, filter_common: false },
|
2025-07-13 18:14:35 +02:00
|
|
|
"MaskEntitiesDeleted" <mask: Set> =>
|
2025-07-27 19:08:27 +02:00
|
|
|
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 },
|
|
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
"EntitiesAdded" =>
|
2025-07-27 19:08:27 +02:00
|
|
|
graph::EdgeDisplayBase::EntitiesAdded
|
|
|
|
|
{ mask: None, filter_common: false },
|
2025-07-13 18:14:35 +02:00
|
|
|
"MaskEntitiesAdded" <mask: Set> =>
|
2025-07-27 19:08:27 +02:00
|
|
|
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 },
|
2025-07-12 15:32:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-13 17:28:13 +02:00
|
|
|
/// Edge display formatters separated by arbitrary strings in quotes
|
2025-07-27 14:59:35 +02:00
|
|
|
SeparatorEdge: graph::EdgeDisplay = {
|
|
|
|
|
<v: EdgeDisplay> => graph::EdgeDisplay{ base: vec![v] },
|
2025-07-12 15:32:21 +02:00
|
|
|
<v:(<EdgeDisplay> <LiteralSeparatorEdge>)+> <e: EdgeDisplay?> =>
|
|
|
|
|
match e {
|
2025-07-27 14:59:35 +02:00
|
|
|
None => graph::EdgeDisplay{ base: v.iter().fold(vec![],
|
|
|
|
|
|mut acc, (a, b)| {
|
|
|
|
|
acc.push(a.clone());
|
|
|
|
|
acc.push(b.clone());
|
|
|
|
|
acc.clone()
|
|
|
|
|
}) },
|
2025-07-12 15:32:21 +02:00
|
|
|
Some(e) => {
|
2025-07-13 18:14:35 +02:00
|
|
|
let mut v = v.iter().fold(vec![],
|
|
|
|
|
|mut acc, (a, b)| {
|
|
|
|
|
acc.push(a.clone());
|
|
|
|
|
acc.push(b.clone());
|
|
|
|
|
acc.clone()
|
|
|
|
|
});
|
2025-07-12 15:32:21 +02:00
|
|
|
v.push(e);
|
2025-07-27 14:59:35 +02:00
|
|
|
graph::EdgeDisplay{ base: v }
|
2025-07-12 15:32:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-13 18:14:35 +02:00
|
|
|
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
|
|
|
|
|
ColorNode: graph::NodeColor = {
|
|
|
|
|
<conditionals: Separated_Or<NodeColorConditional, "||">>
|
|
|
|
|
"!" <base_color: PATH> =>
|
2025-07-13 19:08:39 +02:00
|
|
|
graph::NodeColor { conditionals,
|
2025-07-13 18:14:35 +02:00
|
|
|
base_color: base_color.to_string() },
|
|
|
|
|
|
|
|
|
|
"!" <base_color: PATH> =>
|
|
|
|
|
graph::NodeColor { conditionals: vec![],
|
|
|
|
|
base_color: base_color.to_string() },
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-13 19:08:39 +02:00
|
|
|
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()),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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() },
|
|
|
|
|
}
|
2025-07-13 18:14:35 +02:00
|
|
|
|
2025-07-12 15:32:21 +02:00
|
|
|
|
2025-07-11 23:49:59 +02:00
|
|
|
GraphSaveOptions: presets::GraphSaveOptions = {
|
2025-07-13 19:32:11 +02:00
|
|
|
"Dot" "|"? <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> "|"
|
2025-07-13 19:08:39 +02:00
|
|
|
<c_node: ColorNode> "|" <c_edge: ColorEdge> ">"
|
2025-07-12 15:32:21 +02:00
|
|
|
<so: SaveOptions> =>
|
|
|
|
|
presets::GraphSaveOptions::Dot { node_display: s_node,
|
|
|
|
|
edge_display: s_edge,
|
2025-07-13 18:14:35 +02:00
|
|
|
node_color: c_node,
|
2025-07-13 19:08:39 +02:00
|
|
|
edge_color: c_edge,
|
2025-07-12 15:32:21 +02:00
|
|
|
so },
|
2025-07-13 19:32:11 +02:00
|
|
|
"GraphML" "|"? <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> ">"
|
2025-07-12 15:32:21 +02:00
|
|
|
<so: SaveOptions> =>
|
|
|
|
|
presets::GraphSaveOptions::GraphML { node_display: s_node,
|
|
|
|
|
edge_display: s_edge,
|
|
|
|
|
so },
|
2025-07-11 23:49:59 +02:00
|
|
|
"Serialize" "(" <path: Path> ")" =>
|
|
|
|
|
presets::GraphSaveOptions::Serialize { path },
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Instruction: presets::Instruction = {
|
|
|
|
|
"Stats" ">" <so: SaveOptions> =>
|
|
|
|
|
presets::Instruction::Stats { so },
|
|
|
|
|
"Target" ">" <so: SaveOptions> =>
|
|
|
|
|
presets::Instruction::Target { so },
|
|
|
|
|
"Run" ">" <so: SaveOptions> =>
|
|
|
|
|
presets::Instruction::Run { so },
|
|
|
|
|
"Loop" "(" <symbol: Literal> ")" ">" <so: SaveOptions> =>
|
|
|
|
|
presets::Instruction::Loop { symbol, so },
|
2025-07-12 02:42:28 +02:00
|
|
|
"Frequency" ">" <so: SaveOptions> =>
|
|
|
|
|
presets::Instruction::Frequency { so },
|
2025-07-11 23:49:59 +02:00
|
|
|
"LimitFrequency" "(" <p: Path> ")" ">" <so: SaveOptions> =>
|
|
|
|
|
presets::Instruction::LimitFrequency { experiment: p, so },
|
|
|
|
|
"FastFrequency" "(" <p: Path> ")" ">" <so: SaveOptions> =>
|
|
|
|
|
presets::Instruction::FastFrequency { experiment: p, so },
|
|
|
|
|
"Digraph" ">" <gso: Separated_Or<GraphSaveOptions, "|">> =>
|
|
|
|
|
presets::Instruction::Digraph { gso },
|
2025-08-16 21:52:36 +02:00
|
|
|
// <edge_relabeler: Assert>
|
2025-08-18 20:39:43 +02:00
|
|
|
"Bisimilarity" "(" <p: Path> ")" "relabel" <edge_relabeler: Assert>
|
2025-08-15 00:32:58 +02:00
|
|
|
">" <so: SaveOptions> =>
|
2025-08-16 21:52:36 +02:00
|
|
|
presets::Instruction::Bisimilarity {
|
|
|
|
|
system_b: p,
|
2025-08-18 20:39:43 +02:00
|
|
|
edge_relabeler,
|
2025-08-16 21:52:36 +02:00
|
|
|
so
|
|
|
|
|
},
|
2025-07-11 23:49:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub Run: presets::Instructions = {
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="0")]
|
2025-07-11 23:49:59 +02:00
|
|
|
<sys: System> <instr: Separated_Or<Instruction, ",">> =>
|
|
|
|
|
Instructions { system: presets::System::RSsystem { sys },
|
|
|
|
|
instructions: instr },
|
2025-07-13 18:14:35 +02:00
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="1")]
|
2025-07-16 00:05:14 +02:00
|
|
|
<sys: System> =>
|
|
|
|
|
Instructions { system: presets::System::RSsystem { sys },
|
|
|
|
|
instructions: vec![] },
|
|
|
|
|
|
2025-08-20 19:51:03 +02:00
|
|
|
#[precedence(level="2")]
|
2025-07-13 18:14:35 +02:00
|
|
|
"Deserialize" "(" <path: Path> ")"
|
|
|
|
|
<instr: Separated_Or<Instruction, ",">> =>
|
2025-07-11 23:49:59 +02:00
|
|
|
Instructions { system: presets::System::Deserialize { path },
|
|
|
|
|
instructions: instr },
|
|
|
|
|
}
|