tla-parser-s 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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +75 -0
  3. data/VERSION +1 -0
  4. data/bin/tla-resolver.rb +7 -0
  5. data/lib/cli/cli.rb +90 -0
  6. data/lib/parser/exception.rb +6 -0
  7. data/lib/parser/lvalue.rb +63 -0
  8. data/lib/parser/parser.rb +129 -0
  9. data/lib/parser/parser_nodes.rb +1063 -0
  10. data/lib/parser/parser_sexp.treetop +442 -0
  11. data/lib/semantics/context.rb +355 -0
  12. data/lib/semantics/exception.rb +13 -0
  13. data/lib/semantics/resolver.rb +327 -0
  14. data/lib/semantics/symbol_table.rb +139 -0
  15. data/lib/tla-parser-s.rb +15 -0
  16. data/lib/utils/logger.rb +80 -0
  17. data/lib/utils/syntax_node.rb +73 -0
  18. data/lib/utils/version.rb +13 -0
  19. data/spec/fixtures/callables1.tla +64 -0
  20. data/spec/fixtures/directives.tla +7 -0
  21. data/spec/fixtures/resolver1/comments.tla +1 -0
  22. data/spec/fixtures/resolver1/directives.cfg +6 -0
  23. data/spec/fixtures/resolver1/directives.tla +12 -0
  24. data/spec/fixtures/resolver1/empty.tla +0 -0
  25. data/spec/fixtures/resolver1/macro1.tla +3 -0
  26. data/spec/fixtures/resolver1/macro2.tla +3 -0
  27. data/spec/fixtures/resolver1/op1.tla +3 -0
  28. data/spec/fixtures/resolver1/op2.tla +3 -0
  29. data/spec/fixtures/resolver1/proc1.tla +4 -0
  30. data/spec/fixtures/resolver1/proc2.tla +7 -0
  31. data/spec/fixtures/resolver1/proc3.tla +4 -0
  32. data/spec/fixtures/resolver1/proc4.tla +4 -0
  33. data/spec/fixtures/resolver1/proc4_hide.tla +4 -0
  34. data/spec/fixtures/resolver1/proc5.tla +4 -0
  35. data/spec/fixtures/resolver1/proc6.tla +4 -0
  36. data/spec/fixtures/resolver1/proc7.tla +4 -0
  37. data/spec/fixtures/resolver1/stmt_assert.tla +8 -0
  38. data/spec/fixtures/resolver1/stmt_assign.tla +6 -0
  39. data/spec/fixtures/resolver1/stmt_assign2.tla +6 -0
  40. data/spec/fixtures/resolver1/stmt_cond.tla +13 -0
  41. data/spec/fixtures/resolver1/stmt_either.tla +12 -0
  42. data/spec/fixtures/resolver1/stmt_print.tla +5 -0
  43. data/spec/fixtures/resolver1/var4.tla +1 -0
  44. data/spec/fixtures/resolver1/var5.tla +1 -0
  45. data/spec/fixtures/resolver1/var_choose_except.tla +2 -0
  46. data/spec/fixtures/resolver1/var_quantify.tla +4 -0
  47. data/spec/fixtures/resolver1/var_rec_except.tla +4 -0
  48. data/spec/fixtures/resolver1/var_rec_expr.tla +3 -0
  49. data/spec/fixtures/resolver1/var_record.tla +2 -0
  50. data/spec/fixtures/resolver1/var_seq.tla +1 -0
  51. data/spec/fixtures/resolver1/var_set.tla +1 -0
  52. data/spec/fixtures/resolver1/var_set_expr_map.tla +1 -0
  53. data/spec/fixtures/resolver1/var_x.tla +1 -0
  54. data/spec/fixtures/resolver1/variables.tla +4 -0
  55. data/spec/parser/parser_fixtures_spec.rb +117 -0
  56. data/spec/parser/parser_spec.rb +1649 -0
  57. data/spec/semantics/context_spec.rb +392 -0
  58. data/spec/semantics/resolver_spec.rb +364 -0
  59. data/spec/semantics/symbol_table_spec.rb +144 -0
  60. data/spec/spec_helper.rb +5 -0
  61. data/tla-parser-s.gemspec +41 -0
  62. metadata +153 -0
