gisele 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +16 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/gisele.gemspec +1 -0
- data/gisele.noespec +2 -1
- data/lib/gisele/command.rb +21 -6
- data/lib/gisele/language/ast/bool_and.rb +14 -0
- data/lib/gisele/language/ast/bool_expr.rb +14 -0
- data/lib/gisele/language/ast/bool_not.rb +14 -0
- data/lib/gisele/language/ast/bool_or.rb +14 -0
- data/lib/gisele/language/ast/elsif_clause.rb +14 -0
- data/lib/gisele/language/ast/helpers.rb +15 -9
- data/lib/gisele/language/ast/if_st.rb +14 -0
- data/lib/gisele/language/ast/node.rb +39 -3
- data/lib/gisele/language/ast/task_call_st.rb +14 -0
- data/lib/gisele/language/ast/var_ref.rb +14 -0
- data/lib/gisele/language/ast/when_clause.rb +14 -0
- data/lib/gisele/language/ast/while_st.rb +14 -0
- data/lib/gisele/language/ast.rb +2 -2
- data/lib/gisele/language/dot.yml +19 -0
- data/lib/gisele/language/sugar_removal.rb +30 -9
- data/lib/gisele/language/syntax/bool_expr.rb +14 -0
- data/lib/gisele/language/syntax/bool_lit.rb +1 -1
- data/lib/gisele/language/syntax/grammar.citrus +4 -3
- data/lib/gisele/language/syntax/node.rb +2 -1
- data/lib/gisele/language/to_graph.rb +119 -0
- data/lib/gisele/language.rb +4 -1
- data/lib/gisele/loader.rb +1 -0
- data/lib/gisele/version.rb +1 -1
- data/spec/command/main/gisele_ast_ruby.stdout +6 -3
- data/spec/command/main/gisele_graph.cmd +1 -0
- data/spec/command/main/gisele_graph.stdout +30 -0
- data/spec/command/main/gisele_help.stdout +10 -5
- data/spec/command/main/gisele_no_sugar.stdout +11 -5
- data/spec/command/main/gisele_version.stdout +1 -1
- data/spec/fixtures/tasks/complete.gis +18 -0
- data/spec/fixtures/tasks/simple.ast +57 -19
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/language/ast/test_node.rb +22 -0
- data/spec/unit/language/sugar_removal/test_if_to_guarded_commands.rb +32 -12
- data/spec/unit/language/syntax/test_to_ast.rb +23 -11
- data/spec/unit/language/test_syntax.rb +5 -0
- data/spec/unit/language/test_to_graph.rb +10 -0
- metadata +50 -18
data/lib/gisele/language.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Gisele
|
2
2
|
module Language
|
3
3
|
|
4
|
+
DOT_ATTRIBUTES = YAML.load_file(Path.dir/"language/dot.yml")
|
5
|
+
|
4
6
|
def rule2mod(rule)
|
5
7
|
rule.to_s.gsub(/(^|_)([a-z])/){|x| $2.capitalize}.to_sym
|
6
8
|
end
|
@@ -17,4 +19,5 @@ end # module Gisele
|
|
17
19
|
require_relative 'language/syntax'
|
18
20
|
require_relative 'language/ast'
|
19
21
|
require_relative 'language/transformer'
|
20
|
-
require_relative 'language/sugar_removal'
|
22
|
+
require_relative 'language/sugar_removal'
|
23
|
+
require_relative 'language/to_graph'
|
data/lib/gisele/loader.rb
CHANGED
data/lib/gisele/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
gisele --graph tasks/complete.gis
|
@@ -0,0 +1,30 @@
|
|
1
|
+
digraph G {
|
2
|
+
graph[]
|
3
|
+
V0 [shape="circle" style="filled" fillcolor="black" fixed="true" width="0.1" label=""]
|
4
|
+
V1 [shape="circle" style="filled" fillcolor="black" fixed="true" width="0.1" label=""]
|
5
|
+
V2 [shape="box" label="FirstTask"]
|
6
|
+
V3 [shape="diamond" label=""]
|
7
|
+
V4 [shape="box" height="0.1" style="filled" fillcolor="black" label=""]
|
8
|
+
V5 [shape="box" height="0.1" style="filled" fillcolor="black" label=""]
|
9
|
+
V6 [shape="box" label="MakeJoy"]
|
10
|
+
V7 [shape="box" label="DrinkBeers"]
|
11
|
+
V8 [shape="box" label="DrinkBeer"]
|
12
|
+
V9 [shape="box" label="DoNothingSpecial"]
|
13
|
+
V10 [shape="diamond" label="not(endOfTheDay)"]
|
14
|
+
V11 [shape="box" label="WaitAndSee"]
|
15
|
+
V2 -> V3 []
|
16
|
+
V6 -> V5 []
|
17
|
+
V4 -> V6 []
|
18
|
+
V7 -> V5 []
|
19
|
+
V4 -> V7 []
|
20
|
+
V3 -> V4 [label="everyoneHappy"]
|
21
|
+
V5 -> V10 []
|
22
|
+
V8 -> V10 []
|
23
|
+
V3 -> V8 [label="(someoneHappy and not(everyoneHappy))"]
|
24
|
+
V9 -> V10 []
|
25
|
+
V3 -> V9 [label="(not(someoneHappy) and not(everyoneHappy))"]
|
26
|
+
V11 -> V10 []
|
27
|
+
V10 -> V1 [label="false"]
|
28
|
+
V10 -> V11 [label="true"]
|
29
|
+
V0 -> V2 []
|
30
|
+
}
|
@@ -3,11 +3,12 @@ Gisele - A Process Analyzer Toolset
|
|
3
3
|
|
4
4
|
SYNOPSIS
|
5
5
|
gisele [--version] [--help]
|
6
|
-
gisele [--ast] PROCESS_FILE
|
6
|
+
gisele [--ast | --graph] PROCESS_FILE
|
7
7
|
|
8
8
|
OPTIONS
|
9
9
|
--ast=[MODE] Prints the process abstract syntax tree (debug,ruby)
|
10
10
|
--no-sugar Apply syntactic sugar removal
|
11
|
+
--graph=[MODE] Converts and print a graph (dot)
|
11
12
|
--help Show this help message
|
12
13
|
--version Show version and exit
|
13
14
|
|
@@ -15,13 +16,17 @@ DESCRIPTION
|
|
15
16
|
The Gisele process analyzer toolset provides tools and technique to model and analyze
|
16
17
|
complex process models such as care processes.
|
17
18
|
|
18
|
-
When --
|
19
|
+
When --no-sugar is specified, syntactic sugar is first removed before making any other
|
20
|
+
transformation. For now, this rewrites all `if` statements as explicit `case` guarded
|
21
|
+
commands.
|
22
|
+
|
23
|
+
When --ast is used, the command parses the process file and prints its Abstract Syntax
|
19
24
|
Tree (AST) on standard output. By default, this option prints the AST for manual
|
20
25
|
debugging, that is with colors and extra information. Use --ast=ruby to get a ruby
|
21
26
|
array for automatic processing.
|
22
27
|
|
23
|
-
When --
|
24
|
-
|
25
|
-
|
28
|
+
When --graph is used, the command parses the process file. It then converts the AST into
|
29
|
+
a directed graph representing the process as a box-and-arrow workflow and outputs it on
|
30
|
+
standard output. For now, the only output format available is dot (from graphviz).
|
26
31
|
|
27
32
|
SystemExit
|
@@ -28,10 +28,13 @@
|
|
28
28
|
[
|
29
29
|
:when_clause,
|
30
30
|
[
|
31
|
-
:
|
31
|
+
:bool_expr,
|
32
32
|
[
|
33
|
-
:
|
34
|
-
|
33
|
+
:bool_not,
|
34
|
+
[
|
35
|
+
:var_ref,
|
36
|
+
"diagKnown"
|
37
|
+
]
|
35
38
|
]
|
36
39
|
],
|
37
40
|
[
|
@@ -42,8 +45,11 @@
|
|
42
45
|
[
|
43
46
|
:when_clause,
|
44
47
|
[
|
45
|
-
:
|
46
|
-
|
48
|
+
:bool_expr,
|
49
|
+
[
|
50
|
+
:var_ref,
|
51
|
+
"diagKnown"
|
52
|
+
]
|
47
53
|
],
|
48
54
|
[
|
49
55
|
:task_call_st,
|
@@ -1,2 +1,2 @@
|
|
1
|
-
gisele 0.0
|
1
|
+
gisele 0.2.0 (c) The University of Louvain
|
2
2
|
SystemExit
|
@@ -1,19 +1,57 @@
|
|
1
|
-
[
|
2
|
-
|
3
|
-
[
|
4
|
-
|
5
|
-
|
6
|
-
[
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
[
|
2
|
+
:unit,
|
3
|
+
[
|
4
|
+
:task_def,
|
5
|
+
"Simple",
|
6
|
+
[
|
7
|
+
:task_signature,
|
8
|
+
[
|
9
|
+
:fluent,
|
10
|
+
"diagKnown",
|
11
|
+
[
|
12
|
+
:event_set,
|
13
|
+
"Diagnosis:start"
|
14
|
+
],
|
15
|
+
[
|
16
|
+
:event_set,
|
17
|
+
"Treatment:end"
|
18
|
+
],
|
19
|
+
nil
|
20
|
+
]
|
21
|
+
],
|
22
|
+
[
|
23
|
+
:task_refinement,
|
24
|
+
[
|
25
|
+
:seq_st,
|
26
|
+
[
|
27
|
+
:if_st,
|
28
|
+
[
|
29
|
+
:bool_expr,
|
30
|
+
[
|
31
|
+
:bool_not,
|
32
|
+
[
|
33
|
+
:var_ref,
|
34
|
+
"diagKnown"
|
35
|
+
]
|
36
|
+
]
|
37
|
+
],
|
38
|
+
[
|
39
|
+
:task_call_st,
|
40
|
+
"Diagnosis"
|
41
|
+
],
|
42
|
+
[
|
43
|
+
:else_clause,
|
44
|
+
[
|
45
|
+
:task_call_st,
|
46
|
+
"NoDiag"
|
47
|
+
]
|
48
|
+
]
|
49
|
+
],
|
50
|
+
[
|
51
|
+
:task_call_st,
|
52
|
+
"Treatment"
|
53
|
+
]
|
54
|
+
]
|
55
|
+
]
|
56
|
+
]
|
57
|
+
]
|
data/spec/spec_helper.rb
CHANGED
@@ -21,6 +21,14 @@ module SpecHelpers
|
|
21
21
|
fixtures_dir.glob(glob)
|
22
22
|
end
|
23
23
|
|
24
|
+
def simple_ast
|
25
|
+
Gisele::ast(fixtures_dir/:tasks/"simple.gis")
|
26
|
+
end
|
27
|
+
|
28
|
+
def complete_ast
|
29
|
+
Gisele::ast(fixtures_dir/:tasks/"complete.gis")
|
30
|
+
end
|
31
|
+
|
24
32
|
end
|
25
33
|
|
26
34
|
RSpec.configure do |c|
|
@@ -21,6 +21,14 @@ module Gisele::Language::AST
|
|
21
21
|
|
22
22
|
end # children
|
23
23
|
|
24
|
+
describe 'markers' do
|
25
|
+
|
26
|
+
it 'defaults to an empty hash' do
|
27
|
+
node([:hello]).markers.should eq({})
|
28
|
+
end
|
29
|
+
|
30
|
+
end # markers
|
31
|
+
|
24
32
|
describe 'copy' do
|
25
33
|
|
26
34
|
it 'collects block results ala `inject`' do
|
@@ -40,6 +48,13 @@ module Gisele::Language::AST
|
|
40
48
|
target.should be_a(Unit)
|
41
49
|
end
|
42
50
|
|
51
|
+
it 'keeps the markers unchanged' do
|
52
|
+
node = node([:unit], {:hello => "World"})
|
53
|
+
copy = node.copy do |memo,child| end
|
54
|
+
copy.markers.should eq({:hello => "World"})
|
55
|
+
copy.markers.object_id.should_not eq(node.markers.object_id)
|
56
|
+
end
|
57
|
+
|
43
58
|
end
|
44
59
|
|
45
60
|
describe 'dup' do
|
@@ -55,6 +70,13 @@ module Gisele::Language::AST
|
|
55
70
|
node(arr).dup.should be_a(Node)
|
56
71
|
end
|
57
72
|
|
73
|
+
it 'keeps the markers unchanged' do
|
74
|
+
node = node([:unit, "etc."], {:hello => "World"})
|
75
|
+
copy = node.dup
|
76
|
+
copy.markers.should eq({:hello => "World"})
|
77
|
+
copy.markers.object_id.should_not eq(node.markers.object_id)
|
78
|
+
end
|
79
|
+
|
58
80
|
end # dup
|
59
81
|
|
60
82
|
end
|
@@ -16,7 +16,9 @@ module Gisele::Language
|
|
16
16
|
source = ast("if goodCond Task1 end")
|
17
17
|
expected = \
|
18
18
|
[:case_st,
|
19
|
-
[:when_clause,
|
19
|
+
[:when_clause,
|
20
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
21
|
+
[:task_call_st, "Task1"] ]]
|
20
22
|
rewrite(source).should eq(expected)
|
21
23
|
end
|
22
24
|
|
@@ -24,8 +26,12 @@ module Gisele::Language
|
|
24
26
|
source = ast("if goodCond Task1 else Task2 end")
|
25
27
|
expected = \
|
26
28
|
[:case_st,
|
27
|
-
[:when_clause,
|
28
|
-
|
29
|
+
[:when_clause,
|
30
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
31
|
+
[:task_call_st, "Task1"] ],
|
32
|
+
[:when_clause,
|
33
|
+
[:bool_expr, [:bool_not, [:var_ref, "goodCond"]]],
|
34
|
+
[:task_call_st, "Task2"] ]
|
29
35
|
]
|
30
36
|
rewrite(source).should eq(expected)
|
31
37
|
end
|
@@ -41,26 +47,26 @@ module Gisele::Language
|
|
41
47
|
expected = \
|
42
48
|
[:case_st,
|
43
49
|
[:when_clause,
|
44
|
-
[:var_ref, "c1"],
|
50
|
+
[:bool_expr, [:var_ref, "c1"]],
|
45
51
|
[:task_call_st, "Task1"] ],
|
46
52
|
[:when_clause,
|
47
|
-
[:bool_and,
|
53
|
+
[:bool_expr, [:bool_and,
|
48
54
|
[:var_ref, "c2"],
|
49
|
-
[:bool_not, [:var_ref, "c1"]] ],
|
55
|
+
[:bool_not, [:var_ref, "c1"]] ]],
|
50
56
|
[:task_call_st, "Task2"] ],
|
51
57
|
[:when_clause,
|
52
|
-
[:bool_and,
|
58
|
+
[:bool_expr, [:bool_and,
|
53
59
|
[:var_ref, "c3"],
|
54
60
|
[:bool_and,
|
55
61
|
[:bool_not, [:var_ref, "c2"]],
|
56
|
-
[:bool_not, [:var_ref, "c1"]] ]],
|
62
|
+
[:bool_not, [:var_ref, "c1"]] ]]],
|
57
63
|
[:task_call_st, "Task3"] ],
|
58
64
|
[:when_clause,
|
59
|
-
[:bool_and,
|
65
|
+
[:bool_expr, [:bool_and,
|
60
66
|
[:bool_not, [:var_ref, "c3"]],
|
61
67
|
[:bool_and,
|
62
68
|
[:bool_not, [:var_ref, "c2"]],
|
63
|
-
[:bool_not, [:var_ref, "c1"]]]],
|
69
|
+
[:bool_not, [:var_ref, "c1"]]]]],
|
64
70
|
[:task_call_st, "Task4"] ],
|
65
71
|
]
|
66
72
|
rewrite(source).should eq(expected)
|
@@ -71,10 +77,10 @@ module Gisele::Language
|
|
71
77
|
expected = \
|
72
78
|
[:case_st,
|
73
79
|
[:when_clause,
|
74
|
-
[:bool_not, [:var_ref, "goodCond"]],
|
80
|
+
[:bool_expr, [:bool_not, [:var_ref, "goodCond"]]],
|
75
81
|
[:task_call_st, "Task1"] ],
|
76
82
|
[:when_clause,
|
77
|
-
[:var_ref, "goodCond"],
|
83
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
78
84
|
[:task_call_st, "Task2"] ] ]
|
79
85
|
rewrite(source).should eq(expected)
|
80
86
|
end
|
@@ -85,6 +91,20 @@ module Gisele::Language
|
|
85
91
|
rewrite([:unit, if_st]).should eq([:unit, rw_st])
|
86
92
|
end
|
87
93
|
|
94
|
+
it 'keeps traceability markers on a single if' do
|
95
|
+
if_st = ast("if goodCond Task1 end")
|
96
|
+
rw_st = rewrite(if_st)
|
97
|
+
rw_st.markers.should eq(if_st.markers)
|
98
|
+
rw_st.last.markers.should eq(if_st.markers)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'keeps traceability markers when a else if present' do
|
102
|
+
if_st = ast("if goodCond Task1 else Task2 end")
|
103
|
+
rw_st = rewrite(if_st)
|
104
|
+
rw_st.markers.should eq(if_st.markers)
|
105
|
+
rw_st.last.markers.should eq(if_st.last.markers)
|
106
|
+
end
|
107
|
+
|
88
108
|
end
|
89
109
|
end
|
90
110
|
end
|
@@ -11,20 +11,27 @@ module Gisele::Language::Syntax
|
|
11
11
|
describe "the bool_expr rule" do
|
12
12
|
|
13
13
|
it 'returns expected ast on simple expressions' do
|
14
|
-
expected =
|
14
|
+
expected = \
|
15
|
+
[:bool_expr, [:bool_and, [:var_ref, "diagKnown"], [:var_ref, "platLow"]]]
|
15
16
|
ast("diagKnown and platLow", :bool_expr).should eq(expected)
|
16
17
|
end
|
17
18
|
|
18
19
|
it 'respects priorities' do
|
19
|
-
expected = [:
|
20
|
+
expected = [:bool_expr,
|
21
|
+
[:bool_or, [:bool_and, [:var_ref, "diagKnown"], [:var_ref, "platLow"]], [:var_ref, "platHigh"]]]
|
20
22
|
ast("diagKnown and platLow or platHigh", :bool_expr).should eq(expected)
|
21
23
|
end
|
22
24
|
|
23
25
|
it 'supports double negations' do
|
24
|
-
expected = [:bool_not, [:bool_not, [:var_ref, "diagKnown"]]]
|
26
|
+
expected = [:bool_expr, [:bool_not, [:bool_not, [:var_ref, "diagKnown"]]]]
|
25
27
|
ast("not not(diagKnown)", :bool_expr).should eq(expected)
|
26
28
|
end
|
27
29
|
|
30
|
+
it 'makes boolean literals explicit' do
|
31
|
+
ast("true", :bool_expr).should eq([:bool_expr, [:bool_lit, true]])
|
32
|
+
ast("false", :bool_expr).should eq([:bool_expr, [:bool_lit, false]])
|
33
|
+
end
|
34
|
+
|
28
35
|
end # bool_expr
|
29
36
|
|
30
37
|
describe 'the event_set rule' do
|
@@ -131,7 +138,7 @@ module Gisele::Language::Syntax
|
|
131
138
|
expr = "while goodCond Task1 end"
|
132
139
|
expected = \
|
133
140
|
[:while_st,
|
134
|
-
[:var_ref, "goodCond"],
|
141
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
135
142
|
[:task_call_st, "Task1"]]
|
136
143
|
ast(expr, :while_st).should eq(expected)
|
137
144
|
end
|
@@ -140,7 +147,7 @@ module Gisele::Language::Syntax
|
|
140
147
|
expr = "while goodCond Task1 Task2 end"
|
141
148
|
expected = \
|
142
149
|
[:while_st,
|
143
|
-
[:var_ref, "goodCond"],
|
150
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
144
151
|
[:seq_st, [:task_call_st, "Task1"], [:task_call_st, "Task2"]]]
|
145
152
|
ast(expr, :while_st).should eq(expected)
|
146
153
|
end
|
@@ -163,7 +170,9 @@ module Gisele::Language::Syntax
|
|
163
170
|
it 'parses as expected' do
|
164
171
|
expr = "elsif goodCond Task1 "
|
165
172
|
expected = \
|
166
|
-
[:elsif_clause,
|
173
|
+
[:elsif_clause,
|
174
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
175
|
+
[:task_call_st, "Task1"]]
|
167
176
|
ast(expr, :elsif_clause).should eq(expected)
|
168
177
|
end
|
169
178
|
|
@@ -174,7 +183,9 @@ module Gisele::Language::Syntax
|
|
174
183
|
it 'parses as expected' do
|
175
184
|
expr = "if goodCond Task1 end"
|
176
185
|
expected = \
|
177
|
-
[:if_st,
|
186
|
+
[:if_st,
|
187
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
188
|
+
[:task_call_st, "Task1"]]
|
178
189
|
ast(expr, :if_st).should eq(expected)
|
179
190
|
end
|
180
191
|
|
@@ -182,7 +193,8 @@ module Gisele::Language::Syntax
|
|
182
193
|
expr = "if goodCond Task1 else Task2 end"
|
183
194
|
expected = \
|
184
195
|
[:if_st,
|
185
|
-
[:
|
196
|
+
[:bool_expr, [:var_ref, "goodCond"]],
|
197
|
+
[:task_call_st, "Task1"],
|
186
198
|
[:else_clause, [:task_call_st, "Task2"]] ]
|
187
199
|
ast(expr, :if_st).should eq(expected)
|
188
200
|
end
|
@@ -191,11 +203,11 @@ module Gisele::Language::Syntax
|
|
191
203
|
expr = "if goodCond Task1 elsif otherCond Task2 elsif stillAnother Task3 else Task4 end"
|
192
204
|
expected = \
|
193
205
|
[:if_st,
|
194
|
-
[:var_ref, "goodCond"], [:task_call_st, "Task1"],
|
206
|
+
[:bool_expr, [:var_ref, "goodCond"]], [:task_call_st, "Task1"],
|
195
207
|
[:elsif_clause,
|
196
|
-
[:var_ref, "otherCond"], [:task_call_st, "Task2"]],
|
208
|
+
[:bool_expr, [:var_ref, "otherCond"]], [:task_call_st, "Task2"]],
|
197
209
|
[:elsif_clause,
|
198
|
-
[:var_ref, "stillAnother"], [:task_call_st, "Task3"]],
|
210
|
+
[:bool_expr, [:var_ref, "stillAnother"]], [:task_call_st, "Task3"]],
|
199
211
|
[:else_clause,
|
200
212
|
[:task_call_st, "Task4"]] ]
|
201
213
|
ast(expr, :if_st).should eq(expected)
|
@@ -30,6 +30,11 @@ module Gisele::Language
|
|
30
30
|
ast.first.should eq(:if_st)
|
31
31
|
end
|
32
32
|
|
33
|
+
it 'sets traceability marks correctly' do
|
34
|
+
ast = ast("if goodCond Task1 end", :root => :if_st)
|
35
|
+
ast.markers[:match].should_not be_nil
|
36
|
+
end
|
37
|
+
|
33
38
|
fixture_files('tasks/**/*.gis').each do |file|
|
34
39
|
it "works on #{file}" do
|
35
40
|
parsed = Syntax.ast(file)
|