gisele 0.0.1 → 0.1.0

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