Execute function for assert
This commit is contained in:
@ -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"] }
|
||||||
|
|||||||
25
src/main.rs
25
src/main.rs
@ -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());
|
||||||
|
|||||||
@ -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)?;
|
u.associate(&type_exp)
|
||||||
if type_exp == AssertionTypes::Label {
|
|
||||||
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user