gisele 0.0.1 → 0.1.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.
Files changed (58) hide show
  1. data/CHANGELOG.md +39 -1
  2. data/gisele.noespec +1 -1
  3. data/lib/gisele/command.rb +13 -4
  4. data/lib/gisele/errors.rb +21 -0
  5. data/lib/gisele/language/ast/helpers.rb +37 -0
  6. data/lib/gisele/language/ast/node.rb +54 -0
  7. data/lib/gisele/language/ast/unit.rb +10 -0
  8. data/lib/gisele/language/ast.rb +14 -0
  9. data/lib/gisele/language/sugar_removal.rb +53 -0
  10. data/lib/gisele/language/syntax/bool_and.rb +14 -0
  11. data/lib/gisele/language/syntax/bool_lit.rb +14 -0
  12. data/lib/gisele/language/syntax/bool_not.rb +14 -0
  13. data/lib/gisele/language/syntax/bool_or.rb +14 -0
  14. data/lib/gisele/language/syntax/bool_paren.rb +14 -0
  15. data/lib/gisele/language/syntax/else_clause.rb +14 -0
  16. data/lib/gisele/language/syntax/elsif_clause.rb +16 -0
  17. data/lib/gisele/language/syntax/event_set.rb +15 -0
  18. data/lib/gisele/language/syntax/fluent_def.rb +18 -0
  19. data/lib/gisele/language/syntax/grammar.citrus +202 -0
  20. data/lib/gisele/language/syntax/if_st.rb +18 -0
  21. data/lib/gisele/language/syntax/implicit_seq_st.rb +16 -0
  22. data/lib/gisele/language/syntax/node.rb +35 -0
  23. data/lib/gisele/language/syntax/par_st.rb +14 -0
  24. data/lib/gisele/language/syntax/seq_st.rb +14 -0
  25. data/lib/gisele/language/syntax/st_list.rb +14 -0
  26. data/lib/gisele/language/syntax/task_call_st.rb +14 -0
  27. data/lib/gisele/language/syntax/task_def.rb +17 -0
  28. data/lib/gisele/language/syntax/task_refinement.rb +15 -0
  29. data/lib/gisele/language/syntax/task_signature.rb +15 -0
  30. data/lib/gisele/language/syntax/trackvar_def.rb +19 -0
  31. data/lib/gisele/language/syntax/unit.rb +14 -0
  32. data/lib/gisele/language/syntax/var_ref.rb +14 -0
  33. data/lib/gisele/language/syntax/while_st.rb +16 -0
  34. data/lib/gisele/language/syntax.rb +29 -0
  35. data/lib/gisele/language/transformer.rb +38 -0
  36. data/lib/gisele/language.rb +15 -1
  37. data/lib/gisele/version.rb +2 -2
  38. data/lib/gisele.rb +7 -1
  39. data/spec/command/main/gisele_ast_ruby.stdout +38 -28
  40. data/spec/command/main/gisele_help.stdout +5 -0
  41. data/spec/command/main/gisele_no_sugar.cmd +1 -0
  42. data/spec/command/main/gisele_no_sugar.stdout +61 -0
  43. data/spec/fixtures/tasks/simple.ast +18 -14
  44. data/spec/fixtures/tasks/simple.gis +2 -0
  45. data/spec/spec_helper.rb +3 -3
  46. data/spec/test_examples.rb +3 -3
  47. data/spec/unit/language/ast/test_node.rb +61 -0
  48. data/spec/unit/language/sugar_removal/test_if_to_guarded_commands.rb +90 -0
  49. data/spec/unit/language/{test_grammar.rb → syntax/test_grammar.rb} +18 -30
  50. data/spec/unit/language/syntax/test_to_ast.rb +245 -0
  51. data/spec/unit/language/test_ast.rb +21 -247
  52. data/spec/unit/language/test_syntax.rb +48 -0
  53. data/spec/unit/language/test_transformer.rb +68 -0
  54. data/spec/unit/test_language.rb +35 -0
  55. metadata +69 -25
  56. data/lib/gisele/language/grammar.citrus +0 -246
  57. data/lib/gisele/language/parser.rb +0 -30
  58. data/spec/unit/language/test_parser.rb +0 -27
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ module Gisele::Language
3
+ describe SugarRemoval do
4
+ describe "if_st to case_st" do
5
+ include AST::Helpers
6
+
7
+ def ast(source)
8
+ Syntax.ast(source.strip, :root => :if_st)
9
+ end
10
+
11
+ def rewrite(ast)
12
+ SugarRemoval.new.call(ast)
13
+ end
14
+
15
+ it 'rewrites single if correctly' do
16
+ source = ast("if goodCond Task1 end")
17
+ expected = \
18
+ [:case_st,
19
+ [:when_clause, [:var_ref, "goodCond"], [:task_call_st, "Task1"] ]]
20
+ rewrite(source).should eq(expected)
21
+ end
22
+
23
+ it 'negates the else clause' do
24
+ source = ast("if goodCond Task1 else Task2 end")
25
+ expected = \
26
+ [:case_st,
27
+ [:when_clause, [:var_ref, "goodCond"], [:task_call_st, "Task1"] ],
28
+ [:when_clause, [:bool_not, [:var_ref, "goodCond"]], [:task_call_st, "Task2"] ]
29
+ ]
30
+ rewrite(source).should eq(expected)
31
+ end
32
+
33
+ it 'handles elsif clauses correctly' do
34
+ source = ast(<<-IF)
35
+ if c1 Task1
36
+ elsif c2 Task2
37
+ elsif c3 Task3
38
+ else Task4
39
+ end
40
+ IF
41
+ expected = \
42
+ [:case_st,
43
+ [:when_clause,
44
+ [:var_ref, "c1"],
45
+ [:task_call_st, "Task1"] ],
46
+ [:when_clause,
47
+ [:bool_and,
48
+ [:var_ref, "c2"],
49
+ [:bool_not, [:var_ref, "c1"]] ],
50
+ [:task_call_st, "Task2"] ],
51
+ [:when_clause,
52
+ [:bool_and,
53
+ [:var_ref, "c3"],
54
+ [:bool_and,
55
+ [:bool_not, [:var_ref, "c2"]],
56
+ [:bool_not, [:var_ref, "c1"]] ]],
57
+ [:task_call_st, "Task3"] ],
58
+ [:when_clause,
59
+ [:bool_and,
60
+ [:bool_not, [:var_ref, "c3"]],
61
+ [:bool_and,
62
+ [:bool_not, [:var_ref, "c2"]],
63
+ [:bool_not, [:var_ref, "c1"]]]],
64
+ [:task_call_st, "Task4"] ],
65
+ ]
66
+ rewrite(source).should eq(expected)
67
+ end
68
+
69
+ it 'avoids double negations' do
70
+ source = ast("if not(goodCond) Task1 else Task2 end")
71
+ expected = \
72
+ [:case_st,
73
+ [:when_clause,
74
+ [:bool_not, [:var_ref, "goodCond"]],
75
+ [:task_call_st, "Task1"] ],
76
+ [:when_clause,
77
+ [:var_ref, "goodCond"],
78
+ [:task_call_st, "Task2"] ] ]
79
+ rewrite(source).should eq(expected)
80
+ end
81
+
82
+ it 'recurse on other nodes' do
83
+ if_st = ast("if goodCond Task1 end")
84
+ rw_st = rewrite(if_st)
85
+ rewrite([:unit, if_st]).should eq([:unit, rw_st])
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
- module Gisele::Language
2
+ module Gisele::Language::Syntax
3
3
  describe Grammar do