@@ -0,0 +1,4 @@
1
+ var_rec_except = [ var5 EXCEPT ![id] = op1, ![uid] = @ ]
2
+
3
+
4
+
@@ -0,0 +1,3 @@
1
+ var_rec_expr = var4.a[op1]
2
+
3
+
@@ -0,0 +1,2 @@
1
+ var_record = [ id |-> var5 ]
2
+
@@ -0,0 +1 @@
1
+ var_seq = << op1, op2 >>
@@ -0,0 +1 @@
1
+ var_set = { op1 }
@@ -0,0 +1 @@
1
+ var_set_expr_map = { x.id : x \in var4 }
@@ -0,0 +1 @@
1
+ x = 1
@@ -0,0 +1,4 @@
1
+ var1 = op1
2
+
3
+ var2 = {}
4
+
@@ -0,0 +1,117 @@
1
+ require_relative "../spec_helper"
2
+
3
+ describe TlaParserS::Parser do
4
+
5
+
6
+ let ( :parser ) { described_class.new }
7
+
8
+ describe "Fixture 1: callables1.tla" do
9
+
10
+ file = "#{FIXTURE_ROOT}/callables1.tla"
11
+ let ( :tree ) { parser.parse( File.new(file) ) }
12
+
13
+
14
+
15
+ it "#defines" do
16
+ # puts ""
17
+ # puts tree.inspect
18
+ expect( tree.defines.length ).to eql( 10 )
19
+ end # it
20
+
21
+ it "#callables" do
22
+ # puts ""
23
+ # puts tree.inspect
24
+ expect( tree.callables.length ).to eql( 7 )
25
+ end # it
26
+
27
+ context "variables" do
28
+ let (:variable_nodes) { tree.recursive_select( Sexp::VariableDef ) }
29
+
30
+ it "#number of variable definitions" do
31
+ expect( variable_nodes.length ).to eql( 3 )
32
+ end # it
33
+
34
+ it "#identifiers" do
35
+ expect( variable_nodes.map { |m| m.name } ).to eql( ["a", "b", "c" ] )
36
+ end # it
37
+
38
+
39
+ end
40
+
41
+ context "macros" do
42
+
43
+ let (:macro_nodes) { tree.recursive_select( Sexp::Macro ) }
44
+
45
+ it "#number of macro definitions" do
46
+ expect( macro_nodes.length ).to eql( 2 )
47
+ end # it
48
+
49
+ it "#identifiers" do
50
+ expect( macro_nodes.map { |m| m.name } ).to eql( ["macroid1", "macroid2" ] )
51
+ end # it
52
+
53
+ context "first macro" do
54
+ let ( :macro_node ) { macro_nodes[0] }
55
+
56
+ it "Parameter identifiers" do
57
+ expect( macro_node.parameters_node.identifier_nodes.map{ |i| i.node_value } ).to eql( ["m1_p1","m1_p2"] )
58
+ end # it
59
+
60
+
61
+ end
62
+
63
+
64
+ end # context "macros" do
65
+
66
+ context "operators" do
67
+
68
+ let (:operator_nodes) { tree.recursive_select( Sexp::OperatorDef ) }
69
+
70
+ it "#number of operator definitions" do
71
+ expect( operator_nodes.length ).to eql( 2 )
72
+ end # it
73
+
74
+ it "#identifiers" do
75
+ expect( operator_nodes.map { |m| m.name } ).to eql( ["ItWorks", "ItCalls" ] )
76
+ end # it
77
+ end # context "operators" do
78
+
79
+ context "procedures" do
80
+
81
+ let (:procedure_nodes) { tree.recursive_select( Sexp::Procedure ) }
82
+
83
+ it "#number of operator definitions" do
84
+ expect( procedure_nodes.length ).to eql( 3 )
85
+ end # it
86
+
87
+ it "#identifiers" do
88
+ expect( procedure_nodes.map { |m| m.name } ).to eql( ["proc0", "proc1", "proc2" ] )
89
+ end # it
90
+ end # context "operators" do
91
+
92
+
93
+
94
+ end # describe "directives"
95
+
96
+ describe "Fixture 2: directives.tla" do
97
+
98
+ file = "#{FIXTURE_ROOT}/directives.tla"
99
+ let ( :tree ) { parser.parse( File.new(file) ) }
100
+
101
+ it "#directives" do
102
+ # puts ""
103
+ # puts tree.inspect
104
+ expect( tree.directives.length ).to eql( 4 )
105
+ end # it
106
+
107
+ it "#directive definitision" do
108
+ # puts ""
109
+ # puts tree.inspect
110
+ expect( tree.directive_definitions ).to eql( ["Assume_Domains","a2", "a3", "i1", "i2", "i3" ] )
111
+ end # it
112
+
113
+
114
+ end
115
+
116
+
117
+ end
@@ -0,0 +1,1649 @@
1
+ require_relative "../spec_helper"
2
+
3
+ describe TlaParserS::Parser do
4
+
5
+ let ( :parser ) { described_class.new }
6
+
7
+ # parse 'str' and extract array of node value of type 'klass'
8
+ # @param str [String] to parse
9
+ # @param start [symbol] treep grammar non-terminal to start iwth
10
+ def parse_nodes( str, start )
11
+ # parser.parse( str, start ).recursive_select( klass ).map { |n| n.value }
12
+ # parser.parse( str, start ).map { |n| n.value }
13
+ parser.parse( str, start ).value
14
+ end
15
+
16
+ # ------------------------------------------------------------------
17
+ # Visitor for statements
18
+
19
+ def statement_value( node_type, node )
20
+
21
+ case node_type
22
+ when "Statement"
23
+ "#{node.statement_label}: "
24
+
25
+ when "Skip"
26
+ "skip"
27
+ when "Return"
28
+ "return"
29
+
30
+ when "Goto"
31
+ "goto #{node.goto_label}"
32
+
33
+ when "Conditional"
34
+ # eval confition
35
+ condition = node.condition.traverse { |m, node_type, enode, node_val | m.concat( expression_value(node_type, enode, node_val)) }
36
+
37
+ # eval if -branch
38
+ true_stmts = node.if_true.traverse do |memo,node_type, node|
39
+ memo.concat( statement_value( node_type, node ))
40
+ end
41
+
42
+ # default else empty
43
+ else_stmts = nil
44
+ else_stmts = node.if_not_true.traverse do |memo,node_type, node|
45
+ memo.concat( statement_value( node_type, node ))
46
+ end if node.if_not_true
47
+
48
+
49
+ "if ( #{condition} ) #{true_stmts}#{ else_stmts ? ' else ' + else_stmts : '' }"
50
+
51
+ when "Either"
52
+
53
+ statements = []
54
+ # iterate all statemens in and collect an rray
55
+ node.choices.each do |s|
56
+ statements << s.traverse do |memo,node_type, node|
57
+ memo.concat( statement_value( node_type, node ))
58
+ end
59
+ end
60
+
61
+ "either #{statements.first} or #{statements[1..-1].join( " or " )}"
62
+ when "Print"
63
+ print_expression = node.print_expression && node.print_expression.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val)) }
64
+ "print #{print_expression}"
65
+ when "Assert"
66
+ assertion = node.assertion.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val)) }
67
+ "assert( #{assertion} )"
68
+
69
+ when "Assignment"
70
+ lvalue = node.lvalue.recurse_lvalue()
71
+ rvalue = node.rvalue.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val)) }
72
+ "#{lvalue}:=#{rvalue}"
73
+ when "CompoundStatement"
74
+ statements = []
75
+ # iterate all statemens in and collect an rray
76
+ node.statements.each do |s|
77
+ statements << s.traverse(""){ |memo,node_type, node|
78
+ memo.concat( statement_value( node_type, node ))
79
+ }
80
+ end
81
+ "{#{statements.map {|s| s + ";\n" }.join }}"
82
+ when "Call", "MacroCall"
83
+ # evaluate expression to collect actual parameters
84
+ actual_paramters = []
85
+ node.actual_parameters.each do |expr_node|
86
+ actual_paramters << expr_node.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val)) }
87
+ end
88
+ "#{node_type == 'Call' ? 'call ' : '' }#{node.called}(#{actual_paramters.join(',')})"
89
+ else
90
+ raise "Unknwon expression node type #{node_type} for node #{node}"
91
+ end
92
+ end
93
+
94
+ # ------------------------------------------------------------------
95
+ # Visitor for expresssion
96
+
97
+ # @param node_type [String] AST node type
98
+ # @param node [SyntaxNode] current AST node being traversed
99
+ # @param node_val [String] prefix,infix, postfix value overridded in `AbstactExpression`
100
+ # @return [String] value for traversing the node
101
+ def expression_value( node_type, node, node_val )
102
+ # puts( "#{__method__} entered node_type=#{node_type}, node_val=#{node_val}, parent=#{node.parent.node_type}" )
103
+ case node_type
104
+ when "AdditiveExpression", "MultitiveExpression", "UnaryExpression", "ParenthesisExpression",
105
+ "Identifier", "RecordField", "StringValue", "OriginalValue"
106
+ node_val
107
+ when "PrimaryExpression"
108
+ accessors=[]
109
+ node.attribute_accessors && node.attribute_accessors.each do |identfier|
110
+ attribute = identfier.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
111
+ accessors << attribute
112
+ end
113
+ ret = accessors.join('')
114
+ ret
115
+ when "FieldByName"
116
+ ".#{node_val}"
117
+ when "FieldByValue"
118
+ ret = "[#{node_val}]"
119
+ # puts "FieldByValue=>#{ret}"
120
+ ret
121
+ when "RecordExcept"
122
+ elements=[]
123
+ node.record_field_definitions && node.record_field_definitions.each_with_index do |field_node,i|
124
+ lvalue_expression = field_node.lvalue_expression.recurse_lvalue
125
+ rvalue_expression = field_node.rvalue_expression.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
126
+ elements << "#{lvalue_expression}=#{rvalue_expression}"
127
+ end
128
+ ret = "[#{node.record_identifier} EXCEPT #{elements.join(',')}]"
129
+ # puts "RecordExcept=>#{ret}"
130
+ ret
131
+ when "RecordDefinition"
132
+ elements=[]
133
+ node.record_fields.each do |field|
134
+ element_name = field.element_name.node_value
135
+ element_value = field.element_expression.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
136
+ elements << "#{element_name}|->#{element_value}"
137
+ end
138
+ "[#{elements.join(',')}]"
139
+ when "SetExpressionMap"
140
+ "#{node_val}"
141
+
142
+ bind_var = nil
143
+ bind_set = nil
144
+
145
+ set_expression = node.set_expression && node.set_expression.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
146
+
147
+ bind_set = node.binds_node && node.binds_node.bind_set.traverse { |m, node_type, enode, node_val | m.concat( expression_value(node_type, enode, node_val)) }
148
+ bind_var = node.binds_node && node.binds_node.bind_var.node_value
149
+ # puts "SetExpression: bind_var=#{bind_var}"
150
+
151
+ return "{#{set_expression}: #{bind_var} \\in #{bind_set}}"
152
+
153
+ when "SetExpression"
154
+ set_expression = nil
155
+ bind_var = nil
156
+ bind_set = nil
157
+
158
+ if node.set_expression then
159
+ set_expression = node.set_expression.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
160
+ # puts "SetExpression: set_expression=#{set_expression}"
161
+ end
162
+
163
+ if node.binds_node then
164
+ bind_set = node.binds_node.bind_set.traverse { |m, node_type, enode, node_val | m.concat( expression_value(node_type, enode, node_val)) }
165
+ # puts "SetExpression: bind_set=#{bind_set}"
166
+ bind_var = node.binds_node.bind_var.node_value
167
+ # puts "SetExpression: bind_var=#{bind_var}"
168
+ end
169
+
170
+ if bind_var && set_expression
171
+ return "{ #{bind_var} \\in #{bind_set} : #{ set_expression} }"
172
+ elsif set_expression
173
+ return "{#{ set_expression}}"
174
+ else
175
+ "{}"
176
+ end
177
+ when "SequenceExpression"
178
+ tuples=[]
179
+ node.tuples.each { |tuple|
180
+ tuples << tuple.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
181
+ }
182
+
183
+ "<<#{tuples.join(',')}>>"
184
+ when "OperatorExpression"
185
+
186
+ arguments=[]
187
+ node.arguments.each { |arg|
188
+ arguments << arg.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
189
+ }
190
+ record_field = node.record_field
191
+
192
+ "#{node_val}(#{arguments.join(',')})#{ record_field ? "." + record_field : ''}"
193
+
194
+ when "ChooseExpression"
195
+ bind_set = node.binds_node.bind_set.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
196
+ bind_var = node.binds_node.bind_var.node_value
197
+ choose_expression = node.choose_expression.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
198
+
199
+ "CHOOSE #{bind_var} \\in #{bind_set}: #{choose_expression}"
200
+ when "QuantifyExpression"
201
+ binds = []
202
+ node.binds_nodes.each { |b|
203
+ bind_set = b.bind_set.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
204
+ bind_var = b.bind_var.node_value
205
+ binds << "#{bind_var} \\in #{bind_set}"
206
+ }
207
+ # manually traverse quantified expression
208
+ quantified_expression = node.quantified_expression.traverse { |m, node_type, enode, node_val| m.concat( expression_value(node_type, enode, node_val )) }
209
+ "#{node_val} #{binds.join(', ')} : #{quantified_expression}"
210
+ when "IntegerValue"
211
+ "#{node_val}"
212
+ else
213
+ raise "Unknwon expression node type #{node_type} with value #{node_val}"
214
+ end
215
+ end
216
+
217
+
218
+ # ------------------------------------------------------------------
219
+ # interface
220
+ describe "interface" do
221
+
222
+ describe "static" do
223
+
224
+ it "#version" do
225
+ expect( described_class ).to respond_to( :version )
226
+ end
227
+ end # static
228
+
229
+ end
230
+
231
+ # ------------------------------------------------------------------
232
+ # parse
233
+ describe "parse" do
234
+
235
+
236
+
237
+ context "egde-case" do
238
+
239
+ it "#returns nil for nil input" do
240
+ expect( parser.parse( nil )).to eql( nil )
241
+ end
242
+
243
+ end
244
+
245
+
246
+ # ---------------------------------
247
+ # ReservedWords
248
+
249
+ describe "ReservedWord" do
250
+
251
+ [
252
+ "ASSUME", "ELSE", "LOCAL", "UNION", "ASSUMPTION", "ENABLED",
253
+ "MODULE", "VARIABLE", "AXIOM", "EXCEPT", "OTHER",
254
+ "VARIABLES", "CASE", "EXTENDS", "SF_", "WF_", "CHOOSE",
255
+ "IF", "SUBSET", "WITH", "CONSTANT", "IN", "THEN",
256
+ "CONSTANTS" , "INSTANCE", "THEOREM", "COROLLARY", "DOMAIN",
257
+ "LET", "UNCHANGED", "BY", "HAVE", "QED", "TAKE", "DEF",
258
+ "HIDE", "RECURSIVE", "USE", "DEFINE", "PROOF", "WITNESS",
259
+ "PICK", "DEFS", "PROVE", "SUFFICES", "NEW", "LAMBDA",
260
+ "STATE", "ACTION", "TEMPORAL", "OBVIOUS", "OMITTED",
261
+ "ONLY",
262
+ "LEMMA", "PROPOSITION",
263
+ ].each do |word|
264
+ it "#ReservedWord #{word}" do
265
+ expect( parse_nodes( word, :reserved_word ) ).to eql( { :node_type => "ReservedWord", :value => word } )
266
+ end
267
+ end # each
268
+
269
+ end # describe reservedWord
270
+
271
+ # ------------------------------------------------------------------
272
+ # Common cases
273
+
274
+ describe "Common" do
275
+ [
276
+
277
+ # ------------------------------------------------------------------
278
+ # String
279
+ {
280
+ :str => '"string value"',
281
+ :desc => "String value in double quotes",
282
+ :start => :string,
283
+ :exception => nil,
284
+ :expect => { :node_type => "StringValue", :value => '"string value"' },
285
+ },
286
+
287
+ # ------------------------------------------------------------------
288
+ # Integer
289
+
290
+ {
291
+ :str => "139",
292
+ :desc => "Positive integer",
293
+ :start => :integer,
294
+ :expect => { :node_type => "IntegerValue", :value => 139 },
295
+ },
296
+ {
297
+ :str => "+140",
298
+ :desc => "Positive integer, prefix +",
299
+ :start => :integer,
300
+ :expect => { :node_type => "IntegerValue", :value => 140 },
301
+ },
302
+ {
303
+ :str => "-141",
304
+ :desc => "Negative integer, prefix -",
305
+ :start => :integer,
306
+ :expect => { :node_type => "IntegerValue", :value => -141 },
307
+ },
308
+
309
+ # ------------------------------------------------------------------
310
+ # Identifiers
311
+
312
+ {
313
+ :str => "tst",
314
+ :desc => "Simple case for identifier",
315
+ :start => :identifier,
316
+ :expect => { :node_type => "Identifier", :value => "tst" },
317
+ },
318
+ {
319
+ :str => "id1,
320
+ id2",
321
+ :desc => "Identifier list",
322
+ :start => :identifier_list,
323
+ :expect => {
324
+ :node_type => "IdentifierList",
325
+ :value => [{ :node_type => "Identifier", :value => "id1" }, { :node_type => "Identifier", :value => "id2" }] }
326
+ },
327
+
328
+ # ------------------------------------------------------------------
329
+ # Keywords
330
+
331
+
332
+ {
333
+ :str => "OTHER",
334
+ :desc => "Reserved word is not an identifier",
335
+ :start => :identifier,
336
+ :exception => "Expected one of",
337
+ :expect => nil,
338
+ },
339
+ {
340
+ :str => "OTHER",
341
+ :desc => "Reserved word parse",
342
+ :start => :reserved_word,
343
+ :expect => { :node_type => "ReservedWord", :value => "OTHER" },
344
+ },
345
+
346
+
347
+ ].each_with_index do |testCase,i|
348
+
349
+
350
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
351
+
352
+ if ( testCase[:debug] )
353
+ tree = parser.parse( testCase[:str], testCase[:start] )
354
+ puts ""
355
+ puts tree.inspect
356
+ end
357
+
358
+ if testCase[:exception] then
359
+ expect { parse_nodes( testCase[:str], testCase[:start] ) }.to raise_exception TlaParserS::ParseException, %r<#{testCase[:exception]}>
360
+ else
361
+ expect( parse_nodes( testCase[:str], testCase[:start] ) ).to eql( testCase[:expect] )
362
+ end
363
+ end
364
+
365
+
366
+ end # each
367
+
368
+ end # common
369
+
370
+
371
+
372
+ end # describe "parse" do
373
+
374
+
375
+ # ------------------------------------------------------------------
376
+ # Version
377
+ describe "version" do
378
+ it "#is string" do
379
+ expect( described_class.version ).to be_a( String )
380
+ end
381
+
382
+ end
383
+
384
+ # ------------------------------------------------------------------
385
+ # statement
386
+
387
+ describe "Statements" do
388
+
389
+ [
390
+ {
391
+ :str => "skip",
392
+ :desc => "Skip",
393
+ :debug => false,
394
+ :start => :statement,
395
+ :exception => nil,
396
+ :expect => "skip",
397
+ },
398
+
399
+
400
+ {
401
+ :str => "l1: skip",
402
+ :desc => "Skip with label",
403
+ :debug => false,
404
+ :start => :statement,
405
+ :exception => nil,
406
+ :expect => "l1: skip",
407
+ },
408
+
409
+
410
+ {
411
+ :str => "goto goto_label",
412
+ :desc => "Unlabeled goto",
413
+ :debug => false,
414
+ :start => :statement,
415
+ :exception => nil,
416
+ :expect => "goto goto_label",
417
+ },
418
+
419
+ {
420
+ :str => "assert TRUE",
421
+ :desc => "Assert expression",
422
+ :debug => false,
423
+ :start => :statement,
424
+ :exception => nil,
425
+ :expect => "assert( TRUE )",
426
+ },
427
+
428
+ {
429
+ :str => "l1: goto leibel",
430
+ :desc => "Labeled goto",
431
+ :debug => false,
432
+ :start => :statement,
433
+ :exception => nil,
434
+ :expect => "l1: goto leibel",
435
+ },
436
+
437
+ {
438
+ :str => "call proc( )",
439
+ :desc => "Call procedure, no paramters",
440
+ :debug => false,
441
+ :start => :statement,
442
+ :exception => nil,
443
+ :expect => "call proc()",
444
+ },
445
+
446
+ {
447
+ :str => "call proc( 1 )",
448
+ :desc => "Call procedure, 1 integer",
449
+ :debug => false,
450
+ :start => :statement,
451
+ :exception => nil,
452
+ :expect => "call proc(1)",
453
+ },
454
+
455
+
456
+ {
457
+ :str => "call proc( 2 , 3 )",
458
+ :desc => "Call procedure, 2 integers",
459
+ :debug => false,
460
+ :start => :statement,
461
+ :exception => nil,
462
+ :expect => "call proc(2,3)",
463
+ },
464
+
465
+ {
466
+ :str => "call proc( 2 , 3+c * 4, ( 1*8) )",
467
+ :desc => "Call procedure, three expressions",
468
+ :debug => false,
469
+ :start => :statement,
470
+ :exception => nil,
471
+ :expect => "call proc(2,3+c*4,(1*8))",
472
+ },
473
+
474
+ {
475
+ :str => "{}",
476
+ :desc => "Empty Compound statement",
477
+ :debug => false,
478
+ :start => :statement,
479
+ :exception => nil,
480
+ :expect => "{}",
481
+ },
482
+
483
+ {
484
+ :str => "{ skip; }",
485
+ :desc => "Compound statement with skip",
486
+ :debug => false,
487
+ :start => :statement,
488
+ :exception => nil,
489
+ :expect => "{skip;\n}",
490
+ },
491
+
492
+ {
493
+ :str => "{ l1: skip; }",
494
+ :desc => "Compound statement with label",
495
+ :debug => false,
496
+ :start => :statement,
497
+ :exception => nil,
498
+ :expect => "{l1: skip;\n}",
499
+ },
500
+
501
+ {
502
+ :str => "{ l1before_comment:
503
+ (* This is a comment *)
504
+ skip;
505
+ }",
506
+ :desc => "Comment after a label",
507
+ :debug => false,
508
+ :start => :statement,
509
+ :exception => nil,
510
+ :expect => "{l1before_comment: skip;\n}",
511
+ },
512
+
513
+ {
514
+ :str => '{ l2before_comment:
515
+
516
+ \* Comment
517
+
518
+ skip;
519
+ }',
520
+ :desc => "Comment after a label",
521
+ :debug => false,
522
+ :start => :statement,
523
+ :exception => nil,
524
+ :expect => "{l2before_comment: skip;\n}",
525
+ },
526
+
527
+ {
528
+ :str => '{ skip;
529
+
530
+ (* comment*)
531
+
532
+ \* Comment
533
+
534
+ skip;
535
+ }',
536
+ :desc => "Two comments",
537
+ :debug => false,
538
+ :start => :statement,
539
+ :exception => nil,
540
+ :expect => "{skip;\nskip;\n}",
541
+ },
542
+
543
+ {
544
+ :str => "{ return; }",
545
+ :desc => "Return statement",
546
+ :debug => false,
547
+ :start => :statement,
548
+ :exception => nil,
549
+ :expect => "{return;\n}",
550
+ },
551
+
552
+
553
+ {
554
+ :str => '{ l0: skip;
555
+ l1: goto l0;}',
556
+ :desc => "Compound statement with two statemenets",
557
+ :debug => false,
558
+ :start => :statement,
559
+ :exception => nil,
560
+ :expect => "{l0: skip;\nl1: goto l0;\n}",
561
+ },
562
+ {
563
+ :str => '{
564
+ if ( TRUE )
565
+ skip;
566
+ return;
567
+ }',
568
+ :desc => "if-no else within compound",
569
+ :debug => false,
570
+ :start => :statement,
571
+ :exception => nil,
572
+ :expect => "{if ( TRUE ) skip;\nreturn;\n}",
573
+ },
574
+
575
+
576
+
577
+ {
578
+ :str => '{
579
+ if ( TRUE ) {
580
+ skip;
581
+ };
582
+ return;
583
+ }',
584
+ :desc => "Compound statement with if-no else",
585
+ :debug => false,
586
+ :start => :statement,
587
+ :exception => nil,
588
+ :expect => "{if ( TRUE ) {skip;\n};\nreturn;\n}",
589
+ },
590
+
591
+
592
+ {
593
+ :str => "either skip or goto l1",
594
+ :desc => "Either or (simple)",
595
+ :debug => false,
596
+ :start => :statement,
597
+ :exception => nil,
598
+ :expect => "either skip or goto l1",
599
+ },
600
+
601
+ {
602
+ :str => "either { skip; goto l1;} or goto l8",
603
+ :desc => "Either or (compouund)",
604
+ :debug => false,
605
+ :start => :statement,
606
+ :exception => nil,
607
+ :expect => "either {skip;\ngoto l1;\n} or goto l8",
608
+ },
609
+
610
+ {
611
+ :str => "if (TRUE) skip",
612
+ :desc => "Simplest if-then",
613
+ :debug => false,
614
+ :start => :statement,
615
+ :exception => nil,
616
+ :expect => "if ( TRUE ) skip",
617
+ },
618
+
619
+ {
620
+ :str => "if (TRUE) { skip; skip; } else goto muualle ",
621
+ :desc => "Simplest if-then-else",
622
+ :debug => false,
623
+ :start => :statement,
624
+ :exception => nil,
625
+ :expect => "if ( TRUE ) {skip;\nskip;\n} else goto muualle",
626
+ },
627
+
628
+ {
629
+ :str => 'if ( TRUE ) { skip; } else { skip; }',
630
+ :desc => "If-then(single)-else(compound)",
631
+ :debug => false,
632
+ :start => :statement,
633
+ :exception => nil,
634
+ :expect => "if ( TRUE ) {skip;\n} else {skip;\n}",
635
+ },
636
+
637
+
638
+ {
639
+ :str => "macro1( )",
640
+ :desc => "macro call",
641
+ :debug => false,
642
+ :start => :statement,
643
+ :exception => nil,
644
+ :expect => "macro1()",
645
+ },
646
+
647
+ {
648
+ :str => "macro2( 1,A )",
649
+ :desc => "macro call with actual parameters",
650
+ :debug => false,
651
+ :start => :statement,
652
+ :exception => nil,
653
+ :expect => "macro2(1,A)",
654
+ },
655
+
656
+ {
657
+ :str => "print 1",
658
+ :desc => "Print expression",
659
+ :debug => false,
660
+ :start => :statement,
661
+ :exception => nil,
662
+ :expect => "print 1",
663
+ },
664
+
665
+
666
+ {
667
+ :str => "a := 1",
668
+ :desc => "Assignment statement",
669
+ :debug => false,
670
+ :start => :statement,
671
+ :exception => nil,
672
+ :expect => "a:=1",
673
+ },
674
+
675
+ {
676
+ :str => "A.b := 43",
677
+ :desc => "Assignment rec.field",
678
+ :debug => false,
679
+ :start => :statement,
680
+ :exception => nil,
681
+ :expect => "A.b:=43",
682
+ },
683
+
684
+ {
685
+ :str => "Apu[beetta] := 44",
686
+ :desc => "Assignment rec[name]",
687
+ :debug => false,
688
+ :start => :statement,
689
+ :exception => nil,
690
+ :expect => "Apu[beetta]:=44",
691
+ },
692
+
693
+ ].each_with_index do |testCase,i|
694
+
695
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
696
+
697
+
698
+ tree = parser.parse( testCase[:str], testCase[:start] )
699
+ if ( testCase[:debug] )
700
+ puts ""
701
+ puts tree.inspect
702
+ end
703
+
704
+ result = tree.traverse( "" ) do |memo, node_type, node |
705
+ # memo collect the string
706
+ memo.concat( statement_value( node_type, node ))
707
+ end
708
+
709
+ expect( result ).to eql( testCase[:expect] )
710
+ end
711
+ end
712
+
713
+ end # statement
714
+
715
+
716
+ describe "Misc" do
717
+
718
+ describe "Newline" do
719
+
720
+ it "#newline" do
721
+ str = "\n"
722
+ expect = {:node_type=>"SyntaxNode", :value =>"\n" }
723
+ tree = parser.parse( str, :newline )
724
+ # puts
725
+ # puts tree.inspect
726
+ expect( tree.value ).to eql( expect )
727
+ end
728
+
729
+ end
730
+
731
+ describe "comments" do
732
+
733
+ it "#line comment without newline" do
734
+ str = '\* comment '
735
+ expect = {:node_type=>"SyntaxNode", :value=> str }
736
+ tree = parser.parse( str, :comment )
737
+ # puts
738
+ # puts tree.inspect
739
+ expect( tree.value ).to eql( expect )
740
+ end
741
+ it "#line comment with newline" do
742
+ str = "\\* commentti \n"
743
+ expect = {:node_type=>"SyntaxNode", :value=> str }
744
+ tree = parser.parse( str, :comment )
745
+ # puts
746
+ # puts tree.inspect
747
+ expect( tree.value ).to eql( expect )
748
+ end
749
+ it "#block comment without newline" do
750
+ str = '(* comment *) '
751
+ expect = {:node_type=>"SyntaxNode", :value=> str }
752
+ tree = parser.parse( str, :comment )
753
+ # puts
754
+ # puts tree.inspect
755
+ expect( tree.value ).to eql( expect )
756
+ end
757
+
758
+ it "#block comment with newline" do
759
+ str = "(* comment \n line 2 *)"
760
+ expect = {:node_type=>"SyntaxNode", :value=> str }
761
+ tree = parser.parse( str, :comment )
762
+ # puts
763
+ # puts tree.inspect
764
+ expect( tree.value ).to eql( expect )
765
+ end
766
+
767
+ end
768
+
769
+ end # misc
770
+
771
+ # ------------------------------------------------------------------
772
+ # Macro
773
+
774
+ describe "macro" do
775
+
776
+ context "testCases" do
777
+
778
+ [
779
+ {
780
+ :str => "macro id(){}",
781
+ :desc => "Macro 1 ",
782
+ :start => :macro,
783
+ :exception => nil,
784
+ :debug => false,
785
+ :expect => true,
786
+ },
787
+
788
+ {
789
+ :str => "macro id () {}",
790
+ :desc => "Macro 1 ",
791
+ :start => :macro,
792
+ :exception => nil,
793
+ :debug => false,
794
+ :expect => true,
795
+ },
796
+
797
+ {
798
+ :str => "macro id (a) {}",
799
+ :desc => "Macro 1 ",
800
+ :start => :macro,
801
+ :exception => nil,
802
+ :debug => false,
803
+ :expect => true,
804
+ },
805
+
806
+ ].each_with_index do |testCase,i|
807
+
808
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
809
+
810
+
811
+ tree = parser.parse( testCase[:str], testCase[:start] )
812
+ if ( testCase[:debug] )
813
+ puts ""
814
+ puts tree.inspect
815
+ end
816
+ expect( tree ).not_to eql( nil ) if testCase[:expect]
817
+
818
+ end # it
819
+ end # each
820
+
821
+ end # testCases
822
+
823
+
824
+
825
+ str = "macro id(a, b){skip;}"
826
+ let ( :tree ) { parser.parse( str, :macro ) }
827
+
828
+ it "#name" do
829
+ expect = {}
830
+ # puts
831
+ # puts tree.inspect
832
+ expect( tree.name ).to eql( "id" )
833
+ end
834
+
835
+ it "#parameters" do
836
+ expect = {:node_type=>"Parameters", :value=>[{:node_type=>"Identifier", :value=>"a"}, {:node_type=>"Identifier", :value=>"b"}]}
837
+ # puts
838
+ # puts tree.inspect
839
+ expect( tree ).to respond_to( :parameters )
840
+ expect( tree.parameters ).to eql( expect )
841
+ end
842
+
843
+ it "#symbol_definitions" do
844
+ parameters = tree.parameters[:value]
845
+ symbol_definitions = tree.symbol_definitions
846
+ # TODO add local parameters here
847
+ expect( symbol_definitions ).to eql( parameters )
848
+ end
849
+
850
+ it "#body" do
851
+ expect = "{skip;\n}"
852
+ # puts
853
+ # puts tree.inspect
854
+ result = tree.body_node.traverse do |memo, node_type, node |
855
+ # memo collect the string
856
+ memo.concat( statement_value( node_type, node ))
857
+ end
858
+ expect( result ).to eql( expect )
859
+ end
860
+ end # macro
861
+
862
+ # ------------------------------------------------------------------
863
+ # expression
864
+
865
+ describe "expression" do
866
+
867
+ [
868
+ {
869
+ :str => "1 ",
870
+ :desc => "Integer value",
871
+ :start => :expression,
872
+ :debug => false,
873
+ :expect => "1",
874
+ },
875
+
876
+ {
877
+ :str => "+ 1",
878
+ :desc => "Unary operator ",
879
+ :start => :expression,
880
+ :debug => false,
881
+ :expect => "+1",
882
+ },
883
+
884
+ {
885
+ :str => "~ TRUE",
886
+ :desc => "Not operator ",
887
+ :start => :expression,
888
+ :debug => false,
889
+ :expect => "~TRUE",
890
+ },
891
+
892
+ {
893
+ :str => "~TRUE",
894
+ :desc => "Not operator no spaces",
895
+ :start => :expression,
896
+ :debug => false,
897
+ :expect => "~TRUE",
898
+ },
899
+
900
+ {
901
+ :str => "- 1",
902
+ :desc => "Unary operator ",
903
+ :start => :expression,
904
+ :debug => false,
905
+ :expect => "-1",
906
+ },
907
+
908
+ {
909
+ :str => "A ",
910
+ :desc => "Simple indentifier",
911
+ :start => :expression,
912
+ :debug => false,
913
+ :expect => "A",
914
+ },
915
+
916
+ {
917
+ :str => "1 + 3 ",
918
+ :desc => "Addition",
919
+ :start => :expression,
920
+ :debug => false,
921
+ :expect => "1+3",
922
+ },
923
+
924
+ {
925
+ :str => "1 \\/ 3 ",
926
+ :desc => "TLA or",
927
+ :start => :expression,
928
+ :debug => false,
929
+ :expect => '1\/3',
930
+ },
931
+
932
+ {
933
+ :str => 'A /\\ B \\/ C',
934
+ :desc => "TLA or",
935
+ :start => :expression,
936
+ :debug => false,
937
+ :expect => 'A/\B\/C',
938
+ },
939
+
940
+ {
941
+ :str => "1 - 3 ",
942
+ :desc => "Minus",
943
+ :start => :expression,
944
+ :debug => false,
945
+ :expect => "1-3",
946
+ },
947
+
948
+ {
949
+ :str => "1 / 3 ",
950
+ :desc => "Divide",
951
+ :start => :expression,
952
+ :debug => false,
953
+ :expect => "1/3",
954
+ },
955
+
956
+ {
957
+ :str => "1 *6 ",
958
+ :desc => "Multiplication",
959
+ :start => :expression,
960
+ :debug => false,
961
+ :expect => "1*6",
962
+ },
963
+
964
+ {
965
+ :str => "-1 * +6 ",
966
+ :desc => "Unary operators in expression" ,
967
+ :start => :expression,
968
+ :debug => false,
969
+ :expect => "-1*+6",
970
+ },
971
+
972
+ {
973
+ :str => "1 + 2 * 3",
974
+ :desc => "Plus-multiplication",
975
+ :start => :expression,
976
+ :debug => false,
977
+ :expect => "1+2*3",
978
+ },
979
+
980
+ {
981
+ :str => "11 + 12 * 13",
982
+ :desc => "Mult plus",
983
+ :start => :expression,
984
+ :debug => false,
985
+ :expect => "11+12*13",
986
+ },
987
+
988
+ {
989
+ :str => "(111 + 112 ) * 113",
990
+ :desc => "Parentehesis",
991
+ :start => :expression,
992
+ :debug => false,
993
+ :expect => "(111+112)*113",
994
+ },
995
+
996
+ {
997
+ :str => "(111 + 112 ) * (113 * A)",
998
+ :desc => "Parentehesis",
999
+ :start => :expression,
1000
+ :debug => false,
1001
+ :expect => "(111+112)*(113*A)",
1002
+ },
1003
+
1004
+
1005
+ {
1006
+ :str => '\A a \in Set1 , b \in Set2: TRUE',
1007
+ :desc => "Quatification for-all",
1008
+ :start => :expression,
1009
+ :debug => false,
1010
+ :expect => '\A a \in Set1, b \in Set2 : TRUE',
1011
+ },
1012
+
1013
+ {
1014
+ :str => '\E b \in Set1: b \/ TRUE',
1015
+ :desc => "Quatification for-all",
1016
+ :start => :expression,
1017
+ :debug => false,
1018
+ :expect => '\E b \in Set1 : b\/TRUE',
1019
+ },
1020
+
1021
+ {
1022
+ :str => '<< >>',
1023
+ :desc => "Empty sequence 0-tuple",
1024
+ :start => :expression,
1025
+ :debug => false,
1026
+ :expect => '<<>>',
1027
+ },
1028
+
1029
+ {
1030
+ :str => '<< 1 >>',
1031
+ :desc => "Sequence one 1-tuple",
1032
+ :start => :expression,
1033
+ :debug => false,
1034
+ :expect => '<<1>>',
1035
+ },
1036
+
1037
+ {
1038
+ :str => '<< 1, 2+A >>',
1039
+ :desc => "Sequence one 2-tuple",
1040
+ :start => :expression,
1041
+ :debug => false,
1042
+ :expect => '<<1,2+A>>',
1043
+ },
1044
+
1045
+
1046
+ {
1047
+ :str => '{ }',
1048
+ :desc => "Empty set expression",
1049
+ :start => :expression,
1050
+ :debug => false,
1051
+ :expect => '{}',
1052
+ },
1053
+
1054
+ {
1055
+ :str => '{ 1 }',
1056
+ :desc => "Set with expression",
1057
+ :start => :expression,
1058
+ :debug => false,
1059
+ :expect => '{1}',
1060
+ },
1061
+
1062
+
1063
+ {
1064
+ :str => '{ x \in Set: TRUE }',
1065
+ :desc => "Set contruction using select expression",
1066
+ :start => :expression,
1067
+ :debug => false,
1068
+ :expect => '{ x \in Set : TRUE }',
1069
+ },
1070
+
1071
+ {
1072
+ :str => '{ x.id : x \in Set }',
1073
+ :desc => "Set contruction using element mapper",
1074
+ :start => :expression,
1075
+ :debug => false,
1076
+ :expect => '{x.id: x \in Set}',
1077
+ },
1078
+
1079
+ {
1080
+ :str => 'op()',
1081
+ :desc => "Operator expression - no parameters",
1082
+ :start => :expression,
1083
+ :debug => false,
1084
+ :expect => 'op()',
1085
+ },
1086
+
1087
+ {
1088
+ :str => 'op( ).kentta',
1089
+ :desc => "Operator expression - field",
1090
+ :start => :expression,
1091
+ :debug => false,
1092
+ :expect => 'op().kentta',
1093
+ },
1094
+
1095
+ {
1096
+ :str => 'op( ).k1.k2',
1097
+ :desc => "Operator expression - fields",
1098
+ :start => :expression,
1099
+ :debug => false,
1100
+ :expect => 'op().k1.k2',
1101
+ },
1102
+
1103
+ {
1104
+ :str => 'op ( 1, TRUE )',
1105
+ :desc => "Operator expression - with parametes",
1106
+ :start => :expression,
1107
+ :debug => false,
1108
+ :expect => 'op(1,TRUE)',
1109
+ },
1110
+
1111
+
1112
+ {
1113
+ :str => 'A = B',
1114
+ :desc => "Equal as expression",
1115
+ :start => :expression,
1116
+ :debug => false,
1117
+ :expect => 'A=B',
1118
+ },
1119
+
1120
+ {
1121
+ :str => '1 # 2',
1122
+ :desc => "Inqueality",
1123
+ :start => :expression,
1124
+ :debug => false,
1125
+ :expect => '1#2',
1126
+ },
1127
+
1128
+ {
1129
+ :str => '1 = 2 + 3',
1130
+ :desc => "Equal as expression",
1131
+ :start => :expression,
1132
+ :debug => false,
1133
+ :expect => '1=2+3',
1134
+ },
1135
+
1136
+ {
1137
+ :str => '1 > 2',
1138
+ :desc => "Greater than operator",
1139
+ :start => :expression,
1140
+ :debug => false,
1141
+ :expect => '1>2',
1142
+ },
1143
+
1144
+ {
1145
+ :str => '1 >= 2',
1146
+ :desc => "Greater than or equal operator",
1147
+ :start => :expression,
1148
+ :debug => false,
1149
+ :expect => '1>=2',
1150
+ },
1151
+
1152
+
1153
+ {
1154
+ :str => '1 <= 2',
1155
+ :desc => "Less than or equal operator",
1156
+ :start => :expression,
1157
+ :debug => false,
1158
+ :expect => '1<=2',
1159
+ },
1160
+
1161
+
1162
+ {
1163
+ :str => '[ ]',
1164
+ :desc => "Empty record",
1165
+ :start => :expression,
1166
+ :debug => false,
1167
+ :expect => '[]',
1168
+ },
1169
+
1170
+ {
1171
+ :str => '[ a|->b]',
1172
+ :desc => "One record field",
1173
+ :start => :expression,
1174
+ :debug => false,
1175
+ :expect => '[a|->b]',
1176
+ },
1177
+
1178
+ {
1179
+ :str => 'FALSE => TRUE',
1180
+ :desc => "Implication",
1181
+ :start => :expression,
1182
+ :debug => false,
1183
+ :expect => 'FALSE=>TRUE',
1184
+ },
1185
+
1186
+
1187
+ {
1188
+ :str => '1 = 2 => 3 = 4',
1189
+ :desc => "Implication w. association",
1190
+ :start => :expression,
1191
+ :debug => false,
1192
+ :expect => '1=2=>3=4',
1193
+ },
1194
+
1195
+ {
1196
+ :str => "A.id ",
1197
+ :desc => "Record field by name",
1198
+ :start => :expression,
1199
+ :debug => false,
1200
+ :expect => "A.id",
1201
+ },
1202
+
1203
+ {
1204
+ :str => "A.id1.id2 ",
1205
+ :desc => "Record field by names",
1206
+ :start => :expression,
1207
+ :debug => false,
1208
+ :expect => "A.id1.id2",
1209
+ },
1210
+
1211
+ {
1212
+ :str => "A.id1.id2.id3 ",
1213
+ :desc => "Record field by three names",
1214
+ :start => :expression,
1215
+ :debug => false,
1216
+ :expect => "A.id1.id2.id3",
1217
+ },
1218
+
1219
+
1220
+ {
1221
+ :str => 'rec[key] ',
1222
+ :desc => "Record access by value",
1223
+ :start => :expression,
1224
+ :debug => false,
1225
+ :expect => 'rec[key]',
1226
+ },
1227
+
1228
+ {
1229
+ :str => '[ name |-> name, address |-> address ]',
1230
+ :desc => "Record as an expression",
1231
+ :start => :expression,
1232
+ :debug => false,
1233
+ :expect => '[name|->name,address|->address]',
1234
+ },
1235
+
1236
+ # v_ids := [ v_ids EXCEPT ![id_type] = @ \ { Next_id( id_type ) } ] ;
1237
+
1238
+ {
1239
+ :str => '[ v_ids EXCEPT ![id] = a ] ',
1240
+ :desc => "Record except, one field using a (indetifier)",
1241
+ :start => :expression,
1242
+ :debug => false,
1243
+ :expect => '[v_ids EXCEPT ![id]=a]',
1244
+ },
1245
+
1246
+ {
1247
+ :str => '[ v_ids EXCEPT ![id] = a ] . fiildi [ aa ] ',
1248
+ :desc => "Record except with record access)",
1249
+ :start => :expression,
1250
+ :debug => false,
1251
+ :expect => '[v_ids EXCEPT ![id]=a].fiildi[aa]',
1252
+ },
1253
+
1254
+ {
1255
+ :str => '[ v_ids EXCEPT ![id] = @ ] ',
1256
+ :desc => "Record except, one field using @ (original value)",
1257
+ :start => :expression,
1258
+ :debug => false,
1259
+ :expect => '[v_ids EXCEPT ![id]=@]',
1260
+ },
1261
+
1262
+
1263
+ {
1264
+ :str => '[ v_ids EXCEPT ![id] = 0, ![uid] = 1+2 ] ',
1265
+ :desc => "Record except",
1266
+ :start => :expression,
1267
+ :debug => false,
1268
+ :expect => '[v_ids EXCEPT ![id]=0,![uid]=1+2]',
1269
+ },
1270
+
1271
+ {
1272
+ :str => '[ v_ids EXCEPT ![id] = A*a ] ',
1273
+ :desc => "Record except, one field",
1274
+ :start => :expression,
1275
+ :debug => false,
1276
+ :expect => '[v_ids EXCEPT ![id]=A*a]',
1277
+ },
1278
+
1279
+
1280
+ {
1281
+ :str => 'A \ B \cup C \union D \cap E \intersect F \/ TRUE /\ FALSE',
1282
+ :desc => "Set operators",
1283
+ :start => :expression,
1284
+ :debug => false,
1285
+ :expect => 'A\B\cupC\unionD\capE\intersectF\/TRUE/\FALSE',
1286
+ },
1287
+
1288
+ {
1289
+ :str => 'CHOOSE x \in t_Owner : 1+2',
1290
+ :desc => "CHOOSE expression",
1291
+ :start => :expression,
1292
+ :debug => false,
1293
+ :expect => 'CHOOSE x \in t_Owner: 1+2',
1294
+ },
1295
+
1296
+ {
1297
+ :str => 'elementti \in Set',
1298
+ :desc => "Expr in setup ",
1299
+ :start => :expression,
1300
+ :debug => false,
1301
+ :expect => 'elementti\inSet',
1302
+ },
1303
+
1304
+
1305
+
1306
+ ].each_with_index do |testCase,i|
1307
+
1308
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
1309
+
1310
+ tree = parser.parse( testCase[:str], testCase[:start] )
1311
+ if ( testCase[:debug] )
1312
+ puts ""
1313
+ puts tree.inspect
1314
+ end
1315
+
1316
+ expect( tree.traverse( "" ) { |memo, node_type, enode, node_val|
1317
+ # memo collect the string
1318
+ memo.concat( expression_value( node_type, enode, node_val ))
1319
+ } ).to eql( testCase[:expect] )
1320
+ end # it
1321
+
1322
+ end # each
1323
+
1324
+ end # expression
1325
+
1326
+ # ------------------------------------------------------------------
1327
+ # Directives
1328
+
1329
+ describe "Directive" do
1330
+
1331
+ [
1332
+ {
1333
+ :str => "ASSUME Assume_Domains",
1334
+ :desc => "Singe asssume",
1335
+ :start => :directive,
1336
+ :exception => nil,
1337
+ :debug => false,
1338
+ :expect => [ "Assume_Domains" ],
1339
+ },
1340
+
1341
+ {
1342
+ :str => "ASSUME a1 a2",
1343
+ :desc => "Two asssumes",
1344
+ :start => :directive,
1345
+ :exception => nil,
1346
+ :debug => false,
1347
+ :expect => [ "a1", "a2" ],
1348
+ },
1349
+
1350
+ {
1351
+ :str => "INVARIANT i1",
1352
+ :desc => "Singe asssume",
1353
+ :start => :directive,
1354
+ :exception => nil,
1355
+ :debug => false,
1356
+ :expect => [ "i1" ],
1357
+ },
1358
+
1359
+ {
1360
+ :str => "INVARIANT i2 i3",
1361
+ :desc => "Two invaints",
1362
+ :start => :directive,
1363
+ :exception => nil,
1364
+ :debug => false,
1365
+ :expect => [ "i2", "i3" ],
1366
+ },
1367
+
1368
+
1369
+ ].each_with_index do |testCase,i|
1370
+
1371
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
1372
+
1373
+
1374
+ tree = parser.parse( testCase[:str], testCase[:start] )
1375
+ if ( testCase[:debug] )
1376
+ puts ""
1377
+ puts tree.inspect
1378
+ end
1379
+
1380
+ result = tree.directives
1381
+
1382
+ expect( result ).to eql( testCase[:expect] )
1383
+ end
1384
+ end # each testCases
1385
+ end #
1386
+
1387
+
1388
+
1389
+ # ------------------------------------------------------------------
1390
+ # Operator definition
1391
+
1392
+ describe "Operator definition" do
1393
+
1394
+ [
1395
+ {
1396
+ :str => "operator == TRUE",
1397
+ :desc => "Simple constant operator without parameters",
1398
+ :start => :operator,
1399
+ :exception => nil,
1400
+ :debug => false,
1401
+ :expect => {
1402
+ :parameters=>nil,
1403
+ :expression => "TRUE"
1404
+ },
1405
+ },
1406
+
1407
+ {
1408
+ :str => "itWork( param1 ) == TRUE",
1409
+ :desc => "Simple constant operator with parameters",
1410
+ :start => :operator,
1411
+ :exception => nil,
1412
+ :debug => false,
1413
+ :expect => {
1414
+ :parameters=>{:node_type=>"Parameters", :value=>[{:node_type=>"Identifier", :value=>"param1"}]},
1415
+ :expression => "TRUE"
1416
+ },
1417
+ },
1418
+
1419
+ {
1420
+ :str => 'itCalls == itWorks( param1 ) \/ TRUE',
1421
+ :desc => "Constant operator defining operator expression with parameter",
1422
+ :start => :operator,
1423
+ :exception => nil,
1424
+ :debug => false,
1425
+ :expect => {
1426
+ :expression => 'itWorks(param1)\/TRUE'
1427
+ },
1428
+ },
1429
+
1430
+ ].each_with_index do |testCase,i|
1431
+
1432
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
1433
+
1434
+ tree = parser.parse( testCase[:str], testCase[:start] )
1435
+
1436
+ if ( testCase[:debug] )
1437
+ puts ""
1438
+ puts tree.inspect
1439
+ end
1440
+
1441
+
1442
+ if testCase[:exception] then
1443
+ expect { parse_nodes( testCase[:str], testCase[:start] ) }.to raise_exception TlaParserS::ParseException, %r<#{testCase[:exception]}>
1444
+ else
1445
+ result = {}
1446
+ testCase[:expect].each do |k,v|
1447
+ case k
1448
+ when :parameters
1449
+ result[k] = tree.parameters
1450
+ when :expression
1451
+ result[k] = tree.body_node.traverse( "" ) { |memo, node_type, enode, node_val|
1452
+ # memo collect the string
1453
+ memo.concat( expression_value( node_type, enode, node_val ))
1454
+ }
1455
+ else
1456
+ raise "Unknow expection type #{k} in #{testCase[:expect]}"
1457
+ end
1458
+ end
1459
+ expect( result ).to eql( testCase[:expect] )
1460
+
1461
+ end
1462
+ end # it
1463
+
1464
+ end # each
1465
+
1466
+
1467
+ end # operator
1468
+
1469
+ # ------------------------------------------------------------------
1470
+ # operator
1471
+
1472
+ describe "operator" do
1473
+
1474
+ str = "A( id ) == 1"
1475
+ let ( :tree ) { parser.parse( str, :operator ) }
1476
+
1477
+ it "#parameters" do
1478
+ expect( tree.parameters[:value].length ).to eql( 1 )
1479
+ end
1480
+
1481
+
1482
+ it "#symbol_definitions" do
1483
+ parameters = tree.parameters[:value]
1484
+ symbol_definitions = tree.symbol_definitions
1485
+ expect( symbol_definitions ).to eql( parameters )
1486
+ end
1487
+
1488
+ end
1489
+
1490
+ # ------------------------------------------------------------------
1491
+ # Variable definition
1492
+
1493
+ describe "variables" do
1494
+
1495
+ context "testCases" do
1496
+
1497
+ [
1498
+ {
1499
+ :str => "a= {}",
1500
+ :desc => "Init to emty set",
1501
+ :start => :variable,
1502
+ :exception => nil,
1503
+ :debug => false,
1504
+ :expect => "{}",
1505
+ },
1506
+
1507
+ {
1508
+ :str => "a= {} ;",
1509
+ :desc => "Init to emty set optional semicolnon",
1510
+ :start => :variable,
1511
+ :exception => nil,
1512
+ :debug => false,
1513
+ :expect => "{}",
1514
+ },
1515
+
1516
+
1517
+ {
1518
+ :str => "a = {}",
1519
+ :desc => "Init to emty set",
1520
+ :start => :variable,
1521
+ :exception => nil,
1522
+ :debug => false,
1523
+ :expect => "{}",
1524
+ },
1525
+
1526
+ {
1527
+ :str => "a = 1",
1528
+ :desc => "Init to integerer",
1529
+ :start => :variable,
1530
+ :exception => nil,
1531
+ :debug => false,
1532
+ :expect => "1",
1533
+ },
1534
+
1535
+ ].each_with_index do |testCase,i|
1536
+
1537
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
1538
+ tree = parser.parse( testCase[:str], testCase[:start] )
1539
+ if ( testCase[:debug] )
1540
+ puts ""
1541
+ puts tree.inspect
1542
+ end
1543
+ expect( tree ).not_to eql( nil ) unless testCase[:exception]
1544
+ expect( tree.init.traverse { |memo, node_type, enode, node_val|
1545
+ memo.concat( expression_value( node_type, enode, node_val ))
1546
+ } ).to eql( testCase[:expect] )
1547
+
1548
+
1549
+ end # it
1550
+ end # each
1551
+
1552
+ end # testCases
1553
+
1554
+ end # describe "variables" do
1555
+
1556
+
1557
+ # ------------------------------------------------------------------
1558
+ # Procedure definition
1559
+
1560
+ describe "procedure" do
1561
+
1562
+ context "testCases" do
1563
+
1564
+ [
1565
+ {
1566
+ :str => "procedure id(a){}",
1567
+ :desc => "Procedure ",
1568
+ :start => :procedure,
1569
+ :exception => nil,
1570
+ :debug => false,
1571
+ :expect => true,
1572
+ },
1573
+ {
1574
+ :str => "procedure id(){}",
1575
+ :desc => "Procedure ",
1576
+ :start => :procedure,
1577
+ :exception => nil,
1578
+ :debug => false,
1579
+ :expect => true,
1580
+ },
1581
+ {
1582
+ :str => "procedure id( a ) {} ;",
1583
+ :desc => "Procedure ",
1584
+ :start => :procedure,
1585
+ :exception => nil,
1586
+ :debug => false,
1587
+ :expect => true,
1588
+ },
1589
+ {
1590
+ :str => "procedure id( a,b ){}",
1591
+ :desc => "Procedure ",
1592
+ :start => :procedure,
1593
+ :exception => nil,
1594
+ :debug => false,
1595
+ :expect => true,
1596
+ },
1597
+ ].each_with_index do |testCase,i|
1598
+
1599
+ it "#Case #{i}: #{testCase[:desc]} - parse '#{testCase[:str]}' starting '#{testCase[:start]}'" do
1600
+
1601
+
1602
+ tree = parser.parse( testCase[:str], testCase[:start] )
1603
+ if ( testCase[:debug] )
1604
+ puts ""
1605
+ puts tree.inspect
1606
+ end
1607
+ expect( tree ).not_to eql( nil ) if testCase[:expect]
1608
+
1609
+ end # it
1610
+ end # each
1611
+
1612
+ end # testCases
1613
+
1614
+ str = "procedure id(a,b){ goto l88; skip; }"
1615
+ let ( :tree ) { parser.parse( str, :procedure ) }
1616
+
1617
+ it "#name" do
1618
+ expect = {}
1619
+ expect( tree.name ).to eql( "id" )
1620
+ end
1621
+
1622
+ it "#parameters" do
1623
+ expect = {:node_type=>"Parameters", :value=>[{:node_type=>"Identifier", :value=>"a"}, {:node_type=>"Identifier", :value=>"b"}]}
1624
+ expect( tree.parameters ).to eql( expect )
1625
+ end
1626
+
1627
+ it "#symbol_definitions" do
1628
+ parameters = tree.parameters[:value]
1629
+ symbol_definitions = tree.symbol_definitions
1630
+ # TODO add local parameters here
1631
+ expect( symbol_definitions ).to eql( parameters )
1632
+ end
1633
+
1634
+ it "#body" do
1635
+ expect = "{goto l88;\nskip;\n}"
1636
+ # puts
1637
+ # puts tree.inspect
1638
+ result = tree.body_node.traverse do |memo, node_type, node |
1639
+ # memo collect the string
1640
+ memo.concat( statement_value( node_type, node ))
1641
+ end
1642
+ expect( result ).to eql( expect )
1643
+
1644
+ end
1645
+
1646
+ end # procedure
1647
+
1648
+
1649
+ end