modl 0.3.25 → 0.3.27

Sign up to get free protection for your applications and to get access to all the features.
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