Execute function for assert

This commit is contained in:
elvis
2025-08-02 06:50:01 +02:00
parent 39837498b3
commit 3af6ce5130
4 changed files with 577 additions and 86 deletions

View File

@ -7,6 +7,7 @@ edition = "2024"
lalrpop = "0.22" lalrpop = "0.22"
[dependencies] [dependencies]
rand = { version = "*" }
regex = { version = "1", features = ["unicode-bool"] } regex = { version = "1", features = ["unicode-bool"] }
lalrpop-util = { version = "*", features = ["lexer", "unicode"] } lalrpop-util = { version = "*", features = ["lexer", "unicode"] }
petgraph = { version = "*", features = ["serde-1"] } petgraph = { version = "*", features = ["serde-1"] }

View File

@ -1,10 +1,27 @@
fn main() { fn main() {
let now = std::time::Instant::now(); let now = std::time::Instant::now();
use reactionsystems::rsprocess::presets; // use reactionsystems::rsprocess::presets;
match presets::run("testing/first.system".into()) { // match presets::run("testing/first.system".into()) {
Ok(_) => {}, // Ok(_) => {},
Err(e) => {println!("{e}")} // Err(e) => {println!("{e}")}
// }
use reactionsystems::grammar::AssertParser;
use reactionsystems::rsprocess::translator::Translator;
let contents = r#"label { if (substr("e", ('e').tostr)) then {return 'e'} else {return (("e").toel)} }"#;
let mut translator = Translator::new();
let tree = AssertParser::new().parse(&mut translator, contents).unwrap();
println!("{tree}");
match tree.typecheck() {
Ok(_) => println!("ok"),
Err(e) => println!("error: {e}")
}
match tree.execute(&reactionsystems::rsprocess::structure::RSlabel::new(), &mut translator) {
Ok(val) => println!("ok: {val}"),
Err(e) => println!("error: {e}")
} }
println!("{} milliseconds elapsed", now.elapsed().as_millis()); println!("{} milliseconds elapsed", now.elapsed().as_millis());

View File

@ -53,6 +53,7 @@ pub enum Range {
IterateInRange(Box<Expression>, Box<Expression>), IterateInRange(Box<Expression>, Box<Expression>),
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Unary { pub enum Unary {
Not, Not,
@ -82,6 +83,60 @@ impl Unary {
!self.is_prefix() !self.is_prefix()
} }
fn associate(
&self,
type_exp: &AssertionTypes
) -> Result<AssertionTypes, String> {
match self {
Self::Not => {
if let AssertionTypes::Boolean = type_exp {
return Ok(AssertionTypes::Boolean)
}
},
Self::Rand => {
if let AssertionTypes::Integer = type_exp {
return Ok(AssertionTypes::Integer)
}
},
Self::Empty => {
if let AssertionTypes::Set = type_exp {
return Ok(AssertionTypes::Boolean)
}
},
Self::Length => {
match type_exp {
AssertionTypes::Set |
AssertionTypes::String => {
return Ok(AssertionTypes::Integer)
}
_ => {}
}
},
Self::ToStr => {
match type_exp {
AssertionTypes::Boolean |
AssertionTypes::Element |
AssertionTypes::Integer => {
return Ok(AssertionTypes::String)
}
_ => {}
}
},
Self::Qualifier(_) => {
if let AssertionTypes::Label = type_exp {
return Ok(AssertionTypes::Set)
}
},
Self::ToEl => {
if let AssertionTypes::String = type_exp {
return Ok(AssertionTypes::Element)
}
}
}
Err(format!("Expression has incompatible type with operation: \
{type_exp} with operation {self}."))
}
fn associated_types_unary(&self) -> Vec<AssertionTypes> { fn associated_types_unary(&self) -> Vec<AssertionTypes> {
match self { match self {
Unary::Not => vec![AssertionTypes::Boolean], Unary::Not => vec![AssertionTypes::Boolean],
@ -109,6 +164,38 @@ pub enum QualifierRestricted {
Products, Products,
} }
impl QualifierRestricted {
pub fn referenced_mut<'a>(
&self,
label: &'a mut super::structure::RSlabel,
) -> &'a mut super::structure::RSset {
match self {
Self::Entities => {&mut label.available_entities},
Self::Context => {&mut label.context},
Self::Reactants => {&mut label.reactants},
Self::ReactantsAbsent => {&mut label.reactants_absent},
Self::Inhibitors => {&mut label.inhibitors},
Self::InhibitorsPresent => {&mut label.inhibitors_present},
Self::Products => {&mut label.products},
}
}
pub fn referenced<'a>(
&self,
label: &'a super::structure::RSlabel,
) -> &'a super::structure::RSset {
match self {
Self::Entities => {&label.available_entities},
Self::Context => {&label.context},
Self::Reactants => {&label.reactants},
Self::ReactantsAbsent => {&label.reactants_absent},
Self::Inhibitors => {&label.inhibitors},
Self::InhibitorsPresent => {&label.inhibitors_present},
Self::Products => {&label.products},
}
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Qualifier { pub enum Qualifier {
AvailableEntities, AvailableEntities,
@ -117,6 +204,28 @@ pub enum Qualifier {
Restricted(QualifierRestricted), Restricted(QualifierRestricted),
} }
impl Qualifier {
pub fn get(
&self,
l: &super::structure::RSlabel,
) -> super::structure::RSset {
match self {
Qualifier::AvailableEntities => {
l.t.clone()
},
Qualifier::AllReactants => {
l.reactants.union(&l.reactants_absent)
},
Qualifier::AllInhibitors => {
l.inhibitors.union(&l.inhibitors_present)
},
Qualifier::Restricted(q) => {
q.referenced(l).clone()
}
}
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Binary { pub enum Binary {
And, And,
@ -295,20 +404,20 @@ impl Binary {
} }
use core::fmt;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt;
struct Context { struct TypeContext {
data: HashMap<String, AssertionTypes>, data: HashMap<String, AssertionTypes>,
ty_return: Option<AssertionTypes> return_ty: Option<AssertionTypes>
} }
impl Context { impl TypeContext {
pub fn new() -> Self { pub fn new() -> Self {
Context { TypeContext {
data: HashMap::new(), data: HashMap::new(),
ty_return: None return_ty: None
} }
} }
@ -340,7 +449,7 @@ impl Context {
&mut self, &mut self,
ty: AssertionTypes ty: AssertionTypes
) -> Result<(), String> { ) -> Result<(), String> {
if let Some(ty_return) = self.ty_return { if let Some(ty_return) = self.return_ty {
if ty_return == ty { if ty_return == ty {
Ok(()) Ok(())
} else { } else {
@ -348,7 +457,7 @@ impl Context {
{ty} found.")) {ty} found."))
} }
} else { } else {
self.ty_return = Some(ty); self.return_ty = Some(ty);
Ok(()) Ok(())
} }
} }
@ -383,23 +492,20 @@ impl Context {
v: &AssignmentVariable, v: &AssignmentVariable,
) -> Result<AssertionTypes, String> { ) -> Result<AssertionTypes, String> {
match v { match v {
AssignmentVariable::Var(v) => { AssignmentVariable::Var(Variable::Label) => {
match v { Ok(AssertionTypes::Label)
Variable::Label => Ok(AssertionTypes::Label), },
Variable::Id(v) => { AssignmentVariable::Var(Variable::Id(v)) => {
if let Some(ty) = self.data.get(v) { if let Some(ty) = self.data.get(v) {
Ok(*ty) Ok(*ty)
} else { } else {
Err(format!("Could not find variable {v}.")) Err(format!("Could not find variable {v}."))
} }
}
}
}, },
AssignmentVariable::QualifiedVar(var, _) => { AssignmentVariable::QualifiedVar(Variable::Label, _) => {
let var = match var { Ok(AssertionTypes::Set)
Variable::Id(v) => v, },
Variable::Label => return Ok(AssertionTypes::Set), AssignmentVariable::QualifiedVar(Variable::Id(var), _) => {
};
if let Some(ty) = self.data.get(var) { if let Some(ty) = self.data.get(var) {
if *ty == AssertionTypes::Label { if *ty == AssertionTypes::Label {
Ok(AssertionTypes::Set) Ok(AssertionTypes::Set)
@ -411,10 +517,108 @@ impl Context {
} }
} }
} }
} }
} }
struct Context<'a> {
data: HashMap<String, AssertReturnValue>,
label: &'a super::structure::RSlabel,
}
impl<'a> Context<'a> {
pub fn new(label: &'a super::structure::RSlabel) -> Self {
Self { data: HashMap::new(), label }
}
pub fn assign(
&mut self,
v: &AssignmentVariable,
val: AssertReturnValue,
) -> Result<(), String> {
match v {
AssignmentVariable::Var(v) => {
if let Variable::Id(v) = v {
self.data.insert(v.clone(), val);
}
Ok(())
},
AssignmentVariable::QualifiedVar(Variable::Label, _) => Ok(()),
AssignmentVariable::QualifiedVar(Variable::Id(v), q) => {
match self.data.entry(v.clone()) {
std::collections::hash_map::Entry::Vacant(_ve) =>
Err(format!("Variable {v} has no value while trying to \
assign a value to the field {q} of a label\
")),
std::collections::hash_map::Entry::Occupied(mut oe) => {
if let AssertReturnValue::Set(s) = val {
let l = oe.get_mut();
match l {
AssertReturnValue::Label(l) => {
*q.referenced_mut(l) = s;
// if we modified available entities or the
// context we need to sync it with t
match q {
QualifierRestricted::Context |
QualifierRestricted::Entities => {
l.t = l.available_entities.union(
&l.context
);
},
_ => {},
}
Ok(())
},
_ => {
Err(format!("Variable {v} does not have \
type label while trying to \
assign to qualification {q}"))
}
}
} else {
Err(format!("Value {val} is not a set while trying \
to assign to qualification {q} of \
variable {v}"))
}
}
}
}
}
}
pub fn get(
&self,
v: &AssignmentVariable
) -> Result<AssertReturnValue, String> {
match v {
AssignmentVariable::Var(Variable::Id(var)) => {
self.data.get(var)
.cloned()
.ok_or(format!("Variable {v} used, but no value assigned."))
},
AssignmentVariable::QualifiedVar(Variable::Id(var), q) => {
let val = self.data.get(var)
.ok_or(format!("Variable {v} used, but no value assigned."
))?;
match val {
AssertReturnValue::Label(l) => {
Ok(AssertReturnValue::Set(q.referenced(l).clone()))
},
_ => {Err(format!("Variable {v} is not a label but was \
quantified with {q}."))}
}
},
AssignmentVariable::Var(Variable::Label) => {
Ok(AssertReturnValue::Label(self.label.clone()))
},
AssignmentVariable::QualifiedVar(Variable::Label, q) => {
Ok(AssertReturnValue::Set(q.referenced(self.label).clone()))
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
enum AssertionTypes { enum AssertionTypes {
Boolean, Boolean,
@ -428,23 +632,158 @@ enum AssertionTypes {
RangeSet, RangeSet,
} }
impl fmt::Display for AssertionTypes { #[derive(Debug, Clone)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { pub enum AssertReturnValue {
match self { Boolean(bool),
AssertionTypes::Boolean => write!(f, "boolean"), Integer(IntegerType),
AssertionTypes::Integer => write!(f, "integer"), String(String),
AssertionTypes::String => write!(f, "string"), Label(super::structure::RSlabel),
AssertionTypes::Label => write!(f, "label"), Set(super::structure::RSset),
AssertionTypes::Set => write!(f, "set"), Element(super::translator::IdType),
AssertionTypes::Element => write!(f, "element"), }
AssertionTypes::NoType => write!(f, "no type"),
AssertionTypes::RangeInteger => write!(f, "range of integers"), impl AssertReturnValue {
AssertionTypes::RangeSet => write!(f, "range of set"), pub fn unary(
self,
u: &Unary,
translator: &mut super::translator::Translator
) -> Result<AssertReturnValue, String> {
match (self, u) {
(AssertReturnValue::Boolean(b), Unary::Not) => {
Ok(AssertReturnValue::Boolean(!b))
},
(AssertReturnValue::Integer(i), Unary::Rand) => {
Ok(AssertReturnValue::Integer(rand::random_range(0..i)))
},
(AssertReturnValue::Set(set), Unary::Empty) => {
Ok(AssertReturnValue::Boolean(set.is_empty()))
},
(AssertReturnValue::String(s), Unary::Empty) => {
Ok(AssertReturnValue::Boolean(s.is_empty()))
},
(AssertReturnValue::Set(set), Unary::Length) => {
Ok(AssertReturnValue::Integer(set.len() as i64))
},
(AssertReturnValue::String(s), Unary::Length) => {
Ok(AssertReturnValue::Integer(s.len() as i64))
},
(AssertReturnValue::Boolean(b), Unary::ToStr) => {
Ok(AssertReturnValue::String(format!("{b}")))
},
(AssertReturnValue::Integer(i), Unary::ToStr) => {
Ok(AssertReturnValue::String(format!("{i}")))
},
(AssertReturnValue::Element(el), Unary::ToStr) => {
Ok(AssertReturnValue::String(
translator.decode(el).ok_or(
format!("Could not find element {el}.")
)?
))
},
(AssertReturnValue::Label(l), Unary::Qualifier(q)) => {
Ok(AssertReturnValue::Set(q.get(&l)))
},
(AssertReturnValue::String(s), Unary::ToEl) => {
Ok(AssertReturnValue::Element(translator.encode(s)))
},
(val, u) => {
Err(format!("Incompatible unary operation {u} on value {val}"))
} }
} }
}
pub fn binary(
self,
b: &Binary,
other: AssertReturnValue,
_translator: &mut super::translator::Translator
) -> Result<AssertReturnValue, String> {
use AssertReturnValue::*;
Ok(match (b, self, other) {
(Binary::And, Boolean(b1), Boolean(b2)) => {Boolean(b1 && b2)},
(Binary::Or, Boolean(b1), Boolean(b2)) => {Boolean(b1 || b2)},
(Binary::Xor, Boolean(b1), Boolean(b2)) => {Boolean(b1 ^ b2)},
(Binary::Xor, Set(s1), Set(s2)) => {
Set(s1.union(&s2).subtraction(&s1.intersection(&s2)))
},
(Binary::Less, Integer(i1), Integer(i2)) => {Boolean(i1 < i2)},
(Binary::Less, Set(s1), Set(s2)) => {
Boolean(s1.is_subset(&s2) && !s2.is_subset(&s1))},
(Binary::LessEq, Integer(i1), Integer(i2)) => {Boolean(i1 <= i2)},
(Binary::LessEq, Set(s1), Set(s2)) => {
Boolean(s1.is_subset(&s2))},
(Binary::More, Integer(i1), Integer(i2)) => {Boolean(i1 > i2)},
(Binary::More, Set(s1), Set(s2)) => {
Boolean(s2.is_subset(&s1) && !s1.is_subset(&s2))},
(Binary::MoreEq, Integer(i1), Integer(i2)) => {Boolean(i1 >= i2)},
(Binary::MoreEq, Set(s1), Set(s2)) => {
Boolean(s1.is_subset(&s2))},
(Binary::Eq, Integer(i1), Integer(i2)) => {Boolean(i1 == i2)},
(Binary::Eq, Boolean(b1), Boolean(b2)) => {Boolean(b1 == b2)},
(Binary::Eq, Element(el1), Element(el2)) => {Boolean(el1 == el2)},
(Binary::Eq, Label(l1), Label(l2)) => {Boolean(l1 == l2)},
(Binary::Eq, String(s1), String(s2)) => {Boolean(s1 == s2)},
(Binary::Eq, Set(set1), Set(set2)) => {Boolean(set1 == set2)},
(Binary::NotEq, Integer(i1), Integer(i2)) => {Boolean(i1 != i2)},
(Binary::NotEq, Boolean(b1), Boolean(b2)) => {Boolean(b1 != b2)},
(Binary::NotEq, Element(el1), Element(el2)) => {
Boolean(el1 != el2)},
(Binary::NotEq, Label(l1), Label(l2)) => {Boolean(l1 != l2)},
(Binary::NotEq, String(s1), String(s2)) => {Boolean(s1 != s2)},
(Binary::NotEq, Set(set1), Set(set2)) => {Boolean(set1 != set2)},
(Binary::Plus, Integer(i1), Integer(i2)) => {Integer(i1 + i2)},
(Binary::Plus, Set(set1), Set(set2)) => {Set(set1.union(&set2))},
(Binary::Minus, Integer(i1), Integer(i2)) => {Integer(i1 - i2)},
(Binary::Minus, Set(set1), Set(set2)) => {
Set(set1.subtraction(&set2))},
(Binary::Times, Integer(i1), Integer(i2)) => {Integer(i1 * i2)},
(Binary::Times, Set(set1), Set(set2)) => {
Set(set1.intersection(&set2))},
(Binary::Exponential, Integer(i1), Integer(i2)) => {
if i2 < 0 {
Integer(0)
} else {
Integer(i1.pow(i2 as u32))}
},
(Binary::Quotient, Integer(i1), Integer(i2)) => {
Integer(i1.div_euclid(i2))},
(Binary::Reminder, Integer(i1), Integer(i2)) => {
Integer(i1.rem_euclid(i2))},
(Binary::Concat, String(s1), String(s2)) => {String(s1 + &s2)},
(Binary::SubStr, String(s1), String(s2)) => {
let mut len = s1.len() as i64;
for (p, c) in s1.chars().enumerate() {
if s2.chars().nth(p) != Some(c) {
len = p as i64;
break;
}
}
Integer(len)
},
(Binary::Min, Integer(i1), Integer(i2)) => {Integer(i1.min(i2))},
(Binary::Max, Integer(i1), Integer(i2)) => {Integer(i1.max(i2))},
(Binary::CommonSubStr, String(s1), String(s2)) => {
let mut s = std::string::String::new();
for (p, c) in s1.chars().enumerate() {
if s2.chars().nth(p) != Some(c) {
break;
}
s.push(c);
}
String(s)
},
(b, val1, val2) =>
return Err(format!("Operation {b} on values {val1} and {val2} \
could not be executed."))
})
}
} }
fn typecheck(tree: &Tree, c: &mut Context) -> Result<AssertionTypes, String> { fn typecheck(
tree: &Tree,
c: &mut TypeContext
) -> Result<AssertionTypes, String>
{
match tree { match tree {
Tree::Concat(t1, t2) => { Tree::Concat(t1, t2) => {
typecheck(t1, c)?; typecheck(t1, c)?;
@ -492,7 +831,7 @@ fn typecheck(tree: &Tree, c: &mut Context) -> Result<AssertionTypes, String> {
fn typecheck_expression( fn typecheck_expression(
exp: &Expression, exp: &Expression,
c: &Context c: &TypeContext
) -> Result<AssertionTypes, String> { ) -> Result<AssertionTypes, String> {
match exp { match exp {
Expression::True | Expression::True |
@ -505,23 +844,8 @@ fn typecheck_expression(
Expression::Var(v) => c.get(v), Expression::Var(v) => c.get(v),
Expression::Unary(u, exp) => { Expression::Unary(u, exp) => {
if let Unary::Qualifier(_) = u {
let type_exp = typecheck_expression(exp, c)?; let type_exp = typecheck_expression(exp, c)?;
if type_exp == AssertionTypes::Label { u.associate(&type_exp)
Ok(AssertionTypes::Set)
} else {
Err("Trying to get the field of a label, but value is not \
a label.".into())
}
} else {
let type_exp = typecheck_expression(exp, c)?;
let possible_types = u.associated_types_unary();
if possible_types.contains(&type_exp) {
Ok(type_exp)
} else {
Err(format!("Cannot use operation {u} on type {type_exp}"))
}
}
}, },
Expression::Binary(b, exp1, exp2) => { Expression::Binary(b, exp1, exp2) => {
@ -535,7 +859,7 @@ fn typecheck_expression(
fn typecheck_range( fn typecheck_range(
range: &Range, range: &Range,
c: &mut Context c: &mut TypeContext
) -> Result<AssertionTypes, String> { ) -> Result<AssertionTypes, String> {
match range { match range {
Range::IterateInRange(exp1, exp2) => { Range::IterateInRange(exp1, exp2) => {
@ -562,11 +886,137 @@ fn typecheck_range(
} }
} }
fn execute(
tree: &Tree,
c: &mut Context,
translator: &mut super::translator::Translator,
) -> Result<AssertReturnValue, String> {
match tree {
Tree::Concat(t1, t2) => {
execute(t1, c, translator)?;
execute(t2, c, translator)
},
Tree::If(exp, t) => {
let guard = execute_exp(exp, c, translator)?;
if let AssertReturnValue::Boolean(true) = guard {
execute(t, c, translator)
} else {
Ok(AssertReturnValue::Boolean(true))
}
},
Tree::IfElse(exp, t1, t2) => {
let guard = execute_exp(exp, c, translator)?;
if let AssertReturnValue::Boolean(true) = guard {
execute(t1, c, translator)
} else {
execute(t2, c, translator)
}
},
Tree::Assignment(v, exp) => {
let val = execute_exp(exp, c, translator)?;
c.assign(v, val)?;
Ok(AssertReturnValue::Boolean(true))
},
Tree::Return(exp) => {
execute_exp(exp, c, translator)
},
Tree::For(v, r, t) => {
let range = range_into_iter(r, c, translator)?;
for val in range {
c.assign(&AssignmentVariable::Var(v.clone()), val)?;
execute(t, c, translator)?;
}
Ok(AssertReturnValue::Boolean(true))
},
}
}
type RangeIterator = std::vec::IntoIter<AssertReturnValue>;
fn range_into_iter(
range: &Range,
c: &mut Context,
translator: &mut super::translator::Translator,
) -> Result<RangeIterator, String> {
match range {
Range::IterateOverSet(exp) => {
let val = execute_exp(exp, c, translator)?;
if let AssertReturnValue::Set(set) = val {
Ok(set.into_iter().map(AssertReturnValue::Element)
.collect::<Vec<_>>().into_iter())
} else {
Err(format!("{val} is not a set in for cycle."))
}
},
Range::IterateInRange(exp1, exp2) => {
let val1 = execute_exp(exp1, c, translator)?;
let val2 = execute_exp(exp2, c, translator)?;
match (val1, val2) {
(AssertReturnValue::Integer(i1),
AssertReturnValue::Integer(i2)) =>
Ok((i1..i2).map(AssertReturnValue::Integer)
.collect::<Vec<_>>().into_iter()),
(val1, val2) =>
Err(format!("{val1}..{val2} is not a valid integer range \
in for cycle."))
}
}
}
}
fn execute_exp(
exp: &Expression,
c: &Context,
translator: &mut super::translator::Translator,
) -> Result<AssertReturnValue, String> {
match exp {
Expression::True => Ok(AssertReturnValue::Boolean(true)),
Expression::False => Ok(AssertReturnValue::Boolean(false)),
Expression::Integer(i) => Ok(AssertReturnValue::Integer(*i)),
Expression::Label(l) => Ok(AssertReturnValue::Label(*l.clone())),
Expression::Set(set) => Ok(AssertReturnValue::Set(set.clone())),
Expression::Element(el) =>
Ok(AssertReturnValue::Element(*el)),
Expression::String(s) => Ok(AssertReturnValue::String(s.clone())),
Expression::Var(var) => c.get(var),
Expression::Unary(u, exp) => {
let val = execute_exp(exp, c, translator)?;
val.unary(u, translator)
},
Expression::Binary(b, exp1, exp2) => {
let val1 = execute_exp(exp1, c, translator)?;
let val2 = execute_exp(exp2, c, translator)?;
val1.binary(b, val2, translator)
},
}
}
impl RSassert { impl RSassert {
pub fn typecheck(&self) -> Result<(), String> { pub fn typecheck(&self) -> Result<(), String> {
let mut context = Context::new(); let mut context = TypeContext::new();
typecheck(&self.tree, &mut context)?; typecheck(&self.tree, &mut context)?;
Ok(()) let ty = context.return_ty.unwrap_or(AssertionTypes::NoType);
match ty {
AssertionTypes::Boolean |
AssertionTypes::Integer |
AssertionTypes::String |
AssertionTypes::Label |
AssertionTypes::Set |
AssertionTypes::Element => Ok(()),
AssertionTypes::NoType |
AssertionTypes::RangeInteger |
AssertionTypes::RangeSet =>
Err(format!("Returned type {ty} is not a valid return type.")),
}
}
pub fn execute(
&self,
label: &super::structure::RSlabel,
translator: &mut super::translator::Translator,
) -> Result<AssertReturnValue, String> {
let mut context = Context::new(label);
execute(&self.tree, &mut context, translator)
} }
} }
@ -620,9 +1070,9 @@ impl fmt::Display for Expression {
Self::True => {write!(f, "True")}, Self::True => {write!(f, "True")},
Self::False => {write!(f, "False")}, Self::False => {write!(f, "False")},
Self::Integer(i) => {write!(f, "{i}")}, Self::Integer(i) => {write!(f, "{i}")},
Self::Label(rslabel) => {write!(f, "{rslabel:?}")}, Self::Label(rslabel) => {write!(f, "{{debug: {rslabel:?}}}")},
Self::Set(set) => {write!(f, "{set:?}")}, Self::Set(set) => {write!(f, "{{debug: {set:?}}}")},
Self::Element(el) => {write!(f, "'{el}'")}, Self::Element(el) => {write!(f, "'{{debug: {el:?}}}'")},
Self::String(s) => {write!(f, r#""{s}""#)}, Self::String(s) => {write!(f, r#""{s}""#)},
Self::Var(v) => {write!(f, "{v}")}, Self::Var(v) => {write!(f, "{v}")},
Self::Unary(u, exp) => { Self::Unary(u, exp) => {
@ -661,13 +1111,13 @@ impl fmt::Display for Range {
impl fmt::Display for Unary { impl fmt::Display for Unary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Unary::Not => write!(f, "not"), Self::Not => write!(f, "not"),
Unary::Rand => write!(f, "rand"), Self::Rand => write!(f, "rand"),
Unary::Empty => write!(f, ".empty"), Self::Empty => write!(f, ".empty"),
Unary::Length => write!(f, ".length"), Self::Length => write!(f, ".length"),
Unary::ToStr => write!(f, ".tostr"), Self::ToStr => write!(f, ".tostr"),
Unary::Qualifier(q) => write!(f, ".{q}"), Self::Qualifier(q) => write!(f, ".{q}"),
Unary::ToEl => write!(f, ".toel") Self::ToEl => write!(f, ".toel")
} }
} }
} }
@ -675,20 +1125,13 @@ impl fmt::Display for Unary {
impl fmt::Display for QualifierRestricted { impl fmt::Display for QualifierRestricted {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
QualifierRestricted::Entities => Self::Entities => write!(f, "Entities"),
write!(f, "Entities"), Self::Context => write!(f, "Context"),
QualifierRestricted::Context => Self::Reactants => write!(f, "Reactants"),
write!(f, "Context"), Self::ReactantsAbsent => write!(f, "ReactantsAbsent"),
QualifierRestricted::Reactants => Self::Inhibitors => write!(f, "Inhibitors"),
write!(f, "Reactants"), Self::InhibitorsPresent => write!(f, "InhibitorsPresent"),
QualifierRestricted::ReactantsAbsent => Self::Products => write!(f, "Products"),
write!(f, "ReactantsAbsent"),
QualifierRestricted::Inhibitors =>
write!(f, "Inhibitors"),
QualifierRestricted::InhibitorsPresent =>
write!(f, "InhibitorsPresent"),
QualifierRestricted::Products =>
write!(f, "Products"),
} }
} }
} }
@ -730,3 +1173,32 @@ impl fmt::Display for Binary {
} }
} }
} }
impl fmt::Display for AssertReturnValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Boolean(b) => {write!(f, "{b}")},
Self::Integer(i) => {write!(f, "{i}")},
Self::String(s) => {write!(f, r#""{s}""#)},
Self::Label(l) => {write!(f, "{{debug: {l:?}}}")},
Self::Set(set) => {write!(f, "{{debug: {set:?}}}")},
Self::Element(el) => {write!(f, "{{debug: {el:?}}}")},
}
}
}
impl fmt::Display for AssertionTypes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Boolean => write!(f, "boolean"),
Self::Integer => write!(f, "integer"),
Self::String => write!(f, "string"),
Self::Label => write!(f, "label"),
Self::Set => write!(f, "set"),
Self::Element => write!(f, "element"),
Self::NoType => write!(f, "no type"),
Self::RangeInteger => write!(f, "range of integers"),
Self::RangeSet => write!(f, "range of set"),
}
}
}

View File

@ -261,6 +261,7 @@ AssertUnarySuffix: assert::Unary = {
".empty" => assert::Unary::Empty, ".empty" => assert::Unary::Empty,
".length" => assert::Unary::Length, ".length" => assert::Unary::Length,
".tostr" => assert::Unary::ToStr, ".tostr" => assert::Unary::ToStr,
".toel" => assert::Unary::ToEl,
"." <q: AssertQualifier> => assert::Unary::Qualifier(q), "." <q: AssertQualifier> => assert::Unary::Qualifier(q),
} }