modl 0.3.25 → 0.3.27

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -140
  3. data/Gemfile +4 -2
  4. data/LICENSE.txt +1 -1
  5. data/README.md +19 -11
  6. data/Rakefile +5 -3
  7. data/lib/modl/interpreter.rb +38 -0
  8. data/lib/modl/model/model.rb +264 -0
  9. data/lib/modl/parser/parser.rb +272 -59
  10. data/lib/modl/tokeniser/context.rb +113 -0
  11. data/lib/modl/tokeniser/tokeniser.rb +28 -0
  12. data/lib/modl/util/functions.rb +74 -0
  13. data/lib/modl/util/unicode.rb +44 -0
  14. data/lib/modl/version.rb +5 -0
  15. data/lib/modl.rb +7 -32
  16. data/modl.gemspec +8 -11
  17. metadata +16 -75
  18. data/.DS_Store +0 -0
  19. data/.idea/vcs.xml +0 -6
  20. data/.rspec +0 -3
  21. data/.rubocop.yml +0 -5
  22. data/.travis.yml +0 -7
  23. data/bin/console +0 -14
  24. data/bin/setup +0 -8
  25. data/lib/modl/parser/MODLLexer.interp +0 -132
  26. data/lib/modl/parser/MODLLexer.rb +0 -324
  27. data/lib/modl/parser/MODLLexer.tokens +0 -40
  28. data/lib/modl/parser/MODLParser.interp +0 -93
  29. data/lib/modl/parser/MODLParser.rb +0 -2492
  30. data/lib/modl/parser/MODLParser.tokens +0 -40
  31. data/lib/modl/parser/MODLParserBaseListener.rb +0 -164
  32. data/lib/modl/parser/MODLParserBaseVisitor.rb +0 -107
  33. data/lib/modl/parser/MODLParserListener.rb +0 -151
  34. data/lib/modl/parser/MODLParserVisitor.rb +0 -56
  35. data/lib/modl/parser/class_processor.rb +0 -411
  36. data/lib/modl/parser/evaluator.rb +0 -125
  37. data/lib/modl/parser/file_importer.rb +0 -101
  38. data/lib/modl/parser/global_parse_context.rb +0 -318
  39. data/lib/modl/parser/instruction_processor.rb +0 -84
  40. data/lib/modl/parser/interpreter.rb +0 -75
  41. data/lib/modl/parser/modl_class.rb +0 -138
  42. data/lib/modl/parser/modl_index.rb +0 -54
  43. data/lib/modl/parser/modl_keylist.rb +0 -81
  44. data/lib/modl/parser/modl_method.rb +0 -172
  45. data/lib/modl/parser/object_cache.rb +0 -88
  46. data/lib/modl/parser/orphan_handler.rb +0 -98
  47. data/lib/modl/parser/parsed.rb +0 -1470
  48. data/lib/modl/parser/ref_processor.rb +0 -258
  49. data/lib/modl/parser/substitutions.rb +0 -101
  50. data/lib/modl/parser/sutil.rb +0 -108
  51. data/lib/modl/parser/throwing_error_listener.rb +0 -44
  52. data/lib/modl/parser/unicode_escape_replacer.rb +0 -148
  53. data/lib/modl/parser/unicode_escapes.rb +0 -112
  54. data/lib/modl/parser/version.rb +0 -29
