More examples, better defaults

grammar_separated is grammar but with all functions exposed
This commit is contained in:
elvis
2025-10-17 19:45:20 +02:00
parent 164e1d883c
commit 08d195ab06
30 changed files with 8698 additions and 49 deletions

View File

@ -0,0 +1,294 @@
use std::str::FromStr;
use lalrpop_util::ParseError;
use assert::relabel;
use rsprocess::{set, label};
use rsprocess::translator::Translator;
use crate::custom_error;
grammar(translator: &mut Translator);
extern {
type Error = custom_error::UserError;
}
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
// order
match {
"!", "!=", "%", "&&", "'", "(", ")", "*", "+", ",", "-", "..", "/", ":",
"::", ";", "<", "<=", "=", "==", ">", ">=", "AllInhibitors", "AllReactants",
"AvailableEntities", "Context", "Entities", "Inhibitors",
"InhibitorsPresent", "Products", "Reactants", "ReactantsAbsent",
"SystemContext", "SystemEntities", "[", "\"", "]", "^", "^^", "edge",
"else", "empty", "false", "for", "if", "in", "label", "length", "let",
"neighbours", "not", "rand", "return", "source", "system", "target", "then",
"toel", "tostr", "true", "{", "||", "}",
} 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(),
};
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
}
})
}
}
};
// 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
// -----------------------------------------------------------------------------
Set: set::Set = {
<s: Separated_Empty<"{", Literal, ",", "}">> =>
set::Set::from(s.into_iter().map(|t| translator.encode(t))
.collect::<Vec<_>>())
};
// -----------------------------------------------------------------------------
// LabelParser
// -----------------------------------------------------------------------------
Label: label::Label = {
"["
"Entities" ":" <e: Set> ","
"Context" ":" <c: Set> ","
"Reactants" ":" <r: Set> ","
"ReactantsAbsent" ":" <r_a: Set> ","
"Inhibitors" ":" <i: Set> ","
"InhibitorsPresent" ":" <i_p: Set> ","
"Products" ":" <p: Set> ","?
"]" => label::Label::create(e, c, r, r_a, i, i_p, p)
}
// -----------------------------------------------------------------------------
// AssertParser
// -----------------------------------------------------------------------------
pub Assert: Box<relabel::Assert> = {
"label" "{" <f: AssertTree> "}" =>
Box::new(relabel::Assert{tree: f}),
};
AssertTree: relabel::Tree = {
<t1: AssertTree2> <t2: AssertTree> =>
relabel::Tree::Concat(Box::new(t1), Box::new(t2)),
<t: AssertTree2> => t,
}
AssertTree2: relabel::Tree = {
#[precedence(level="1")]
"if" <e: AssertExpression>
"then" "{" <t: AssertTree> "}" ";"? =>
relabel::Tree::If(Box::new(e), Box::new(t)),
#[precedence(level="0")]
"if" <e: AssertExpression>
"then" "{" <t1: AssertTree> "}"
"else" "{" <t2: AssertTree> "}" ";"? =>
relabel::Tree::IfElse(Box::new(e), Box::new(t1), Box::new(t2)),
"let" <v: AssertVariable> <q: AssertQualifier?> "=" <e: AssertExpression>
";"
=> relabel::Tree::Assignment(v, q, Box::new(e)),
"return" <e: AssertExpression> ";" =>
relabel::Tree::Return(Box::new(e)),
"for" <v: AssertVariable> "in" <r: AssertRange> "{" <t: AssertTree> "}" ";"?
=> relabel::Tree::For(v, r, Box::new(t)),
}
AssertVariable: relabel::Variable = {
#[precedence(level="0")]
"label" => relabel::Variable::Special(relabel::Special::Label),
"edge" => relabel::Variable::Special(relabel::Special::Edge),
#[precedence(level="1")]
<v: Literal> => relabel::Variable::Id(v),
}
AssertExpression: relabel::Expression = {
#[precedence(level="100")]
<unp: AssertUnaryPrefix> "(" <e: AssertExpression> ")" =>
relabel::Expression::Unary(unp, Box::new(e)),
#[precedence(level="50")]
<e: AssertExpression> "." <uns: AssertUnarySuffix> =>
relabel::Expression::Unary(uns, Box::new(e)),
#[precedence(level="100")] #[assoc(side="left")]
"(" <e1: AssertExpression> <b: AssertBinary> <e2: AssertExpression> ")" =>
relabel::Expression::Binary(b, Box::new(e1), Box::new(e2)),
#[precedence(level="100")]
<b: AssertBinaryPrefix>
"(" <e1: AssertExpression> "," <e2: AssertExpression> ")" =>
relabel::Expression::Binary(b, Box::new(e1), Box::new(e2)),
#[precedence(level="0")]
<t: AssertTerm> => t,
}
AssertTerm: relabel::Expression = {
"true" => relabel::Expression::True,
"false" => relabel::Expression::False,
<v: AssertVariable> => relabel::Expression::Var(v),
// If changing IntegerType in assert.rs, also change from Num to another
// similar parser with different return type
<i: Num> => relabel::Expression::Integer(i),
<lab: Label> => relabel::Expression::Label(Box::new(lab)),
<set: Set> => relabel::Expression::Set(set),
"'" <el: Literal> "'" =>
relabel::Expression::Element(translator.encode(el)),
// strings
PATH => relabel::Expression::String(<>.trim_end_matches("\"")
.trim_start_matches("\"")
.to_string()),
// allow arbitrary parenthesis
"(" <e: AssertExpression> ")" => e,
}
AssertRange: relabel::Range = {
"{" <e: AssertExpression> "}" =>
relabel::Range::IterateOverSet(Box::new(e)),
"{" <e1: AssertExpression> ".." <e2: AssertExpression> "}" =>
relabel::Range::IterateInRange(Box::new(e1), Box::new(e2)),
}
AssertUnaryPrefix: relabel::Unary = {
"not" => relabel::Unary::Not,
"rand" => relabel::Unary::Rand,
}
AssertUnarySuffix: relabel::Unary = {
#[precedence(level="0")]
"empty" => relabel::Unary::Empty,
"length" => relabel::Unary::Length,
"tostr" => relabel::Unary::ToStr,
"toel" => relabel::Unary::ToEl,
#[precedence(level="1")]
<q: AssertQualifier> => relabel::Unary::Qualifier(q),
}
AssertQualifierRestricted: relabel::QualifierRestricted = {
"Entities" => relabel::QualifierRestricted::Entities,
"Context" => relabel::QualifierRestricted::Context,
"Reactants" => relabel::QualifierRestricted::Reactants,
"ReactantsAbsent" => relabel::QualifierRestricted::ReactantsAbsent,
"Inhibitors" => relabel::QualifierRestricted::Inhibitors,
"InhibitorsPresent" => relabel::QualifierRestricted::InhibitorsPresent,
"Products" => relabel::QualifierRestricted::Products,
}
AssertQualifierLabel: relabel::QualifierLabel = {
"AvailableEntities" => relabel::QualifierLabel::AvailableEntities,
"AllReactants" => relabel::QualifierLabel::AllReactants,
"AllInhibitors" => relabel::QualifierLabel::AllInhibitors,
}
AssertQualifierSystem: relabel::QualifierSystem = {
"SystemEntities" => relabel::QualifierSystem::Entities,
"SystemContext" => relabel::QualifierSystem::Context,
}
AssertQualifierEdge: relabel::QualifierEdge = {
"source" => relabel::QualifierEdge::Source,
"target" => relabel::QualifierEdge::Target,
}
AssertQualifierNode: relabel::QualifierNode = {
"neighbours" => relabel::QualifierNode::Neighbours,
"system" => relabel::QualifierNode::System,
}
AssertQualifier: relabel::Qualifier = {
<q: AssertQualifierSystem> => relabel::Qualifier::System(q),
<q: AssertQualifierLabel> => relabel::Qualifier::Label(q),
<q: AssertQualifierRestricted> => relabel::Qualifier::Restricted(q),
<q: AssertQualifierEdge> => relabel::Qualifier::Edge(q),
<q: AssertQualifierNode> => relabel::Qualifier::Node(q),
}
AssertBinary: relabel::Binary = {
"&&" => relabel::Binary::And,
"||" => relabel::Binary::Or,
"^^" => relabel::Binary::Xor,
"<" => relabel::Binary::Less,
"<=" => relabel::Binary::LessEq,
">" => relabel::Binary::More,
">=" => relabel::Binary::MoreEq,
"==" => relabel::Binary::Eq,
"!=" => relabel::Binary::NotEq,
"+" => relabel::Binary::Plus,
"-" => relabel::Binary::Minus,
"*" => relabel::Binary::Times,
"^" => relabel::Binary::Exponential,
"/" => relabel::Binary::Quotient,
"%" => relabel::Binary::Reminder,
"::" => relabel::Binary::Concat,
}
AssertBinaryPrefix: relabel::Binary = {
"substr" => relabel::Binary::SubStr,
"min" => relabel::Binary::Min,
"max" => relabel::Binary::Max,
"commonsubstr" => relabel::Binary::CommonSubStr,
}

