gisele 0.0.1
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 +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +31 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +16 -0
- data/README.md +30 -0
- data/Rakefile +23 -0
- data/bin/gisele +8 -0
- data/examples/meeting-scheduler/MeetingScheduling.gis +73 -0
- data/gisele.gemspec +191 -0
- data/gisele.noespec +36 -0
- data/lib/gisele/command.rb +63 -0
- data/lib/gisele/language/grammar.citrus +246 -0
- data/lib/gisele/language/parser.rb +30 -0
- data/lib/gisele/language.rb +6 -0
- data/lib/gisele/loader.rb +4 -0
- data/lib/gisele/version.rb +14 -0
- data/lib/gisele.rb +14 -0
- data/spec/command/main/gisele_ast_ruby.cmd +1 -0
- data/spec/command/main/gisele_ast_ruby.stdout +44 -0
- data/spec/command/main/gisele_help.cmd +1 -0
- data/spec/command/main/gisele_help.stdout +22 -0
- data/spec/command/main/gisele_version.cmd +1 -0
- data/spec/command/main/gisele_version.stdout +2 -0
- data/spec/command/test_command.rb +27 -0
- data/spec/fixtures/tasks/simple.ast +15 -0
- data/spec/fixtures/tasks/simple.gis +9 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/test_examples.rb +14 -0
- data/spec/unit/language/test_ast.rb +264 -0
- data/spec/unit/language/test_grammar.rb +329 -0
- data/spec/unit/language/test_parser.rb +27 -0
- data/spec/unit/test_gisele.rb +8 -0
- data/tasks/debug_mail.rake +75 -0
- data/tasks/debug_mail.txt +13 -0
- data/tasks/gem.rake +68 -0
- data/tasks/spec_test.rake +71 -0
- data/tasks/unit_test.rake +76 -0
- data/tasks/yard.rake +51 -0
- metadata +196 -0
@@ -0,0 +1,264 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Gisele::Language
|
3
|
+
describe Grammar, "ast" do
|
4
|
+
|
5
|
+
let(:grammar){ Gisele::Language::Grammar }
|
6
|
+
|
7
|
+
def ast(text, rule, consume = true)
|
8
|
+
grammar.parse(text, :root => rule, :consume => consume).value
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "the bool_expr rule" do
|
12
|
+
|
13
|
+
it 'returns expected ast on simple expressions' do
|
14
|
+
expected = [:and, [:varref, "diagKnown"], [:varref, "platLow"]]
|
15
|
+
ast("diagKnown and platLow", :bool_expr).should eq(expected)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'respects priorities' do
|
19
|
+
expected = [:or, [:and, [:varref, "diagKnown"], [:varref, "platLow"]], [:varref, "platHigh"]]
|
20
|
+
ast("diagKnown and platLow or platHigh", :bool_expr).should eq(expected)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'supports double negations' do
|
24
|
+
expected = [:not, [:not, [:varref, "diagKnown"]]]
|
25
|
+
ast("not not(diagKnown)", :bool_expr).should eq(expected)
|
26
|
+
end
|
27
|
+
|
28
|
+
end # bool_expr
|
29
|
+
|
30
|
+
describe 'the event_commalist rule' do
|
31
|
+
|
32
|
+
it 'parses singleton lists as expected' do
|
33
|
+
expr = 'Diagnosis:start'
|
34
|
+
expected = ["Diagnosis:start"]
|
35
|
+
ast(expr, :event_commalist).should eq(expected)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'parses non empty lists as expected' do
|
39
|
+
expr = 'Diagnosis:start, an_event'
|
40
|
+
expected = ["Diagnosis:start", "an_event"]
|
41
|
+
ast(expr, :event_commalist).should eq(expected)
|
42
|
+
end
|
43
|
+
|
44
|
+
end # event_commalist
|
45
|
+
|
46
|
+
describe 'the event_set rule' do
|
47
|
+
|
48
|
+
it 'parses non empty lists as expected' do
|
49
|
+
expr = '{Diagnosis:start, an_event}'
|
50
|
+
expected = [:event_set, "Diagnosis:start", "an_event"]
|
51
|
+
ast(expr, :event_set).should eq(expected)
|
52
|
+
end
|
53
|
+
|
54
|
+
end # event_set
|
55
|
+
|
56
|
+
describe "the fluent_def rule" do
|
57
|
+
|
58
|
+
it 'parses fluent definitions as expected' do
|
59
|
+
defn = "fluent diagKnown {Diagnosis:start, diagnosis}, {Treatment:end} initially false"
|
60
|
+
expected = [:fluent,
|
61
|
+
"diagKnown",
|
62
|
+
[:event_set, "Diagnosis:start", "diagnosis"],
|
63
|
+
[:event_set, "Treatment:end"],
|
64
|
+
false]
|
65
|
+
ast(defn, :fluent_def).should eq(expected)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'does not require the initial value' do
|
69
|
+
defn = "fluent diagKnown {Diagnosis:start, diagnosis}, {Treatment:end}"
|
70
|
+
expected = [:fluent,
|
71
|
+
"diagKnown",
|
72
|
+
[:event_set, "Diagnosis:start", "diagnosis"],
|
73
|
+
[:event_set, "Treatment:end"],
|
74
|
+
nil]
|
75
|
+
ast(defn, :fluent_def).should eq(expected)
|
76
|
+
end
|
77
|
+
|
78
|
+
end # fluent_def rule
|
79
|
+
|
80
|
+
describe "the trackvar_def rule" do
|
81
|
+
|
82
|
+
it 'parses tracking variable definitions as expected' do
|
83
|
+
defn = "trackvar mplus {Diagnosis:start}"
|
84
|
+
expected = [:trackvar,
|
85
|
+
"mplus",
|
86
|
+
[:event_set, "Diagnosis:start"],
|
87
|
+
[:event_set],
|
88
|
+
nil]
|
89
|
+
ast(defn, :trackvar_def).should eq(expected)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'supports obsolete events and initial value' do
|
93
|
+
defn = "trackvar mplus {Diagnosis:start}, {Treatment:end} initially true"
|
94
|
+
expected = [:trackvar,
|
95
|
+
"mplus",
|
96
|
+
[:event_set, "Diagnosis:start"],
|
97
|
+
[:event_set, "Treatment:end"],
|
98
|
+
true]
|
99
|
+
ast(defn, :trackvar_def).should eq(expected)
|
100
|
+
end
|
101
|
+
|
102
|
+
end # trackvar_def rule
|
103
|
+
|
104
|
+
describe "the task_call_statement rule" do
|
105
|
+
|
106
|
+
it 'parses as expected' do
|
107
|
+
ast("Diagnosis", :task_call_statement).should eq([:task_call, "Diagnosis"])
|
108
|
+
end
|
109
|
+
|
110
|
+
end # task_call_statement
|
111
|
+
|
112
|
+
describe "the statement_list rule" do
|
113
|
+
|
114
|
+
it 'parses a list of 2 elements' do
|
115
|
+
expr = "Task1 Task2"
|
116
|
+
expected = [[:task_call, "Task1"], [:task_call, "Task2"]]
|
117
|
+
ast(expr, :statement_list).should eq(expected)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'parses a list of 3 elements' do
|
121
|
+
expr = "Task1 Task2 Task3"
|
122
|
+
expected = [[:task_call, "Task1"], [:task_call, "Task2"], [:task_call, "Task3"]]
|
123
|
+
ast(expr, :statement_list).should eq(expected)
|
124
|
+
end
|
125
|
+
|
126
|
+
end # statement_list
|
127
|
+
|
128
|
+
describe "the par_statement rule" do
|
129
|
+
|
130
|
+
it 'parses as expected' do
|
131
|
+
expr = "par Task1 Task2 end"
|
132
|
+
expected = [:par, [:task_call, "Task1"], [:task_call, "Task2"]]
|
133
|
+
ast(expr, :par_statement).should eq(expected)
|
134
|
+
end
|
135
|
+
|
136
|
+
end # par_statement
|
137
|
+
|
138
|
+
describe "the seq_statement rule" do
|
139
|
+
|
140
|
+
it 'parses as expected' do
|
141
|
+
expr = "seq Task1 Task2 end"
|
142
|
+
expected = [:seq, [:task_call, "Task1"], [:task_call, "Task2"]]
|
143
|
+
ast(expr, :seq_statement).should eq(expected)
|
144
|
+
end
|
145
|
+
|
146
|
+
end # seq_statement
|
147
|
+
|
148
|
+
describe "the while_statement rule" do
|
149
|
+
|
150
|
+
it 'parses as expected' do
|
151
|
+
expr = "while goodCond Task1 end"
|
152
|
+
expected = \
|
153
|
+
[:while,
|
154
|
+
[:varref, "goodCond"],
|
155
|
+
[:task_call, "Task1"]]
|
156
|
+
ast(expr, :while_statement).should eq(expected)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'recognizes implicit sequences' do
|
160
|
+
expr = "while goodCond Task1 Task2 end"
|
161
|
+
expected = \
|
162
|
+
[:while,
|
163
|
+
[:varref, "goodCond"],
|
164
|
+
[:seq, [:task_call, "Task1"], [:task_call, "Task2"]]]
|
165
|
+
ast(expr, :while_statement).should eq(expected)
|
166
|
+
end
|
167
|
+
|
168
|
+
end # while_statement
|
169
|
+
|
170
|
+
describe "the else_clause rule" do
|
171
|
+
|
172
|
+
it 'parses as expected' do
|
173
|
+
expr = "else Task1 "
|
174
|
+
expected = \
|
175
|
+
[:else, [:task_call, "Task1"]]
|
176
|
+
ast(expr, :else_clause).should eq(expected)
|
177
|
+
end
|
178
|
+
|
179
|
+
end # else_clause
|
180
|
+
|
181
|
+
describe "the elsif_clause rule" do
|
182
|
+
|
183
|
+
it 'parses as expected' do
|
184
|
+
expr = "elsif goodCond Task1 "
|
185
|
+
expected = \
|
186
|
+
[:elsif, [:varref, "goodCond"], [:task_call, "Task1"]]
|
187
|
+
ast(expr, :elsif_clause).should eq(expected)
|
188
|
+
end
|
189
|
+
|
190
|
+
end # elsif_clause
|
191
|
+
|
192
|
+
describe "the if_statement rule" do
|
193
|
+
|
194
|
+
it 'parses as expected' do
|
195
|
+
expr = "if goodCond Task1 end"
|
196
|
+
expected = \
|
197
|
+
[:if, [:varref, "goodCond"], [:task_call, "Task1"]]
|
198
|
+
ast(expr, :if_statement).should eq(expected)
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'supports a else clause' do
|
202
|
+
expr = "if goodCond Task1 else Task2 end"
|
203
|
+
expected = \
|
204
|
+
[:if,
|
205
|
+
[:varref, "goodCond"], [:task_call, "Task1"],
|
206
|
+
[:else, [:task_call, "Task2"]] ]
|
207
|
+
ast(expr, :if_statement).should eq(expected)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'supports elsif clauses' do
|
211
|
+
expr = "if goodCond Task1 elsif otherCond Task2 elsif stillAnother Task3 else Task4 end"
|
212
|
+
expected = \
|
213
|
+
[:if,
|
214
|
+
[:varref, "goodCond"], [:task_call, "Task1"],
|
215
|
+
[:elsif,
|
216
|
+
[:varref, "otherCond"], [:task_call, "Task2"]],
|
217
|
+
[:elsif,
|
218
|
+
[:varref, "stillAnother"], [:task_call, "Task3"]],
|
219
|
+
[:else,
|
220
|
+
[:task_call, "Task4"]] ]
|
221
|
+
ast(expr, :if_statement).should eq(expected)
|
222
|
+
end
|
223
|
+
|
224
|
+
end # if_statement
|
225
|
+
|
226
|
+
describe 'the task_refinement rule' do
|
227
|
+
|
228
|
+
it 'parses as expected' do
|
229
|
+
expr = "refinement Task1 end"
|
230
|
+
expected = [:task_call, "Task1"]
|
231
|
+
ast(expr, :task_refinement).should eq(expected)
|
232
|
+
end
|
233
|
+
|
234
|
+
end # task_refinement
|
235
|
+
|
236
|
+
describe 'the task_signature rule' do
|
237
|
+
|
238
|
+
it 'parses as expected' do
|
239
|
+
expr = "fluent diagKnown {}, {}\ntrackvar mplus {}"
|
240
|
+
expected = \
|
241
|
+
[ [:fluent, "diagKnown", [:event_set], [:event_set], nil],
|
242
|
+
[:trackvar, "mplus", [:event_set], [:event_set], nil]]
|
243
|
+
ast(expr, :task_signature).should eq(expected)
|
244
|
+
end
|
245
|
+
|
246
|
+
end # task_signature
|
247
|
+
|
248
|
+
describe 'the task_def rule' do
|
249
|
+
|
250
|
+
it 'parses as expected' do
|
251
|
+
expr = "task Task1 fluent diagKnown {}, {} refinement Task2 end end"
|
252
|
+
expected = \
|
253
|
+
[:task, "Task1",
|
254
|
+
[:signature,
|
255
|
+
[:fluent, "diagKnown", [:event_set], [:event_set], nil]],
|
256
|
+
[:refinement,
|
257
|
+
[:task_call, "Task2"]]]
|
258
|
+
ast(expr, :task_def).should eq(expected)
|
259
|
+
end
|
260
|
+
|
261
|
+
end # task_def
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Gisele::Language
|
3
|
+
describe Grammar do
|
4
|
+
|
5
|
+
let(:grammar){ Gisele::Language::Grammar }
|
6
|
+
|
7
|
+
def parse(text, rule, consume = true)
|
8
|
+
grammar.parse(text, :root => rule, :consume => consume)
|
9
|
+
end
|
10
|
+
|
11
|
+
### Spacing
|
12
|
+
|
13
|
+
describe 'the spaces rule' do
|
14
|
+
|
15
|
+
it 'parses all kind of spaces' do
|
16
|
+
parse(' ', :spaces).should eq(' ')
|
17
|
+
parse("\t", :spaces).should eq("\t")
|
18
|
+
parse("\n", :spaces).should eq("\n")
|
19
|
+
parse(" \t\n", :spaces).should eq(" \t\n")
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'enforces mandatory spacing' do
|
23
|
+
lambda{ parse('', :spaces) }.should raise_error(Citrus::ParseError)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'the spacing rule' do
|
29
|
+
|
30
|
+
it 'parses all kind of spaces' do
|
31
|
+
parse(' ', :spacing).should eq(' ')
|
32
|
+
parse("\t", :spacing).should eq("\t")
|
33
|
+
parse("\n", :spacing).should eq("\n")
|
34
|
+
parse(" \t\n", :spacing).should eq(" \t\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not enforces mandatory spacing' do
|
38
|
+
parse('', :spacing).should eq('')
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
### Literals
|
44
|
+
|
45
|
+
describe 'the boolean_literal rule' do
|
46
|
+
|
47
|
+
it 'parses booleans' do
|
48
|
+
parse('true', :boolean_literal).should eq('true')
|
49
|
+
parse('false', :boolean_literal).should eq('false')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'does not parses integers' do
|
53
|
+
lambda{ parse('0', :boolean_literal) }.should raise_error(Citrus::ParseError)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
### Names
|
59
|
+
|
60
|
+
describe 'the task_name rule' do
|
61
|
+
|
62
|
+
it 'parses correct task names' do
|
63
|
+
parse('A', :task_name).should eq('A')
|
64
|
+
parse('Diagnosis', :task_name).should eq('Diagnosis')
|
65
|
+
parse('TaskName', :task_name).should eq('TaskName')
|
66
|
+
parse('Task_Name', :task_name).should eq('Task_Name')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'raises on invalid task names' do
|
70
|
+
lambda{ parse('not_a_task_name', :task_name) }.should raise_error(Citrus::ParseError)
|
71
|
+
end
|
72
|
+
|
73
|
+
end # task_name
|
74
|
+
|
75
|
+
describe 'the variable_name rule' do
|
76
|
+
|
77
|
+
it 'parses correct variable names' do
|
78
|
+
parse('a', :variable_name).should eq('a')
|
79
|
+
parse('diagnosis', :variable_name).should eq('diagnosis')
|
80
|
+
parse('varName', :variable_name).should eq('varName')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'raises on invalid variable names' do
|
84
|
+
lambda{ parse('NotAVarName', :variable_name) }.should raise_error(Citrus::ParseError)
|
85
|
+
end
|
86
|
+
|
87
|
+
end # variable_name
|
88
|
+
|
89
|
+
describe 'the event_name rule' do
|
90
|
+
|
91
|
+
it 'parses correct event names' do
|
92
|
+
parse('a', :event_name).should eq('a')
|
93
|
+
parse('event', :event_name).should eq('event')
|
94
|
+
parse('event_name', :event_name).should eq('event_name')
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'raises on invalid variable names' do
|
98
|
+
lambda{ parse('NotAnEventName', :event_name) }.should raise_error(Citrus::ParseError)
|
99
|
+
lambda{ parse('notAnEventName', :event_name) }.should raise_error(Citrus::ParseError)
|
100
|
+
end
|
101
|
+
|
102
|
+
end # event_name
|
103
|
+
|
104
|
+
### Events
|
105
|
+
|
106
|
+
describe 'the task_start_or_end rule' do
|
107
|
+
|
108
|
+
it 'parses correct event names' do
|
109
|
+
parse('Task:start', :task_start_or_end).should eq('Task:start')
|
110
|
+
parse('Task:end', :task_start_or_end).should eq('Task:end')
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'raises on simple task names' do
|
114
|
+
lambda{ parse('Task', :task_start_or_end) }.should raise_error(Citrus::ParseError)
|
115
|
+
end
|
116
|
+
|
117
|
+
end # task_start_or_end
|
118
|
+
|
119
|
+
describe 'the event rule' do
|
120
|
+
|
121
|
+
it 'parses correct events' do
|
122
|
+
parse('Task:start', :event).should eq('Task:start')
|
123
|
+
parse('Task:end', :event).should eq('Task:end')
|
124
|
+
parse('an_event', :event).should eq('an_event')
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'raises on invalid event names' do
|
128
|
+
lambda{ parse('Task', :event) }.should raise_error(Citrus::ParseError)
|
129
|
+
end
|
130
|
+
|
131
|
+
end # event
|
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
|
+
describe 'the event_set rule' do
|
150
|
+
|
151
|
+
it 'parses empty sets' do
|
152
|
+
parse('{}', :event_set).should eq('{}')
|
153
|
+
parse('{ }', :event_set).should eq('{ }')
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'parses event singletons' do
|
157
|
+
parse('{Task:start}', :event_set).should eq('{Task:start}')
|
158
|
+
parse('{ Task:start }', :event_set).should eq('{ Task:start }')
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'recognizes invalid events in the set' do
|
162
|
+
lambda{ parse('{Task:start, NotAnEvent}', :event_set) }.should raise_error(Citrus::ParseError)
|
163
|
+
end
|
164
|
+
|
165
|
+
end # event_set
|
166
|
+
|
167
|
+
### Variables
|
168
|
+
|
169
|
+
describe 'the fluent_def rule' do
|
170
|
+
|
171
|
+
it 'parses valid fluent definitions' do
|
172
|
+
defn = 'fluent diagKnown {Diagnosis:start}, {Treatment:end} initially false'
|
173
|
+
parse(defn, :fluent_def).should eq(defn)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'supports a missing initial value' do
|
177
|
+
defn = 'fluent diagKnown {Diagnosis:start}, {Treatment:end}'
|
178
|
+
parse(defn, :fluent_def).should eq(defn)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'supports empty sets for events' do
|
182
|
+
defn = 'fluent diagKnown {}, {} initially true'
|
183
|
+
parse(defn, :fluent_def).should eq(defn)
|
184
|
+
end
|
185
|
+
|
186
|
+
end # fluent_def
|
187
|
+
|
188
|
+
describe 'the trackvar_def rule' do
|
189
|
+
|
190
|
+
it 'parses valid tracking variable definitions' do
|
191
|
+
defn = 'trackvar plateletLow {BloodTest:end}'
|
192
|
+
parse(defn, :trackvar_def).should eq(defn)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'supports an optional initial value' do
|
196
|
+
defn = 'trackvar plateletLow {BloodTest:end} initially false'
|
197
|
+
parse(defn, :trackvar_def).should eq(defn)
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'supports optional obsolete events' do
|
201
|
+
defn = 'trackvar plateletLow {BloodTest:end}, {Chemotherapy:end}'
|
202
|
+
parse(defn, :trackvar_def).should eq(defn)
|
203
|
+
end
|
204
|
+
|
205
|
+
end # trackvar_def
|
206
|
+
|
207
|
+
describe 'the bool_expr rule' do
|
208
|
+
|
209
|
+
it 'parses single variable references' do
|
210
|
+
parse('diagKnown', :bool_expr).should eq('diagKnown')
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'parses boolean literals' do
|
214
|
+
parse('true', :bool_expr).should eq('true')
|
215
|
+
parse('false', :bool_expr).should eq('false')
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'parses negated expression' do
|
219
|
+
parse('not diagKnown', :bool_expr).should eq('not diagKnown')
|
220
|
+
parse('not true', :bool_expr).should eq('not true')
|
221
|
+
parse('not false', :bool_expr).should eq('not false')
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'parses or expressions' do
|
225
|
+
parse('diagKnown or platLow', :bool_expr).should eq('diagKnown or platLow')
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'parses and expressions' do
|
229
|
+
parse('diagKnown and platLow', :bool_expr).should eq('diagKnown and platLow')
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'parses complex expressions' do
|
233
|
+
expr = 'diagKnown and (platLow or not(metastased and mplus))'
|
234
|
+
parse(expr, :bool_expr).should eq(expr)
|
235
|
+
end
|
236
|
+
|
237
|
+
end # bool_expr
|
238
|
+
|
239
|
+
### Process statements
|
240
|
+
|
241
|
+
describe 'the par_statement rule' do
|
242
|
+
|
243
|
+
it 'parses a single parallel statement' do
|
244
|
+
expr = 'par Task1 Task2 end'
|
245
|
+
parse(expr, :par_statement).should eq(expr)
|
246
|
+
end
|
247
|
+
|
248
|
+
end # par_statement
|
249
|
+
|
250
|
+
describe 'the seq_statement rule' do
|
251
|
+
|
252
|
+
it 'parses a single sequence statement' do
|
253
|
+
expr = 'seq Task1 Task2 end'
|
254
|
+
parse(expr, :seq_statement).should eq(expr)
|
255
|
+
end
|
256
|
+
|
257
|
+
end # seq_statement
|
258
|
+
|
259
|
+
describe 'the while_statement rule' do
|
260
|
+
|
261
|
+
it 'parses a single while statement' do
|
262
|
+
expr = 'while badCond Task end'
|
263
|
+
parse(expr, :while_statement).should eq(expr)
|
264
|
+
end
|
265
|
+
|
266
|
+
end # while_statement
|
267
|
+
|
268
|
+
describe 'the if_statement rule' do
|
269
|
+
|
270
|
+
it 'parses a single if statement' do
|
271
|
+
expr = 'if goodCond Task end'
|
272
|
+
parse(expr, :if_statement).should eq(expr)
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'supports an optional else' do
|
276
|
+
expr = 'if goodCond GoodTask else BadTask end'
|
277
|
+
parse(expr, :if_statement).should eq(expr)
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'supports an optional elsif clauses' do
|
281
|
+
expr = 'if goodCond GoodTask elsif otherCond OtherTask elsif yetAnother BadTask end'
|
282
|
+
parse(expr, :if_statement).should eq(expr)
|
283
|
+
end
|
284
|
+
|
285
|
+
end # if_statement
|
286
|
+
|
287
|
+
describe 'the process_statement rule' do
|
288
|
+
|
289
|
+
it 'parses a simple process statement' do
|
290
|
+
expr = <<-PROCESS.strip
|
291
|
+
DoSomething
|
292
|
+
if goodCond
|
293
|
+
DoForGood
|
294
|
+
else
|
295
|
+
DoForBad
|
296
|
+
end
|
297
|
+
CleanDesk
|
298
|
+
PROCESS
|
299
|
+
parse(expr, :process_statement).should eq(expr)
|
300
|
+
end
|
301
|
+
|
302
|
+
end # process_statement
|
303
|
+
|
304
|
+
describe 'the task_def rule' do
|
305
|
+
|
306
|
+
it 'parses a simple task definition' do
|
307
|
+
taskdef = <<-TASKDEF.strip
|
308
|
+
task Process
|
309
|
+
refinement Diagnosis end
|
310
|
+
end
|
311
|
+
TASKDEF
|
312
|
+
parse(taskdef, :task_def).should eq(taskdef)
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'supports optional variable definitions in the signature' do
|
316
|
+
taskdef = <<-TASKDEF.strip
|
317
|
+
task Process
|
318
|
+
fluent diagKnown {Diagnosis:start}, {} initially false
|
319
|
+
trackvar mplus {Diagnosis:end}
|
320
|
+
refinement Diagnosis end
|
321
|
+
end
|
322
|
+
TASKDEF
|
323
|
+
parse(taskdef, :task_def).should eq(taskdef)
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
329
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Gisele::Language
|
3
|
+
describe Parser do
|
4
|
+
|
5
|
+
fixture_files('tasks/**/*.gis').each do |file|
|
6
|
+
if file.sub_ext(".ast").exist?
|
7
|
+
|
8
|
+
it "returns the expected ast on #{file}" do
|
9
|
+
parsed = Parser.parse(file)
|
10
|
+
expected = Kernel::eval(file.sub_ext(".ast").read, TOPLEVEL_BINDING, file.sub_ext(".ast").to_s)
|
11
|
+
parsed.should eq(expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
else
|
15
|
+
|
16
|
+
it "parses #{file} without error" do
|
17
|
+
parsed = Parser.parse(file)
|
18
|
+
parsed.should be_a(Array)
|
19
|
+
parsed.first.should eq(:task)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Installs a rake task for debuging the announcement mail.
|
2
|
+
#
|
3
|
+
# This file installs the 'rake debug_mail' that flushes an announcement mail
|
4
|
+
# for your library on the standard output. It is automatically generated
|
5
|
+
# by Noe from your .noespec file, and should therefore be configured there,
|
6
|
+
# under the variables/rake_tasks/debug_mail entry, as illustrated below:
|
7
|
+
#
|
8
|
+
# variables:
|
9
|
+
# rake_tasks:
|
10
|
+
# debug_mail:
|
11
|
+
# rx_changelog_sections: /^#/
|
12
|
+
# nb_changelog_sections: 1
|
13
|
+
# ...
|
14
|
+
#
|
15
|
+
# If you have specific needs requiring manual intervention on this file,
|
16
|
+
# don't forget to set safe-override to false in your noe specification:
|
17
|
+
#
|
18
|
+
# template-info:
|
19
|
+
# manifest:
|
20
|
+
# tasks/debug_mail.rake:
|
21
|
+
# safe-override: false
|
22
|
+
#
|
23
|
+
# The mail template used can be found in debug_mail.txt. That file may be
|
24
|
+
# changed to tune the mail you want to send. If you do so, don't forget to
|
25
|
+
# add a manifest entry in your .noespec file to avoid overriding you
|
26
|
+
# changes. The mail template uses wlang, with parentheses for block
|
27
|
+
# delimiters.
|
28
|
+
#
|
29
|
+
# template-info:
|
30
|
+
# manifest:
|
31
|
+
# tasks/debug_mail.txt:
|
32
|
+
# safe-override: false
|
33
|
+
#
|
34
|
+
desc "Debug the release announcement mail"
|
35
|
+
task :debug_mail do
|
36
|
+
begin
|
37
|
+
require 'wlang'
|
38
|
+
rescue LoadError
|
39
|
+
abort "wlang is not available. Try 'gem install wlang'"
|
40
|
+
end
|
41
|
+
require 'yaml'
|
42
|
+
|
43
|
+
# Check that a .noespec file exists
|
44
|
+
noespec_file = File.expand_path('../../gisele.noespec', __FILE__)
|
45
|
+
unless File.exists?(noespec_file)
|
46
|
+
raise "Unable to find .noespec project file, sorry."
|
47
|
+
end
|
48
|
+
|
49
|
+
# Load it as well as variables and options
|
50
|
+
noespec = YAML::load(File.read(noespec_file))
|
51
|
+
vars = noespec['variables'] || {}
|
52
|
+
|
53
|
+
# Changes are taken from CHANGELOG
|
54
|
+
logs = Dir[File.expand_path("../../CHANGELOG.*", __FILE__)]
|
55
|
+
unless logs.size == 1
|
56
|
+
abort "Unable to find a changelog file"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Load interesting changesets
|
60
|
+
changes, end_found = [], 0
|
61
|
+
File.readlines(logs.first).select{|line|
|
62
|
+
if line =~ /^# /
|
63
|
+
break if end_found >= 1
|
64
|
+
end_found += 1
|
65
|
+
end
|
66
|
+
changes << line
|
67
|
+
}
|
68
|
+
vars['changes'] = changes.join
|
69
|
+
|
70
|
+
# WLang template
|
71
|
+
template = File.expand_path('../debug_mail.txt', __FILE__)
|
72
|
+
|
73
|
+
# Let's go!
|
74
|
+
$stdout << WLang::file_instantiate(template, vars, "wlang/active-text")
|
75
|
+
end
|