custom grammar errors, better handling of user facing errors
fuckery for modules in grammar, maybe fixable?
This commit is contained in:
@ -2,6 +2,7 @@ use execution::presets;
|
|||||||
use lalrpop_util::ParseError;
|
use lalrpop_util::ParseError;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use grammar::grammar;
|
use grammar::grammar;
|
||||||
|
use ::grammar::user_error::{UserError, UserErrorTypes};
|
||||||
|
|
||||||
pub struct Parsers {}
|
pub struct Parsers {}
|
||||||
|
|
||||||
@ -27,37 +28,41 @@ impl presets::FileParsers for Parsers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reformat_error<T, S>(
|
fn create_error<S, T>(
|
||||||
e: ParseError<usize, T, &'static str>,
|
|
||||||
input_str: &str,
|
input_str: &str,
|
||||||
|
l: usize,
|
||||||
|
t: T,
|
||||||
|
r: usize,
|
||||||
|
expected: Option<Vec<String>>,
|
||||||
|
error: Option<UserErrorTypes>,
|
||||||
) -> Result<S, String>
|
) -> Result<S, String>
|
||||||
where
|
where
|
||||||
T: Display,
|
T: Display,
|
||||||
{
|
{
|
||||||
match e {
|
use colored::Colorize;
|
||||||
| ParseError::ExtraToken { token: (l, t, r) } => Err(format!(
|
|
||||||
"Unexpected token \"{t}\" between positions {l} and {r}."
|
|
||||||
)),
|
|
||||||
| ParseError::UnrecognizedEof {
|
|
||||||
location: _,
|
|
||||||
expected: _,
|
|
||||||
} => Err("End of file encountered while parsing.".into()),
|
|
||||||
| ParseError::InvalidToken { location } =>
|
|
||||||
Err(format!("Invalid token at position {location}.")),
|
|
||||||
| ParseError::UnrecognizedToken {
|
|
||||||
token: (l, t, r),
|
|
||||||
expected,
|
|
||||||
} => {
|
|
||||||
use colored::Colorize;
|
|
||||||
|
|
||||||
let mut err = format!(
|
let mut err = {
|
||||||
|
if let Some(error) = error {
|
||||||
|
format!(
|
||||||
|
"{error} {}{}{} \
|
||||||
|
between positions {l} and {r}.",
|
||||||
|
"\"".red(),
|
||||||
|
t.to_string().red(),
|
||||||
|
"\"".red(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
"Unrecognized token {}{}{} \
|
"Unrecognized token {}{}{} \
|
||||||
between positions {l} and {r}.",
|
between positions {l} and {r}.",
|
||||||
"\"".red(),
|
"\"".red(),
|
||||||
t.to_string().red(),
|
t.to_string().red(),
|
||||||
"\"".red(),
|
"\"".red(),
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
if let Some(expected) = expected {
|
||||||
// Temporary debug.
|
// Temporary debug.
|
||||||
err.push_str("\nExpected: ");
|
err.push_str("\nExpected: ");
|
||||||
let mut it = expected.iter().peekable();
|
let mut it = expected.iter().peekable();
|
||||||
@ -70,44 +75,74 @@ where
|
|||||||
err.push(' ');
|
err.push(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let right_new_line = input_str[l..]
|
}
|
||||||
.find("\n")
|
}
|
||||||
.map(|pos| pos + l)
|
let right_new_line = input_str[l..]
|
||||||
.unwrap_or(input_str.len());
|
.find("\n")
|
||||||
let left_new_line = input_str[..r]
|
.map(|pos| pos + l)
|
||||||
.rfind("\n")
|
.unwrap_or(input_str.len());
|
||||||
.map(|pos| pos + 1)
|
let left_new_line = input_str[..r]
|
||||||
.unwrap_or_default();
|
.rfind("\n")
|
||||||
|
.map(|pos| pos + 1)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let line_number = input_str[..l].match_indices('\n').count() + 1;
|
let line_number = input_str[..l].match_indices('\n').count() + 1;
|
||||||
let pre_no_color = format!("{line_number} |");
|
let pre_no_color = format!("{line_number} |");
|
||||||
let pre = format!("{}", pre_no_color.blue());
|
let pre = format!("{}", pre_no_color.blue());
|
||||||
|
|
||||||
let line_pos_l = l - left_new_line;
|
let line_pos_l = l - left_new_line;
|
||||||
let line_pos_r = r - left_new_line;
|
let line_pos_r = r - left_new_line;
|
||||||
|
|
||||||
err.push_str(&format!(
|
err.push_str(&format!(
|
||||||
"\nLine {} position {} to {}:\n{}{}{}{}",
|
"\nLine {} position {} to {}:\n{}{}{}{}",
|
||||||
line_number,
|
line_number,
|
||||||
line_pos_l,
|
line_pos_l,
|
||||||
line_pos_r,
|
line_pos_r,
|
||||||
&pre,
|
&pre,
|
||||||
&input_str[left_new_line..l].green(),
|
&input_str[left_new_line..l].green(),
|
||||||
&input_str[l..r].red(),
|
&input_str[l..r].red(),
|
||||||
&input_str[r..right_new_line],
|
&input_str[r..right_new_line],
|
||||||
));
|
));
|
||||||
err.push('\n');
|
err.push('\n');
|
||||||
err.push_str(&" ".repeat(pre_no_color.len() - 1));
|
err.push_str(&" ".repeat(pre_no_color.len() - 1));
|
||||||
err.push_str(&format!("{}", "|".blue()));
|
err.push_str(&format!("{}", "|".blue()));
|
||||||
err.push_str(&" ".repeat(l - left_new_line));
|
err.push_str(&" ".repeat(l - left_new_line));
|
||||||
err.push_str(&format!("{}", &"↑".red()));
|
err.push_str(&format!("{}", &"↑".red()));
|
||||||
if r - l > 2 {
|
if r - l > 2 {
|
||||||
err.push_str(&" ".repeat(r - l - 2));
|
err.push_str(&" ".repeat(r - l - 2));
|
||||||
err.push_str(&format!("{}", &"↑".red()));
|
err.push_str(&format!("{}", &"↑".red()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(err)
|
Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reformat_error<T, S>(
|
||||||
|
e: ParseError<usize, T, UserError>,
|
||||||
|
input_str: &str,
|
||||||
|
) -> Result<S, String>
|
||||||
|
where
|
||||||
|
T: Display,
|
||||||
|
{
|
||||||
|
match e {
|
||||||
|
| ParseError::ExtraToken { token: (l, t, r) } =>
|
||||||
|
Err(format!("Unexpected extra token \"{t}\" between positions {l} \
|
||||||
|
and {r}.")),
|
||||||
|
| ParseError::UnrecognizedEof {
|
||||||
|
location: _,
|
||||||
|
expected: _,
|
||||||
|
} => Err("End of file encountered while parsing.".into()),
|
||||||
|
| ParseError::InvalidToken { location } =>
|
||||||
|
Err(format!("Invalid token at position {location}.")),
|
||||||
|
| ParseError::UnrecognizedToken {
|
||||||
|
token: (l, t, r),
|
||||||
|
expected,
|
||||||
|
} => {
|
||||||
|
create_error(input_str, l, t, r, Some(expected), None)
|
||||||
|
},
|
||||||
|
| ParseError::User {
|
||||||
|
error: UserError { token: (l, t, r), error }
|
||||||
|
} => {
|
||||||
|
create_error(input_str, l, t, r, None, Some(error))
|
||||||
},
|
},
|
||||||
| ParseError::User { error } => Err(error.to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,9 +92,11 @@ pub enum Instruction {
|
|||||||
},
|
},
|
||||||
Target {
|
Target {
|
||||||
so: SaveOptions,
|
so: SaveOptions,
|
||||||
|
limit: Option<usize>,
|
||||||
},
|
},
|
||||||
Run {
|
Run {
|
||||||
so: SaveOptions,
|
so: SaveOptions,
|
||||||
|
limit: Option<usize>,
|
||||||
},
|
},
|
||||||
Loop {
|
Loop {
|
||||||
symbol: String,
|
symbol: String,
|
||||||
@ -132,43 +134,45 @@ pub enum System {
|
|||||||
impl System {
|
impl System {
|
||||||
/// Deserialize the graph if applicable.
|
/// Deserialize the graph if applicable.
|
||||||
pub fn compute(
|
pub fn compute(
|
||||||
&self,
|
self,
|
||||||
translator: Translator,
|
translator: Translator,
|
||||||
) -> Result<EvaluatedSystem, String> {
|
) -> Result<EvaluatedSystem, String> {
|
||||||
match self {
|
match self {
|
||||||
| Self::System { sys } => Ok(EvaluatedSystem::System {
|
| Self::System { sys } =>
|
||||||
sys: sys.to_owned(),
|
Ok(EvaluatedSystem::from_sys(sys, translator)),
|
||||||
translator,
|
|
||||||
}),
|
|
||||||
| Self::Deserialize { path } => {
|
| Self::Deserialize { path } => {
|
||||||
let (graph, translator) = deserialize(path.into())?;
|
let (graph, translator) = deserialize(path)?;
|
||||||
Ok(EvaluatedSystem::Graph { graph, translator })
|
Ok(EvaluatedSystem::from_graph(graph, translator))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum EvaluatedSystem {
|
pub struct EvaluatedSystem {
|
||||||
Graph {
|
sys: Option<system::System>,
|
||||||
graph: graph::SystemGraph,
|
graph: Option<graph::SystemGraph>,
|
||||||
translator: Translator,
|
positive: Option<system::PositiveSystem>,
|
||||||
},
|
translator: Translator,
|
||||||
System {
|
|
||||||
sys: system::System,
|
|
||||||
translator: Translator,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EvaluatedSystem {
|
impl EvaluatedSystem {
|
||||||
pub fn get_translator(&mut self) -> &mut Translator {
|
pub fn get_translator(&mut self) -> &mut Translator {
|
||||||
match self {
|
&mut self.translator
|
||||||
| EvaluatedSystem::Graph {
|
}
|
||||||
graph: _,
|
|
||||||
translator,
|
pub fn from_graph(
|
||||||
} => translator,
|
graph: graph::SystemGraph,
|
||||||
| EvaluatedSystem::System { sys: _, translator } => translator,
|
translator: Translator
|
||||||
}
|
) -> Self {
|
||||||
|
Self { sys: None, graph: Some(graph), positive: None, translator }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_sys(
|
||||||
|
sys: system::System,
|
||||||
|
translator: Translator,
|
||||||
|
) -> Self {
|
||||||
|
Self { sys: Some(sys), graph: None, positive: None, translator }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,65 +252,127 @@ fn save_file(contents: &String, path_string: String) -> Result<(), String> {
|
|||||||
/// Prints statistics of the system.
|
/// Prints statistics of the system.
|
||||||
/// Equivalent main_do(stat) or main_do(stat, MissingE)
|
/// Equivalent main_do(stat) or main_do(stat, MissingE)
|
||||||
pub fn stats(system: &EvaluatedSystem) -> Result<String, String> {
|
pub fn stats(system: &EvaluatedSystem) -> Result<String, String> {
|
||||||
match system {
|
if let Some(sys) = &system.sys {
|
||||||
| EvaluatedSystem::System { sys, translator } =>
|
Ok(sys.statistics(&system.translator))
|
||||||
Ok(sys.statistics(translator)),
|
} else if let Some(graph) = &system.graph {
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
let Some(sys) = graph.node_weights().next() else {
|
||||||
let Some(sys) = graph.node_weights().next() else {
|
return Err("No node found in graph.".into());
|
||||||
return Err("No node found in graph.".into());
|
};
|
||||||
};
|
Ok(sys.statistics(&system.translator))
|
||||||
Ok(sys.statistics(translator))
|
} else {
|
||||||
},
|
Err("Statistics not available for supplied system.".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a final set of entities in a terminating Reaction System.
|
/// Prints a final set of entities in a terminating Reaction System.
|
||||||
/// The system needs to terminate to return.
|
/// The system needs to terminate to return.
|
||||||
/// Equivalent to main_do(target, E)
|
/// Equivalent to main_do(target, E)
|
||||||
pub fn target(system: &EvaluatedSystem) -> Result<String, String> {
|
pub fn target(
|
||||||
let (res, translator) = match system {
|
system: &EvaluatedSystem,
|
||||||
| EvaluatedSystem::System { sys, translator } =>
|
limit: Option<usize>
|
||||||
(sys.target()?, translator),
|
) -> Result<String, String> {
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
if let Some(sys) = &system.sys {
|
||||||
let Some(sys) = graph.node_weights().next() else {
|
let res = if let Some(limit) = limit {
|
||||||
return Err("No node found in graph.".into());
|
sys.target_limit(limit)?
|
||||||
};
|
} else {
|
||||||
(sys.target()?, translator)
|
sys.target()?
|
||||||
},
|
};
|
||||||
};
|
Ok(format!(
|
||||||
Ok(format!(
|
"After {} steps we arrive at state:\n{}",
|
||||||
"After {} steps we arrive at state:\n{}",
|
res.0,
|
||||||
res.0,
|
translator::Formatter::from(&system.translator, &res.1)
|
||||||
translator::Formatter::from(translator, &res.1)
|
))
|
||||||
))
|
} else if let Some(graph) = &system.graph {
|
||||||
|
let Some(sys) = graph.node_weights().next() else {
|
||||||
|
return Err("No node found in graph.".into());
|
||||||
|
};
|
||||||
|
let res = if let Some(limit) = limit {
|
||||||
|
sys.target_limit(limit)?
|
||||||
|
} else {
|
||||||
|
sys.target()?
|
||||||
|
};
|
||||||
|
Ok(format!(
|
||||||
|
"After {} steps we arrive at state:\n{}",
|
||||||
|
res.0,
|
||||||
|
translator::Formatter::from(&system.translator, &res.1)
|
||||||
|
))
|
||||||
|
} else if let Some(positive) = &system.positive {
|
||||||
|
let res = if let Some(limit) = limit {
|
||||||
|
positive.target_limit(limit)?
|
||||||
|
} else {
|
||||||
|
positive.target()?
|
||||||
|
};
|
||||||
|
Ok(format!(
|
||||||
|
"After {} steps we arrive at state:\n{}",
|
||||||
|
res.0,
|
||||||
|
translator::Formatter::from(&system.translator, &res.1)
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err("Target not available for supplied system.".into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the list of traversed states in a (deterministic) terminating
|
/// Finds the list of traversed states in a (deterministic) terminating
|
||||||
/// reaction.
|
/// reaction.
|
||||||
/// The system needs to terminate to return.
|
/// The system needs to terminate to return.
|
||||||
/// equivalent to main_do(run,Es)
|
/// equivalent to main_do(run,Es)
|
||||||
pub fn traversed(system: &EvaluatedSystem) -> Result<String, String> {
|
pub fn traversed(
|
||||||
let (res, translator) = match system {
|
system: &EvaluatedSystem,
|
||||||
| EvaluatedSystem::System { sys, translator } =>
|
limit: Option<usize>
|
||||||
(sys.run_separated()?, translator),
|
) -> Result<String, String> {
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
|
||||||
let Some(sys) = graph.node_weights().next() else {
|
|
||||||
return Err("No node found in graph.".into());
|
|
||||||
};
|
|
||||||
(sys.run_separated()?, translator)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
output.push_str("The trace is composed by the set of entities: ");
|
if let Some(sys) = &system.sys {
|
||||||
for (e, _c, _t) in res {
|
let res = if let Some(limit) = limit {
|
||||||
output.push_str(&format!(
|
sys.run_separated_limit(limit)?
|
||||||
"{}",
|
} else {
|
||||||
translator::Formatter::from(translator, &e)
|
sys.run_separated()?
|
||||||
));
|
};
|
||||||
|
|
||||||
|
output.push_str("The trace is composed by the set of entities: ");
|
||||||
|
for (e, _c, _t) in res {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"{}",
|
||||||
|
translator::Formatter::from(&system.translator, &e)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(output)
|
||||||
|
} else if let Some(graph) = &system.graph {
|
||||||
|
let Some(sys) = graph.node_weights().next() else {
|
||||||
|
return Err("No node found in graph.".into());
|
||||||
|
};
|
||||||
|
let res = if let Some(limit) = limit {
|
||||||
|
sys.run_separated_limit(limit)?
|
||||||
|
} else {
|
||||||
|
sys.run_separated()?
|
||||||
|
};
|
||||||
|
|
||||||
|
output.push_str("The trace is composed by the set of entities: ");
|
||||||
|
for (e, _c, _t) in res {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"{}",
|
||||||
|
translator::Formatter::from(&system.translator, &e)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(output)
|
||||||
|
} else if let Some(positive) = &system.positive {
|
||||||
|
let res = if let Some(limit) = limit {
|
||||||
|
positive.run_separated_limit(limit)?
|
||||||
|
} else {
|
||||||
|
positive.run_separated()?
|
||||||
|
};
|
||||||
|
|
||||||
|
output.push_str("The trace is composed by the set of entities: ");
|
||||||
|
for (e, _c, _t) in res {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"{}",
|
||||||
|
translator::Formatter::from(&system.translator, &e)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(output)
|
||||||
|
} else {
|
||||||
|
Err("Run not available for supplied system.".into())
|
||||||
}
|
}
|
||||||
Ok(output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the looping list of states in a reaction system with a perpetual
|
/// Finds the looping list of states in a reaction system with a perpetual
|
||||||
@ -318,38 +384,68 @@ pub fn hoop(
|
|||||||
symbol: String,
|
symbol: String,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
use system::LoopSystem;
|
use system::LoopSystem;
|
||||||
|
// we retrieve the id for the input symbol, error if not found.
|
||||||
let (res, translator) = match system {
|
let Some(id) = system.translator.encode_not_mut(&symbol) else {
|
||||||
| EvaluatedSystem::System { sys, translator } => (sys, translator),
|
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
|
||||||
let Some(sys) = graph.node_weights().next() else {
|
|
||||||
return Err("No node found in graph.".into());
|
|
||||||
};
|
|
||||||
(sys, translator)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// we retrieve the id for "x" and use it to find the corresponding loop
|
|
||||||
let Some(id) = translator.encode_not_mut(&symbol) else {
|
|
||||||
return Err(format!("Symbol {symbol} not found."));
|
return Err(format!("Symbol {symbol} not found."));
|
||||||
};
|
};
|
||||||
let res = match res.lollipops_only_loop_named(id) {
|
|
||||||
| Some(o) => o,
|
|
||||||
| None => {
|
|
||||||
return Err("No loop found.".into());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
output.push_str("The loop is composed by the sets: ");
|
if let Some(sys) = &system.sys {
|
||||||
for e in res {
|
let res = match sys.lollipops_only_loop_named(id) {
|
||||||
output.push_str(&format!(
|
| Some(o) => o,
|
||||||
"{}",
|
| None => {
|
||||||
translator::Formatter::from(translator, &e)
|
return Err("No loop found.".into());
|
||||||
));
|
},
|
||||||
}
|
};
|
||||||
|
output.push_str("The loop is composed by the sets: ");
|
||||||
|
for e in res {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"{}",
|
||||||
|
translator::Formatter::from(&system.translator, &e)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(output)
|
Ok(output)
|
||||||
|
} else if let Some(graph) = &system.graph {
|
||||||
|
let Some(sys) = graph.node_weights().next() else {
|
||||||
|
return Err("No node found in graph.".into());
|
||||||
|
};
|
||||||
|
let res = match sys.lollipops_only_loop_named(id) {
|
||||||
|
| Some(o) => o,
|
||||||
|
| None => {
|
||||||
|
return Err("No loop found.".into());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
output.push_str("The loop is composed by the sets: ");
|
||||||
|
for e in res {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"{}",
|
||||||
|
translator::Formatter::from(&system.translator, &e)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
} else if let Some(positive) = &system.positive {
|
||||||
|
let res = match positive.lollipops_only_loop_named(id) {
|
||||||
|
| Some(o) => o,
|
||||||
|
| None => {
|
||||||
|
return Err("No loop found.".into());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
output.push_str("The loop is composed by the sets: ");
|
||||||
|
for e in res {
|
||||||
|
output.push_str(&format!(
|
||||||
|
"{}",
|
||||||
|
translator::Formatter::from(&system.translator, &e)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
} else {
|
||||||
|
Err("Loop not available for supplied system.".into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the frequency of each entity in the traversed states for a
|
/// Finds the frequency of each entity in the traversed states for a
|
||||||
@ -358,22 +454,33 @@ pub fn hoop(
|
|||||||
pub fn freq(system: &EvaluatedSystem) -> Result<String, String> {
|
pub fn freq(system: &EvaluatedSystem) -> Result<String, String> {
|
||||||
use frequency::BasicFrequency;
|
use frequency::BasicFrequency;
|
||||||
|
|
||||||
let (sys, translator) = match system {
|
if let Some(sys) = &system.sys {
|
||||||
| EvaluatedSystem::System { sys, translator } => (sys, translator),
|
let res = frequency::Frequency::naive_frequency(sys)?;
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
|
||||||
let Some(sys) = graph.node_weights().next() else {
|
|
||||||
return Err("No node found in graph.".into());
|
|
||||||
};
|
|
||||||
(sys, translator)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let res = frequency::Frequency::naive_frequency(sys)?;
|
Ok(format!(
|
||||||
|
"Frequency of encountered symbols:\n{}",
|
||||||
|
translator::Formatter::from(&system.translator, &res)
|
||||||
|
))
|
||||||
|
} else if let Some(graph) = &system.graph {
|
||||||
|
let Some(sys) = graph.node_weights().next() else {
|
||||||
|
return Err("No node found in graph.".into());
|
||||||
|
};
|
||||||
|
let res = frequency::Frequency::naive_frequency(sys)?;
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"Frequency of encountered symbols:\n{}",
|
"Frequency of encountered symbols:\n{}",
|
||||||
translator::Formatter::from(translator, &res)
|
translator::Formatter::from(&system.translator, &res)
|
||||||
))
|
))
|
||||||
|
} else if let Some(positive) = &system.positive {
|
||||||
|
let res = frequency::PositiveFrequency::naive_frequency(positive)?;
|
||||||
|
|
||||||
|
Ok(format!(
|
||||||
|
"Frequency of encountered symbols:\n{}",
|
||||||
|
translator::Formatter::from(&system.translator, &res)
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err("Frequency not available for supplied system.".into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the frequency of each entity in the limit loop of a nonterminating
|
/// Finds the frequency of each entity in the limit loop of a nonterminating
|
||||||
@ -389,33 +496,65 @@ where
|
|||||||
{
|
{
|
||||||
use frequency::BasicFrequency;
|
use frequency::BasicFrequency;
|
||||||
|
|
||||||
let (sys, translator): (&system::System, &mut Translator) = match system {
|
let (_, sets) =
|
||||||
| EvaluatedSystem::System { sys, translator } => (sys, translator),
|
read_file(&mut system.translator, experiment, parser_experiment)?;
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
|
||||||
let Some(sys) = graph.node_weights().next() else {
|
|
||||||
return Err("No node found in graph.".into());
|
|
||||||
};
|
|
||||||
(sys, translator)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let (_, sets) = read_file(translator, experiment, parser_experiment)?;
|
if let Some(sys) = &system.sys {
|
||||||
|
let res = match frequency::Frequency::limit_frequency(
|
||||||
|
&sets,
|
||||||
|
&sys.reaction_rules,
|
||||||
|
&sys.available_entities,
|
||||||
|
) {
|
||||||
|
| Some(e) => e,
|
||||||
|
| None => {
|
||||||
|
return Err("Error calculating frequency.".into());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let res = match frequency::Frequency::limit_frequency(
|
Ok(format!(
|
||||||
&sets,
|
"Frequency of encountered symbols:\n{}",
|
||||||
&sys.reaction_rules,
|
translator::Formatter::from(&system.translator, &res)
|
||||||
&sys.available_entities,
|
))
|
||||||
) {
|
} else if let Some(graph) = &system.graph {
|
||||||
| Some(e) => e,
|
let Some(sys) = graph.node_weights().next() else {
|
||||||
| None => {
|
return Err("No node found in graph.".into());
|
||||||
return Err("Error calculating frequency.".into());
|
};
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(format!(
|
let res = match frequency::Frequency::limit_frequency(
|
||||||
"Frequency of encountered symbols:\n{}",
|
&sets,
|
||||||
translator::Formatter::from(translator, &res)
|
&sys.reaction_rules,
|
||||||
))
|
&sys.available_entities,
|
||||||
|
) {
|
||||||
|
| Some(e) => e,
|
||||||
|
| None => {
|
||||||
|
return Err("Error calculating frequency.".into());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(format!(
|
||||||
|
"Frequency of encountered symbols:\n{}",
|
||||||
|
translator::Formatter::from(&system.translator, &res)
|
||||||
|
))
|
||||||
|
} else if let Some(_positive) = &system.positive {
|
||||||
|
todo!()
|
||||||
|
// let res = match frequency::PositiveFrequency::limit_frequency(
|
||||||
|
// &sets,
|
||||||
|
// &positive.reaction_rules,
|
||||||
|
// &positive.available_entities,
|
||||||
|
// ) {
|
||||||
|
// | Some(e) => e,
|
||||||
|
// | None => {
|
||||||
|
// return Err("Error calculating frequency.".into());
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// Ok(format!(
|
||||||
|
// "Frequency of encountered symbols:\n{}",
|
||||||
|
// translator::Formatter::from(&system.translator, &res)
|
||||||
|
// ))
|
||||||
|
} else {
|
||||||
|
Err("LimitFrequency not available for supplied system.".into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the frequency of each entity in the traversed loops of a terminating
|
/// Finds the frequency of each entity in the traversed loops of a terminating
|
||||||
@ -433,48 +572,69 @@ where
|
|||||||
{
|
{
|
||||||
use frequency::BasicFrequency;
|
use frequency::BasicFrequency;
|
||||||
|
|
||||||
let (sys, translator): (&system::System, &mut Translator) = match system {
|
let (weights, sets) =
|
||||||
| EvaluatedSystem::System { sys, translator } => (sys, translator),
|
read_file(&mut system.translator, experiment, parser_experiment)?;
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
|
||||||
let Some(sys) = graph.node_weights().next() else {
|
|
||||||
return Err("No node found in graph".into());
|
|
||||||
};
|
|
||||||
(sys, translator)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let (weights, sets) = read_file(translator, experiment, parser_experiment)?;
|
if let Some(sys) = &system.sys {
|
||||||
|
let res = match frequency::Frequency::fast_frequency(
|
||||||
|
&sets,
|
||||||
|
&sys.reaction_rules,
|
||||||
|
&sys.available_entities,
|
||||||
|
&weights,
|
||||||
|
) {
|
||||||
|
| Some(e) => e,
|
||||||
|
| None => {
|
||||||
|
return Err("Error calculating frequency.".into());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let res = match frequency::Frequency::fast_frequency(
|
Ok(format!(
|
||||||
&sets,
|
"Frequency of encountered symbols:\n{}",
|
||||||
&sys.reaction_rules,
|
translator::Formatter::from(&system.translator, &res)
|
||||||
&sys.available_entities,
|
))
|
||||||
&weights,
|
} else if let Some(graph) = &system.graph {
|
||||||
) {
|
let Some(sys) = graph.node_weights().next() else {
|
||||||
| Some(e) => e,
|
return Err("No node found in graph".into());
|
||||||
| None => {
|
};
|
||||||
return Err("Error calculating frequency.".into());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(format!(
|
let res = match frequency::Frequency::fast_frequency(
|
||||||
"Frequency of encountered symbols:\n{}",
|
&sets,
|
||||||
translator::Formatter::from(translator, &res)
|
&sys.reaction_rules,
|
||||||
))
|
&sys.available_entities,
|
||||||
|
&weights,
|
||||||
|
) {
|
||||||
|
| Some(e) => e,
|
||||||
|
| None => {
|
||||||
|
return Err("Error calculating frequency.".into());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(format!(
|
||||||
|
"Frequency of encountered symbols:\n{}",
|
||||||
|
translator::Formatter::from(&system.translator, &res)
|
||||||
|
))
|
||||||
|
} else if let Some(_positive) = &system.positive {
|
||||||
|
todo!()
|
||||||
|
} else {
|
||||||
|
Err("FastFrequency not available for supplied system.".into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the LTS.
|
/// Computes the LTS.
|
||||||
/// equivalent to main_do(digraph, Arcs) or to main_do(advdigraph, Arcs)
|
/// equivalent to main_do(digraph, Arcs) or to main_do(advdigraph, Arcs)
|
||||||
pub fn digraph(system: &mut EvaluatedSystem) -> Result<(), String> {
|
pub fn digraph(system: &mut EvaluatedSystem) -> Result<(), String> {
|
||||||
if let EvaluatedSystem::System { sys, translator } = system {
|
if let Some(sys) = &system.sys && system.graph.is_none() {
|
||||||
*system = EvaluatedSystem::Graph {
|
let graph = sys.digraph()?;
|
||||||
graph: sys.digraph()?,
|
system.graph = Some(graph);
|
||||||
translator: translator.to_owned(),
|
} else if let Some(positive) = &system.positive && system.graph.is_none() {
|
||||||
};
|
let _graph = positive.digraph()?;
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a graph and a function that identifies nodes of the graph, merges
|
||||||
|
/// nodes with the same identifier.
|
||||||
pub fn grouping(
|
pub fn grouping(
|
||||||
system: &mut EvaluatedSystem,
|
system: &mut EvaluatedSystem,
|
||||||
group: &assert::grouping::Assert,
|
group: &assert::grouping::Assert,
|
||||||
@ -482,9 +642,9 @@ pub fn grouping(
|
|||||||
let mut buckets = HashMap::new();
|
let mut buckets = HashMap::new();
|
||||||
let mut leader: HashMap<petgraph::prelude::NodeIndex, _> = HashMap::new();
|
let mut leader: HashMap<petgraph::prelude::NodeIndex, _> = HashMap::new();
|
||||||
|
|
||||||
if let EvaluatedSystem::Graph { graph, translator } = system {
|
if let Some(graph) = &mut system.graph {
|
||||||
for node in graph.node_indices() {
|
for node in graph.node_indices() {
|
||||||
let val = group.execute(graph, &node, translator)?;
|
let val = group.execute(graph, &node, &mut system.translator)?;
|
||||||
println!("node: {node:?} -> val: {val:?}");
|
println!("node: {node:?} -> val: {val:?}");
|
||||||
buckets.entry(val.clone()).or_insert(vec![]).push(node);
|
buckets.entry(val.clone()).or_insert(vec![]).push(node);
|
||||||
let l = buckets.get(&val).unwrap().first().unwrap();
|
let l = buckets.get(&val).unwrap().first().unwrap();
|
||||||
@ -541,59 +701,37 @@ where
|
|||||||
{
|
{
|
||||||
use assert::relabel::AssertReturnValue;
|
use assert::relabel::AssertReturnValue;
|
||||||
|
|
||||||
let system_b = read_file(
|
let system_b = read_file(&mut system_a.translator,
|
||||||
system_a.get_translator(),
|
system_b.to_string(),
|
||||||
system_b.to_string(),
|
parser_instructions)?;
|
||||||
parser_instructions,
|
|
||||||
)?;
|
let mut system_b = system_b
|
||||||
let mut system_b = match system_b
|
|
||||||
.system
|
.system
|
||||||
.compute(system_a.get_translator().clone())?
|
.compute(system_a.get_translator().clone())?;
|
||||||
{
|
|
||||||
| EvaluatedSystem::System { sys, translator } =>
|
if system_b.translator != system_a.translator {
|
||||||
EvaluatedSystem::System { sys, translator },
|
return Err("Bisimilarity not implemented for systems with different \
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
encodings. Serialize the systems with the same translator."
|
||||||
if translator != *system_a.get_translator() {
|
.into());
|
||||||
return Err("Bisimilarity not implemented for systems with \
|
}
|
||||||
different encodings. Serialize the systems \
|
|
||||||
with the same translator."
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
EvaluatedSystem::Graph { graph, translator }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
digraph(system_a)?;
|
digraph(system_a)?;
|
||||||
digraph(&mut system_b)?;
|
digraph(&mut system_b)?;
|
||||||
|
|
||||||
// since we ran digraph on both they have to be graphs
|
// since we ran digraph on both they have to have valid graphs
|
||||||
match (system_a, &mut system_b) {
|
|
||||||
| (
|
let a: Graph<system::System, AssertReturnValue> =
|
||||||
EvaluatedSystem::Graph {
|
system_a.graph.as_ref().unwrap()
|
||||||
graph: a,
|
.map_edges(edge_relabeler, &mut system_a.translator)?;
|
||||||
translator: _,
|
let b: Graph<system::System, AssertReturnValue> =
|
||||||
},
|
system_b.graph.unwrap().map_edges(edge_relabeler, &mut system_b.translator)?;
|
||||||
EvaluatedSystem::Graph {
|
Ok(format!(
|
||||||
graph: b,
|
"{}",
|
||||||
translator: translator_b,
|
// bisimilarity::bisimilarity_kanellakis_smolka::bisimilarity(&
|
||||||
},
|
// &a, &&b)
|
||||||
) => {
|
// bisimilarity::bisimilarity_paige_tarjan::bisimilarity_ignore_labels(&&a, &&b)
|
||||||
let a: Graph<system::System, AssertReturnValue> =
|
bisimilarity::bisimilarity_paige_tarkan::bisimilarity(&&a, &&b)
|
||||||
a.map_edges(edge_relabeler, translator_b)?;
|
))
|
||||||
let b: Graph<system::System, AssertReturnValue> =
|
|
||||||
b.map_edges(edge_relabeler, translator_b)?;
|
|
||||||
Ok(format!(
|
|
||||||
"{}",
|
|
||||||
// bisimilarity::bisimilarity_kanellakis_smolka::bisimilarity(&
|
|
||||||
// &a, &&b)
|
|
||||||
// bisimilarity::bisimilarity_paige_tarjan::bisimilarity_ignore_labels(&&a, &&b)
|
|
||||||
bisimilarity::bisimilarity_paige_tarkan::bisimilarity(&&a, &&b)
|
|
||||||
))
|
|
||||||
},
|
|
||||||
| _ => {
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -608,33 +746,29 @@ pub fn dot(
|
|||||||
node_color: graph::NodeColor,
|
node_color: graph::NodeColor,
|
||||||
edge_color: graph::EdgeColor,
|
edge_color: graph::EdgeColor,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
match system {
|
if let Some(graph) = &system.graph {
|
||||||
| EvaluatedSystem::System {
|
let rc_translator = Rc::new(system.translator.clone());
|
||||||
sys: _,
|
let modified_graph = graph.map(
|
||||||
translator: _,
|
node_display.generate(Rc::clone(&rc_translator), graph),
|
||||||
} => Err("Supplied system is not a graph".into()),
|
edge_display.generate(Rc::clone(&rc_translator), graph),
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
);
|
||||||
let rc_translator = Rc::new(translator.clone());
|
|
||||||
let modified_graph = graph.map(
|
|
||||||
node_display.generate(Rc::clone(&rc_translator), graph),
|
|
||||||
edge_display.generate(Rc::clone(&rc_translator), graph),
|
|
||||||
);
|
|
||||||
|
|
||||||
let graph = Rc::new(graph.to_owned());
|
let graph = Rc::new(graph.to_owned());
|
||||||
|
|
||||||
let node_formatter = node_color
|
let node_formatter = node_color
|
||||||
.generate(Rc::clone(&graph), translator.encode_not_mut("*"));
|
.generate(Rc::clone(&graph), system.translator.encode_not_mut("*"));
|
||||||
let edge_formatter = edge_color.generate(Rc::clone(&graph));
|
let edge_formatter = edge_color.generate(Rc::clone(&graph));
|
||||||
|
|
||||||
let dot = dot::Dot::with_attr_getters(
|
let dot = dot::Dot::with_attr_getters(
|
||||||
&modified_graph,
|
&modified_graph,
|
||||||
&[],
|
&[],
|
||||||
&edge_formatter,
|
&edge_formatter,
|
||||||
&node_formatter,
|
&node_formatter,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(format!("{dot}"))
|
Ok(format!("{dot}"))
|
||||||
},
|
} else {
|
||||||
|
Err("Supplied system is not a graph".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,60 +778,52 @@ pub fn graphml(
|
|||||||
node_display: graph::NodeDisplay,
|
node_display: graph::NodeDisplay,
|
||||||
edge_display: graph::EdgeDisplay,
|
edge_display: graph::EdgeDisplay,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
match system {
|
if let Some(graph) = &system.graph {
|
||||||
| EvaluatedSystem::System {
|
let rc_translator = Rc::new(system.translator.to_owned());
|
||||||
sys: _,
|
|
||||||
translator: _,
|
|
||||||
} => Err("Supplied system is not a graph".into()),
|
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
|
||||||
let rc_translator = Rc::new(translator.to_owned());
|
|
||||||
|
|
||||||
// map each value to the corresponding value we want to display
|
// map each value to the corresponding value we want to display
|
||||||
let modified_graph = graph.map(
|
let modified_graph = graph.map(
|
||||||
node_display.generate(Rc::clone(&rc_translator), graph),
|
node_display.generate(Rc::clone(&rc_translator), graph),
|
||||||
edge_display.generate(rc_translator, graph),
|
edge_display.generate(rc_translator, graph),
|
||||||
);
|
);
|
||||||
|
|
||||||
use petgraph_graphml::GraphMl;
|
use petgraph_graphml::GraphMl;
|
||||||
let graphml = GraphMl::new(&modified_graph)
|
let graphml = GraphMl::new(&modified_graph)
|
||||||
.pretty_print(true)
|
.pretty_print(true)
|
||||||
.export_node_weights_display()
|
.export_node_weights_display()
|
||||||
.export_edge_weights_display();
|
.export_edge_weights_display();
|
||||||
|
|
||||||
Ok(format!("{graphml}"))
|
Ok(format!("{graphml}"))
|
||||||
},
|
} else {
|
||||||
|
Err("Supplied system is not a graph".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the specified graph, translator tuple to file.
|
/// Writes the specified graph and translator to file.
|
||||||
/// N.B. graph size in memory might be much larger after serialization and
|
/// N.B. graph size in memory might be much larger after serialization and
|
||||||
/// deserialization.
|
/// deserialization.
|
||||||
pub fn serialize(system: &EvaluatedSystem, path: String) -> Result<(), String> {
|
pub fn serialize(system: &EvaluatedSystem, path: String) -> Result<(), String> {
|
||||||
match system {
|
if let Some(graph) = &system.graph {
|
||||||
| EvaluatedSystem::System {
|
// relative path
|
||||||
sys: _,
|
let mut path = std::path::PathBuf::from(path);
|
||||||
translator: _,
|
path.set_extension("cbor");
|
||||||
} => Err("Supplied system is not a graph".into()),
|
|
||||||
| EvaluatedSystem::Graph { graph, translator } => {
|
|
||||||
// relative path
|
|
||||||
let mut path = std::path::PathBuf::from(path);
|
|
||||||
path.set_extension("cbor");
|
|
||||||
|
|
||||||
let f = match fs::File::create(&path) {
|
let f = match fs::File::create(&path) {
|
||||||
| Ok(f) => f,
|
| Ok(f) => f,
|
||||||
| Err(_) => {
|
| Err(_) => {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Error creating file {}.",
|
"Error creating file {}.",
|
||||||
path.to_str().unwrap()
|
path.to_str().unwrap()
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
match serialize::ser(f, graph, translator) {
|
match serialize::ser(f, graph, &system.translator) {
|
||||||
| Ok(_) => Ok(()),
|
| Ok(_) => Ok(()),
|
||||||
| Err(_) => Err("Error during serialization.".into()),
|
| Err(_) => Err("Error during serialization.".into()),
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
|
Err("Supplied system is not a graph".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,11 +884,11 @@ fn execute<P: FileParsers>(
|
|||||||
| Instruction::Stats { so } => {
|
| Instruction::Stats { so } => {
|
||||||
save_options!(stats(system)?, so);
|
save_options!(stats(system)?, so);
|
||||||
},
|
},
|
||||||
| Instruction::Target { so } => {
|
| Instruction::Target { so, limit } => {
|
||||||
save_options!(target(system)?, so);
|
save_options!(target(system, limit)?, so);
|
||||||
},
|
},
|
||||||
| Instruction::Run { so } => {
|
| Instruction::Run { so, limit } => {
|
||||||
save_options!(traversed(system)?, so);
|
save_options!(traversed(system, limit)?, so);
|
||||||
},
|
},
|
||||||
| Instruction::Loop { symbol, so } => {
|
| Instruction::Loop { symbol, so } => {
|
||||||
save_options!(hoop(system, symbol)?, so);
|
save_options!(hoop(system, symbol)?, so);
|
||||||
|
|||||||
25
grammar/src/custom_error.rs
Normal file
25
grammar/src/custom_error.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
@ -8,9 +8,14 @@ use rsprocess::element::IdType;
|
|||||||
use rsprocess::translator::Translator;
|
use rsprocess::translator::Translator;
|
||||||
use execution::presets;
|
use execution::presets;
|
||||||
use rsprocess::graph;
|
use rsprocess::graph;
|
||||||
|
use crate::custom_error;
|
||||||
|
|
||||||
grammar(translator: &mut Translator);
|
grammar(translator: &mut Translator);
|
||||||
|
|
||||||
|
extern {
|
||||||
|
type Error = custom_error::UserError;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -31,7 +36,7 @@ match {
|
|||||||
"Print", "Save",
|
"Print", "Save",
|
||||||
"Dot", "GraphML", "Serialize",
|
"Dot", "GraphML", "Serialize",
|
||||||
"Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency",
|
"Stats", "Target", "Run", "Loop", "Frequency", "LimitFrequency",
|
||||||
"FastFrequency", "Digraph", "Bisimilarity",
|
"FastFrequency", "Digraph", "Bisimilarity", "Limit",
|
||||||
"Deserialize",
|
"Deserialize",
|
||||||
"?",
|
"?",
|
||||||
"Hide",
|
"Hide",
|
||||||
@ -160,10 +165,38 @@ LiteralProcess: String = {
|
|||||||
"relabel" => <>.into(),
|
"relabel" => <>.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// all numbers are i64
|
|
||||||
Num: i64 = {
|
Num: i64 = {
|
||||||
NUMBER =>? i64::from_str(<>)
|
<sign: "-"?> <start: @L> <n: NUMBER> <end: @R> =>? {
|
||||||
.map_err(|_| ParseError::User { error: "Number is too big" })
|
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: String = {
|
||||||
@ -1037,12 +1070,12 @@ Instruction: presets::Instruction = {
|
|||||||
"Stats"
|
"Stats"
|
||||||
">" <so: SaveOptions> =>
|
">" <so: SaveOptions> =>
|
||||||
presets::Instruction::Stats { so },
|
presets::Instruction::Stats { so },
|
||||||
"Target"
|
"Target" <limit: ("(" "Limit" ":" NumUsize ")")?>
|
||||||
">" <so: SaveOptions> =>
|
">" <so: SaveOptions> =>
|
||||||
presets::Instruction::Target { so },
|
presets::Instruction::Target { so, limit: limit.map(|l| l.3) },
|
||||||
"Run"
|
"Run" <limit: ("(" "Limit" ":" NumUsize ")")?>
|
||||||
">" <so: SaveOptions> =>
|
">" <so: SaveOptions> =>
|
||||||
presets::Instruction::Run { so },
|
presets::Instruction::Run { so, limit: limit.map(|l| l.3) },
|
||||||
"Loop" "(" <symbol: Literal> ")"
|
"Loop" "(" <symbol: Literal> ")"
|
||||||
">" <so: SaveOptions> =>
|
">" <so: SaveOptions> =>
|
||||||
presets::Instruction::Loop { symbol, so },
|
presets::Instruction::Loop { symbol, so },
|
||||||
|
|||||||
@ -1,3 +1,9 @@
|
|||||||
|
mod custom_error;
|
||||||
|
|
||||||
|
pub mod user_error {
|
||||||
|
pub use crate::custom_error::*;
|
||||||
|
}
|
||||||
|
|
||||||
lalrpop_util::lalrpop_mod!(
|
lalrpop_util::lalrpop_mod!(
|
||||||
#[allow(clippy::uninlined_format_args)] pub grammar, // name of module
|
#[allow(clippy::uninlined_format_args)] pub grammar, // name of module
|
||||||
"/grammar.rs" // location of parser
|
"/grammar.rs" // location of parser
|
||||||
|
|||||||
@ -73,11 +73,19 @@ pub trait ExtensionsSystem: BasicSystem {
|
|||||||
|
|
||||||
fn target(&self) -> Result<(i64, Self::Set), String>;
|
fn target(&self) -> Result<(i64, Self::Set), String>;
|
||||||
|
|
||||||
|
fn target_limit(&self, limit: usize) -> Result<(i64, Self::Set), String>;
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn run_separated(
|
fn run_separated(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<(Self::Set, Self::Set, Self::Set)>, String>;
|
) -> Result<Vec<(Self::Set, Self::Set, Self::Set)>, String>;
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn run_separated_limit(
|
||||||
|
&self,
|
||||||
|
limit: usize
|
||||||
|
) -> Result<Vec<(Self::Set, Self::Set, Self::Set)>, String>;
|
||||||
|
|
||||||
fn traces(self, n: usize) -> Result<Vec<Trace<Self::Label, Self>>, String>;
|
fn traces(self, n: usize) -> Result<Vec<Trace<Self::Label, Self>>, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +170,20 @@ impl<T: BasicSystem> ExtensionsSystem for T {
|
|||||||
Ok((n, current.available_entities().clone()))
|
Ok((n, current.available_entities().clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn target_limit(&self, limit: usize) -> Result<(i64, Self::Set), String> {
|
||||||
|
let current = self.one_transition()?;
|
||||||
|
if current.is_none() {
|
||||||
|
return Ok((0, self.available_entities().clone()));
|
||||||
|
}
|
||||||
|
let mut n = 1;
|
||||||
|
let mut current = current.unwrap().1;
|
||||||
|
while let Some((_, next)) = current.one_transition()? && n < limit {
|
||||||
|
current = next;
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
Ok((n as i64, current.available_entities().clone()))
|
||||||
|
}
|
||||||
|
|
||||||
/// see smartOneRunECT, smartRunECT
|
/// see smartOneRunECT, smartRunECT
|
||||||
fn run_separated(
|
fn run_separated(
|
||||||
&self,
|
&self,
|
||||||
@ -183,6 +205,30 @@ impl<T: BasicSystem> ExtensionsSystem for T {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// see smartOneRunECT, smartRunECT
|
||||||
|
fn run_separated_limit(
|
||||||
|
&self,
|
||||||
|
limit: usize
|
||||||
|
) -> Result<Vec<(Self::Set, Self::Set, Self::Set)>, String> {
|
||||||
|
let mut limit = limit;
|
||||||
|
let mut res = vec![];
|
||||||
|
let current = self.one_transition()?;
|
||||||
|
if current.is_none() {
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
let current = current.unwrap();
|
||||||
|
let (available_entities, context, t) = current.0.get_context();
|
||||||
|
res.push((available_entities.clone(), context.clone(), t.clone()));
|
||||||
|
let mut current = current.1;
|
||||||
|
while let Some((label, next)) = current.one_transition()? && limit > 1 {
|
||||||
|
limit -= 1;
|
||||||
|
current = next;
|
||||||
|
let (available_entities, context, t) = label.get_context();
|
||||||
|
res.push((available_entities.clone(), context.clone(), t.clone()));
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the first n traces. Equivalent to visiting the execution tree
|
/// Return the first n traces. Equivalent to visiting the execution tree
|
||||||
/// depth first and returning the first n leaf nodes and their path to the
|
/// depth first and returning the first n leaf nodes and their path to the
|
||||||
/// root.
|
/// root.
|
||||||
|
|||||||
@ -3,4 +3,6 @@ Initial Entities: {a, b}
|
|||||||
Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
|
Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
|
||||||
Reactions: ([{a,b}, {c}, {b}])
|
Reactions: ([{a,b}, {c}, {b}])
|
||||||
|
|
||||||
Run > Print
|
Run > Print,
|
||||||
|
|
||||||
|
Run (Limit: 2) > Print
|
||||||
|
|||||||
@ -3,4 +3,10 @@ Initial Entities: {a, b}
|
|||||||
Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
|
Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
|
||||||
Reactions: ([{a,b}, {c}, {b}])
|
Reactions: ([{a,b}, {c}, {b}])
|
||||||
|
|
||||||
Target > Print
|
Target > Print,
|
||||||
|
|
||||||
|
Target (Limit: 7) > Print,
|
||||||
|
|
||||||
|
Target (Limit: 6) > Print,
|
||||||
|
|
||||||
|
Target (Limit: 5) > Print
|
||||||
|
|||||||
Reference in New Issue
Block a user