View File

@ -0,0 +1,30 @@
use std::fmt::Display;
pub enum UserErrorTypes {
NumberTooBigUsize,
NumberTooBigi64,
}
impl Display for UserErrorTypes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
| Self::NumberTooBigUsize => write!(
f,
"Specified number is too big (greater than {})",
usize::MAX
),
| Self::NumberTooBigi64 => write!(
f,
"Specified number is too big (lesser than {} or \
greater than {})",
i64::MIN,
i64::MAX
),
}
}
}
pub struct UserError {
pub token: (usize, String, usize),
pub error: UserErrorTypes,
}

View File

@ -0,0 +1,313 @@
use std::rc::Rc;
use std::str::FromStr;
use lalrpop_util::ParseError;
// use assert::{relabel, grouping};
use rsprocess::{set, reaction, process, environment, system, label};
use rsprocess::element::IdType;
use rsprocess::translator::Translator;
// use execution::presets;
// use rsprocess::graph;
use crate::custom_error;
grammar(translator: &mut Translator);
extern {
type Error = custom_error::UserError;
}
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
// order
match {
"!", "(", ")", "+", ",", "-", ".", ":", ";", "<", "<=", "=", "==", ">",
">=", "?", "AbsentReactants", "Bisimilarity", "Context",
"Context.EntitySet", "Context.Nill", "Context.NonDeterministicChoice",
"Context.RecursiveIdentifier", "Context.Summation", "Context.WaitEntity",
"Deserialize", "Difference", "Digraph", "Dot", "Entities", "EntitiesAdded",
"EntitiesDeleted", "Environment", "ExcludeEntities", "FastFrequency",
"GraphML", "Grequency", "Hide", "Inhibitors", "InhibitorsPresent", "Initial
Entities", "Limit", "LimitFrequency", "Loop", "MaskContext",
"MaskDifference", "MaskEntities", "MaskEntitiesAdded",
"MaskEntitiesDeleted", "MaskProducts", "MaskUncommonEntities", "MaskUnion",
"PresentInhibitors", "Print", "Products", "Reactants", "ReactantsAbsent",
"Reactions", "Run", "Save", "Serialize", "Sets", "Stats", "T", "Target",
"UncommonContext", "UncommonDifference", "UncommonEntities",
"UncommonEntitiesAdded", "UncommonEntitiesDeleted", "UncommonMaskContext",
"UncommonMaskDifference", "UncommonMaskEntities",
"UncommonMaskEntitiesAdded", "UncommonMaskEntitiesDeleted",
"UncommonMaskProducts", "UncommonMaskUnion", "UncommonProducts",
"UncommonUnion", "Union", "Weights", "[", "]", "i:", "nill", "p:", "r:",
"relabel", "{", "|", "}", "⊂", "⊃", "⊆", "⊇",
} 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(),
"Bisimilarity" => <>.into(),
"Context" => <>.into(),
"Context.EntitySet" => <>.into(),
"Context.Nill" => <>.into(),
"Context.NonDeterministicChoice" => <>.into(),
"Context.RecursiveIdentifier" => <>.into(),
"Context.Summation" => <>.into(),
"Context.WaitEntity" => <>.into(),
"Deserialize" => <>.into(),
"Difference" => <>.into(),
"Digraph" => <>.into(),
"Dot" => <>.into(),
"Entities" => <>.into(),
"EntitiesAdded" => <>.into(),
"EntitiesDeleted" => <>.into(),
"Environment" => <>.into(),
"ExcludeEntities" => <>.into(),
"FastFrequency" => <>.into(),
"GraphML" => <>.into(),
"Grequency" => <>.into(),
"Hide" => <>.into(),
"Inhibitors" => <>.into(),
"InhibitorsPresent" => <>.into(),
"Initial" => <>.into(),
"Limit" => <>.into(),
"LimitFrequency" => <>.into(),
"Loop" => <>.into(),
"MaskContext" => <>.into(),
"MaskDifference" => <>.into(),
"MaskEntities" => <>.into(),
"MaskEntitiesAdded" => <>.into(),
"MaskEntitiesDeleted" => <>.into(),
"MaskProducts" => <>.into(),
"MaskUncommonEntities" => <>.into(),
"MaskUnion" => <>.into(),
"PresentInhibitors" => <>.into(),
"Print" => <>.into(),
"Products" => <>.into(),
"Reactants" => <>.into(),
"ReactantsAbsent" => <>.into(),
"Reactions" => <>.into(),
"Run" => <>.into(),
"Save" => <>.into(),
"Serialize" => <>.into(),
"Sets" => <>.into(),
"Stats" => <>.into(),
"T" => <>.into(),
"Target" => <>.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(),
"Weights" => <>.into(),
"relabel" => <>.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<_>>())
};
// -----------------------------------------------------------------------------
// ReactionParser
// -----------------------------------------------------------------------------
pub Reactions: Vec<reaction::Reaction> = {
<s: Separated_Empty<"(", Reaction, ";", ")">> => s
}
Reaction: reaction::Reaction = {
#[precedence(level="1")]
"[" <r: Set> "," <i: Set> "," <p: Set> "]" =>
reaction::Reaction::from(r, i, p),
#[precedence(level="0")]
"[" "r:" <r: Set> "," "i:" <i: Set> "," "p:" <p: Set> "]" =>
reaction::Reaction::from(r, i, p),
}
// -----------------------------------------------------------------------------
// ContextParser
// -----------------------------------------------------------------------------
pub Context: process::Process = {
<t: Separated_Empty<"[", ContextProcess, ",", "]">> =>
process::Process::NondeterministicChoice{
children: t.into_iter().map(Rc::new).collect::<Vec<_>>()
}
};
ContextProcess: process::Process = {
"nill" => process::Process::Nill,
<c: Set> "." <k: ContextProcess> =>
process::Process::EntitySet{ entities: c, next_process: Rc::new(k) },
"(" <k: ContextProcess> ")" => k,
"(" <k: Separated<ContextProcess, "+">> ")" =>
process::Process::Summation{
children: k.into_iter().map(Rc::new).collect::<Vec<_>>()
},
"?" <r: Reaction> "?" "." <k: ContextProcess> =>
process::Process::Guarded{ reaction: r, next_process: Rc::new(k) },
"<" <n: Num> "," <k1: ContextProcess> ">" "." <k: ContextProcess> =>
process::Process::WaitEntity{ repeat: n,
repeated_process: Rc::new(k1),
next_process: Rc::new(k) },
<identifier: LiteralProcess> =>
process::Process::RecursiveIdentifier{
identifier: translator.encode(identifier)
}
};
// -----------------------------------------------------------------------------
// EnvironmentParser
// -----------------------------------------------------------------------------
pub Environment: Box<environment::Environment> = {
<t: Separated_Empty<"[", Env_term, ",", "]">> =>
Box::new(environment::Environment::from(t))
};
Env_term: (IdType, process::Process) = {
<identifier: LiteralProcess> "=" <k: ContextProcess> =>
(translator.encode(identifier), k)
};
// -----------------------------------------------------------------------------
// LabelParser
// -----------------------------------------------------------------------------
pub Label: label::Label = {
"["
"Entities" ":" <e: Set> ","
"Context" ":" <c: Set> ","
"Reactants" ":" <r: Set> ","
"ReactantsAbsent" ":" <r_a: Set> ","
"Inhibitors" ":" <i: Set> ","
"InhibitorsPresent" ":" <i_p: Set> ","
"Products" ":" <p: Set> ","?
"]" => label::Label::create(e, c, r, r_a, i, i_p, p)
}
// ----------------------------------------------------------------------------
// 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: system::System = {
"Environment" ":" <delta: Environment>
"Initial Entities" ":" <available_entities: Set>
"Context" ":" <context_process: Context>
"Reactions" ":" <reaction_rules: Reactions>
=> system::System::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<u32>, Vec<set::Set>) = {
"Weights" ":" <w: Separated_Or<Num, ",">>
"Sets" ":" <s: Separated_Or<Set, ",">>
=> (w.into_iter().map(|x| x as u32).collect::<Vec<_>>(), s),
}

