gisele 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|