tla-parser-s 0.1.2 → 0.2.2
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 +4 -4
- data/README.md +1 -1
- data/VERSION +1 -1
- data/lib/parser/lvalue.rb +2 -2
- data/lib/parser/parser.rb +1 -1
- data/lib/parser/parser_nodes.rb +200 -85
- data/lib/parser/parser_sexp.treetop +39 -7
- data/lib/semantics/context.rb +113 -55
- data/lib/semantics/resolver.rb +206 -58
- data/lib/semantics/symbol_table.rb +45 -11
- data/lib/utils/logger.rb +2 -1
- data/spec/fixtures/resolver1/op4.tla +2 -0
- data/spec/fixtures/resolver1/op_let.tla +1 -0
- data/spec/fixtures/resolver1/op_tail_chg.tla +1 -0
- data/spec/fixtures/resolver1/var_rec_expr_add.tla +3 -0
- data/spec/parser/parser_fixtures_spec.rb +4 -4
- data/spec/parser/parser_spec.rb +177 -12
- data/spec/semantics/context_spec.rb +52 -0
- data/spec/semantics/resolver_spec.rb +106 -11
- data/spec/semantics/symbol_table_spec.rb +6 -4
- metadata +6 -2
data/lib/semantics/resolver.rb
CHANGED
@@ -27,9 +27,12 @@ module TlaParserS
|
|
27
27
|
# global context to use in resolving.
|
28
28
|
#
|
29
29
|
# constructor:
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
30
|
+
# Initialize & parse
|
31
|
+
# #initContext: add initContext
|
32
|
+
# #initSnippets: parse TLA+ snippets to context
|
33
|
+
# Services available after init & parse
|
34
|
+
# #resolveModules: resolve modules
|
35
|
+
# #sortModule:
|
33
36
|
#
|
34
37
|
# ******************************************************************
|
35
38
|
|
@@ -37,15 +40,22 @@ module TlaParserS
|
|
37
40
|
# ------------------------------------------------------------------
|
38
41
|
# Logger
|
39
42
|
|
40
|
-
PROGNAME =
|
43
|
+
PROGNAME = nil # progname default class-name
|
41
44
|
include TlaParserS::Utils::MyLogger # mix logger
|
42
45
|
|
43
46
|
# ------------------------------------------------------------------
|
44
|
-
|
47
|
+
|
48
|
+
# @!group Construct && configure
|
49
|
+
|
50
|
+
# construct with 'options'
|
51
|
+
#
|
52
|
+
# @param options [Hash] to configure resolver
|
53
|
+
# @option options [String] :logfile name of file where to log to
|
54
|
+
#
|
45
55
|
def initialize( options={} )
|
46
56
|
|
47
57
|
@logger = getLogger( PROGNAME, options )
|
48
|
-
@logger.info( "#{__method__} initialized" )
|
58
|
+
@logger.info( "#{__method__} initialized parser-resolver version #{TlaParserS::version}" )
|
49
59
|
|
50
60
|
@report_unresolved = options[:report_unresolved]
|
51
61
|
|
@@ -60,37 +70,12 @@ module TlaParserS
|
|
60
70
|
@directive_modules = []
|
61
71
|
end
|
62
72
|
|
63
|
-
#
|
64
|
-
#
|
65
|
-
# @param entry [File|String] to parse
|
66
|
-
# @param moduleName [String] identifying 'entry' for error messages
|
67
|
-
# @return [Snippets] parsed syntax tree node
|
68
|
-
def parseSnippets( entry, moduleName )
|
69
|
-
begin
|
70
|
-
parser.parse( entry )
|
71
|
-
rescue ParseException => ee
|
72
|
-
msg = "Parsing '#{moduleName}' results to error \n\n#{ee.message}"
|
73
|
-
@logger.error( "#{__method__} #{msg}" )
|
74
|
-
raise ParseException.new( ee ), msg, ee.backtrace
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
73
|
+
# @!endgroup
|
78
74
|
|
79
|
-
#
|
80
|
-
# 'moduleName' to '@directive_modules' if any 'snippets' contained
|
81
|
-
# 'directive_definitions'
|
82
|
-
#
|
83
|
-
# @param moduleName [String] name of module where 'snippets' are parses
|
84
|
-
# @param snippets [Snippets] parsed snippts, respons to :directive_definitions
|
85
|
-
def addDirectives( snippets, moduleName )
|
86
|
-
new_directives = snippets.directive_definitions
|
87
|
-
|
88
|
-
@logger.debug( "#{__method__} moduleName=#{moduleName} -> new_directives=#{new_directives}" )
|
89
|
-
@directives = directives + new_directives
|
90
|
-
|
91
|
-
@directive_modules << moduleName if new_directives && new_directives.any?
|
92
|
-
end
|
75
|
+
# ------------------------------------------------------------------
|
93
76
|
|
77
|
+
# @!group Initialize context & parse snippets
|
78
|
+
|
94
79
|
# Build initial context (TLA+ reserved words, etc)
|
95
80
|
#
|
96
81
|
# @param names [String:Array] to put context
|
@@ -107,46 +92,57 @@ module TlaParserS
|
|
107
92
|
}
|
108
93
|
end
|
109
94
|
)
|
110
|
-
|
111
95
|
|
112
96
|
end
|
113
97
|
|
114
|
-
|
115
|
-
# ------------------------------------------------------------------
|
116
98
|
# Load TLA+ snippets from file (or strings in unit test), and
|
117
99
|
# build global context to use in resolving.
|
118
100
|
#
|
119
|
-
# @param
|
101
|
+
# @param [File:Array|String:Array|File|String] entries containg TLA+ snippets
|
120
102
|
#
|
121
103
|
# @param blk [Block] yields entry
|
122
104
|
|
123
105
|
def initSnippets( entries, &blk )
|
124
106
|
|
107
|
+
# Make it to an array
|
108
|
+
entries = [ entries ] unless entries.is_a?( Array ) || entries.nil?
|
109
|
+
|
110
|
+
@logger.info "#{__method__} starts in #{Dir.pwd}"
|
111
|
+
|
125
112
|
# create global context
|
126
113
|
context.pushContext
|
127
114
|
|
115
|
+
# collect symbol definitions parsed
|
116
|
+
parsedSnippets = []
|
117
|
+
|
118
|
+
|
128
119
|
# iterate
|
129
120
|
entries && entries.each_with_index do |entry,i|
|
130
121
|
|
131
122
|
# skip directories
|
132
123
|
# next if entry.is_a?( File ) && File.directory?( entry )
|
133
|
-
next if File.directory?( entry )
|
124
|
+
next if (entry.is_a?( String ) || entry.is_a?( File )) && File.directory?( entry )
|
134
125
|
|
135
126
|
# meaningfull modulename
|
136
|
-
moduleName = entry.is_a?( File ) ? entry.path : "entries[#{i}]"
|
127
|
+
moduleName = entry.is_a?( File ) ? entry.path : entry.respond_to?(:moduleName) ? entry.moduleName : "entries[#{i}]"
|
137
128
|
|
138
|
-
@logger.info( "#{__method__} entry=#{entry}" )
|
129
|
+
@logger.info( "#{__method__} entry=#{entry}, moduleName=#{moduleName}" )
|
139
130
|
begin
|
140
131
|
|
141
132
|
# String|File --> AST
|
142
133
|
snippets = parseSnippets( entry, moduleName )
|
143
134
|
yield( true, entry ) if blk
|
135
|
+
@logger.debug( "#{__method__} #{moduleName}: snippets=#{snippets.inspect}" ) if @logger.debug?
|
136
|
+
|
137
|
+
# collect an array of hashes with :node_type, :value, :true -properties
|
138
|
+
parsedSnippets += snippets.symbol_definitions
|
144
139
|
|
145
|
-
# collect
|
140
|
+
# collect '@directives' and, '@directive_modules' if
|
141
|
+
# snippets.directive_definitions because they should be
|
142
|
+
# included to entry points
|
146
143
|
addDirectives( snippets, moduleName )
|
147
144
|
|
148
|
-
# add to contex tree nodes, which respond to
|
149
|
-
# 'symbol_definitions'
|
145
|
+
# add to contex tree nodes, which respond to 'symbol_definitions'
|
150
146
|
context.addContext( snippets, moduleName )
|
151
147
|
|
152
148
|
rescue TlaParserS::ParseException => e
|
@@ -159,10 +155,18 @@ module TlaParserS
|
|
159
155
|
|
160
156
|
end
|
161
157
|
|
158
|
+
@logger.info "#{__method__} finished"
|
162
159
|
self
|
160
|
+
parsedSnippets
|
163
161
|
end
|
164
162
|
|
163
|
+
|
164
|
+
# @!endgroup
|
165
|
+
|
165
166
|
# ------------------------------------------------------------------
|
167
|
+
# @!group Services to use after init & parse
|
168
|
+
|
169
|
+
|
166
170
|
# Find modules 1) containing TLA+ snippets reachable from
|
167
171
|
# 'entryPoints', 2) modules reachabable for directive defintision,
|
168
172
|
# and 3) modules containing directive definitions
|
@@ -173,9 +177,132 @@ module TlaParserS
|
|
173
177
|
definitionModules = resolveModulesDo( entryPoints + directives, &blk )
|
174
178
|
return definitionModules + directive_modules
|
175
179
|
end
|
180
|
+
|
181
|
+
# ------------------------------------------------------------------
|
182
|
+
# Run topologica sort on module
|
183
|
+
require 'tsort'
|
184
|
+
# Define a class to do topological sort
|
185
|
+
class THash < Hash
|
186
|
+
include TSort
|
187
|
+
alias tsort_each_node each_key
|
188
|
+
def tsort_each_child(node, &block)
|
189
|
+
fetch(node).each(&block)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
# ------------------------------------------------------------------
|
176
193
|
|
194
|
+
# Run topological sort on modules.
|
195
|
+
#
|
196
|
+
# @param modules [String:Array] names of modules to sort
|
197
|
+
#
|
198
|
+
# @return [String:Array] of sorted modules
|
199
|
+
def sortModules( modules, &blk )
|
200
|
+
|
201
|
+
@logger.info "#{__method__}: modulesstart=#{modules} - starts"
|
202
|
+
|
203
|
+
sortteri =
|
204
|
+
modules.
|
205
|
+
#
|
206
|
+
# map { |m| puts "m0=#{m}"; m }.
|
207
|
+
#
|
208
|
+
# Find symbols in module :m to array :s
|
209
|
+
#
|
210
|
+
# [{ :m=<module-name>, :s=>[<symbol definitions in module>]}, ...]
|
211
|
+
#
|
212
|
+
map { |m| { :m => m, :s=> context.resolveModule(m) } }.
|
213
|
+
# map { |m| puts "m1[:s]=#{m[:s].map{ |s| s[:module] +':' + s[:symbol_name] } }"; m }.
|
214
|
+
#
|
215
|
+
# Resolver symbols in :s to array :r
|
216
|
+
#
|
217
|
+
# At this point
|
218
|
+
# [{ :m=<module-name>, :s=>[<symbol definitions in module>], :r=>[{:symbol=>"", :resolved>={} }]}, .... ]
|
219
|
+
#
|
220
|
+
map { |m| m[:r] = m[:s].map{ |s| resolveEntryPoint( s[:symbol_name] ) }.flatten; m }.
|
221
|
+
# map { |m| puts "#{m[:m]}-> m2[:s]=#{m[:s].map{ |s| s[:module] +':' + s[:symbol_name] } }"; m }.
|
222
|
+
# map { |m| puts "#{m[:m]}-> m2[:r]=#{m[:r].map { |r| r[:symbol] + '->' + r[:resolved][:symbol_name] + '@' + (r[:resolved][:module] ||'-' )}}"; m }.
|
223
|
+
#
|
224
|
+
# Drop unresolved symbols from :r
|
225
|
+
#
|
226
|
+
map { |m| m[:r] = m[:r].reject { |r| r[:resolved].nil? }; m}.
|
227
|
+
#
|
228
|
+
# Add m[:d] array of module names (drop resolves, which do not
|
229
|
+
# have module defined (correspoding to local references)
|
230
|
+
#
|
231
|
+
# [{ :m=<module-name>, :d=> [<resolved modules (filepaths?)>] :s=>[<symbol definitions in module>], :r=>[{:symbol=>"", :resolved>={} }]}, .... ]
|
232
|
+
#
|
233
|
+
#
|
234
|
+
map { |m| m[:d] = m[:r].select { |r| r[:resolved][:module]}.map { |r| r[:resolved][:module]}.uniq; m}.
|
235
|
+
# map { |m| puts "m3=#{m[:m]}, :d=#{m[:d]}, [:s]=#{m[:s].map{ |s| s[:module] +':' + s[:symbol_name] } }"; m }.
|
236
|
+
#
|
237
|
+
# Reject modules, which do not define any snippets
|
238
|
+
#
|
239
|
+
select { |m| m[:s].any? }.
|
240
|
+
# map { |m| puts "m4=#{m[:m]}, :d=#{m[:d]}, [:s]=#{m[:s].map{ |s| s[:module] +':' + s[:symbol_name] } }"; m }.
|
241
|
+
#
|
242
|
+
# clear prefix path from modulename in m[:d] elements
|
243
|
+
#
|
244
|
+
map { |m| m[:d] = m[:d].map{ |d| modules.select { |mo| d.end_with?(mo)}.first }.select {|d| d }; m }.
|
245
|
+
# map { |m| puts "m5=#{m[:m]}, :d=#{m[:d]}"; m }.
|
246
|
+
#
|
247
|
+
#
|
248
|
+
# Finally create a tsort hash
|
249
|
+
#
|
250
|
+
inject( THash.new ){ |t, m| t[m[:m]] = m[:d]; t }.
|
251
|
+
#
|
252
|
+
# And sort it
|
253
|
+
#
|
254
|
+
tsort
|
255
|
+
|
256
|
+
sortteri
|
257
|
+
end
|
258
|
+
|
259
|
+
# @!endgroup
|
260
|
+
|
261
|
+
# ------------------------------------------------------------------
|
262
|
+
# @!group Internal methods for parsing
|
263
|
+
|
264
|
+
|
265
|
+
# Parse entry ie. file or possibly a string
|
266
|
+
#
|
267
|
+
# @param entry [File|String] to parse
|
268
|
+
#
|
269
|
+
# @param moduleName [String] identifying 'entry' for error messages
|
270
|
+
#
|
271
|
+
# @return [Snippets] parsed syntax tree node
|
272
|
+
def parseSnippets( entry, moduleName )
|
273
|
+
begin
|
274
|
+
parser.parse( entry )
|
275
|
+
rescue ParseException => ee
|
276
|
+
msg = "Parsing '#{moduleName}' results to error \n\n#{ee.message}"
|
277
|
+
@logger.error( "#{__method__} #{msg}" )
|
278
|
+
raise ParseException.new( ee ), msg, ee.backtrace
|
279
|
+
end
|
280
|
+
|
281
|
+
end
|
282
|
+
|
283
|
+
# Add definition names in 'snippets' to '@directives', and
|
284
|
+
# 'moduleName' to '@directive_modules' if any of the 'snippets'
|
285
|
+
# contains 'directive_definitions'
|
286
|
+
#
|
287
|
+
# @param moduleName [String] name of module where 'snippets' are parses
|
288
|
+
# @param snippets [Snippets] parsed snippts, respons to :directive_definitions
|
289
|
+
def addDirectives( snippets, moduleName )
|
290
|
+
new_directives = snippets.directive_definitions
|
291
|
+
|
292
|
+
@logger.debug( "#{__method__} moduleName=#{moduleName} -> new_directives=#{new_directives}" ) if @logger.debug?
|
293
|
+
@directives = directives + new_directives
|
294
|
+
|
295
|
+
@directive_modules << moduleName if new_directives && new_directives.any?
|
296
|
+
end
|
297
|
+
|
298
|
+
# @!endgroup
|
299
|
+
|
300
|
+
|
177
301
|
|
178
302
|
# ------------------------------------------------------------------
|
303
|
+
|
304
|
+
# @!group implement module resolve
|
305
|
+
|
179
306
|
# Find modules containing TLA+ snippets needed to implement code
|
180
307
|
# for 'entryPoints'. Notice: A module may include additional
|
181
308
|
# entrypoint, which must also be satisfied.
|
@@ -189,7 +316,7 @@ module TlaParserS
|
|
189
316
|
# @return [String:Arrays] of module names needed in implementation.
|
190
317
|
def resolveModulesDo( entryPoints, &blk )
|
191
318
|
|
192
|
-
@logger.info( "#{__method__} resolveModules for entryPoint=#{entryPoints.join(',')}" )
|
319
|
+
@logger.info( "#{__method__} resolveModules for entryPoint=#{entryPoints.join(',')}, symbol-table depth=#{context.symbol_table.depth}" )
|
193
320
|
yield( "start", entryPoints ) if blk
|
194
321
|
|
195
322
|
# collected during processing
|
@@ -203,16 +330,17 @@ module TlaParserS
|
|
203
330
|
|
204
331
|
while TRUE do
|
205
332
|
|
206
|
-
# done - if no
|
333
|
+
# done - if no more in 'unResolved'
|
207
334
|
break if unResolved.empty?
|
208
335
|
# next to resolve
|
209
336
|
entryPoint = unResolved.to_a.shift
|
210
|
-
@logger.info( "#{__method__} next to resolve entryPoint #{entryPoint} " )
|
337
|
+
@logger.info( "#{__method__} next to resolve entryPoint #{entryPoint} " )
|
338
|
+
# already resolved
|
211
339
|
next if resolved.include?( entryPoint )
|
212
340
|
|
213
341
|
# array of hashes how entry point is resolved
|
214
342
|
resolvedSymbols = resolveEntryPoint( entryPoint )
|
215
|
-
@logger.
|
343
|
+
@logger.debug( "#{__method__} entryPoint #{entryPoint} ->resolvedSymbols=#{resolvedSymbols}" ) if @logger.debug?
|
216
344
|
|
217
345
|
resolvedModules = # array of mod.names
|
218
346
|
resolvedSymbols. # { :symbol=>, :resolved=> }
|
@@ -224,7 +352,7 @@ module TlaParserS
|
|
224
352
|
map { |s| s[:module] } # extract moduleName
|
225
353
|
|
226
354
|
|
227
|
-
@logger.debug( "#{__method__} resolvedModules=#{resolvedModules}" )
|
355
|
+
@logger.debug( "#{__method__} resolvedModules=#{resolvedModules}" ) if @logger.debug?
|
228
356
|
newModules = resolvedModules.select { |m| !moduleNames.include?( m ) }
|
229
357
|
|
230
358
|
# collect unresolved
|
@@ -238,7 +366,7 @@ module TlaParserS
|
|
238
366
|
|
239
367
|
# return list of definitions (ie. newEntryPoint) in 'modules'
|
240
368
|
newEntryPoints = entryPointsForModules( newModules )
|
241
|
-
@logger.debug( "#{__method__} newEntryPoints=#{newEntryPoints}" )
|
369
|
+
@logger.debug( "#{__method__} newEntryPoints=#{newEntryPoints}" ) if @logger.debug?
|
242
370
|
|
243
371
|
# one more resolved: move it to resolved
|
244
372
|
unResolved = unResolved.delete( entryPoint )
|
@@ -246,7 +374,7 @@ module TlaParserS
|
|
246
374
|
|
247
375
|
# still to resolve: unResolved + newEntryPoints - resolved
|
248
376
|
unResolved = unResolved.union( newEntryPoints.to_set ).subtract( resolved )
|
249
|
-
@logger.debug( "#{__method__} unResolved=#{unResolved}" )
|
377
|
+
@logger.debug( "#{__method__} unResolved=#{unResolved}" ) if @logger.debug?
|
250
378
|
|
251
379
|
# collect modules
|
252
380
|
moduleNames = moduleNames.union( newModules.to_set )
|
@@ -286,12 +414,18 @@ module TlaParserS
|
|
286
414
|
# @return [Hash:Array] identifier in entry points
|
287
415
|
def resolveEntryPoint( entryPoint )
|
288
416
|
symbolTableEntry = context.resolveSymbol( entryPoint )
|
289
|
-
@logger.debug( "#{__method__} symbolTableEntry #{entryPoint}-->#{symbolTableEntry}" )
|
417
|
+
@logger.debug( "#{__method__} symbolTableEntry #{entryPoint}-->#{symbolTableEntry}" ) if @logger.debug?
|
290
418
|
if symbolTableEntry && symbolTableEntry[:resolved]
|
419
|
+
# return from cache
|
420
|
+
if symbolTableEntry[:cached]
|
421
|
+
return symbolTableEntry[:cached]
|
422
|
+
end
|
291
423
|
tree = symbolTableEntry[:resolved][:tree]
|
292
|
-
@logger.debug( "#{__method__} tree-->#{tree.inspect}" )
|
424
|
+
@logger.debug( "#{__method__} tree-->#{tree.inspect}" ) if @logger.debug?
|
293
425
|
symbols = context.resolveDefine( tree )
|
294
|
-
@logger.debug( "#{__method__} resolveDefine-->#{symbols.join('\n')}" )
|
426
|
+
@logger.debug( "#{__method__} resolveDefine-->#{symbols.join('\n')}" ) if @logger.debug?
|
427
|
+
symbolTableEntry[:cached] = symbols
|
428
|
+
symbols
|
295
429
|
else
|
296
430
|
msg = <<-EOS
|
297
431
|
Unknown entrypoint '#{entryPoint}'
|
@@ -306,12 +440,24 @@ module TlaParserS
|
|
306
440
|
|
307
441
|
end
|
308
442
|
|
443
|
+
# @!endgroup
|
444
|
+
|
445
|
+
|
446
|
+
# ------------------------------------------------------------------
|
447
|
+
# @!group private utilities
|
448
|
+
|
449
|
+
|
309
450
|
# return list of definitions in 'modules'
|
310
451
|
#
|
311
|
-
# @param modules [String:Array] of module names to include
|
312
|
-
#
|
452
|
+
# @param modules [String:Array|String] of module names to include
|
453
|
+
#
|
454
|
+
# @return [String:Array] of entry points in 'modules'
|
455
|
+
#
|
313
456
|
def entryPointsForModules( modules )
|
314
457
|
|
458
|
+
# ensure that it is an array
|
459
|
+
modules = modules.is_a?( Array ) ? modules : [modules]
|
460
|
+
|
315
461
|
moduleSymbols = []
|
316
462
|
modules.each do |moduleName|
|
317
463
|
# resolve module entry poinsts
|
@@ -320,9 +466,11 @@ module TlaParserS
|
|
320
466
|
moduleSymbols = moduleSymbols + moduleEntries
|
321
467
|
end
|
322
468
|
ret = moduleSymbols.map { |s| s[:symbol_name] }
|
323
|
-
@logger.debug( "#{__method__} modules=#{modules.join(',')}-->ret=#{ret.join(',')}" )
|
469
|
+
@logger.debug( "#{__method__} modules=#{modules.join(',')}-->ret=#{ret.join(',')}" ) if @logger.debug?
|
324
470
|
return ret
|
325
471
|
end
|
472
|
+
|
473
|
+
# @!endgroup
|
326
474
|
|
327
475
|
end
|
328
476
|
|
@@ -9,7 +9,7 @@ module TlaParserS
|
|
9
9
|
# ------------------------------------------------------------------
|
10
10
|
# Logger
|
11
11
|
|
12
|
-
PROGNAME =
|
12
|
+
PROGNAME = nil # progname for logger default class name
|
13
13
|
include TlaParserS::Utils::MyLogger # mix logger
|
14
14
|
|
15
15
|
|
@@ -18,19 +18,29 @@ module TlaParserS
|
|
18
18
|
def initialize( options={} )
|
19
19
|
|
20
20
|
@logger = getLogger( PROGNAME, options )
|
21
|
-
@logger.info( "#{__method__} initialized" )
|
21
|
+
@logger.info( "#{__method__} initialized symbol-table" )
|
22
22
|
|
23
23
|
@stack = []
|
24
24
|
end
|
25
25
|
|
26
|
+
def depth
|
27
|
+
@stack.length
|
28
|
+
end
|
29
|
+
|
26
30
|
# Add a hash (with :symbol_type, :context_type, :context,
|
27
31
|
# :symbol_name) to 'currentContext'
|
28
32
|
#
|
29
33
|
# @param entry [Hash] add hash to 'currentContext'
|
30
34
|
def addEntry( entry )
|
31
35
|
# get refeence to current contex
|
36
|
+
# do not ouput :tree property on info stack
|
37
|
+
@logger.info "#{__method__} @[#{@stack.length}] #{entry.inject({}){|e,(k,v)| e[k] = ( k == :tree ? true : v ); e } }"
|
38
|
+
@logger.debug "#{__method__} tree = #{entry[:tree].inspect}" if @logger.debug?
|
39
|
+
# @logger.debug "#{__method__} @[#{@stack.length}] #{entry}"
|
40
|
+
|
32
41
|
context = currentContext
|
33
|
-
context[entry[:symbol_name]] = entry
|
42
|
+
context[entry[:symbol_name]] = entry
|
43
|
+
|
34
44
|
end
|
35
45
|
|
36
46
|
# @param tree_node [SyntaxNode] node implementing
|
@@ -40,7 +50,7 @@ module TlaParserS
|
|
40
50
|
|
41
51
|
if tree_node && tree_node.respond_to?(:symbol_definitions)
|
42
52
|
tree_node.symbol_definitions.each do |symbol_definition|
|
43
|
-
@logger.debug( "#{__method__} symbol_definition=#{symbol_definition}" )
|
53
|
+
@logger.debug( "#{__method__} moduleName #{moduleName}, symbol_definition=#{symbol_definition}" ) if @logger.debug?
|
44
54
|
entry = {
|
45
55
|
:context_type => tree_node.node_type,
|
46
56
|
:context => tree_node.name,
|
@@ -50,7 +60,10 @@ module TlaParserS
|
|
50
60
|
# optionally add moduleName
|
51
61
|
entry[:module] = moduleName if moduleName
|
52
62
|
|
53
|
-
#
|
63
|
+
# output before tree
|
64
|
+
@logger.debug( "#{__method__} @#{stack.length} entry=#{entry}, parse tree=#{symbol_definition[:tree] ? 'given' : 'not given' } " ) if @logger.debug?
|
65
|
+
|
66
|
+
# syntax tree defined only on procedure & macros (and variable defs)
|
54
67
|
entry[:tree] = symbol_definition[:tree] if symbol_definition[:tree]
|
55
68
|
|
56
69
|
addEntry( entry )
|
@@ -93,6 +106,18 @@ module TlaParserS
|
|
93
106
|
entries
|
94
107
|
end
|
95
108
|
|
109
|
+
# @return [Hash:Array] of symbol table entries
|
110
|
+
def symbols
|
111
|
+
entries = {}
|
112
|
+
stack.reverse_each do |context|
|
113
|
+
# add key to entries unless it is already there
|
114
|
+
context.keys().each { |k| entries[k] = context[k] }
|
115
|
+
end
|
116
|
+
entries
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
|
96
121
|
def resolveContext( identifier )
|
97
122
|
stack.reverse_each do |context|
|
98
123
|
# @logger.debug "context=#{context}, identifier=#{identifier}"
|
@@ -101,7 +126,14 @@ module TlaParserS
|
|
101
126
|
return nil
|
102
127
|
end
|
103
128
|
|
129
|
+
|
130
|
+
# Return entries in a module.
|
131
|
+
#
|
132
|
+
# Implementation iterates, in reverse, order symbol table stack,
|
133
|
+
# and searches for entries with :module == 'moduleName'.
|
134
|
+
#
|
104
135
|
# @param moduleName [String] name of module to resolve
|
136
|
+
#
|
105
137
|
# @return [Hash:Array] of symbol definition
|
106
138
|
# {:context_type,:context,:symbol_type,:symbol_name} where
|
107
139
|
# {:module} == 'moduleName'
|
@@ -111,11 +143,12 @@ module TlaParserS
|
|
111
143
|
entries = []
|
112
144
|
stack.reverse_each do |context|
|
113
145
|
context.each do |symbol,entry|
|
114
|
-
@logger.debug( "#{__method__} symbol=#{symbol}, entry=#{entry[:module]}" )
|
115
|
-
entries << entry if entry[:module] == moduleName
|
146
|
+
@logger.debug( "#{__method__} symbol=#{symbol}, entry=#{entry[:module]}" ) if @logger.debug?
|
147
|
+
# entries << entry if entry[:module] == moduleName
|
148
|
+
entries << entry if !entry[:module].nil? && entry[:module].end_with?( moduleName )
|
116
149
|
end
|
117
150
|
end
|
118
|
-
@logger.debug( "#{__method__} entries-->#{entries.join(',')}" )
|
151
|
+
@logger.debug( "#{__method__} entries-->#{entries.join(',')}" ) if @logger.debug?
|
119
152
|
return entries
|
120
153
|
end
|
121
154
|
|
@@ -123,10 +156,11 @@ module TlaParserS
|
|
123
156
|
return stack.last
|
124
157
|
end
|
125
158
|
|
126
|
-
def dumpContext
|
159
|
+
def dumpContext( &blk )
|
127
160
|
stack.reverse_each.with_index do |context, i|
|
128
|
-
|
129
|
-
@logger.debug
|
161
|
+
yield i, context if blk
|
162
|
+
@logger.debug "Context #{i}" if @logger.debug?
|
163
|
+
@logger.debug context.to_yaml if @logger.debug?
|
130
164
|
end
|
131
165
|
end
|
132
166
|
|