View File

@ -0,0 +1,302 @@
use std::rc::Rc;
use std::str::FromStr;
use lalrpop_util::ParseError;
use assert::{relabel, grouping};
use rsprocess::{set, reaction, process, environment, system, label};
use rsprocess::element::IdType;
use rsprocess::translator::Translator;
use execution::presets;
use rsprocess::graph;
use crate::custom_error;
grammar(translator: &mut Translator);
extern {
type Error = custom_error::UserError;
}
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
// order
match {
"!",
} 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(),
};
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
}
})
}
}
};
// 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(t.into_iter().map(|t| translator.encode(t))
.collect::<Vec<_>>())
};
// -----------------------------------------------------------------------------
// LabelParser
// -----------------------------------------------------------------------------
pub Label: label::Label = {
"["
"Entities" ":" <e: Set> ","
"Context" ":" <c: Set> ","
"Reactants" ":" <r: Set> ","
"ReactantsAbsent" ":" <r_a: Set> ","
"Inhibitors" ":" <i: Set> ","
"InhibitorsPresent" ":" <i_p: Set> ","
"Products" ":" <p: Set> ","?
"]" => label::Label::create(e, c, r, r_a, i, i_p, p)
}
// -----------------------------------------------------------------------------
// GroupingParser
// -----------------------------------------------------------------------------
Group: Box<grouping::Assert> = {
">" "node" "{" <f: GroupTree> "}" =>
Box::new(grouping::Assert{tree: f}),
};
GroupTree: grouping::Tree = {
<t1: GroupTree2> <t2: GroupTree> =>
grouping::Tree::Concat(Box::new(t1), Box::new(t2)),
<t: GroupTree2> => t,
}
GroupTree2: grouping::Tree = {
#[precedence(level="1")]
"if" <e: GroupExpression>
"then" "{" <t: GroupTree> "}" ";"? =>
grouping::Tree::If(Box::new(e), Box::new(t)),
#[precedence(level="0")]
"if" <e: GroupExpression>
"then" "{" <t1: GroupTree> "}"
"else" "{" <t2: GroupTree> "}" ";"? =>
grouping::Tree::IfElse(Box::new(e), Box::new(t1), Box::new(t2)),
"let" <v: GroupVariable> <q: GroupQualifier?> "=" <e: GroupExpression> ";"
=> grouping::Tree::Assignment(v, q, Box::new(e)),
"return" <e: GroupExpression> ";" =>
grouping::Tree::Return(Box::new(e)),
"for" <v: GroupVariable> "in" <r: GroupRange> "{" <t: GroupTree> "}" ";"? =>
grouping::Tree::For(v, r, Box::new(t)),
}
GroupVariable: grouping::Variable = {
#[precedence(level="0")]
"entities" => grouping::Variable::Special(grouping::Special::Entities),
"node" => grouping::Variable::Special(grouping::Special::Node),
#[precedence(level="1")]
<v: Literal> => grouping::Variable::Id(v),
}
GroupExpression: grouping::Expression = {
#[precedence(level="100")]
<unp: GroupUnaryPrefix> "(" <e: GroupExpression> ")" =>
grouping::Expression::Unary(unp, Box::new(e)),
#[precedence(level="50")]
<e: GroupExpression> "." <uns: GroupUnarySuffix> =>
grouping::Expression::Unary(uns, Box::new(e)),
#[precedence(level="100")] #[assoc(side="left")]
<e1: GroupExpression> <b: GroupBinary> <e2: GroupExpression> =>
grouping::Expression::Binary(b, Box::new(e1), Box::new(e2)),
#[precedence(level="100")]
<b: GroupBinaryPrefix>
"(" <e1: GroupExpression> "," <e2: GroupExpression> ")" =>
grouping::Expression::Binary(b, Box::new(e1), Box::new(e2)),
#[precedence(level="0")]
<t: GroupTerm> => t,
}
GroupTerm: grouping::Expression = {
"true" => grouping::Expression::True,
"false" => grouping::Expression::False,
<v: GroupVariable> => grouping::Expression::Var(v),
// If changing IntegerType in assert.rs, also change from Num to another
// similar parser with different return type
<i: Num> => grouping::Expression::Integer(i),
<lab: Label> => grouping::Expression::Label(Box::new(lab)),
<set: Set> => grouping::Expression::Set(set),
"'" <el: Literal> "'" =>
grouping::Expression::Element(translator.encode(el)),
// strings
PATH => grouping::Expression::String(<>.trim_end_matches("\"")
.trim_start_matches("\"")
.to_string()),
// allow arbitrary parenthesis
"(" <e: GroupExpression> ")" => e,
}
#[inline]
GroupRange: grouping::Range = {
"{" <e: GroupExpression> "}" =>
grouping::Range::IterateOverSet(Box::new(e)),
"{" <e1: GroupExpression> ".." <e2: GroupExpression> "}" =>
grouping::Range::IterateInRange(Box::new(e1), Box::new(e2)),
}
#[inline]
GroupUnaryPrefix: grouping::Unary = {
"not" => grouping::Unary::Not,
"rand" => grouping::Unary::Rand,
}
#[inline]
GroupUnarySuffix: grouping::Unary = {
#[precedence(level="0")]
"empty" => grouping::Unary::Empty,
"length" => grouping::Unary::Length,
"tostr" => grouping::Unary::ToStr,
"toel" => grouping::Unary::ToEl,
#[precedence(level="1")]
<q: GroupQualifier> => grouping::Unary::Qualifier(q),
}
#[inline]
GroupQualifierRestricted: grouping::QualifierRestricted = {
"Entities" => grouping::QualifierRestricted::Entities,
"Context" => grouping::QualifierRestricted::Context,
"Reactants" => grouping::QualifierRestricted::Reactants,
"ReactantsAbsent" => grouping::QualifierRestricted::ReactantsAbsent,
"Inhibitors" => grouping::QualifierRestricted::Inhibitors,
"InhibitorsPresent" => grouping::QualifierRestricted::InhibitorsPresent,
"Products" => grouping::QualifierRestricted::Products,
}
#[inline]
GroupQualifierLabel: grouping::QualifierLabel = {
"AvailableEntities" => grouping::QualifierLabel::AvailableEntities,
"AllReactants" => grouping::QualifierLabel::AllReactants,
"AllInhibitors" => grouping::QualifierLabel::AllInhibitors,
}
#[inline]
GroupQualifierSystem: grouping::QualifierSystem = {
"SystemEntities" => grouping::QualifierSystem::Entities,
"SystemContext" => grouping::QualifierSystem::Context,
}
#[inline]
GroupQualifierEdge: grouping::QualifierEdge = {
"source" => grouping::QualifierEdge::Source,
"target" => grouping::QualifierEdge::Target,
}
#[inline]
GroupQualifierNode: grouping::QualifierNode = {
"neighbours" => grouping::QualifierNode::Neighbours,
"system" => grouping::QualifierNode::System,
}
#[inline]
GroupQualifier: grouping::Qualifier = {
<q: GroupQualifierSystem> => grouping::Qualifier::System(q),
<q: GroupQualifierLabel> => grouping::Qualifier::Label(q),
<q: GroupQualifierRestricted> => grouping::Qualifier::Restricted(q),
<q: GroupQualifierEdge> => grouping::Qualifier::Edge(q),
<q: GroupQualifierNode> => grouping::Qualifier::Node(q),
}
#[inline]
GroupBinary: grouping::Binary = {
"&&" => grouping::Binary::And,
"||" => grouping::Binary::Or,
"^^" => grouping::Binary::Xor,
"<" => grouping::Binary::Less,
"<=" => grouping::Binary::LessEq,
">" => grouping::Binary::More,
">=" => grouping::Binary::MoreEq,
"==" => grouping::Binary::Eq,
"!=" => grouping::Binary::NotEq,
"+" => grouping::Binary::Plus,
"-" => grouping::Binary::Minus,
"*" => grouping::Binary::Times,
"^" => grouping::Binary::Exponential,
"/" => grouping::Binary::Quotient,
"%" => grouping::Binary::Reminder,
"::" => grouping::Binary::Concat,
}
#[inline]
GroupBinaryPrefix: grouping::Binary = {
"substr" => grouping::Binary::SubStr,
"min" => grouping::Binary::Min,
"max" => grouping::Binary::Max,
"commonsubstr" => grouping::Binary::CommonSubStr,
}