4
4
 
5
- let(:grammar){ Gisele::Language::Grammar }
5
+ let(:grammar){ Gisele::Language::Syntax::Grammar }
6
6
 
7
7
  def parse(text, rule, consume = true)
8
8
  grammar.parse(text, :root => rule, :consume => consume)
@@ -130,22 +130,6 @@ module Gisele::Language
130
130
 
131
131
  end # event
132
132
 
133
- describe 'the event_commalist rule' do
134
-
135
- it 'parses a singleton list' do
136
- parse('Task:start', :event_commalist).should eq('Task:start')
137
- end
138
-
139
- it 'parses multiple events' do
140
- parse('Task:start, an_event', :event_commalist).should eq('Task:start, an_event')
141
- end
142
-
143
- it 'recognizes invalid events' do
144
- lambda{ parse('Task:start, NotAnEvent', :event_commalist) }.should raise_error(Citrus::ParseError)
145
- end
146
-
147
- end # event_commalist
148
-
149
133
  describe 'the event_set rule' do
150
134
 
151
135
  it 'parses empty sets' do
@@ -158,6 +142,10 @@ module Gisele::Language
158
142
  parse('{ Task:start }', :event_set).should eq('{ Task:start }')
159
143
  end
160
144
 
145
+ it 'parses event sets' do
146
+ parse('{Task:start, Task:end}', :event_set).should eq('{Task:start, Task:end}')
147
+ end
148
+
161
149
  it 'recognizes invalid events in the set' do
