-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxmachina.janet
129 lines (110 loc) · 3.4 KB
/
xmachina.janet
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
(import spork/json)
(defn xstate-transition
```
Document this
```
[xs]
(let [transition (xs 0)
target (transition :state-next)]
(if-let [actions (transition :actions)]
{:target (target :id)
:actions (map | ($ :id) actions)}
(target :id))))
(defn tk-3
```
Some doc goes
here and
here.
```
[statements]
(let [evs (filter | (= ($ :stmt-type) :transition) statements)]
(if (not (empty? evs))
(do
(def grp (group-by | (get-in $ [:event :id]) evs))
(loop [[k v] :pairs grp]
(set (grp k) (xstate-transition v)))
{:on grp})
{})))
# TODO: find a better name for this function
(defn tk-2
"Some doc
goes here"
[statements]
{:type (when (find | ($ :final) statements)
:final)})
# TODO: find a better name for this function
(defn tk-1 [statements]
(let [{:state state} (statements 0)]
{(state :id) (merge {}
(tk-2 statements)
(tk-3 statements))}))
(defn ->machine-ast [machine states]
{:predictableActionArguments true
:id (machine :id)
:initial (let [st (filter | ($ :initial) states)]
(assert (= (length st) 1)
(if (empty? st)
"no initial state"
"expected exactly one initial state"))
(get-in st [0 :state :id]))
:states (let [grouped-by-states (group-by | (get-in $ [:state :id]) states)]
(merge {} ;(map tk-1 grouped-by-states)))})
(defn ->id-ast [line column id]
@{:line line
:column column
:id id
:type (if (string/has-suffix? "?" id)
:guard
:unknown)})
(defn ->initial-ast [id]
(set (id :type) :state)
{:initial true
:state id})
(defn ->final-ast [id]
(set (id :type) :state)
{:final true
:state id})
(defn ->transition-ast [from to event &opt actions]
(default actions [])
(set (from :type) :state)
(set (to :type) :state)
(set (event :type) :event)
(def ast
(merge {:stmt-type :transition
:state from
:state-next to
:event event}
(group-by | (if (= ($ :type) :guard)
:guard
:actions)
actions)))
(if-let [guard (ast :guard)]
(do
(assert (= (length guard) 1) "too many guards")
(set (ast :guard) (guard 0))))
ast)
(def xmachina-lang
```
```
(peg/compile
~{:main (* :s* (/ :machine ,->machine-ast) :s* -1)
:id (/ (<- (* (line) (column) :a (any (+ :w (set "_-:."))) (? "?"))) ,->id-ast)
:actions (? (* "(" (group (some (* :s* :id :s*))) ")"))
:initial (/ (* "[*]" :s+ "->" :s+ :id :s* ";") ,->initial-ast)
:transition (/ (* :id :s+ "->" :s+ :id :s+ ":" :s+ :id :s* :actions :s* ";") ,->transition-ast)
:final (/ (* :id :s+ "->" :s+ "[*]" :s* ";") ,->final-ast)
:machine (* "machine" :s+ :id :s+ "{" (group (some (* :s* (+ :transition :initial :final) :s*))) "}")}))
(defn xm->xstate [xm-str]
(if-let [xstate (peg/match xmachina-lang xm-str)]
(json/encode (xstate 0) " " "\n")
# TODO:
# The compilation error message should definitely
# include more details as to what went wrong but I have
# no idea how to do this so I am leaving this other big
# and important piece for later.
(error "compilation error")))
(defn main [&]
(-> stdin
(file/read :all)
(xm->xstate)
(print)))