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