@@ -1,1470 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # The MIT License (MIT)
4
- #
5
- # Copyright (c) 2019 NUM Technology Ltd
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- # THE SOFTWARE.
24
-
25
- require 'modl/parser/MODLParserBaseListener'
26
- require 'modl/parser/global_parse_context'
27
- require 'modl/parser/ref_processor'
28
- require 'modl/parser/unicode_escapes'
29
- require 'modl/parser/substitutions'
30
- require 'modl/parser/file_importer'
31
- require 'antlr4/runtime/parse_cancellation_exception'
32
- require 'modl/parser/sutil'
33
- require 'modl/parser/modl_class'
34
- require 'modl/parser/modl_method'
35
- require 'modl/parser/modl_index'
36
- require 'modl/parser/modl_keylist'
37
- require 'modl/parser/evaluator'
38
- require 'cgi'
39
- require 'net/http'
40
-
41
- module MODL
42
- module Parser
43
- # This class represents a MODL parse tree for a given MODL object.
44
- # It tries to process the parse tree as it is generated as much as
45
- # possible to save revisiting nodes unnecessarily.
46
- #
47
- # Many of the method names are generated by ANTLR4 so are not ruby style.
48
- class Parsed < MODL::Parser::MODLParserBaseListener
49
- attr_accessor :structures
50
- attr_accessor :global
51
-
52
- def initialize(global = nil)
53
- @global = global
54
- @structures = []
55
- end
56
-
57
- def enterModl(ctx)
58
-
59
- @global = GlobalParseContext.new if @global.nil?
60
-
61
- ctx_modl_structure = ctx.modl_structure
62
- ctx_modl_structure.each do |str|
63
- structure = ParsedStructure.new @global
64
- str.enter_rule(structure)
65
- @structures << structure
66
- end
67
-
68
- @structures = @global.structures + @structures
69
-
70
- @global
71
- end
72
-
73
- def self.additional_string_processing(text)
74
- # Special case for a possibly empty graved string ``
75
- unless text.nil?
76
- match_data = /^`([^`]*)`$/.match text
77
- return match_data[1] if match_data&.length&.positive?
78
- end
79
- text
80
- end
81
-
82
- # Class to represent a parsed grammar object
83
- class ParsedMap < MODL::Parser::MODLParserBaseListener
84
- attr_accessor :mapItems
85
-
86
- def initialize(global)
87
- @global = global
88
- @mapItems = []
89
- end
90
-
91
- def find_property(key)
92
- if key.is_a? Integer
93
- return @mapItems[key]
94
- else
95
- @mapItems.each do |mi|
96
- return mi.pair if mi.pair.key == key
97
- end
98
- end
99
- end
100
-
101
- def enterModl_map(ctx)
102
- modl_map_item = ctx.modl_map_item
103
- return if modl_map_item.nil?
104
-
105
- modl_map_item.each do |mi|
106
- map_item = ParsedMapItem.new @global
107
- mi.enter_rule(map_item)
108
- @mapItems << map_item
109
- end
110
- end
111
-
112
- def extract_hash
113
- result = {}
114
- @mapItems.each do |i|
115
- i_hash = i.extract_hash
116
- next unless i_hash.is_a? Hash
117
-
118
- i_hash.keys.each do |k|
119
- result[k] = i_hash[k]
120
- end
121
- end
122
- result.is_a?(Array) && result.length == 1 ? result[0] : result
123
- end
124
-
125
- end
126
-
127
- # Class to represent a parsed grammar object
128
- class ParsedMapItem < MODL::Parser::MODLParserBaseListener
129
- attr_accessor :pair
130
- attr_accessor :mapConditional
131
-
132
- def initialize(global)
133
- @global = global
134
- end
135
-
136
- def enterModl_map_item(ctx)
137
- modl_pair = ctx.modl_pair
138
- unless modl_pair.nil?
139
- @pair = ParsedPair.new @global
140
- modl_pair.enter_rule(@pair)
141
- end
142
- modl_map_conditional = ctx.modl_map_conditional
143
- return if modl_map_conditional.nil?
144
-
145
- @mapConditional = ParsedMapConditional.new @global
146
- modl_map_conditional.enter_rule(@mapConditional)
147
- end
148
-
149
- def extract_hash
150
- return @pair.extract_hash if @pair
151
- return @mapConditional.extract_hash if @mapConditional
152
- end
153
-
154
- end
155
-
156
- # Class to represent a parsed grammar object
157
- class ParsedStructure < MODL::Parser::MODLParserBaseListener
158
- attr_accessor :array
159
- attr_accessor :pair
160
- attr_accessor :top_level_conditional
161
- attr_accessor :map
162
-
163
- def initialize(global)
164
- @global = global
165
- end
166
-
167
- def enterModl_structure(ctx)
168
- modl_pair = ctx.modl_pair
169
- modl_top_level_conditional = ctx.modl_top_level_conditional
170
- modl_map = ctx.modl_map
171
- modl_array = ctx.modl_array
172
-
173
- if !modl_pair.nil?
174
- @pair = ParsedPair.new @global
175
- modl_pair.enter_rule(@pair)
176
- elsif !modl_top_level_conditional.nil?
177
- @top_level_conditional = ParsedTopLevelConditional.new @global
178
- modl_top_level_conditional.enter_rule(@top_level_conditional)
179
- elsif !modl_map.nil?
180
- @map = ParsedMap.new @global
181
- modl_map.enter_rule(@map)
182
- elsif !modl_array.nil?
183
- @array = ParsedArray.new @global
184
- modl_array.enter_rule(@array)
185
- end
186
- end
187
-
188
- def extract_hash
189
- return @array.extract_hash if @array
190
- return @pair.extract_hash if @pair
191
- return @top_level_conditional.extract_hash if @top_level_conditional
192
- return @map.extract_hash if @map
193
- end
194
- end
195
-
196
- # Class to represent a parsed grammar object
197
- class ParsedPair < MODL::Parser::MODLParserBaseListener
198
- attr_accessor :key
199
- attr_accessor :map
200
- attr_accessor :array
201
- attr_accessor :valueItem
202
- attr_accessor :key_lists
203
- attr_accessor :type # A string set to the type of pair that we have found bases on its key
204
- attr_accessor :text # The simple text value rather than the object
205
- attr_accessor :final
206
- attr_accessor :loaded # For *load instructions so we don't load twice
207
-
208
-
209
- def initialize(global)
210
- @global = global
211
- @needs_defref = true
212
- @final = false
213
- @file_importer = FileImporter.instance
214
- @loaded = false
215
- @array = nil
216
- @map = nil
217
- end
218
-
219
- def find_property(key)
220
- return self if key == @key
221
-
222
- return @map.find_property(key) if @map
223
- return @array.find_property(key) if @array
224
- return @valueItem.find_property(key) if @valueItem
225
- end
226
-
227
- # Set the appropriate field base on the value type
228
- def set_value(value)
229
- if value.is_a? Array
230
- @map = nil
231
- @array = ParsedArray.new @global
232
- @array.abstractArrayItems = []
233
- value.each do |item|
234
- array_item = ParsedArrayItem.new @global
235
- array_item.arrayValueItem = ParsedArrayValueItem.new @global
236
- array_item.arrayValueItem.primitive = ParsedPrimitive.new(@global)
237
- array_item.arrayValueItem.primitive.string = ParsedString.new(item)
238
- array_item.arrayValueItem.primitive.text = item
239
- @array.abstractArrayItems << array_item
240
- end
241
- @valueItem = nil
242
- @text = @array.extract_hash
243
- return
244
- elsif value.is_a?(ParsedPair)
245
- @map = value.map ? value.map : nil
246
- @array = value.array ? value.array : nil
247
- @valueItem = value.valueItem ? value.valueItem : nil
248
- return
249
- elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
250
- @map = nil
251
- @array = nil
252
- @valueItem = ParsedValueItem.new @global
253
- @valueItem.value = ParsedValue.new @global
254
- @valueItem.value.primitive = ParsedPrimitive.new(@global)
255
- if value
256
- @valueItem.value.primitive.trueVal = ParsedTrue.instance
257
- else
258
- @valueItem.value.primitive.falseVal = ParsedFalse.instance
259
- end
260
- @valueItem.value.primitive.text = value
261
- @valueItem.value.text = value
262
- @text = value
263
- return
264
- end
265
- value = value.extract_hash unless value.is_a?(String) || value.is_a?(Integer)
266
- @map = nil
267
- @array = nil
268
- @valueItem = ParsedValueItem.new @global
269
- @valueItem.value = ParsedString.new(value)
270
- @text = value
271
- end
272
-
273
- # Convert this object to a simple hash ready for JSON.generate
274
- def extract_hash
275
-
276
- value = @array.extract_hash if @array
277
- value = @valueItem.extract_hash if @valueItem
278
- value = @map.extract_hash if @map
279
-
280
- @text = value
281
-
282
- return if @type == 'index'
283
- return if @type == 'hidden'
284
- return if @type == 'version'
285
- return if @type == 'class'
286
- return if @type == 'method'
287
- return if @type == 'import'
288
- return if @type == 'allow'
289
- return if @type == 'expect'
290
-
291
- formatted_key = Substitutions.process UnicodeEscapes.process @key
292
- {formatted_key => @text}
293
- end
294
-
295
- def enterModl_pair(ctx)
296
- @type = 'pair' # default the type to an ordinary pair
297
-
298
- ctx_string = ctx.STRING
299
- @key = ctx_string.to_s unless ctx_string.nil?
300
- ctx_quoted = ctx.QUOTED
301
- unless ctx_quoted.nil?
302
- @key = ctx_quoted.to_s
303
- @key = Sutil.toptail(@key) # remove the quotes
304
- end
305
-
306
- raise InterpreterError, 'Invalid key - null, true, or false keys are not allowed.' if @key.nil?
307
-
308
- if @key.include?('%') || @key.include?('`')
309
- @key, new_value = RefProcessor.deref @key, @global
310
- unless @key.is_a?(String)
311
- raise InterpreterError, "Error: '" + @key.to_s + "' is an invalid key." if new_value.nil?
312
- @key = new_value.is_a?(String) ? new_value : new_value.text
313
- end
314
- raise InterpreterError, "Error: '" + @key.to_s + "' should de-ref to a string." unless key.is_a?(String)
315
- end
316
-
317
- @final = true if @key.upcase == @key
318
-
319
- modl_array = ctx.modl_array
320
- modl_map = ctx.modl_map
321
- modl_value_item = ctx.modl_value_item
322
-
323
- if !modl_array.nil?
324
- @array = ParsedArray.new @global
325
- modl_array.enter_rule(@array)
326
- elsif !modl_map.nil?
327
- @map = ParsedMap.new @global
328
- modl_map.enter_rule(@map)
329
- elsif !modl_value_item.nil?
330
- @valueItem = ParsedValueItem.new @global
331
- modl_value_item.enter_rule(@valueItem)
332
- end
333
-
334
- set_pair_type
335
- raise InterpreterError, 'Invalid keyword: ' + @key if @type == 'pair' && @key.start_with?('*')
336
-
337
- validate_key if @type == 'pair' || @type == 'hidden'
338
-
339
- # Type-specific processing
340
- case @type
341
- when 'class'
342
- ClassExtractor.extract(self, @global)
343
- when 'id'
344
- extract_value
345
- when 'name'
346
- extract_value
347
- when 'superclass'
348
- extract_value
349
- when 'allow'
350
- extract_value
351
- when 'keylist'
352
- KeylistExtractor.extract(self, @valueItem) if @valueItem
353
- KeylistExtractor.extract(self, @array) if @array
354
- when 'version'
355
- extract_value
356
-
357
- raise InterpreterError, 'Invalid MODL version: ' + @valueItem.value.primitive.text if @valueItem.value.primitive.number.nil?
358
- raise InterpreterError, 'Invalid MODL version: ' + @valueItem.value.primitive.number.num.to_s if @valueItem.value.primitive.number.num.is_a? Float
359
- raise InterpreterError, 'Invalid MODL version: ' + @valueItem.value.primitive.number.num.to_s if @valueItem.value.primitive.number.num.zero?
360
- raise InterpreterError, 'MODL version should be on the first line if specified.' if @global.has_pairs?
361
- @global.syntax_version = @valueItem.value.primitive.number.num
362
-
363
- when 'method'
364
- MethodExtractor.extract(self, @global)
365
- when 'transform'
366
- extract_transform @valueItem
367
- when 'import'
368
- files = @valueItem.extract_hash if @valueItem
369
- files = @array.extract_hash if @array
370
- @file_importer.import_files files, @global unless @global.in_condition?
371
- when 'index'
372
- IndexExtractor.extract(self, @global)
373
- when 'hidden'
374
- extract_value
375
- else
376
- extract_value
377
- end
378
-
379
- return if @global.in_condition? # Don't store pairs in conditionals until we evaluate the conditions
380
-
381
- if @key.start_with? '_'
382
- k = Sutil.tail(@key)
383
- existing = @global.pair(k)
384
- raise InterpreterError, 'Already defined ' + k + ' as final.' if existing&.final && @type != "import"
385
- raise InterpreterError, 'Cannot load multiple files after *LOAD instruction' if existing&.final && @type == "import"
386
-
387
- @global.pair(k, self)
388
- end
389
- existing = @global.pair(@key)
390
- raise InterpreterError, 'Already defined ' + @key + ' as final.' if existing&.final && @type != "import"
391
- raise InterpreterError, 'Cannot load multiple files after *LOAD instruction' if existing&.final && @type == "import"
392
-
393
- @global.pair(@key, self)
394
- end
395
-
396
- private
397
-
398
- def extract_value
399
- item = @valueItem
400
- @text = item.value.text if item.is_a?(ParsedValueItem) && item.value
401
- @text = item.valueItem.value.text if item.is_a?(ParsedPair)
402
- invoke_deref
403
- end
404
-
405
- def extract_transform item
406
- @transform = item.value.primitive.string.string
407
- end
408
-
409
- def validate_key
410
- invalid_chars = "£!$@-+'*#^&"
411
- invalid_chars.each_char do |c|
412
- next unless @key.include?(c)
413
-
414
- raise InterpreterError, 'Invalid key - "' + c + '" character not allowed: ' + @key
415
- end
416
-
417
- key = @key.start_with?('_') ? Sutil.tail(@key) : @key
418
- raise InterpreterError, 'Invalid key - "' + key + '" - entirely numeric keys are not allowed: ' + @key if key == key.to_i.to_s
419
- end
420
-
421
- def invoke_deref
422
- return unless @needs_defref && !@text.nil? && @text.is_a?(String) && @text.include?('%')
423
-
424
- @needs_defref = false
425
- @text, new_value = RefProcessor.deref @text, @global
426
-
427
- if new_value.is_a? ParsedMap
428
- @map = new_value
429
- @valueItem = nil
430
- @array = nil
431
- elsif new_value.is_a? ParsedArray
432
- @array = new_value
433
- @valueItem = nil
434
- @map = nil
435
- elsif new_value.is_a? ParsedValueItem
436
- @valueItem = new_value
437
- elsif new_value.nil?
438
- set_value @text
439
- elsif new_value.is_a? ParsedPair
440
- set_value @text if @text
441
- set_value new_value if @text.nil?
442
- elsif new_value.is_a? String
443
- set_value @text
444
- else
445
- set_value(new_value)
446
- end
447
- end
448
-
449
- # Set the pair type if its a 'special' type
450
- def set_pair_type
451
- @type = 'class' if @key == '*c' || @key == '*class'
452
- if @key == '*C' || @key == '*CLASS'
453
- @type = 'class'
454
- @key = @key.downcase
455
- end
456
- @type = 'id' if @key == '*i' || @key == '*id'
457
- @type = 'name' if @key == '*n' || @key == '*name'
458
- @type = 'name' if @key == '*N' || @key == '*NAME'
459
- @type = 'superclass' if @key == '*S' || @key == '*SUPERCLASS'
460
- @type = 'superclass' if @key == '*s' || @key == '*superclass'
461
- @type = 'keylist' if @key == '*a' || @key == '*assign'
462
- @type = 'version' if @key == '*V' || @key == '*VERSION'
463
- @type = 'method' if @key == '*m' || @key == '*method'
464
- @type = 'transform' if @key == '*t' || @key == '*transform'
465
- if @key == '*L' || @key == '*LOAD'
466
- @key = @key.downcase
467
- @type = 'import'
468
- if @array
469
- @global.freeze_max_files(@array.abstractArrayItems.length)
470
- elsif @valueItem&.value&.array
471
- @global.freeze_max_files(@valueItem&.value&.array.abstractArrayItems.length)
472
- elsif @valueItem&.value&.nbArray
473
- @global.freeze_max_files(@valueItem&.value&.nbArray.arrayItems.length)
474
- else
475
- @global.freeze_max_files(1)
476
- end
477
- end
478
- if @key == '*l' || @key == '*load'
479
- @type = 'import'
480
- end
481
- @type = 'index' if @key == '?'
482
- @type = 'hidden' if @key.start_with? '_'
483
- @type = 'allow' if @key.downcase == '*allow'
484
- @type = 'expect' if @key.downcase == '*expect'
485
- end
486
- end
487
-
488
- # Class to represent a parsed grammar object
489
- class ParsedArrayValueItem < MODL::Parser::MODLParserBaseListener
490
- attr_accessor :map
491
- attr_accessor :array
492
- attr_accessor :pair
493
- attr_accessor :primitive
494
- attr_accessor :text # The simple text value rather than the object
495
-
496
- def initialize(global)
497
- @global = global
498
- end
499
-
500
- def find_property(key)
501
- return @map.find_property(key) if @map
502
- return @array.find_property(key) if @array
503
- return @nbArray.find_property(key) if @nbArray
504
- return @pair.find_property(key) if @pair
505
- return @primitive.find_property(key) if @primitive
506
- end
507
-
508
- def extract_hash
509
- return @map.extract_hash if @map
510
- return @array.extract_hash if @array
511
- return @nbArray.extract_hash if @nbArray
512
- return @pair.extract_hash if @pair
513
- return @primitive.extract_hash if @primitive
514
-
515
- @text
516
- end
517
-
518
- def enterModl_array_value_item(ctx)
519
- @text = nil
520
- modl_map = ctx.modl_map
521
- modl_array = ctx.modl_array
522
- modl_pair = ctx.modl_pair
523
- modl_primitive = ctx.modl_primitive
524
-
525
- if !modl_map.nil?
526
- @map = ParsedMap.new @global
527
- modl_map.enter_rule(@map)
528
- elsif !modl_array.nil?
529
- @array = ParsedArray.new @global
530
- modl_array.enter_rule(@array)
531
- elsif !modl_pair.nil?
532
- @pair = ParsedPair.new @global
533
- modl_pair.enter_rule(@pair)
534
- elsif !modl_primitive.nil?
535
- @primitive = ParsedPrimitive.new @global
536
- modl_primitive.enter_rule(@primitive)
537
- @text = @primitive.text
538
- end
539
-
540
- # ignoring comments!
541
- end
542
- end
543
-
544
- # Class to represent a parsed grammar object
545
- class ParsedValueItem < MODL::Parser::MODLParserBaseListener
546
- attr_accessor :value
547
- attr_accessor :valueConditional
548
-
549
- def initialize(global)
550
- @global = global
551
- end
552
-
553
- def find_property(key)
554
- @value.find_property(key) if @value
555
- end
556
-
557
- def enterModl_value_item(ctx)
558
- modl_value_conditional = ctx.modl_value_conditional
559
- unless modl_value_conditional.nil?
560
- @valueConditional = ParsedValueConditional.new @global
561
- modl_value_conditional.enter_rule(@valueConditional)
562
- end
563
- modl_value = ctx.modl_value
564
- return if modl_value.nil?
565
- @value = ParsedValue.new @global
566
- modl_value.enter_rule(@value)
567
- end
568
-
569
- def extract_hash
570
- return @value.extract_hash if @value
571
- return @valueConditional.extract_hash if @valueConditional
572
- end
573
-
574
- end
575
-
576
- # Class to represent a parsed grammar object
577
- class ParsedValue < MODL::Parser::MODLParserBaseListener
578
- attr_accessor :map
579
- attr_accessor :array
580
- attr_accessor :nbArray
581
- attr_accessor :pair
582
- attr_accessor :primitive
583
- attr_accessor :text # The simple text value rather than the object
584
-
585
- def initialize(global)
586
- @global = global
587
- end
588
-
589
- def find_property(key)
590
- return @map.find_property(key) if @map
591
- return @array.find_property(key) if @array
592
- return @nbArray.find_property(key) if @nbArray
593
- return @pair.find_property(key) if @pair
594
- return @primitive.find_property(key) if @primitive
595
- end
596
-
597
- def extract_hash
598
- return @map.extract_hash if @map
599
- return @array.extract_hash if @array
600
- return @nbArray.extract_hash if @nbArray
601
- return @pair.extract_hash if @pair
602
- return @primitive.extract_hash if @primitive
603
-
604
- @text
605
- end
606
-
607
- def evaluate
608
- return @primitive.evaluate if @primitive
609
-
610
- true
611
- end
612
-
613
- def value_obj
614
- return @map if @map
615
- return @array if @array
616
- return @nbArray if @nbArray
617
- return @pair if @pair
618
- return @primitive if @primitive
619
- end
620
-
621
- def enterModl_value(ctx)
622
- modl_map = ctx.modl_map
623
- modl_nb_array = ctx.modl_nb_array
624
- modl_array = ctx.modl_array
625
- modl_pair = ctx.modl_pair
626
- modl_primitive = ctx.modl_primitive
627
-
628
- if !modl_map.nil?
629
- @map = ParsedMap.new @global
630
- modl_map.enter_rule(@map)
631
- elsif !modl_nb_array.nil?
632
- @nbArray = ParsedNbArray.new @global
633
- modl_nb_array.enter_rule(@nbArray)
634
- elsif !modl_array.nil?
635
- @array = ParsedArray.new @global
636
- modl_array.enter_rule(@array)
637
- elsif !modl_pair.nil?
638
- @pair = ParsedPair.new @global
639
- modl_pair.enter_rule(@pair)
640
- elsif !modl_primitive.nil?
641
- @primitive = ParsedPrimitive.new @global
642
- modl_primitive.enter_rule(@primitive)
643
- @text = @primitive.text
644
- end
645
- # ignoring comments!
646
- end
647
- end
648
-
649
- # Class to represent a parsed grammar object
650
- class ParsedPrimitive < MODL::Parser::MODLParserBaseListener
651
- attr_accessor :quoted
652
- attr_accessor :number
653
- attr_accessor :trueVal
654
- attr_accessor :falseVal
655
- attr_accessor :nilVal
656
- attr_accessor :string
657
- attr_accessor :constant
658
- attr_accessor :text # The simple text value rather than the object
659
-
660
- def initialize(global)
661
- @global = global
662
- @constant = false
663
- end
664
-
665
- def find_property(key)
666
- if @string
667
- user_method = @global.user_method(key)
668
- if user_method
669
- return user_method.run(@string.string)
670
- end
671
- StandardMethods.run_method(key, Substitutions.process(UnicodeEscapes.process(@string.string)))
672
- end
673
- end
674
-
675
- def extract_hash
676
- result, _ignore = RefProcessor.deref(@text, @global) unless @constant
677
- result = @text if @constant
678
- Substitutions.process UnicodeEscapes.process result
679
- end
680
-
681
- def evaluate
682
- return false if @nilVal
683
- return false if @falseVal
684
-
685
- true
686
- end
687
-
688
- def value_obj
689
- return @quoted if @quoted
690
- return @number if @number
691
- return @trueVal if @trueVal
692
- return @falseVal if @falseVal
693
- return @nilVal if @nilVal
694
- return @string if @string
695
-
696
- @text
697
- end
698
-
699
- def enterModl_primitive(ctx)
700
- ctx_number = ctx.NUMBER
701
- ctx_string = ctx.STRING
702
- ctx_quoted = ctx.QUOTED
703
- ctx_null = ctx.NULL
704
- ctx_true = ctx.TRUE
705
- ctx_false = ctx.FALSE
706
-
707
- if !ctx_number.nil?
708
- @number = ParsedNumber.new(ctx_number.text)
709
- @text = @number.num
710
- elsif !ctx_string.nil?
711
- @text = ctx_string.text
712
-
713
- @constant = @text.start_with?('`') && !@text.include?('%') && !@text.include?('`.')
714
- @string = ParsedString.new(@text)
715
- @text = @string.string
716
- elsif !ctx_quoted.nil?
717
- @constant = true
718
- @text = Sutil.toptail ctx_quoted.text
719
- @quoted = ParsedQuoted.new(@text)
720
- elsif !ctx_null.nil?
721
- @nilVal = ParsedNull.instance
722
- @text = nil
723
- elsif !ctx_true.nil?
724
- @trueVal = ParsedTrue.instance
725
- @text = true
726
- elsif !ctx_false.nil?
727
- @falseVal = ParsedFalse.instance
728
- @text = false
729
- end
730
- # ignoring comments!
731
- end
732
- end
733
-
734
- # Class to represent a parsed grammar object
735
- class ParsedString
736
- attr_accessor :string
737
-
738
- def initialize(string)
739
- @string = string
740
- end
741
-
742
- def text
743
- @string
744
- end
745
-
746
- def extract_hash
747
- @string = Substitutions.process UnicodeEscapes.process @string
748
- end
749
- end
750
-
751
- # Class to represent a parsed grammar object
752
- class ParsedNumber
753
- attr_accessor :num
754
-
755
- def initialize(string)
756
- @num = string.include?('.') ? string.to_f : string.to_i
757
- end
758
- end
759
-
760
- # Class to represent a parsed grammar object
761
- class ParsedQuoted
762
- attr_accessor :string
763
-
764
- def initialize(string)
765
- @string = string
766
- end
767
- end
768
-
769
- # Class to represent a parsed grammar object
770
- class ParsedConditionTest < MODL::Parser::MODLParserBaseListener
771
- attr_accessor :subConditionList
772
-
773
- def initialize(global)
774
- @global = global
775
- @subConditionList = []
776
- end
777
-
778
- def evaluate
779
- result = false
780
- @subConditionList.each do |s|
781
- last_operator = s.b.a
782
- should_negate = s.b.b
783
-
784
- partial = s.a.evaluate
785
- case last_operator
786
- when '&'
787
- result &= should_negate ? !partial : partial
788
- when '|'
789
- result |= should_negate ? !partial : partial
790
- else
791
- result |= should_negate ? !partial : partial
792
- end
793
- end
794
- result
795
- end
796
-
797
- def enterModl_condition_test(ctx)
798
- ctx_children = ctx.children
799
- unless ctx_children.empty?
800
- last_operator = nil
801
- should_negate = false
802
- ctx_children.each do |child|
803
- if child.is_a? MODLParser::Modl_condition_groupContext
804
- condition_group = ParsedConditionGroup.new @global
805
- child.enter_rule(condition_group)
806
-
807
- p2 = OpenStruct.new
808
- p2.a = last_operator
809
- p2.b = should_negate
810
-
811
- p1 = OpenStruct.new
812
- p1.a = condition_group
813
- p1.b = p2
814
-
815
- @subConditionList << p1
816
-
817
- last_operator = nil
818
- should_negate = false
819
- elsif child.is_a? MODLParser::Modl_conditionContext
820
- condition = ParsedCondition.new @global
821
- child.enter_rule(condition)
822
- p2 = OpenStruct.new
823
- p2.a = last_operator
824
- p2.b = should_negate
825
-
826
- p1 = OpenStruct.new
827
- p1.a = condition
828
- p1.b = p2
829
-
830
- @subConditionList << p1
831
-
832
- last_operator = nil
833
- should_negate = false
834
- else
835
- if child.text == '!'
836
- should_negate = true
837
- else
838
- last_operator = child.text
839
- end
840
- end
841
- end
842
- end
843
- end
844
- end
845
-
846
- # Class to represent a parsed grammar object
847
- class ParsedConditionGroup < MODL::Parser::MODLParserBaseListener
848
- attr_accessor :conditionsTestList
849
-
850
- def initialize(global)
851
- @global = global
852
- @conditionsTestList = []
853
- end
854
-
855
- def evaluate
856
- result = false
857
- @conditionsTestList.each do |s|
858
- partial = s.a.evaluate
859
- result |= partial
860
- end
861
- result
862
- end
863
-
864
- def enterModl_condition_group(ctx)
865
- ctx_children = ctx.children
866
- return if ctx_children.empty?
867
-
868
- last_operator = nil
869
- ctx_children.each do |child|
870
- if child.is_a? MODLParser::Modl_condition_testContext
871
- condition_test = ParsedConditionTest.new @global
872
- child.enter_rule(condition_test)
873
- p = OpenStruct.new
874
- p.a = condition_test
875
- p.b = last_operator
876
- @conditionsTestList << p
877
- last_operator = nil
878
- else
879
- last_operator = child.text if (child.text != '') && (child.text != '}')
880
- end
881
- end
882
- end
883
- end
884
-
885
- # Class to represent a parsed grammar object
886
- class ParsedCondition < MODL::Parser::MODLParserBaseListener
887
- attr_accessor :values
888
- attr_accessor :operator
889
- attr_accessor :text
890
-
891
- def initialize(global)
892
- @global = global
893
- @values = []
894
- end
895
-
896
- def evaluate
897
- Evaluator.evaluate(@global, self)
898
- end
899
-
900
- def enterModl_condition(ctx)
901
- modl_operator = ctx.modl_operator
902
- @operator = modl_operator.text unless modl_operator.nil?
903
- modl_value = ctx.modl_value
904
- modl_value.each do |v|
905
- value = ParsedValue.new @global
906
- v.enter_rule(value)
907
- @values << value
908
- end
909
- ctx_string = ctx.STRING
910
- if !ctx_string.nil?
911
- @text = Parsed.additional_string_processing(ctx_string.text)
912
- @string = ParsedString.new(@text)
913
- @text = @string.string
914
- end
915
- end
916
- end
917
-
918
- # Class to represent a parsed grammar object
919
- class ParsedMapConditionalReturn < MODL::Parser::MODLParserBaseListener
920
- attr_accessor :mapItems
921
-
922
- def initialize(global)
923
- @global = global
924
- @mapItems = []
925
- end
926
-
927
- def extract_hash
928
- @mapItems[0].extract_hash
929
- end
930
-
931
- def enterModl_map_conditional_return(ctx)
932
- modl_map_item = ctx.modl_map_item
933
- return if modl_map_item.empty?
934
-
935
- modl_map_item.each do |mi|
936
- map_item = ParsedMapItem.new @global
937
- mi.enter_rule(map_item)
938
- @mapItems << map_item
939
- end
940
- end
941
- end
942
-
943
- # Class to represent a parsed grammar object
944
- class ParsedMapConditional < MODL::Parser::MODLParserBaseListener
945
- attr_accessor :conditionTests
946
- attr_accessor :mapConditionalReturns
947
-
948
- def initialize(global)
949
- @global = global
950
- @conditionTests = []
951
- @mapConditionalReturns = []
952
- end
953
-
954
- def extract_hash
955
- return @mapConditionalReturns[0].extract_hash if @result
956
-
957
- @mapConditionalReturns[1].extract_hash if @mapConditionalReturns.length > 1
958
- end
959
-
960
- def enterModl_map_conditional(ctx)
961
- i = 0
962
- modl_condition_test = ctx.modl_condition_test
963
- ctx_modl_map_conditional_return = ctx.modl_map_conditional_return
964
-
965
- while i < modl_condition_test.size
966
- condition_test = ParsedConditionTest.new @global
967
- ctx.modl_condition_test_i(i).enter_rule(condition_test)
968
-
969
- conditional_return = ParsedMapConditionalReturn.new @global
970
- ctx.modl_map_conditional_return_i(i).enter_rule(conditional_return)
971
- @conditionTests[i] = condition_test
972
- @mapConditionalReturns[i] = conditional_return
973
-
974
- if ctx_modl_map_conditional_return.size > modl_condition_test.size
975
- i += 1
976
- conditional_return = ParsedMapConditionalReturn.new @global
977
- ctx.modl_map_conditional_return_i(ctx_modl_map_conditional_return.size - 1).enter_rule(conditional_return)
978
- @mapConditionalReturns[i] = conditional_return
979
- end
980
- i += 1
981
- end
982
- @result = @conditionTests[0].evaluate
983
- end
984
- end
985
-
986
- # Class to represent a parsed grammar object
987
- class ParsedTopLevelConditionalReturn < MODL::Parser::MODLParserBaseListener
988
- attr_accessor :structures
989
-
990
- def initialize(global)
991
- @global = global
992
- @structures = []
993
- end
994
-
995
- def extract_hash
996
- return @structures[0].extract_hash if @structures.length == 1
997
-
998
- result = []
999
- @structures.each do |s|
1000
- hash = s.extract_hash
1001
- result << hash unless hash.nil?
1002
- end
1003
- return result unless result.length == 1
1004
- return result[0] if result.length == 1
1005
- end
1006
-
1007
- def enterModl_top_level_conditional_return(ctx)
1008
- modl_structure = ctx.modl_structure
1009
- return if modl_structure.empty?
1010
-
1011
- modl_structure.each do |str|
1012
- structure = ParsedStructure.new @global
1013
- str.enter_rule(structure)
1014
- @structures << structure
1015
- end
1016
- end
1017
- end
1018
-
1019
- # Class to represent a parsed grammar object
1020
- class ParsedTopLevelConditional < MODL::Parser::MODLParserBaseListener
1021
- attr_accessor :conditionTests
1022
- attr_accessor :topLevelConditionalReturns
1023
-
1024
- def initialize(global)
1025
- @global = global
1026
- @topLevelConditionalReturns = []
1027
- @conditionTests = []
1028
- @file_importer = FileImporter.instance
1029
- end
1030
-
1031
- def extract_hash
1032
- @conditionTests.each_index do |i|
1033
- next unless @conditionTests[i].evaluate
1034
-
1035
- item = @topLevelConditionalReturns[i]
1036
- if item.structures[0].pair
1037
- key = item.structures[0].pair.key
1038
- key = Sutil.tail(key) if key[0] == '_'
1039
- pair = item.structures[0].pair
1040
- @global.pair(key, pair)
1041
-
1042
- if key.downcase.start_with? '*l'
1043
- files = pair.valueItem.extract_hash if pair.valueItem
1044
- files = pair.array.extract_hash if pair.array
1045
- unless pair.loaded
1046
- @file_importer.import_files files, @global
1047
- pair.loaded = true
1048
- end
1049
- end
1050
- end
1051
- item.structures = OrphanHandler.adopt(@global, item.structures)
1052
- return item.extract_hash
1053
- end
1054
- return unless @topLevelConditionalReturns.length > @conditionTests.length
1055
-
1056
- last_item = @topLevelConditionalReturns[-1]
1057
- if last_item.structures[0].pair
1058
- key = last_item.structures[0].pair.key
1059
- key = Sutil.tail(key) if key[0] == '_'
1060
- pair = last_item.structures[0].pair
1061
- @global.pair(key, pair)
1062
-
1063
- if key.downcase.start_with? '*l'
1064
- files = pair.valueItem.extract_hash if pair.valueItem
1065
- files = pair.array.extract_hash if pair.array
1066
- unless pair.loaded
1067
- @file_importer.import_files files, @global
1068
- pair.loaded = true
1069
- end
1070
- end
1071
- end
1072
- last_item.extract_hash
1073
- end
1074
-
1075
- def enterModl_top_level_conditional(ctx)
1076
- @global.enter_condition
1077
- i = 0
1078
- modl_condition_test = ctx.modl_condition_test
1079
- ctx_modl_top_level_conditional_return = ctx.modl_top_level_conditional_return
1080
-
1081
- while i < modl_condition_test.size
1082
- condition_test = ParsedConditionTest.new @global
1083
- ctx.modl_condition_test_i(i).enter_rule(condition_test)
1084
-
1085
- conditional_return = ParsedTopLevelConditionalReturn.new @global
1086
- ctx.modl_top_level_conditional_return_i(i).enter_rule(conditional_return)
1087
- @conditionTests[i] = condition_test
1088
- @topLevelConditionalReturns[i] = conditional_return
1089
- i += 1
1090
- end
1091
- if ctx_modl_top_level_conditional_return.size > modl_condition_test.size
1092
- conditional_return = ParsedTopLevelConditionalReturn.new @global
1093
- ctx.modl_top_level_conditional_return_i(ctx_modl_top_level_conditional_return.size - 1).enter_rule(conditional_return)
1094
- @topLevelConditionalReturns[i] = conditional_return
1095
- end
1096
- extract_hash
1097
- @global.exit_condition
1098
- end
1099
- end
1100
-
1101
- # Class to represent a parsed grammar object
1102
- class ParsedArrayConditionalReturn < MODL::Parser::MODLParserBaseListener
1103
- attr_accessor :arrayItems
1104
-
1105
- def initialize(global)
1106
- @global = global
1107
- @arrayItems = []
1108
- end
1109
-
1110
- def extract_hash
1111
- @arrayItems[0].arrayValueItem.text
1112
- end
1113
-
1114
- def enterModl_array_conditional_return(ctx)
1115
- modl_array_item = ctx.modl_array_item
1116
- return if modl_array_item.empty?
1117
-
1118
- modl_array_item.each do |ai|
1119
- array_item = ParsedArrayItem.new @global
1120
- ai.enter_rule(array_item)
1121
- @arrayItems << array_item
1122
- end
1123
- end
1124
- end
1125
-
1126
- # Class to represent a parsed grammar object
1127
- class ParsedArrayConditional < MODL::Parser::MODLParserBaseListener
1128
- attr_accessor :conditionTest
1129
- attr_accessor :arrayConditionalReturns
1130
-
1131
- def initialize(global)
1132
- @global = global
1133
- @conditionTests = []
1134
- @arrayConditionalReturns = []
1135
- end
1136
-
1137
- def extract_hash
1138
- result = @conditionTests[0].evaluate
1139
- return @arrayConditionalReturns[0].extract_hash if result
1140
- @arrayConditionalReturns[1].extract_hash
1141
- end
1142
-
1143
- def enterModl_array_conditional(ctx)
1144
- i = 0
1145
- ctx_modl_condition_test = ctx.modl_condition_test
1146
- ctx_modl_array_conditional_return = ctx.modl_array_conditional_return
1147
-
1148
- while i < ctx_modl_condition_test.size
1149
- condition_test = ParsedConditionTest.new @global
1150
- ctx.modl_condition_test_i(i).enter_rule(condition_test)
1151
-
1152
- conditional_return = ParsedArrayConditionalReturn.new @global
1153
- ctx.modl_array_conditional_return_i(i).enter_rule(conditional_return)
1154
- @conditionTests[i] = condition_test
1155
- @arrayConditionalReturns[i] = conditional_return
1156
-
1157
- if ctx_modl_array_conditional_return.size > ctx_modl_condition_test.size
1158
- i += 1
1159
- condition_test = ParsedConditionTest.new @global
1160
- conditional_return = ParsedArrayConditionalReturn.new @global
1161
- ctx.modl_array_conditional_return_i(ctx_modl_array_conditional_return.size - 1).enter_rule(conditional_return)
1162
- @conditionTests[i] = condition_test
1163
- @arrayConditionalReturns[i] = conditional_return
1164
- end
1165
-
1166
-
1167
- i += 1
1168
- end
1169
- end
1170
- end
1171
-
1172
- # Class to represent a parsed grammar object
1173
- class ParsedValueConditionalReturn < MODL::Parser::MODLParserBaseListener
1174
- attr_accessor :valueItems
1175
-
1176
- def initialize(global)
1177
- @global = global
1178
- @valueItems = []
1179
- end
1180
-
1181
- def extract_hash
1182
- return @valueItems[0].value.text if @valueItems[0].value.text
1183
-
1184
- return @valueItems[0].value.extract_hash
1185
- end
1186
-
1187
- def enterModl_value_conditional_return(ctx)
1188
- modl_value_item = ctx.modl_value_item
1189
- return if modl_value_item.empty?
1190
-
1191
- modl_value_item.each do |vi|
1192
- valueItem = ParsedValueItem.new @global
1193
- vi.enter_rule(valueItem)
1194
- @valueItems << valueItem
1195
- end
1196
- end
1197
- end
1198
-
1199
- # Class to represent a parsed grammar object
1200
- class ParsedValueConditional < MODL::Parser::MODLParserBaseListener
1201
- attr_accessor :conditionTests
1202
- attr_accessor :valueConditionalReturns
1203
-
1204
- def initialize(global)
1205
- @global = global
1206
- @conditionTests = []
1207
- @valueConditionalReturns = []
1208
- end
1209
-
1210
- def extract_hash
1211
- return @result if @valueConditionalReturns.length == 0
1212
- return @valueConditionalReturns[0].extract_hash if @result
1213
- return @valueConditionalReturns[1].extract_hash
1214
- end
1215
-
1216
- def enterModl_value_conditional(ctx)
1217
- i = 0
1218
- ctx_modl_condition_test = ctx.modl_condition_test
1219
- ctx_modl_value_conditional_return = ctx.modl_value_conditional_return
1220
-
1221
- while i < ctx_modl_condition_test.size
1222
- condition_test = ParsedConditionTest.new @global
1223
- ctx.modl_condition_test_i(i).enter_rule(condition_test)
1224
-
1225
- @conditionTests[i] = condition_test
1226
-
1227
- break if ctx.modl_value_conditional_return_i(i).nil?
1228
-
1229
- conditional_return = ParsedValueConditionalReturn.new @global
1230
-
1231
- ctx.modl_value_conditional_return_i(i).enter_rule(conditional_return)
1232
-
1233
- @valueConditionalReturns[i] = conditional_return
1234
-
1235
- if ctx_modl_value_conditional_return.size > ctx_modl_condition_test.size
1236
- condition_test = ParsedConditionTest.new @global
1237
- conditional_return = ParsedValueConditionalReturn.new @global
1238
- ctx.modl_value_conditional_return_i(ctx_modl_value_conditional_return.size - 1).enter_rule(conditional_return)
1239
- @conditionTests[i + 1] = condition_test
1240
- @valueConditionalReturns[i + 1] = conditional_return
1241
- end
1242
-
1243
- i += 1
1244
- end
1245
- @result = @conditionTests[0].evaluate
1246
- end
1247
- end
1248
-
1249
- # Class to represent a parsed grammar object
1250
- class ParsedNbArray < MODL::Parser::MODLParserBaseListener
1251
- attr_accessor :arrayItems
1252
-
1253
- def initialize(global)
1254
- @global = global
1255
- @arrayItems = []
1256
- end
1257
-
1258
- def find_property(key)
1259
- if key.is_a? Integer
1260
- return @arrayItems[key].arrayValueItem
1261
- else
1262
- @arrayItems.each do |mi|
1263
- return mi.arrayValueItem.pair if mi.arrayValueItem.pair && mi.arrayValueItem.pair.key == key
1264
- end
1265
- nil
1266
- end
1267
- end
1268
-
1269
- def extract_hash
1270
- result = []
1271
-
1272
- @arrayItems.each do |i|
1273
- result << i.extract_hash
1274
- end
1275
-
1276
- result
1277
- end
1278
-
1279
- def enterModl_nb_array(ctx)
1280
- i = 0
1281
- previous = nil
1282
- ctx_children = ctx.children
1283
- ctx_children.each do |pt|
1284
- if pt.is_a? MODLParser::Modl_array_itemContext
1285
- array_item = ParsedArrayItem.new @global
1286
- pt.enter_rule(array_item)
1287
- @arrayItems[i] = array_item
1288
- i += 1
1289
- elsif pt.is_a? Antlr4::Runtime::TerminalNode
1290
- if !previous.nil? && previous.is_a?(Antlr4::Runtime::TerminalNode) && pt.is_a?(Antlr4::Runtime::TerminalNode)
1291
- # If we get here then we have two terminal nodes in a row, so we need to output something unless # the terminal symbols are newlines
1292
- #
1293
- prev_symbol = previous.symbol.type
1294
- current_symbol = pt.symbol.type
1295
-
1296
- if prev_symbol == MODLLexer::COLON && current_symbol == MODLLexer::COLON
1297
- array_item = Parsed.handle_empty_array_item
1298
- @arrayItems[i] = array_item
1299
- i += 1
1300
- end
1301
- end
1302
- end
1303
- previous = pt
1304
- end
1305
- end
1306
- end
1307
-
1308
- def self.handle_empty_array_item
1309
- # Create something for the blank array item
1310
- #
1311
- # The problem is that we might not have any context to tell us what type we need to create
1312
- # so this currently defaults to the nil value
1313
- #
1314
- # TODO : Is there a way to know the type to create or is nil always acceptable?
1315
- array_item = ParsedArrayItem.new @global
1316
- array_item.arrayValueItem = ParsedArrayValueItem.new @global
1317
- array_item.arrayValueItem.primitive = ParsedPrimitive.new @global
1318
- array_item.arrayValueItem.primitive.nilVal = ParsedNull.instance
1319
- array_item
1320
- end
1321
-
1322
- # Class to represent a parsed grammar object
1323
- class ParsedArray < MODL::Parser::MODLParserBaseListener
1324
- # We now have a list of < array_item | nb_array >
1325
- attr_accessor :abstractArrayItems
1326
-
1327
- def initialize(global)
1328
- @global = global
1329
- @abstractArrayItems = []
1330
- end
1331
-
1332
- def find_property(key)
1333
- if key.is_a? Integer
1334
- return @abstractArrayItems[key]
1335
- else
1336
- @abstractArrayItems.each do |mi|
1337
- return mi.arrayValueItem.pair if mi.arrayValueItem.pair && mi.arrayValueItem.pair.key == key
1338
- end
1339
- nil
1340
- end
1341
- end
1342
-
1343
- def extract_hash
1344
- result = []
1345
-
1346
- abstractArrayItems.each do |i|
1347
- result << i.extract_hash
1348
- end
1349
-
1350
- result
1351
- end
1352
-
1353
- def enterModl_array(ctx)
1354
- # Create the new abstractArrayItems list first, sized to the total of array_item.size and nb_array.size
1355
- i = 0
1356
- previous = nil
1357
- ctx_children = ctx.children
1358
- ctx_children.each do |pt|
1359
- if pt.is_a? MODLParser::Modl_array_itemContext
1360
- array_item = ParsedArrayItem.new @global
1361
- pt.enter_rule(array_item)
1362
- @abstractArrayItems[i] = array_item
1363
- i += 1
1364
- elsif pt.is_a? MODLParser::Modl_nb_arrayContext
1365
- nb_array = ParsedNbArray.new @global
1366
- pt.enter_rule(nb_array)
1367
- @abstractArrayItems[i] = nb_array
1368
- i += 1
1369
- elsif pt.is_a? Antlr4::Runtime::TerminalNode
1370
- if !previous.nil? && previous.is_a?(Antlr4::Runtime::TerminalNode) && pt.is_a?(Antlr4::Runtime::TerminalNode)
1371
-
1372
- # If we get here then we have two terminal nodes in a row, so we need to output something unless # the terminal symbols are newlines
1373
- #
1374
- prev_symbol = previous.symbol.type
1375
- current_symbol = pt.symbol.type
1376
-
1377
- if prev_symbol == MODLLexer::LSBRAC && current_symbol == MODLLexer::RSBRAC
1378
- next # This allows empty arrays
1379
- end
1380
-
1381
- if prev_symbol == MODLLexer::STRUCT_SEP && current_symbol == MODLLexer::STRUCT_SEP
1382
-
1383
- # Create something for the blank array item
1384
- #
1385
- # The problem is that we might not have any context to tell us what type we need to create
1386
- # so this currently defaults to the nil
1387
- #
1388
- # TODO : Is there a way to know the type to create or is nil always acceptable?
1389
- array_item = Parsed.handle_empty_array_item
1390
-
1391
- @abstractArrayItems[i] = array_item
1392
- i += 1
1393
- end
1394
- end
1395
- end
1396
- previous = pt
1397
- end
1398
- end
1399
- end
1400
-
1401
- # Class to represent a parsed grammar object
1402
- class ParsedArrayItem < MODL::Parser::MODLParserBaseListener
1403
- attr_accessor :arrayValueItem
1404
- attr_accessor :arrayConditional
1405
-
1406
- def initialize(global)
1407
- @global = global
1408
- end
1409
-
1410
- def find_property(key)
1411
- return @arrayValueItem.find_property(key)
1412
- end
1413
-
1414
- def enterModl_array_item(ctx)
1415
- ctx_modl_array_conditional = ctx.modl_array_conditional
1416
- unless ctx_modl_array_conditional.nil?
1417
- @arrayConditional = ParsedArrayConditional.new @global
1418
- ctx_modl_array_conditional.enter_rule(@arrayConditional)
1419
- end
1420
- ctx_modl_array_value_item = ctx.modl_array_value_item
1421
- unless ctx_modl_array_value_item.nil?
1422
- @arrayValueItem = ParsedArrayValueItem.new @global
1423
- ctx_modl_array_value_item.enter_rule(@arrayValueItem)
1424
- end
1425
- end
1426
-
1427
- def extract_hash
1428
- return @arrayValueItem.extract_hash if @arrayValueItem
1429
- return @arrayConditional.extract_hash if @arrayConditional
1430
- end
1431
-
1432
- end
1433
-
1434
- # Singleton class to represent a true value
1435
- class ParsedTrue < MODL::Parser::MODLParserBaseListener
1436
- include Singleton
1437
- end
1438
-
1439
- # Singleton class to represent a false value
1440
- class ParsedFalse < MODL::Parser::MODLParserBaseListener
1441
- include Singleton
1442
- end
1443
-
1444
- # Singleton class to represent a null value
1445
- class ParsedNull < MODL::Parser::MODLParserBaseListener
1446
- include Singleton
1447
- end
1448
-
1449
- # Convert the parse tree to a simpler structure suitable for JSON.generate.
1450
- def extract_hash
1451
- result = []
1452
- if @structures.length.positive?
1453
- @structures.each do |s|
1454
- value = s.extract_hash
1455
- result << value unless value.nil?
1456
- end
1457
- else
1458
- result = {}
1459
- end
1460
- case result.length
1461
- when 0
1462
- return nil
1463
- when 1
1464
- return result[0]
1465
- end
1466
- result
1467
- end
1468
- end
1469
- end
1470
- end