1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#![allow(clippy::unit_arg)]
mod schema;
mod utils;
use scdlang::{self as scdlang, prelude::*, Scdlang};
pub use schema::*;
use from_pest::FromPest;
use serde::{Deserialize, Serialize};
use std::{error, fmt};
use utils::pairs;
#[derive(Default, Serialize, Deserialize)]
pub struct Machine<'a> {
#[serde(flatten)]
schema: StateChart,
#[serde(skip)]
builder: Scdlang<'a>,
}
impl<'a> Parser<'a> for Machine<'a> {
fn configure(&mut self) -> &mut Builder<'a> {
&mut self.builder
}
fn parse(&mut self, source: &str) -> Result<(), DynError> {
let ast = Self::try_parse(source, self.builder.to_owned())?;
Ok(self.schema.states = ast.schema.states)
}
fn insert_parse(&mut self, source: &str) -> Result<(), DynError> {
let ast = Self::try_parse(source, self.builder.to_owned())?;
Ok(self.schema.states.extend(ast.schema.states))
}
fn try_parse(source: &str, builder: Scdlang<'a>) -> Result<Self, DynError> {
let mut parse_tree = scdlang::parse(&source)?;
let schema = if pairs::is_expression(&parse_tree) {
let line = &format!(r#"expression("{line}")"#, line = parse_tree.as_str());
StateChart::from_pest(&mut parse_tree).expect(line)
} else {
StateChart::default()
};
Ok(Machine { schema, builder })
}
}
impl fmt::Display for Machine<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", serde_json::to_string_pretty(&self.schema).map_err(|_| fmt::Error)?)
}
}
type DynError = Box<dyn error::Error>;
#[cfg(test)]
mod test {
use super::*;
use assert_json_diff::assert_json_eq;
use serde_json::json;
#[test]
#[ignore]
fn transient_transition() -> Result<(), DynError> {
let mut machine = Machine::default();
machine.parse("A -> B")?;
Ok(assert_json_eq!(
json!({
"states": {
"A": {
"on": {
"": "B"
}
}
}
}),
json!(machine)
))
}
#[test]
#[ignore]
fn eventful_transition() -> Result<(), DynError> {
let mut machine = Machine::default();
machine.parse(
"A -> B @ C
A -> D @ E",
)?;
Ok(assert_json_eq!(
json!({
"states": {
"A": {
"on": {
"C":"B",
"E":"D"
}
}
}
}),
json!(machine)
))
}
}