162
150
  lambda{ parse('{Task:start, NotAnEvent}', :event_set) }.should raise_error(Citrus::ParseError)
163
151
  end
@@ -238,51 +226,51 @@ module Gisele::Language
238
226
 
239
227
  ### Process statements
240
228
 
241
- describe 'the par_statement rule' do
229
+ describe 'the par_st rule' do
242
230
 
243
231
  it 'parses a single parallel statement' do
244
232
  expr = 'par Task1 Task2 end'
245
- parse(expr, :par_statement).should eq(expr)
233
+ parse(expr, :par_st).should eq(expr)
246
234
  end
247
235
 
248
- end # par_statement
236
+ end # par_st
249
237
 
250
- describe 'the seq_statement rule' do
238
+ describe 'the seq_st rule' do
251
239
 
252
240
  it 'parses a single sequence statement' do
253
241
  expr = 'seq Task1 Task2 end'
254
- parse(expr, :seq_statement).should eq(expr)
242
+ parse(expr, :seq_st).should eq(expr)
255
243
  end
256
244
 
257
- end # seq_statement
245
+ end # seq_st
258
246
 
259
247
  describe 'the while_statement rule' do
260
248
 
261
249
  it 'parses a single while statement' do
262
250
  expr = 'while badCond Task end'
263
- parse(expr, :while_statement).should eq(expr)
251
+ parse(expr, :while_st).should eq(expr)
264
252
  end
265
253
 
266
254
  end # while_statement
267
255
 
268
- describe 'the if_statement rule' do
256
+ describe 'the if_st rule' do
269
257
 
270
258
  it 'parses a single if statement' do
271
259
  expr = 'if goodCond Task end'
272
- parse(expr, :if_statement).should eq(expr)
260
+ parse(expr, :if_st).should eq(expr)
273
261
  end
274
262
 
275
263
  it 'supports an optional else' do
276
264
  expr = 'if goodCond GoodTask else BadTask end'
277
- parse(expr, :if_statement).should eq(expr)
265
+ parse(expr, :if_st).should eq(expr)
278
266
  end
279
267
 
280
268
  it 'supports an optional elsif clauses' do
281
269
  expr = 'if goodCond GoodTask elsif otherCond OtherTask elsif yetAnother BadTask end'
282
- parse(expr, :if_statement).should eq(expr)
270
+ parse(expr, :if_st).should eq(expr)
283
271
  end
284
272
 
285
- end # if_statement
273
+ end # if_st
286
274
 
287
275
  describe 'the process_statement rule' do
288
276
 
