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.
- checksums.yaml +7 -0
- data/README.md +75 -0
- data/VERSION +1 -0
- data/bin/tla-resolver.rb +7 -0
- data/lib/cli/cli.rb +90 -0
- data/lib/parser/exception.rb +6 -0
- data/lib/parser/lvalue.rb +63 -0
- data/lib/parser/parser.rb +129 -0
- data/lib/parser/parser_nodes.rb +1063 -0
- data/lib/parser/parser_sexp.treetop +442 -0
- data/lib/semantics/context.rb +355 -0
- data/lib/semantics/exception.rb +13 -0
- data/lib/semantics/resolver.rb +327 -0
- data/lib/semantics/symbol_table.rb +139 -0
- data/lib/tla-parser-s.rb +15 -0
- data/lib/utils/logger.rb +80 -0
- data/lib/utils/syntax_node.rb +73 -0
- data/lib/utils/version.rb +13 -0
- data/spec/fixtures/callables1.tla +64 -0
- data/spec/fixtures/directives.tla +7 -0
- data/spec/fixtures/resolver1/comments.tla +1 -0
- data/spec/fixtures/resolver1/directives.cfg +6 -0
- data/spec/fixtures/resolver1/directives.tla +12 -0
- data/spec/fixtures/resolver1/empty.tla +0 -0
- data/spec/fixtures/resolver1/macro1.tla +3 -0
- data/spec/fixtures/resolver1/macro2.tla +3 -0
- data/spec/fixtures/resolver1/op1.tla +3 -0
- data/spec/fixtures/resolver1/op2.tla +3 -0
- data/spec/fixtures/resolver1/proc1.tla +4 -0
- data/spec/fixtures/resolver1/proc2.tla +7 -0
- data/spec/fixtures/resolver1/proc3.tla +4 -0
- data/spec/fixtures/resolver1/proc4.tla +4 -0
- data/spec/fixtures/resolver1/proc4_hide.tla +4 -0
- data/spec/fixtures/resolver1/proc5.tla +4 -0
- data/spec/fixtures/resolver1/proc6.tla +4 -0
- data/spec/fixtures/resolver1/proc7.tla +4 -0
- data/spec/fixtures/resolver1/stmt_assert.tla +8 -0
- data/spec/fixtures/resolver1/stmt_assign.tla +6 -0
- data/spec/fixtures/resolver1/stmt_assign2.tla +6 -0
- data/spec/fixtures/resolver1/stmt_cond.tla +13 -0
- data/spec/fixtures/resolver1/stmt_either.tla +12 -0
- data/spec/fixtures/resolver1/stmt_print.tla +5 -0
- data/spec/fixtures/resolver1/var4.tla +1 -0
- data/spec/fixtures/resolver1/var5.tla +1 -0
- data/spec/fixtures/resolver1/var_choose_except.tla +2 -0
- data/spec/fixtures/resolver1/var_quantify.tla +4 -0
- data/spec/fixtures/resolver1/var_rec_except.tla +4 -0
- data/spec/fixtures/resolver1/var_rec_expr.tla +3 -0
- data/spec/fixtures/resolver1/var_record.tla +2 -0
- data/spec/fixtures/resolver1/var_seq.tla +1 -0
- data/spec/fixtures/resolver1/var_set.tla +1 -0
- data/spec/fixtures/resolver1/var_set_expr_map.tla +1 -0
- data/spec/fixtures/resolver1/var_x.tla +1 -0
- data/spec/fixtures/resolver1/variables.tla +4 -0
- data/spec/parser/parser_fixtures_spec.rb +117 -0
- data/spec/parser/parser_spec.rb +1649 -0
- data/spec/semantics/context_spec.rb +392 -0
- data/spec/semantics/resolver_spec.rb +364 -0
- data/spec/semantics/symbol_table_spec.rb +144 -0
- data/spec/spec_helper.rb +5 -0
- data/tla-parser-s.gemspec +41 -0
- metadata +153 -0
@@ -0,0 +1,442 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
grammar Sexp
|
3
|
+
|
4
|
+
# ------------------------------------------------------------------
|
5
|
+
# Default starting point we will parse TLA+ snippets
|
6
|
+
|
7
|
+
rule snippets
|
8
|
+
( space / directive space? <Snippet>/ callable space? <Snippet> / variable space? <Snippet>)* <Snippets>
|
9
|
+
end
|
10
|
+
|
11
|
+
# ------------------------------------------------------------------
|
12
|
+
# directive
|
13
|
+
|
14
|
+
rule directive
|
15
|
+
invariants / assumptions
|
16
|
+
end
|
17
|
+
|
18
|
+
rule assumptions
|
19
|
+
'ASSUME' space? identifier (assumption* <Assumption> ) <Assumption>
|
20
|
+
end
|
21
|
+
|
22
|
+
rule assumption
|
23
|
+
space? identifier <NonTerminal>
|
24
|
+
end
|
25
|
+
|
26
|
+
rule invariants
|
27
|
+
'INVARIANT' space? identifier (invariant* <Invariant> ) <Invariant>
|
28
|
+
end
|
29
|
+
|
30
|
+
rule invariant
|
31
|
+
space? identifier <NonTerminal>
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# ------------------------------------------------------------------
|
36
|
+
# callable
|
37
|
+
|
38
|
+
rule callable
|
39
|
+
procedure / macro / operator
|
40
|
+
end
|
41
|
+
|
42
|
+
rule procedure
|
43
|
+
|
44
|
+
'procedure' space? identifier ( '(' space? identifier_list? ')' <Parameters> ) space? &'{' statement space* ';'? <Procedure>
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
rule macro
|
49
|
+
|
50
|
+
'macro' space? identifier space?
|
51
|
+
( '(' space? identifier_list? space? ')' space? <Parameters> )
|
52
|
+
&'{' statement ';'? <Macro>
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
rule operator
|
57
|
+
identifier space?
|
58
|
+
( '(' space? identifier_list? ')' space? <Parameters> )?
|
59
|
+
'==' space? expression <OperatorDef>
|
60
|
+
end
|
61
|
+
|
62
|
+
# ------------------------------------------------------------------
|
63
|
+
# Formal parameters (for macro & procedure definitions)
|
64
|
+
|
65
|
+
|
66
|
+
rule identifier_list
|
67
|
+
identifier space? identifier_list_tail? <IdentifierList>
|
68
|
+
end
|
69
|
+
|
70
|
+
# Right recursive rule
|
71
|
+
rule identifier_list_tail
|
72
|
+
',' space? identifier_list <NonTerminal>
|
73
|
+
end
|
74
|
+
|
75
|
+
# ------------------------------------------------------------------
|
76
|
+
# actual parameters
|
77
|
+
|
78
|
+
rule expression_list
|
79
|
+
expression expression_list_tail? <ExpressionList>
|
80
|
+
end
|
81
|
+
|
82
|
+
rule expression_list_tail
|
83
|
+
',' space? expression_list <NonTerminal>
|
84
|
+
end
|
85
|
+
|
86
|
+
# ------------------------------------------------------------------
|
87
|
+
# Expression
|
88
|
+
|
89
|
+
rule expression
|
90
|
+
|
91
|
+
additive_expression space? <Expression>
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
rule additive_expression
|
96
|
+
|
97
|
+
multitive_expression space? additive_expression_tail? <AdditiveExpression>
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
rule additive_expression_tail
|
102
|
+
additive_operator space? additive_expression <AdditiveExpression>
|
103
|
+
end
|
104
|
+
|
105
|
+
rule multitive_expression
|
106
|
+
|
107
|
+
# primary_expression space? multitive_expression_tail? <MultitiveExpression>
|
108
|
+
unary_expression space? multitive_expression_tail? <MultitiveExpression>
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
rule multitive_expression_tail
|
113
|
+
multitive_operator space? multitive_expression <MultitiveExpression>
|
114
|
+
end
|
115
|
+
|
116
|
+
rule unary_expression
|
117
|
+
unary_operator space? primary_expression <UnaryExpression> / primary_expression
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
rule primary_expression
|
122
|
+
unit_expression space* ( unit_expression_tail* <UnitExpression> ) <PrimaryExpression>
|
123
|
+
end
|
124
|
+
|
125
|
+
rule unit_expression
|
126
|
+
sequence_expression / set_expression / set_expression_map / record_expression / operator_expression / quantify_expression / choose_expression
|
127
|
+
/ identifier
|
128
|
+
/ record_self
|
129
|
+
/ original_value
|
130
|
+
/ string / integer / ( '(' space? expression space? ')' <ParenthesisExpression>) <UnitExpression>
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
rule unit_expression_tail
|
135
|
+
|
136
|
+
'.' space* identifier space* <FieldByName> / '[' space* unit_expression space* ']' space* <FieldByValue>
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
rule operator_expression
|
142
|
+
identifier space? '(' space? expression_list? space? ')' <OperatorExpression>
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
rule record_expression
|
147
|
+
&( '[' space* identifier space* 'EXCEPT' ) '[' space* record_except ']' <RecordExcept>
|
148
|
+
/ '[' space? record_expression_element? ']' <RecordDefinition>
|
149
|
+
end
|
150
|
+
|
151
|
+
rule record_expression_element
|
152
|
+
|
153
|
+
( identifier space? '|->' space? expression <RecordElement>) space? record_expression_element_tail? <NonTerminal>
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
rule record_expression_element_tail
|
158
|
+
',' space? record_expression_element <NonTerminal>
|
159
|
+
end
|
160
|
+
|
161
|
+
rule record_except
|
162
|
+
( identifier space* 'EXCEPT' <RecordExceptIdentifier>) space* (lvalue space* '=' space* expression space* <RecordExceptField>) ( record_except_tail* <RecordExceptField>) <NonTerminal>
|
163
|
+
end
|
164
|
+
|
165
|
+
rule record_except_tail
|
166
|
+
',' space* lvalue space* '=' space* expression <Root>
|
167
|
+
end
|
168
|
+
|
169
|
+
rule choose_expression
|
170
|
+
|
171
|
+
'CHOOSE' space* bound_expression space* ':' space* expression <ChooseExpression>
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
rule quantify_expression
|
176
|
+
quantify_operator space? ( quantify_expression_bound+ <BindsInExpression>) ':' space? space? expression <QuantifyExpression>
|
177
|
+
end
|
178
|
+
|
179
|
+
rule quantify_expression_bound
|
180
|
+
bound_expression space? quantify_expression_bound_tail? <BindsInExpression>
|
181
|
+
end
|
182
|
+
|
183
|
+
rule quantify_expression_bound_tail
|
184
|
+
',' space? quantify_expression_bound <BindsInExpression>
|
185
|
+
end
|
186
|
+
|
187
|
+
rule sequence_expression
|
188
|
+
'<<' space* expression_list? space* '>>' <SequenceExpression>
|
189
|
+
end
|
190
|
+
|
191
|
+
rule set_expression_map
|
192
|
+
'{' ( space* expression space* <SetExpressionDef>) ':' ( space* bound_expression <BoundInExpression> ) '}' <SetExpressionMap>
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
rule set_expression
|
197
|
+
'{' space* ( bound_expression ':' space* <BoundInExpression> )? (space* expression? <SetExpressionDef>) '}' <SetExpression>
|
198
|
+
end
|
199
|
+
|
200
|
+
rule bound_expression
|
201
|
+
identifier space* '\in' space+ 'DOMAIN'? space? expression space* <BoundInExpression>
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
# ------------------------------------------------------------------
|
207
|
+
# statement
|
208
|
+
|
209
|
+
rule statement
|
210
|
+
space* (identifier ':' space* <Label>)? unlabeled_statement space* <Statement>
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
# ------------------------------------------------------------------
|
215
|
+
# unlabeled statements
|
216
|
+
|
217
|
+
rule unlabeled_statement
|
218
|
+
goto / print / return_statement / skip / call / assignment_statement / compound_statement / assert /either / conditional / macro_call
|
219
|
+
end
|
220
|
+
|
221
|
+
rule conditional
|
222
|
+
'if' space* '(' space* expression space* ')' space* statement conditional_else? <Conditional>
|
223
|
+
end
|
224
|
+
|
225
|
+
rule conditional_else
|
226
|
+
'else' statement <Statement>
|
227
|
+
end
|
228
|
+
|
229
|
+
rule assignment_statement
|
230
|
+
|
231
|
+
lvalue ':=' space* expression <Assignment>
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
rule lvalue
|
237
|
+
primary_expression space* <LValue>
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
rule compound_statement
|
242
|
+
'{' space* ( compound_statement_list* <StatementList>) space* '}' <CompoundStatement>
|
243
|
+
end
|
244
|
+
|
245
|
+
rule compound_statement_list
|
246
|
+
statement ';' <StatementList>
|
247
|
+
end
|
248
|
+
|
249
|
+
rule goto
|
250
|
+
'goto' space* identifier <Goto>
|
251
|
+
end
|
252
|
+
|
253
|
+
rule print
|
254
|
+
'print' space* expression <Print>
|
255
|
+
end
|
256
|
+
|
257
|
+
rule either
|
258
|
+
'either' space* statement space* (either_list+ <StatementList>) <Either>
|
259
|
+
end
|
260
|
+
|
261
|
+
rule either_list
|
262
|
+
'or' space* statement <StatementList>
|
263
|
+
end
|
264
|
+
|
265
|
+
rule assert
|
266
|
+
'assert' space* expression <Assert>
|
267
|
+
end
|
268
|
+
|
269
|
+
rule return_statement
|
270
|
+
'return' <Return>
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
rule macro_call
|
275
|
+
identifier space? "(" space* expression_list? space* ")" <MacroCall>
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
rule call
|
280
|
+
'call' space? identifier space? "(" space? expression_list? space? ")" <Call>
|
281
|
+
end
|
282
|
+
|
283
|
+
rule skip
|
284
|
+
'skip' <Skip>
|
285
|
+
end
|
286
|
+
|
287
|
+
# ------------------------------------------------------------------
|
288
|
+
# variable
|
289
|
+
|
290
|
+
rule variable
|
291
|
+
identifier space? '=' space? expression space* ';'? <VariableDef>
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
# ------------------------------------------------------------------
|
296
|
+
# elementary
|
297
|
+
|
298
|
+
rule identifier
|
299
|
+
!reserved_word name <Identifier>
|
300
|
+
end
|
301
|
+
|
302
|
+
rule record_self
|
303
|
+
'!' <Self>
|
304
|
+
end
|
305
|
+
|
306
|
+
rule original_value
|
307
|
+
'@' <OriginalValue>
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
rule name
|
312
|
+
[_A-Za-z] [_A-Za-z0-9]*
|
313
|
+
end
|
314
|
+
|
315
|
+
rule string
|
316
|
+
'"' [^"]* '"' <StringValue>
|
317
|
+
end
|
318
|
+
|
319
|
+
rule integer
|
320
|
+
('+'/'-')? [0-9]+ <IntegerValue>
|
321
|
+
end
|
322
|
+
|
323
|
+
# ------------------------------------------------------------------
|
324
|
+
# atoms
|
325
|
+
|
326
|
+
rule multitive_operator
|
327
|
+
'/\\' <Operator> / '/' <Operator> / '*' <Operator> / '\cap' <Operator> / '\intersect' <Operator> / '\in' <Operator>
|
328
|
+
end
|
329
|
+
|
330
|
+
rule additive_operator
|
331
|
+
"=>" <Operator> / '#' <Operator> /
|
332
|
+
'<=>' <Operator> /
|
333
|
+
'>=' <Operator> / '>' <Operator> / '=' <Operator> /
|
334
|
+
'<=' <Operator> / '<' <Operator> /
|
335
|
+
'-' <Operator> / '+' <Operator>
|
336
|
+
/ '\/' <Operator> / '\cup' <Operator> / '\union' <Operator>
|
337
|
+
/ '\\' <Operator>
|
338
|
+
end
|
339
|
+
|
340
|
+
rule unary_operator
|
341
|
+
'-' <Operator> / '+' <Operator> / "\\lnot" <Operator> / "~" <Operator>
|
342
|
+
end
|
343
|
+
|
344
|
+
rule quantify_operator
|
345
|
+
'\\A' <Operator> / '\\E' <Operator>
|
346
|
+
end
|
347
|
+
|
348
|
+
rule reserved_word
|
349
|
+
"ASSUME" <ReservedWord> /
|
350
|
+
"ELSE" <ReservedWord> /
|
351
|
+
"LOCAL" <ReservedWord> /
|
352
|
+
"UNION" <ReservedWord> /
|
353
|
+
"ASSUMPTION" <ReservedWord> /
|
354
|
+
"ENABLED" <ReservedWord> /
|
355
|
+
"MODULE" <ReservedWord> /
|
356
|
+
"AXIOM" <ReservedWord> /
|
357
|
+
"EXCEPT" <ReservedWord> /
|
358
|
+
"OTHER" <ReservedWord> /
|
359
|
+
"VARIABLES" <ReservedWord> /
|
360
|
+
"VARIABLE" <ReservedWord> /
|
361
|
+
"CASE" <ReservedWord> /
|
362
|
+
"EXTENDS" <ReservedWord> /
|
363
|
+
"SF_" <ReservedWord> /
|
364
|
+
"WF_" <ReservedWord> /
|
365
|
+
"CHOOSE" <ReservedWord> /
|
366
|
+
"IF" <ReservedWord> /
|
367
|
+
"SUBSET" <ReservedWord> /
|
368
|
+
"WITH" <ReservedWord> /
|
369
|
+
"INSTANCE" <ReservedWord> /
|
370
|
+
"IN" <ReservedWord> /
|
371
|
+
"THEN" <ReservedWord> /
|
372
|
+
"CONSTANTS" <ReservedWord> /
|
373
|
+
"CONSTANT" <ReservedWord> /
|
374
|
+
"THEOREM" <ReservedWord> /
|
375
|
+
"COROLLARY" <ReservedWord> /
|
376
|
+
"DOMAIN" <ReservedWord> /
|
377
|
+
"LET" <ReservedWord> /
|
378
|
+
"UNCHANGED" <ReservedWord> /
|
379
|
+
"BY" <ReservedWord> /
|
380
|
+
"HAVE" <ReservedWord> /
|
381
|
+
"QED" <ReservedWord> /
|
382
|
+
"TAKE" <ReservedWord> /
|
383
|
+
"HIDE" <ReservedWord> /
|
384
|
+
"RECURSIVE" <ReservedWord> /
|
385
|
+
"USE" <ReservedWord> /
|
386
|
+
"DEFINE" <ReservedWord> /
|
387
|
+
"PROOF" <ReservedWord> /
|
388
|
+
"WITNESS" <ReservedWord> /
|
389
|
+
"PICK" <ReservedWord> /
|
390
|
+
"DEFS" <ReservedWord> /
|
391
|
+
"DEF" <ReservedWord> /
|
392
|
+
"PROVE" <ReservedWord> /
|
393
|
+
"SUFFICES" <ReservedWord> /
|
394
|
+
"NEW" <ReservedWord> /
|
395
|
+
"LAMBDA" <ReservedWord> /
|
396
|
+
"STATE" <ReservedWord> /
|
397
|
+
"ACTION" <ReservedWord> /
|
398
|
+
"TEMPORAL" <ReservedWord> /
|
399
|
+
"OBVIOUS" <ReservedWord> /
|
400
|
+
"OMITTED" <ReservedWord> /
|
401
|
+
"LEMMA" <ReservedWord> /
|
402
|
+
"PROPOSITION" <ReservedWord> /
|
403
|
+
"ONLY" <ReservedWord>
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
|
408
|
+
# ------------------------------------------------------------------
|
409
|
+
# spaces && comments
|
410
|
+
|
411
|
+
rule space
|
412
|
+
whitespace / newline / comment
|
413
|
+
end
|
414
|
+
|
415
|
+
rule whitespace
|
416
|
+
[\s]+
|
417
|
+
end
|
418
|
+
|
419
|
+
rule newline
|
420
|
+
[\n]+
|
421
|
+
end
|
422
|
+
|
423
|
+
rule comment
|
424
|
+
line_comment / block_comment
|
425
|
+
end
|
426
|
+
|
427
|
+
# New may be missing on last line on a file
|
428
|
+
rule line_comment
|
429
|
+
'\\*' [^\n]* [\n]?
|
430
|
+
end
|
431
|
+
|
432
|
+
rule block_comment
|
433
|
+
'(*'
|
434
|
+
|
435
|
+
(
|
436
|
+
!'*)'
|
437
|
+
(. / "\n")
|
438
|
+
)*
|
439
|
+
'*)' space?
|
440
|
+
end
|
441
|
+
|
442
|
+
end
|
@@ -0,0 +1,355 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module TlaParserS
|
6
|
+
|
7
|
+
# ******************************************************************
|
8
|
+
#
|
9
|
+
# Manage context to parse TLA+ snippets
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# Builds context in three phases:
|
13
|
+
#
|
14
|
+
# 1) Initial context includes TLA+ standard definitions e.g. TRUE, FALSE
|
15
|
+
# when context is created
|
16
|
+
# 2) Global context includes snippets defining macros, procedures,
|
17
|
+
# operators, and variables. Using pushContext/addContext
|
18
|
+
# 3) During resolve phase push to context formal parameters, quantification
|
19
|
+
# bind variables, variables in set constructor generator. Uses
|
20
|
+
# pushContext/addContext methods internally from 'resolveDefine',
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# ******************************************************************
|
24
|
+
|
25
|
+
class Context
|
26
|
+
|
27
|
+
extend Forwardable # for easy delegation
|
28
|
+
|
29
|
+
attr_accessor :symbol_table
|
30
|
+
|
31
|
+
def_delegators :symbol_table, :currentContext, :dumpContext,
|
32
|
+
:popContext, :entries, :resolveModule
|
33
|
+
|
34
|
+
# ------------------------------------------------------------------
|
35
|
+
# Logger
|
36
|
+
|
37
|
+
PROGNAME = "context" # progname for logger
|
38
|
+
include TlaParserS::Utils::MyLogger # mix logger
|
39
|
+
|
40
|
+
# # TLA+ standar library symbols
|
41
|
+
|
42
|
+
# GLOABLS = %w( TRUE FALSE )
|
43
|
+
|
44
|
+
|
45
|
+
# ------------------------------------------------------------------
|
46
|
+
# constructore
|
47
|
+
def initialize( options={} )
|
48
|
+
|
49
|
+
@logger = getLogger( PROGNAME, options )
|
50
|
+
@logger.info( "#{__method__} initialized" )
|
51
|
+
|
52
|
+
initContext
|
53
|
+
end
|
54
|
+
|
55
|
+
# ------------------------------------------------------------------
|
56
|
+
# manage context
|
57
|
+
|
58
|
+
def initContext
|
59
|
+
@symbol_table = SymbolTable.new
|
60
|
+
|
61
|
+
# # create context for standar library && add entries
|
62
|
+
# @symbol_table.pushContext( nil )
|
63
|
+
# GLOABLS.each do |global|
|
64
|
+
# entry = {
|
65
|
+
# :context_type => "Init",
|
66
|
+
# :context => "Global",
|
67
|
+
# :symbol_type => "StandardLib",
|
68
|
+
# :symbol_name => global,
|
69
|
+
# }
|
70
|
+
|
71
|
+
# @symbol_table.addEntry( entry )
|
72
|
+
# end
|
73
|
+
return self
|
74
|
+
end
|
75
|
+
|
76
|
+
# Create new context in symbol table && add etnries
|
77
|
+
def initEntries( entries )
|
78
|
+
|
79
|
+
return unless entries && entries.any?
|
80
|
+
|
81
|
+
# create new context
|
82
|
+
pushContext
|
83
|
+
|
84
|
+
# add entries
|
85
|
+
entries.each do |entry|
|
86
|
+
@symbol_table.addEntry( entry )
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Add more symbols to current context levell
|
93
|
+
#
|
94
|
+
def addContext( snippets, moduleName=nil )
|
95
|
+
symbol_table.addContext( snippets, moduleName )
|
96
|
+
return self
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Add one level to context & and add snipets there
|
101
|
+
#
|
102
|
+
# @param snippets [SyntaxNode] implementing 'symbol_definitions` method
|
103
|
+
#
|
104
|
+
def pushContext( snippets=nil, moduleName=nil )
|
105
|
+
warn "Method symbol_definitions not implemented on #{snippets}" if snippets && !snippets.respond_to?(:symbol_definitions)
|
106
|
+
symbol_table.pushContext( snippets, moduleName )
|
107
|
+
return self
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# @param symbol [String] to resolve
|
112
|
+
# @return [Hash] with :symbol, :resolved properties
|
113
|
+
def resolveSymbol( symbol )
|
114
|
+
resolved = symbol_table.resolveContext( symbol )
|
115
|
+
return {
|
116
|
+
:symbol => symbol,
|
117
|
+
:resolved => resolved,
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
# ------------------------------------------------------------------
|
122
|
+
# Resolver
|
123
|
+
|
124
|
+
# @param stmt [Statement] parse tree node for statement to resolve
|
125
|
+
# @return see 'resolveExpression'
|
126
|
+
private def resolveStatement( stmt, ret=[] )
|
127
|
+
|
128
|
+
stmt.traverse(ret) do |ret,node_type, node|
|
129
|
+
@logger.debug( "#{__method__}: enter node_type=#{node_type}, #{node.text_value}ret=#{ret}." )
|
130
|
+
case node_type
|
131
|
+
when "Statement"
|
132
|
+
when "Skip"
|
133
|
+
when "Return"
|
134
|
+
when "Goto"
|
135
|
+
when "Identifier"
|
136
|
+
@logger.debug( "#{__method__}: Identifier node=#{node.inspect}" )
|
137
|
+
ret.concat( resolveExpression( node ))
|
138
|
+
when "Conditional"
|
139
|
+
ret.concat( resolveExpression( node.condition ))
|
140
|
+
@logger.debug( "#{__method__}: Conditional if_true=#{node.if_true.inspect}" )
|
141
|
+
ret.concat( resolveStatement( node.if_true, ret ))
|
142
|
+
ret.concat( resolveStatement( node.if_not_true, ret )) if node.if_not_true
|
143
|
+
when "Either"
|
144
|
+
ret = node.choices.each { |s| resolveStatement( s, ret ) }
|
145
|
+
when "Assert"
|
146
|
+
ret.concat( resolveExpression( node.assertion ))
|
147
|
+
when "Assignment"
|
148
|
+
lvalue = node.lvalue
|
149
|
+
@logger.debug( "#{__method__}: Assignment lvalue=#{lvalue.inspect}" )
|
150
|
+
ret.concat( resolveExpression( node.lvalue.expression ) )
|
151
|
+
ret.concat( resolveExpression( node.rvalue ))
|
152
|
+
# lvalue = node.lvalue.node_value
|
153
|
+
# @logger.debug( "#{__method__}: Assign lvalue=#{lvalue}" )
|
154
|
+
# # take just first variable
|
155
|
+
# lvalue = lvalue.split( /[.\[]/ ).first
|
156
|
+
# ret << resolvedIdentifier( lvalue, symbol_table.resolveContext( lvalue ))
|
157
|
+
# # resovel expression
|
158
|
+
# ret.concat( resolveExpression( node.rvalue ))
|
159
|
+
when "Print"
|
160
|
+
@logger.debug( "#{__method__}: Print node=#{node.inspect}" )
|
161
|
+
sret = resolveExpression( node.print_expression )
|
162
|
+
@logger.debug( "#{__method__}: Print sret=#{sret}" )
|
163
|
+
ret = ret.concat( sret )
|
164
|
+
when "CompoundStatement"
|
165
|
+
ret = node.statements.each { |s| resolveStatement( s, ret ) }
|
166
|
+
# sret = []
|
167
|
+
# node.statements.each { |s| sret = resolveStatement( s, sret ) }
|
168
|
+
# ret.concat( sret )
|
169
|
+
when "MacroCall"
|
170
|
+
# resolve macro definition
|
171
|
+
ret << resolvedIdentifier( node.called, symbol_table.resolveContext( node.called ) )
|
172
|
+
# resolve actual parameters
|
173
|
+
node.actual_parameters.each do |expr_node|
|
174
|
+
eret = resolveExpression(expr_node )
|
175
|
+
@logger.debug "actual param eret=#{eret}"
|
176
|
+
ret.concat( eret )
|
177
|
+
end # actual paramtere
|
178
|
+
when "Call"
|
179
|
+
# resolve procedure definition
|
180
|
+
ret << resolvedIdentifier( node.called, symbol_table.resolveContext( node.called ) )
|
181
|
+
# resolve actual parameters
|
182
|
+
ret = node.actual_parameters.each do |expr_node|
|
183
|
+
ret.concat( resolveExpression( expr_node ))
|
184
|
+
end # actual paramtere
|
185
|
+
else
|
186
|
+
msg = "#{__method__}: Unknwon statement node type #{node_type} for node #{node.inspect}"
|
187
|
+
@logger.warn( msg )
|
188
|
+
warn msg
|
189
|
+
end
|
190
|
+
@logger.debug( "#{__method__}: leave node_type=#{node_type} ret=#{ret}." )
|
191
|
+
ret
|
192
|
+
end
|
193
|
+
ret
|
194
|
+
end # def resolveStatement( stmt )
|
195
|
+
|
196
|
+
|
197
|
+
# @return see 'resolveStatement'
|
198
|
+
def resolveDefine( defineNode )
|
199
|
+
# @logger.debug "resolveDefine starting callable=#{defineNode.inspect}"
|
200
|
+
|
201
|
+
pushContext( defineNode )
|
202
|
+
# dumpContext
|
203
|
+
if defineNode.respond_to?( :body_node ) then
|
204
|
+
@logger.info( "#{__method__} start with resolveStatement for #{defineNode.body_node}" )
|
205
|
+
if defineNode.body_node.is_a?(Sexp::Expression)
|
206
|
+
ret = resolveExpression( defineNode.body_node )
|
207
|
+
else
|
208
|
+
ret = resolveStatement( defineNode.body_node )
|
209
|
+
end
|
210
|
+
elsif defineNode.respond_to?( :init ) then
|
211
|
+
@logger.info( "#{__method__} start with resolveExpression #{defineNode.init}" )
|
212
|
+
ret = resolveExpression( defineNode.init )
|
213
|
+
@logger.debug( "#{__method__} resolveExpression-->#{ret}" )
|
214
|
+
else
|
215
|
+
msg = <<-EOS
|
216
|
+
Unknown tree node object #{defineNode}.
|
217
|
+
|
218
|
+
Should be 'Callabe' or 'VariableDef'
|
219
|
+
EOS
|
220
|
+
@logger.error( "#{__method__} #{msg}" )
|
221
|
+
raise ContextException.new msg
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
popContext()
|
226
|
+
ret
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
# @param expression [Expression] parse tree node for exprresion to resolve
|
231
|
+
# @return [Hash:Array] {:symbol,:resolved} hashes, where :resolved is the result
|
232
|
+
# of symbol table lookup
|
233
|
+
def resolveExpression( expr )
|
234
|
+
|
235
|
+
ret = []
|
236
|
+
expr && expr.traverse do |m, node_type, enode, node_val |
|
237
|
+
@logger.debug( "#{__method__} node_type=#{node_type}, node_val=#{node_val}" )
|
238
|
+
case node_type
|
239
|
+
when "Identifier"
|
240
|
+
ret << resolvedIdentifier( node_val, symbol_table.resolveContext( node_val ) )
|
241
|
+
when "AdditiveExpression", "MultitiveExpression", "UnaryExpression", "ParenthesisExpression"
|
242
|
+
when "PrimaryExpression"
|
243
|
+
sret = []
|
244
|
+
enode.attribute_accessors && enode.attribute_accessors.each do |identifier|
|
245
|
+
sret = sret.concat( resolveExpression( identifier ))
|
246
|
+
end
|
247
|
+
ret = ret.concat( sret )
|
248
|
+
when "FieldByValue"
|
249
|
+
ret << resolvedIdentifier( node_val, symbol_table.resolveContext( node_val ) )
|
250
|
+
when "FieldByName"
|
251
|
+
when "SequenceExpression"
|
252
|
+
@logger.debug( "#{__method__} SequenceExpression: enode=#{enode.inspect}" )
|
253
|
+
sret = []
|
254
|
+
enode.tuples && enode.tuples.each do |tuple_expr|
|
255
|
+
sret = sret.concat( resolveExpression( tuple_expr ))
|
256
|
+
end
|
257
|
+
ret = ret.concat( sret )
|
258
|
+
when "ChooseExpression"
|
259
|
+
@logger.debug( "#{__method__} ChooseExpression: enode=#{enode.inspect}" )
|
260
|
+
@logger.debug( "#{__method__} ChooseExpression: enode.binds_node=#{enode.binds_node}" )
|
261
|
+
# bind node defines symbol table
|
262
|
+
pushContext( enode )
|
263
|
+
choose_expression=enode.choose_expression
|
264
|
+
@logger.debug( "#{__method__} ChooseExpression: choose_expression=#{choose_expression.inspect}" )
|
265
|
+
sret = resolveExpression( choose_expression )
|
266
|
+
@logger.info( "#{__method__} ChooseExpression: resolved sret=#{sret.map {|e| { e[:symbol] => e[:resolved] ? e[:resolved][:symbol_type]+':'+e[:resolved][:context] : nil} }}" )
|
267
|
+
ret = ret.concat( sret )
|
268
|
+
popContext()
|
269
|
+
when "RecordDefinition"
|
270
|
+
@logger.debug( "#{__method__} RecordDefinition: enode=#{enode.inspect}" )
|
271
|
+
sret = []
|
272
|
+
enode.record_fields.each do |record_field|
|
273
|
+
sret = sret.concat( resolveExpression( record_field.element_expression ))
|
274
|
+
end
|
275
|
+
@logger.info( "#{__method__} RecordDefinition: resolved sret=#{sret.map {|e| { e[:symbol] => e[:resolved] ? e[:resolved][:symbol_type]+':'+e[:resolved][:context] : nil} }}" )
|
276
|
+
ret = ret.concat( sret )
|
277
|
+
when "RecordExcept"
|
278
|
+
# resolve where identier poinst
|
279
|
+
id = enode.record_identifier
|
280
|
+
ret << resolvedIdentifier( id, symbol_table.resolveContext( id ) )
|
281
|
+
@logger.debug( "#{__method__} RecordExcept: id=#{id}, ret=#{ret}" )
|
282
|
+
sret = []
|
283
|
+
# resolve EXCEPT constructor field rvalue expression
|
284
|
+
enode.record_field_definitions && enode.record_field_definitions.each do |field_definition|
|
285
|
+
sret = sret.concat( resolveExpression( field_definition.rvalue_expression ))
|
286
|
+
end
|
287
|
+
ret = ret.concat( sret )
|
288
|
+
when "SetExpressionMap"
|
289
|
+
@logger.debug( "#{__method__} SetExpressionMap: enode=#{enode.inspect}" )
|
290
|
+
# resolve set mapped
|
291
|
+
sret = resolveExpression( enode.binds_node.bind_set )
|
292
|
+
ret = ret.concat( sret )
|
293
|
+
|
294
|
+
# resolve expression in set map
|
295
|
+
pushContext( enode )
|
296
|
+
sret = resolveExpression( enode.set_expression )
|
297
|
+
@logger.debug( "#{__method__} SetExpressionMap: resolved sret=#{sret}" )
|
298
|
+
ret = ret.concat( sret )
|
299
|
+
when "SetExpression"
|
300
|
+
@logger.debug( "#{__method__} SetExpression: enode=#{enode.inspect}" )
|
301
|
+
pushContext( enode )
|
302
|
+
sret = resolveExpression( enode.set_expression )
|
303
|
+
@logger.debug( "#{__method__} SetExpression: resolved sret=#{sret}" )
|
304
|
+
ret = ret.concat( sret )
|
305
|
+
popContext( )
|
306
|
+
when "OperatorExpression"
|
307
|
+
@logger.debug( "#{__method__} OperatorExpression: enode=#{enode.inspect}" )
|
308
|
+
operator_name = enode.operator_name
|
309
|
+
ret << resolvedIdentifier( operator_name, symbol_table.resolveContext( operator_name ) )
|
310
|
+
sret = []
|
311
|
+
enode.arguments && enode.arguments.each do |argument_node|
|
312
|
+
sret = sret.concat( resolveExpression( argument_node ))
|
313
|
+
end
|
314
|
+
@logger.info( "#{__method__} OperatorExpression: resolved sret=#{sret.map {|e| { e[:symbol] => e[:resolved] ? e[:resolved][:symbol_type]+':'+e[:resolved][:context] : nil} }}" )
|
315
|
+
ret = ret.concat( sret )
|
316
|
+
|
317
|
+
when "QuantifyExpression"
|
318
|
+
|
319
|
+
@logger.debug( "#{__method__} SetExpression: node.symbol_definitions=#{enode.symbol_definitions}" )
|
320
|
+
pushContext( enode )
|
321
|
+
sret = resolveExpression( enode.binds_nodes.first.bind_set )
|
322
|
+
ret = ret.concat( sret )
|
323
|
+
@logger.debug( "#{__method__} resolved sret=#{sret}" )
|
324
|
+
@logger.debug( "#{__method__} SetExpression: #{enode.quantified_expression.inspect}" )
|
325
|
+
qret = resolveExpression( enode.quantified_expression )
|
326
|
+
@logger.debug( "#{__method__} resolved qret=#{qret}" )
|
327
|
+
ret = ret.concat( qret )
|
328
|
+
@logger.debug( "#{__method__} resolved ret=#{ret}" )
|
329
|
+
popContext( )
|
330
|
+
when "IntegerValue", "StringValue", "OriginalValue"
|
331
|
+
else
|
332
|
+
|
333
|
+
msg = "Unknwon expression node type #{node_type} with value #{node_val}"
|
334
|
+
@logger.error( "#{__method__} #{msg}" )
|
335
|
+
raise ContextException.new msg
|
336
|
+
|
337
|
+
end
|
338
|
+
end
|
339
|
+
ret
|
340
|
+
end # def resolveExpression( expr )
|
341
|
+
|
342
|
+
private
|
343
|
+
# @return {Hash} with {:sybol,:resolved} -properties
|
344
|
+
def resolvedIdentifier( identifier, resolved )
|
345
|
+
{ :symbol => identifier, :resolved => resolved }
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
|
350
|
+
|
351
|
+
end # class
|
352
|
+
|
353
|
+
|
354
|
+
|
355
|
+
end
|