Execute function for assert
This commit is contained in:
@ -7,6 +7,7 @@ edition = "2024"
|
||||
lalrpop = "0.22"
|
||||
|
||||
[dependencies]
|
||||
rand = { version = "*" }
|
||||
regex = { version = "1", features = ["unicode-bool"] }
|
||||
lalrpop-util = { version = "*", features = ["lexer", "unicode"] }
|
||||
petgraph = { version = "*", features = ["serde-1"] }
|
||||
|
||||
25
src/main.rs
25
src/main.rs
@ -1,10 +1,27 @@
|
||||
fn main() {
|
||||
let now = std::time::Instant::now();
|
||||
|
||||
use reactionsystems::rsprocess::presets;
|
||||
match presets::run("testing/first.system".into()) {
|
||||
Ok(_) => {},
|
||||
Err(e) => {println!("{e}")}
|
||||
// use reactionsystems::rsprocess::presets;
|
||||
// match presets::run("testing/first.system".into()) {
|
||||
// Ok(_) => {},
|
||||
// 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());
|
||||
|
||||
@ -53,6 +53,7 @@ pub enum Range {
|
||||
IterateInRange(Box<Expression>, Box<Expression>),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Unary {
|
||||
Not,
|
||||
@ -82,6 +83,60 @@ impl Unary {
|
||||
!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> {
|
||||
match self {
|
||||
Unary::Not => vec![AssertionTypes::Boolean],
|
||||
@ -109,6 +164,38 @@ pub enum QualifierRestricted {
|
||||
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)]
|
||||
pub enum Qualifier {
|
||||
AvailableEntities,
|
||||
@ -117,6 +204,28 @@ pub enum Qualifier {
|
||||
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)]
|
||||
pub enum Binary {
|
||||
And,
|
||||
@ -295,20 +404,20 @@ impl Binary {
|
||||
}
|
||||
|
||||
|
||||
use core::fmt;
|
||||
// -----------------------------------------------------------------------------
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
struct Context {
|
||||
struct TypeContext {
|
||||
data: HashMap<String, AssertionTypes>,
|
||||
ty_return: Option<AssertionTypes>
|
||||
return_ty: Option<AssertionTypes>
|
||||
}
|
||||
|
||||
impl Context {
|
||||
impl TypeContext {
|
||||
pub fn new() -> Self {
|
||||
Context {
|
||||
TypeContext {
|
||||
data: HashMap::new(),
|
||||
ty_return: None
|
||||
return_ty: None
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,7 +449,7 @@ impl Context {
|
||||
&mut self,
|
||||
ty: AssertionTypes
|
||||
) -> Result<(), String> {
|
||||
if let Some(ty_return) = self.ty_return {
|
||||
if let Some(ty_return) = self.return_ty {
|
||||
if ty_return == ty {
|
||||
Ok(())
|
||||
} else {
|
||||
@ -348,7 +457,7 @@ impl Context {
|
||||
{ty} found."))
|
||||
}
|
||||
} else {
|
||||
self.ty_return = Some(ty);
|
||||
self.return_ty = Some(ty);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -383,23 +492,20 @@ impl Context {
|
||||
v: &AssignmentVariable,
|
||||
) -> Result<AssertionTypes, String> {
|
||||
match v {
|
||||
AssignmentVariable::Var(v) => {
|
||||
match v {
|
||||
Variable::Label => Ok(AssertionTypes::Label),
|
||||
Variable::Id(v) => {
|
||||
AssignmentVariable::Var(Variable::Label) => {
|
||||
Ok(AssertionTypes::Label)
|
||||
},
|
||||
AssignmentVariable::Var(Variable::Id(v)) => {
|
||||
if let Some(ty) = self.data.get(v) {
|
||||
Ok(*ty)
|
||||
} else {
|
||||
Err(format!("Could not find variable {v}."))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
AssignmentVariable::QualifiedVar(var, _) => {
|
||||
let var = match var {
|
||||
Variable::Id(v) => v,
|
||||
Variable::Label => return Ok(AssertionTypes::Set),
|
||||
};
|
||||
AssignmentVariable::QualifiedVar(Variable::Label, _) => {
|
||||
Ok(AssertionTypes::Set)
|
||||
},
|
||||
AssignmentVariable::QualifiedVar(Variable::Id(var), _) => {
|
||||
if let Some(ty) = self.data.get(var) {
|
||||
if *ty == AssertionTypes::Label {
|
||||
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)]
|
||||
enum AssertionTypes {
|
||||
Boolean,
|
||||
@ -428,23 +632,158 @@ enum AssertionTypes {
|
||||
RangeSet,
|
||||
}
|
||||
|
||||
impl fmt::Display for AssertionTypes {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AssertionTypes::Boolean => write!(f, "boolean"),
|
||||
AssertionTypes::Integer => write!(f, "integer"),
|
||||
AssertionTypes::String => write!(f, "string"),
|
||||
AssertionTypes::Label => write!(f, "label"),
|
||||
AssertionTypes::Set => write!(f, "set"),
|
||||
AssertionTypes::Element => write!(f, "element"),
|
||||
AssertionTypes::NoType => write!(f, "no type"),
|
||||
AssertionTypes::RangeInteger => write!(f, "range of integers"),
|
||||
AssertionTypes::RangeSet => write!(f, "range of set"),
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AssertReturnValue {
|
||||
Boolean(bool),
|
||||
Integer(IntegerType),
|
||||
String(String),
|
||||
Label(super::structure::RSlabel),
|
||||
Set(super::structure::RSset),
|
||||
Element(super::translator::IdType),
|
||||
}
|
||||
|
||||
impl AssertReturnValue {
|
||||
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 {
|
||||
Tree::Concat(t1, t2) => {
|
||||
typecheck(t1, c)?;
|
||||
@ -492,7 +831,7 @@ fn typecheck(tree: &Tree, c: &mut Context) -> Result<AssertionTypes, String> {
|
||||
|
||||
fn typecheck_expression(
|
||||
exp: &Expression,
|
||||
c: &Context
|
||||
c: &TypeContext
|
||||
) -> Result<AssertionTypes, String> {
|
||||
match exp {
|
||||
Expression::True |
|
||||
@ -505,23 +844,8 @@ fn typecheck_expression(
|
||||
Expression::Var(v) => c.get(v),
|
||||
|
||||
Expression::Unary(u, exp) => {
|
||||
if let Unary::Qualifier(_) = u {
|
||||
let type_exp = typecheck_expression(exp, c)?;
|
||||
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}"))
|
||||
}
|
||||
}
|
||||
u.associate(&type_exp)
|
||||
},
|
||||
|
||||
Expression::Binary(b, exp1, exp2) => {
|
||||
@ -535,7 +859,7 @@ fn typecheck_expression(
|
||||
|
||||
fn typecheck_range(
|
||||
range: &Range,
|
||||
c: &mut Context
|
||||
c: &mut TypeContext
|
||||
) -> Result<AssertionTypes, String> {
|
||||
match range {
|
||||
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 {
|
||||
pub fn typecheck(&self) -> Result<(), String> {
|
||||
let mut context = Context::new();
|
||||
let mut context = TypeContext::new();
|
||||
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::False => {write!(f, "False")},
|
||||
Self::Integer(i) => {write!(f, "{i}")},
|
||||
Self::Label(rslabel) => {write!(f, "{rslabel:?}")},
|
||||
Self::Set(set) => {write!(f, "{set:?}")},
|
||||
Self::Element(el) => {write!(f, "'{el}'")},
|
||||
Self::Label(rslabel) => {write!(f, "{{debug: {rslabel:?}}}")},
|
||||
Self::Set(set) => {write!(f, "{{debug: {set:?}}}")},
|
||||
Self::Element(el) => {write!(f, "'{{debug: {el:?}}}'")},
|
||||
Self::String(s) => {write!(f, r#""{s}""#)},
|
||||
Self::Var(v) => {write!(f, "{v}")},
|
||||
Self::Unary(u, exp) => {
|
||||
@ -661,13 +1111,13 @@ impl fmt::Display for Range {
|
||||
impl fmt::Display for Unary {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Unary::Not => write!(f, "not"),
|
||||
Unary::Rand => write!(f, "rand"),
|
||||
Unary::Empty => write!(f, ".empty"),
|
||||
Unary::Length => write!(f, ".length"),
|
||||
Unary::ToStr => write!(f, ".tostr"),
|
||||
Unary::Qualifier(q) => write!(f, ".{q}"),
|
||||
Unary::ToEl => write!(f, ".toel")
|
||||
Self::Not => write!(f, "not"),
|
||||
Self::Rand => write!(f, "rand"),
|
||||
Self::Empty => write!(f, ".empty"),
|
||||
Self::Length => write!(f, ".length"),
|
||||
Self::ToStr => write!(f, ".tostr"),
|
||||
Self::Qualifier(q) => write!(f, ".{q}"),
|
||||
Self::ToEl => write!(f, ".toel")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -675,20 +1125,13 @@ impl fmt::Display for Unary {
|
||||
impl fmt::Display for QualifierRestricted {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
QualifierRestricted::Entities =>
|
||||
write!(f, "Entities"),
|
||||
QualifierRestricted::Context =>
|
||||
write!(f, "Context"),
|
||||
QualifierRestricted::Reactants =>
|
||||
write!(f, "Reactants"),
|
||||
QualifierRestricted::ReactantsAbsent =>
|
||||
write!(f, "ReactantsAbsent"),
|
||||
QualifierRestricted::Inhibitors =>
|
||||
write!(f, "Inhibitors"),
|
||||
QualifierRestricted::InhibitorsPresent =>
|
||||
write!(f, "InhibitorsPresent"),
|
||||
QualifierRestricted::Products =>
|
||||
write!(f, "Products"),
|
||||
Self::Entities => write!(f, "Entities"),
|
||||
Self::Context => write!(f, "Context"),
|
||||
Self::Reactants => write!(f, "Reactants"),
|
||||
Self::ReactantsAbsent => write!(f, "ReactantsAbsent"),
|
||||
Self::Inhibitors => write!(f, "Inhibitors"),
|
||||
Self::InhibitorsPresent => write!(f, "InhibitorsPresent"),
|
||||
Self::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,
|
||||
".length" => assert::Unary::Length,
|
||||
".tostr" => assert::Unary::ToStr,
|
||||
".toel" => assert::Unary::ToEl,
|
||||
"." <q: AssertQualifier> => assert::Unary::Qualifier(q),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user