@@ -0,0 +1,245 @@
1
+ require 'spec_helper'
2
+ module Gisele::Language::Syntax
3
+ describe Grammar, "to_ast" do
4
+
5
+ def ast(text, rule, consume = true)
6
+ @parsed = Grammar.parse(text, :root => rule, :consume => consume).to_ast
7
+ end
8
+
9
+ after{ @parsed.should be_a(Gisele::Language::AST::Node) }
10
+
11
+ describe "the bool_expr rule" do
12
+
13
+ it 'returns expected ast on simple expressions' do
14
+ expected = [:bool_and, [:var_ref, "diagKnown"], [:var_ref, "platLow"]]
15
+ ast("diagKnown and platLow", :bool_expr).should eq(expected)
16
+ end
17
+
18
+ it 'respects priorities' do
19
+ expected = [:bool_or, [:bool_and, [:var_ref, "diagKnown"], [:var_ref, "platLow"]], [:var_ref, "platHigh"]]
20
+ ast("diagKnown and platLow or platHigh", :bool_expr).should eq(expected)
21
+ end
22
+
23
+ it 'supports double negations' do
24
+ expected = [:bool_not, [:bool_not, [:var_ref, "diagKnown"]]]
25
+ ast("not not(diagKnown)", :bool_expr).should eq(expected)
26
+ end
27
+
28
+ end # bool_expr
29
+
30
+ describe 'the event_set rule' do
31
+
32
+ it 'parses empty lists as expected' do
33
+ expr = '{ }'
34
+ expected = [:event_set]
35
+ ast(expr, :event_set).should eq(expected)
36
+ end
37
+
38
+ it 'parses singleton lists as expected' do
39
+ expr = '{Diagnosis:start}'
40
+ expected = [:event_set, "Diagnosis:start"]
41
+ ast(expr, :event_set).should eq(expected)
42
+ end
43
+
44
+ it 'parses non empty lists as expected' do
45
+ expr = '{Diagnosis:start, an_event, another_one}'
46
+ expected = [:event_set, "Diagnosis:start", "an_event", "another_one"]
47
+ ast(expr, :event_set).should eq(expected)
48
+ end
49
+
50
+ end # event_set
51
+
52
+ describe "the fluent_def rule" do
53
+
54
+ it 'parses fluent definitions as expected' do
55
+ defn = "fluent diagKnown {Diagnosis:start, diagnosis}, {Treatment:end} initially false"
56
+ expected = [:fluent,
57
+ "diagKnown",
58
+ [:event_set, "Diagnosis:start", "diagnosis"],
59
+ [:event_set, "Treatment:end"],
60
+ false]
61
+ ast(defn, :fluent_def).should eq(expected)
62
+ end
63
+
64
+ it 'does not require the initial value' do
65
+ defn = "fluent diagKnown {Diagnosis:start, diagnosis}, {Treatment:end}"
66
+ expected = [:fluent,
67
+ "diagKnown",
68
+ [:event_set, "Diagnosis:start", "diagnosis"],
69
+ [:event_set, "Treatment:end"],
70
+ nil]
71
+ ast(defn, :fluent_def).should eq(expected)
72
+ end
73
+
74
+ end # fluent_def rule
75
+
76
+ describe "the trackvar_def rule" do
77
+
78
+ it 'parses tracking variable definitions as expected' do
79
+ defn = "trackvar mplus {Diagnosis:start}"
80
+ expected = [:trackvar,
81
+ "mplus",
82
+ [:event_set, "Diagnosis:start"],
83
+ [:event_set],
84
+ nil]
85
+ ast(defn, :trackvar_def).should eq(expected)
86
+ end
87
+
88
+ it 'supports obsolete events and initial value' do
89
+ defn = "trackvar mplus {Diagnosis:start}, {Treatment:end} initially true"
90
+ expected = [:trackvar,
91
+ "mplus",
92
+ [:event_set, "Diagnosis:start"],
93
+ [:event_set, "Treatment:end"],
94
+ true]
95
+ ast(defn, :trackvar_def).should eq(expected)
96
+ end
97
+
98
+ end # trackvar_def rule
99
+
100
+ describe "the task_call_st rule" do
101
+
102
+ it 'parses as expected' do
103
+ ast("Diagnosis", :task_call_st).should eq([:task_call_st, "Diagnosis"])
104
+ end
105
+
106
+ end # task_call_statement
107
+
108
+ describe "the par_st rule" do
109
+
110
+ it 'parses as expected' do
111
+ expr = "par Task1 Task2 end"
112
+ expected = [:par_st, [:task_call_st, "Task1"], [:task_call_st, "Task2"]]
113
+ ast(expr, :par_st).should eq(expected)
114
+ end
115
+
116
+ end # par_st
117
+
118
+ describe "the seq_st rule" do
119
+
120
+ it 'parses as expected' do
121
+ expr = "seq Task1 Task2 end"
122
+ expected = [:seq_st, [:task_call_st, "Task1"], [:task_call_st, "Task2"]]
123
+ ast(expr, :seq_st).should eq(expected)
124
+ end
125
+
126
+ end # seq_st
127
+
128
+ describe "the while_statement rule" do
129
+
130
+ it 'parses as expected' do
131
+ expr = "while goodCond Task1 end"
132
+ expected = \
133
+ [:while_st,
134
+ [:var_ref, "goodCond"],
135
+ [:task_call_st, "Task1"]]
136
+ ast(expr, :while_st).should eq(expected)
137
+ end
138
+
139
+ it 'recognizes implicit sequences' do
140
+ expr = "while goodCond Task1 Task2 end"
141
+ expected = \
142
+ [:while_st,
143
+ [:var_ref, "goodCond"],
144
+ [:seq_st, [:task_call_st, "Task1"], [:task_call_st, "Task2"]]]
145
+ ast(expr, :while_st).should eq(expected)
146
+ end
147
+
148
+ end # while_statement
149
+
150
+ describe "the else_clause rule" do
151
+
152
+ it 'parses as expected' do
153
+ expr = "else Task1 "
154
+ expected = \
155
+ [:else_clause, [:task_call_st, "Task1"]]
156
+ ast(expr, :else_clause).should eq(expected)
157
+ end
158
+
159
+ end # else_clause
160
+
161
+ describe "the elsif_clause rule" do
162
+
163
+ it 'parses as expected' do
164
+ expr = "elsif goodCond Task1 "
165
+ expected = \
166
+ [:elsif_clause, [:var_ref, "goodCond"], [:task_call_st, "Task1"]]
167
+ ast(expr, :elsif_clause).should eq(expected)
168
+ end
169
+
170
+ end # elsif_clause
171
+
172
+ describe "the if_statement rule" do
173
+
174
+ it 'parses as expected' do
175
+ expr = "if goodCond Task1 end"
176
+ expected = \
177
+ [:if_st, [:var_ref, "goodCond"], [:task_call_st, "Task1"]]
178
+ ast(expr, :if_st).should eq(expected)
179
+ end
180
+
181
+ it 'supports a else clause' do
182
+ expr = "if goodCond Task1 else Task2 end"
183
+ expected = \
184
+ [:if_st,
185
+ [:var_ref, "goodCond"], [:task_call_st, "Task1"],
186
+ [:else_clause, [:task_call_st, "Task2"]] ]
187
+ ast(expr, :if_st).should eq(expected)
188
+ end
189
+
190
+ it 'supports elsif clauses' do
191
+ expr = "if goodCond Task1 elsif otherCond Task2 elsif stillAnother Task3 else Task4 end"
192
+ expected = \
193
+ [:if_st,
194
+ [:var_ref, "goodCond"], [:task_call_st, "Task1"],
195
+ [:elsif_clause,
196
+ [:var_ref, "otherCond"], [:task_call_st, "Task2"]],
197
+ [:elsif_clause,
198
+ [:var_ref, "stillAnother"], [:task_call_st, "Task3"]],
199
+ [:else_clause,
200
+ [:task_call_st, "Task4"]] ]
201
+ ast(expr, :if_st).should eq(expected)
202
+ end
203
+
204
+ end # if_statement
205
+
206
+ describe 'the task_refinement rule' do
207
+
208
+ it 'parses as expected' do
209
+ expr = "refinement Task1 end"
210
+ expected = [:task_refinement, [:task_call_st, "Task1"]]
211
+ ast(expr, :task_refinement).should eq(expected)
212
+ end
213
+
214
+ end # task_refinement
215
+
216
+ describe 'the task_signature rule' do
217
+
218
+ it 'parses as expected' do
219
+ expr = "fluent diagKnown {}, {}\ntrackvar mplus {}"
220
+ expected = \
221
+ [ :task_signature,
222
+ [:fluent, "diagKnown", [:event_set], [:event_set], nil],
223
+ [:trackvar, "mplus", [:event_set], [:event_set], nil]]
224
+ ast(expr, :task_signature).should eq(expected)
225
+ end
226
+
227
+ end # task_signature
228
+
229
+ describe 'the task_def rule' do
230
+
231
+ it 'parses as expected' do
232
+ expr = "task Task1 fluent diagKnown {}, {} refinement Task2 end end"
233
+ expected = \
234
+ [:task_def, "Task1",
235
+ [:task_signature,
236
+ [:fluent, "diagKnown", [:event_set], [:event_set], nil]],
237
+ [:task_refinement,
238
+ [:task_call_st, "Task2"]]]
239
+ ast(expr, :task_def).should eq(expected)
240
+ end
241
+
242
+ end # task_def
243
+
244
+ end
245
+ end