View 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 },
// }

View File

@ -0,0 +1,38 @@
mod custom_error;
pub mod user_error {
pub use crate::custom_error::*;
}
#[rustfmt::skip]
#[allow(clippy::extra_unused_lifetimes)]
#[allow(clippy::needless_lifetimes)]
#[allow(clippy::let_unit_value)]
#[allow(clippy::just_underscores_and_digits)]
#[allow(clippy::uninlined_format_args)]
#[allow(clippy::type_complexity)]
pub mod grammar {
include!(concat!(env!("OUT_DIR"), "/src/grammar.rs"));
}
#[rustfmt::skip]
#[allow(clippy::extra_unused_lifetimes)]
#[allow(clippy::needless_lifetimes)]
#[allow(clippy::let_unit_value)]
#[allow(clippy::just_underscores_and_digits)]
#[allow(clippy::uninlined_format_args)]
#[allow(clippy::type_complexity)]
pub mod assert {
include!(concat!(env!("OUT_DIR"), "/src/assert.rs"));
}
#[rustfmt::skip]
#[allow(clippy::extra_unused_lifetimes)]
#[allow(clippy::needless_lifetimes)]
#[allow(clippy::let_unit_value)]
#[allow(clippy::just_underscores_and_digits)]
#[allow(clippy::uninlined_format_args)]
#[allow(clippy::type_complexity)]
pub mod instructions {
include!(concat!(env!("OUT_DIR"), "/src/instructions.rs"));
}