modl 0.3.26 → 0.3.28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -149
- data/Gemfile +4 -2
- data/LICENSE.txt +1 -1
- data/README.md +19 -11
- data/Rakefile +5 -3
- data/lib/modl/interpreter.rb +38 -0
- data/lib/modl/model/model.rb +264 -0
- data/lib/modl/parser/parser.rb +280 -59
- data/lib/modl/tokeniser/context.rb +113 -0
- data/lib/modl/tokeniser/tokeniser.rb +28 -0
- data/lib/modl/util/functions.rb +74 -0
- data/lib/modl/util/unicode.rb +44 -0
- data/lib/modl/version.rb +5 -0
- data/lib/modl.rb +7 -32
- data/modl.gemspec +8 -11
- metadata +16 -75
- data/.DS_Store +0 -0
- data/.idea/vcs.xml +0 -6
- data/.rspec +0 -3
- data/.rubocop.yml +0 -5
- data/.travis.yml +0 -7
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/modl/parser/MODLLexer.interp +0 -132
- data/lib/modl/parser/MODLLexer.rb +0 -324
- data/lib/modl/parser/MODLLexer.tokens +0 -40
- data/lib/modl/parser/MODLParser.interp +0 -93
- data/lib/modl/parser/MODLParser.rb +0 -2492
- data/lib/modl/parser/MODLParser.tokens +0 -40
- data/lib/modl/parser/MODLParserBaseListener.rb +0 -164
- data/lib/modl/parser/MODLParserBaseVisitor.rb +0 -107
- data/lib/modl/parser/MODLParserListener.rb +0 -151
- data/lib/modl/parser/MODLParserVisitor.rb +0 -56
- data/lib/modl/parser/class_processor.rb +0 -411
- data/lib/modl/parser/evaluator.rb +0 -125
- data/lib/modl/parser/file_importer.rb +0 -101
- data/lib/modl/parser/global_parse_context.rb +0 -318
- data/lib/modl/parser/instruction_processor.rb +0 -82
- data/lib/modl/parser/interpreter.rb +0 -75
- data/lib/modl/parser/modl_class.rb +0 -138
- data/lib/modl/parser/modl_index.rb +0 -54
- data/lib/modl/parser/modl_keylist.rb +0 -81
- data/lib/modl/parser/modl_method.rb +0 -172
- data/lib/modl/parser/object_cache.rb +0 -88
- data/lib/modl/parser/orphan_handler.rb +0 -98
- data/lib/modl/parser/parsed.rb +0 -1469
- data/lib/modl/parser/ref_processor.rb +0 -258
- data/lib/modl/parser/substitutions.rb +0 -101
- data/lib/modl/parser/sutil.rb +0 -108
- data/lib/modl/parser/throwing_error_listener.rb +0 -44
- data/lib/modl/parser/unicode_escape_replacer.rb +0 -148
- data/lib/modl/parser/unicode_escapes.rb +0 -112
- data/lib/modl/parser/version.rb +0 -29
@@ -1,318 +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
|
-
module MODL
|
26
|
-
module Parser
|
27
|
-
# Each time we run the parser on a MODL file we need to keep track of a few things so they can be made available
|
28
|
-
# to other areas of the code. This class is the container for that contextual information, which is gathered
|
29
|
-
# as the MODL::Parser:Parsed object processes the parse tree.
|
30
|
-
class GlobalParseContext
|
31
|
-
|
32
|
-
attr_accessor :syntax_version
|
33
|
-
attr_accessor :max_files_allowed
|
34
|
-
attr_accessor :structures
|
35
|
-
attr_reader :interpreter_syntax_version
|
36
|
-
attr_reader :loaded_files
|
37
|
-
|
38
|
-
def initialize
|
39
|
-
# This keeps track of all loaded structures from parsed files.
|
40
|
-
@structures = []
|
41
|
-
# This is set to true if we encounter a *L[OAD] instruction
|
42
|
-
@max_files_allowed = 2147483647
|
43
|
-
# Holds the index array from a MODL file, e.g. '?=a:b:c:d'
|
44
|
-
@index = []
|
45
|
-
# Contains all pairs as they are encountered in the parsing process.
|
46
|
-
@pairs = {}
|
47
|
-
# Contains all defined and loaded classes for the current MODL document.
|
48
|
-
@classes_by_id = {}
|
49
|
-
@classes_by_name = {}
|
50
|
-
# Hold the user-defined methods.
|
51
|
-
@methods_hash = {}
|
52
|
-
@methods_by_id = {}
|
53
|
-
# Tracks the nesting depth for conditional clauses.
|
54
|
-
@conditional = 0
|
55
|
-
# Defaults to 1 and can be overridden by the *version command.
|
56
|
-
@syntax_version = 1
|
57
|
-
@interpreter_syntax_version = 1
|
58
|
-
@loaded_files = []
|
59
|
-
# Arrays
|
60
|
-
@arrays_by_id = {}
|
61
|
-
@arrays_by_name = {}
|
62
|
-
end
|
63
|
-
|
64
|
-
def loaded_file(str)
|
65
|
-
@loaded_files << str unless str.nil?
|
66
|
-
raise InterpreterError, 'Cannot load multiple files after *LOAD instruction' if @loaded_files.length > @max_files_allowed
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def index_value(n, default)
|
71
|
-
return default if n > @index.length
|
72
|
-
|
73
|
-
@index[n]
|
74
|
-
end
|
75
|
-
|
76
|
-
def in_condition?
|
77
|
-
@conditional.positive?
|
78
|
-
end
|
79
|
-
|
80
|
-
def freeze_max_files(plus)
|
81
|
-
@max_files_allowed = @loaded_files.length + plus
|
82
|
-
end
|
83
|
-
|
84
|
-
def enter_condition
|
85
|
-
@conditional += 1
|
86
|
-
end
|
87
|
-
|
88
|
-
def exit_condition
|
89
|
-
@conditional -= 1
|
90
|
-
end
|
91
|
-
|
92
|
-
def pair(key, val = nil)
|
93
|
-
return @pairs[key] unless val
|
94
|
-
|
95
|
-
@pairs[key] = val
|
96
|
-
end
|
97
|
-
|
98
|
-
def classs(key)
|
99
|
-
if key.is_a? String
|
100
|
-
result = @classes_by_id[key]
|
101
|
-
result = @classes_by_name[key] if result.nil?
|
102
|
-
result
|
103
|
-
elsif key.is_a? MODLClass
|
104
|
-
@classes_by_id[key.id] = key if key.id
|
105
|
-
@classes_by_name[key.name] = key if key.name
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def arrays(key)
|
110
|
-
if key.is_a? String
|
111
|
-
result = @arrays_by_id[key]
|
112
|
-
result = @arrays_by_name[key] if result.nil?
|
113
|
-
result
|
114
|
-
elsif key.is_a? MODLArray
|
115
|
-
@arrays_by_id[key.id] = key if key.id
|
116
|
-
@arrays_by_name[key.name] = key if key.name
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def merge_pairs(other)
|
121
|
-
@pairs.merge!(other.all_pairs)
|
122
|
-
end
|
123
|
-
|
124
|
-
def merge_classes(other)
|
125
|
-
@classes_by_id.merge!(other.all_classes_by_id)
|
126
|
-
@classes_by_name.merge!(other.all_classes_by_name)
|
127
|
-
end
|
128
|
-
|
129
|
-
def merge_loaded_files(other)
|
130
|
-
@loaded_files.concat(other.loaded_files)
|
131
|
-
raise InterpreterError, 'Cannot load multiple files after *LOAD instruction' if @loaded_files.length > @max_files_allowed
|
132
|
-
end
|
133
|
-
|
134
|
-
def has_pairs?
|
135
|
-
@pairs.length.positive?
|
136
|
-
end
|
137
|
-
|
138
|
-
def has_class?(key)
|
139
|
-
@classes_by_id.keys.include?(key) || @classes_by_name.keys.include?(key)
|
140
|
-
end
|
141
|
-
|
142
|
-
def has_array?(key)
|
143
|
-
@arrays_by_id.keys.include?(key) || @arrays_by_name.keys.include?(key)
|
144
|
-
end
|
145
|
-
|
146
|
-
def has_user_method?(key)
|
147
|
-
@methods_hash.keys.include?(key)
|
148
|
-
end
|
149
|
-
|
150
|
-
def add_to_index(item)
|
151
|
-
@index << item
|
152
|
-
end
|
153
|
-
|
154
|
-
def user_method(key, val = nil)
|
155
|
-
return @methods_hash[key] unless val
|
156
|
-
|
157
|
-
@methods_hash[key] = val
|
158
|
-
end
|
159
|
-
|
160
|
-
def user_method_id(key, val)
|
161
|
-
@methods_hash[key] = val
|
162
|
-
@methods_by_id[key] = val
|
163
|
-
end
|
164
|
-
|
165
|
-
def class_list
|
166
|
-
result = []
|
167
|
-
@classes_by_id.values.each do |clazz|
|
168
|
-
new_item = {}
|
169
|
-
new_item[clazz.id] = class_to_hash(clazz)
|
170
|
-
result << new_item
|
171
|
-
end
|
172
|
-
result
|
173
|
-
end
|
174
|
-
|
175
|
-
def method_list
|
176
|
-
result = []
|
177
|
-
@methods_by_id.values.each do |m|
|
178
|
-
new_item = {}
|
179
|
-
new_item[m.id] = method_to_hash(m)
|
180
|
-
result << new_item
|
181
|
-
end
|
182
|
-
result
|
183
|
-
end
|
184
|
-
|
185
|
-
def file_list
|
186
|
-
@loaded_files.dup
|
187
|
-
end
|
188
|
-
|
189
|
-
def id_list
|
190
|
-
ids = {}
|
191
|
-
ids['methods'] = @methods_by_id.keys.dup.sort!
|
192
|
-
ids['classes'] = @classes_by_id.keys.dup.sort!
|
193
|
-
ids
|
194
|
-
end
|
195
|
-
|
196
|
-
def name_list
|
197
|
-
names = {}
|
198
|
-
names['methods'] = @methods_hash.keys.dup.sort!
|
199
|
-
names['classes'] = @classes_by_name.keys.dup.sort!
|
200
|
-
names
|
201
|
-
end
|
202
|
-
|
203
|
-
def superclass_list
|
204
|
-
result = {}
|
205
|
-
@classes_by_id.each do |c|
|
206
|
-
result[c[0]] = c[1].superclass
|
207
|
-
end
|
208
|
-
result
|
209
|
-
end
|
210
|
-
|
211
|
-
def assign_list
|
212
|
-
result = {}
|
213
|
-
@classes_by_id.each do |c|
|
214
|
-
result[c[0]] = c[1].assign
|
215
|
-
end
|
216
|
-
result
|
217
|
-
end
|
218
|
-
|
219
|
-
def transform_list
|
220
|
-
result = {}
|
221
|
-
@methods_by_id.each do |c|
|
222
|
-
result[c[0]] = c[1].transform
|
223
|
-
end
|
224
|
-
result
|
225
|
-
end
|
226
|
-
|
227
|
-
def allow_list
|
228
|
-
result = {}
|
229
|
-
@classes_by_id.each do |c|
|
230
|
-
result[c[0]] = c[1].allow.nil? ? nil : c[1].allow.extract_hash
|
231
|
-
end
|
232
|
-
result
|
233
|
-
end
|
234
|
-
|
235
|
-
protected
|
236
|
-
|
237
|
-
def all_classes_by_id
|
238
|
-
@classes_by_id
|
239
|
-
end
|
240
|
-
|
241
|
-
def all_classes_by_name
|
242
|
-
@classes_by_name
|
243
|
-
end
|
244
|
-
|
245
|
-
def all_pairs
|
246
|
-
result = {}
|
247
|
-
@pairs.keys.each do |k|
|
248
|
-
result[k] = @pairs[k] unless k.start_with?('*')
|
249
|
-
end
|
250
|
-
result
|
251
|
-
end
|
252
|
-
|
253
|
-
private
|
254
|
-
|
255
|
-
def class_to_hash(clazz)
|
256
|
-
map = {}
|
257
|
-
# name
|
258
|
-
map['name'] = clazz.name
|
259
|
-
|
260
|
-
# superclass
|
261
|
-
map['superclass'] = clazz.superclass
|
262
|
-
|
263
|
-
# assign
|
264
|
-
if clazz.assign
|
265
|
-
map['assign'] = clazz.assign
|
266
|
-
end
|
267
|
-
|
268
|
-
# allow
|
269
|
-
if clazz.allow
|
270
|
-
map['allow'] = clazz.allow.extract_hash
|
271
|
-
end
|
272
|
-
|
273
|
-
# expect
|
274
|
-
if clazz.expect
|
275
|
-
map['expect'] = clazz.expect.extract_hash
|
276
|
-
end
|
277
|
-
|
278
|
-
# content
|
279
|
-
if clazz.content.length.positive?
|
280
|
-
clazz.content.each do |item|
|
281
|
-
map[item[0]] = item[1].extract_hash
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
map
|
286
|
-
end
|
287
|
-
|
288
|
-
def method_to_hash(mthd)
|
289
|
-
map = {}
|
290
|
-
# name
|
291
|
-
map['name'] = mthd.name
|
292
|
-
|
293
|
-
# superclass
|
294
|
-
map['transform'] = mthd.transform
|
295
|
-
|
296
|
-
map
|
297
|
-
end
|
298
|
-
|
299
|
-
def new_map_item(key, value)
|
300
|
-
map_item = Parsed::ParsedMapItem.new(self)
|
301
|
-
map_item.pair = Parsed::ParsedPair.new(self)
|
302
|
-
map_item.pair.key = key
|
303
|
-
map_item.pair.valueItem = Parsed::ParsedValueItem.new(self)
|
304
|
-
if value.is_a? Parsed::ParsedValue
|
305
|
-
map_item.pair.valueItem.value = value
|
306
|
-
else
|
307
|
-
map_item.pair.valueItem.value = Parsed::ParsedValue.new(self)
|
308
|
-
map_item.pair.valueItem.value.primitive = Parsed::ParsedPrimitive.new(self)
|
309
|
-
map_item.pair.valueItem.value.primitive = Parsed::ParsedPrimitive.new(self)
|
310
|
-
map_item.pair.valueItem.value.primitive.string = Parsed::ParsedString.new(value)
|
311
|
-
map_item.pair.valueItem.value.primitive.text = value
|
312
|
-
map_item.pair.valueItem.value.text = value
|
313
|
-
end
|
314
|
-
map_item
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
end
|
@@ -1,82 +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
|
-
module MODL
|
26
|
-
module Parser
|
27
|
-
# This class handles the conversion of objects that refer to classes into instances of those classes.
|
28
|
-
# It works recursively since class usage can be nested.
|
29
|
-
class InstructionProcessor
|
30
|
-
def self.process(global, obj)
|
31
|
-
if obj.is_a? Hash
|
32
|
-
nvals = {}
|
33
|
-
obj.keys.each do |k|
|
34
|
-
o = obj[k]
|
35
|
-
if o.is_a? String
|
36
|
-
nv = process_instruction(global, o)
|
37
|
-
nvals[k] = nv unless nv.nil?
|
38
|
-
else
|
39
|
-
process(global, o)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
obj.merge!(nvals)
|
43
|
-
elsif obj.is_a? Array
|
44
|
-
i = 0
|
45
|
-
while i < obj.length
|
46
|
-
o = obj[i]
|
47
|
-
if o.is_a? String
|
48
|
-
nv = process_instruction(global, o)
|
49
|
-
obj[i] = nv unless nv.nil?
|
50
|
-
else
|
51
|
-
process(global, o)
|
52
|
-
end
|
53
|
-
i += 1
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.process_instruction(global, str)
|
59
|
-
case str
|
60
|
-
when '%*class'
|
61
|
-
return global.class_list
|
62
|
-
when '%*method'
|
63
|
-
return global.method_list
|
64
|
-
when '%*load'
|
65
|
-
return global.file_list
|
66
|
-
when '%*id'
|
67
|
-
return global.id_list
|
68
|
-
when '%*name'
|
69
|
-
return global.name_list
|
70
|
-
when '%*superclass'
|
71
|
-
return global.superclass_list
|
72
|
-
when '%*assign'
|
73
|
-
return global.assign_list
|
74
|
-
when '%*transform'
|
75
|
-
return global.transform_list
|
76
|
-
when '%*allow'
|
77
|
-
return global.allow_list
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,75 +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/MODLParserListener'
|
26
|
-
require 'modl/parser/MODLParserVisitor'
|
27
|
-
require 'modl/parser/MODLLexer'
|
28
|
-
require 'modl/parser/MODLParser'
|
29
|
-
require 'modl/parser/class_processor'
|
30
|
-
require 'modl/parser/orphan_handler'
|
31
|
-
require 'modl/parser/parser'
|
32
|
-
require 'json'
|
33
|
-
|
34
|
-
module MODL
|
35
|
-
# Interpreter-specific errors
|
36
|
-
class InterpreterError < StandardError
|
37
|
-
end
|
38
|
-
|
39
|
-
class ParserError < StandardError
|
40
|
-
end
|
41
|
-
|
42
|
-
# This is the main Ruby Interpreter entry point. Supply a String containing MODL text and it will return a String
|
43
|
-
# containing the JSON equivalent. The JSON isn't pretty-printed unless pretty is true
|
44
|
-
class Interpreter
|
45
|
-
def self.interpret(str, pretty = false)
|
46
|
-
interpreted = MODL.parse(str)
|
47
|
-
return interpreted if interpreted.is_a? String
|
48
|
-
|
49
|
-
# Otherwise generate a JSON string.
|
50
|
-
if pretty
|
51
|
-
JSON.pretty_generate interpreted
|
52
|
-
else
|
53
|
-
JSON.generate interpreted
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Parse a MODL string and return a hash, array, or String depending on how the MODL is structured.
|
59
|
-
def self.parse(string)
|
60
|
-
# Parse the MODL string into a MODL::Parser::Parsed object.
|
61
|
-
parsed = MODL::Parser::Parser.parse(string)
|
62
|
-
|
63
|
-
# Check for orphan pairs and adopt them.
|
64
|
-
parsed.structures = MODL::Parser::OrphanHandler.adopt(parsed.global, parsed.structures)
|
65
|
-
|
66
|
-
# Convert the Parsed object into a simpler structure of and Array or Hash
|
67
|
-
interpreted = parsed.extract_hash
|
68
|
-
|
69
|
-
# Process any class definitions used by the MODL file.
|
70
|
-
interpreted = MODL::Parser::ClassProcessor.process(parsed.global, interpreted)
|
71
|
-
MODL::Parser::InstructionProcessor.process(parsed.global, interpreted)
|
72
|
-
# If the result is a simple string then just return it.
|
73
|
-
interpreted
|
74
|
-
end
|
75
|
-
end
|
@@ -1,138 +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
|
-
module MODL
|
26
|
-
module Parser
|
27
|
-
# Represents a *class defined, or loaded by, a MODL document.
|
28
|
-
class MODLClass
|
29
|
-
attr_accessor :id
|
30
|
-
attr_accessor :name
|
31
|
-
attr_accessor :superclass
|
32
|
-
attr_accessor :assign
|
33
|
-
attr_accessor :content
|
34
|
-
attr_accessor :allow
|
35
|
-
attr_accessor :expect
|
36
|
-
|
37
|
-
def initialize
|
38
|
-
@content = {}
|
39
|
-
end
|
40
|
-
|
41
|
-
# Find a keylist of the right length from the *assign array of arrays.
|
42
|
-
def keylist_of_length(len)
|
43
|
-
return nil if @assign.nil?
|
44
|
-
|
45
|
-
# *assign can support iteration, e.g. *assign=[[person*]]
|
46
|
-
# so return a list of the right length in this case
|
47
|
-
if @assign.length == 1 && @assign[0].length == 1 && @assign[0][0].end_with?('*')
|
48
|
-
key = Sutil.head @assign[0][0]
|
49
|
-
return Array.new(len, key)
|
50
|
-
end
|
51
|
-
|
52
|
-
@assign.each do |kl|
|
53
|
-
return kl if kl.length == len
|
54
|
-
end
|
55
|
-
|
56
|
-
raise InterpreterError,
|
57
|
-
'Interpreter Error: No key list of the correct length in class ' + @id + ' - looking for one of length ' + len.to_s
|
58
|
-
end
|
59
|
-
|
60
|
-
def merge_content(new_value)
|
61
|
-
@content.each do |k, v|
|
62
|
-
new_value[k] = v.extract_hash unless new_value[k]
|
63
|
-
end
|
64
|
-
new_value
|
65
|
-
end
|
66
|
-
|
67
|
-
def name_or_id
|
68
|
-
@name.nil? ? @id : @name
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Extract a class from a ParsedPair object
|
73
|
-
class ClassExtractor
|
74
|
-
def self.extract(pair, global)
|
75
|
-
return unless pair.type == 'class'
|
76
|
-
|
77
|
-
clazz = MODLClass.new
|
78
|
-
map = pair.map if pair.map
|
79
|
-
map = pair.valueItem&.value&.map if pair.valueItem&.value&.map
|
80
|
-
|
81
|
-
map.mapItems.each do |item|
|
82
|
-
next unless item&.pair&.type
|
83
|
-
|
84
|
-
case item&.pair&.type
|
85
|
-
when 'id'
|
86
|
-
str_value = item.pair.valueItem.value.primitive.string.string
|
87
|
-
raise InterpreterError, 'Reserved class id - cannot redefine: ' + str_value if reserved?(str_value)
|
88
|
-
|
89
|
-
clazz.id = str_value
|
90
|
-
when 'name'
|
91
|
-
str_value = item.pair.valueItem.value.primitive.string.string
|
92
|
-
raise InterpreterError, 'Reserved class name - cannot redefine: ' + str_value if reserved?(str_value)
|
93
|
-
|
94
|
-
clazz.name = str_value
|
95
|
-
when 'superclass'
|
96
|
-
str_value = item.pair.valueItem.value.primitive.string.string
|
97
|
-
clazz.superclass = str_value
|
98
|
-
when 'keylist'
|
99
|
-
clazz.assign = item.pair.key_lists
|
100
|
-
when 'allow'
|
101
|
-
clazz.allow = item.pair.array if item.pair.array
|
102
|
-
clazz.allow = item.pair.valueItem.value.array if item.pair.valueItem.value.array
|
103
|
-
when 'expect'
|
104
|
-
clazz.expect = item.pair.array if item.pair.array
|
105
|
-
clazz.expect = item.pair.valueItem.value.array if item.pair.valueItem.value.array
|
106
|
-
else
|
107
|
-
clazz.content[item.pair.key] = item.pair.array if item.pair.array
|
108
|
-
clazz.content[item.pair.key] = item.pair.map if item.pair.map
|
109
|
-
clazz.content[item.pair.key] = item.pair.valueItem.value if item.pair.valueItem.value
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
superclass = clazz.superclass
|
114
|
-
|
115
|
-
if superclass && !reserved?(superclass) && !global.has_class?(superclass)
|
116
|
-
raise InterpreterError, 'Invalid superclass: ' + superclass.to_s
|
117
|
-
end
|
118
|
-
raise InterpreterError, 'Missing id for class' if clazz.id.nil?
|
119
|
-
|
120
|
-
# Make sure the class name isn't redefining an existing class
|
121
|
-
if !global.has_class?(clazz.id) && !global.has_class?(clazz.name)
|
122
|
-
|
123
|
-
# store the classes by id and name to make them easier to find later
|
124
|
-
global.classs(clazz)
|
125
|
-
else
|
126
|
-
id = clazz.id.nil? ? 'undefined' : clazz.id
|
127
|
-
name = clazz.name.nil? ? 'undefined' : clazz.name
|
128
|
-
raise InterpreterError, 'Class name or id already defined - cannot redefine: ' + id + ', ' + name
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# Check for a reserved class name
|
133
|
-
def self.reserved?(str)
|
134
|
-
%w[map str arr num].include?(str)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
@@ -1,54 +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
|
-
module MODL
|
26
|
-
module Parser
|
27
|
-
# Extracts an index definition from a ParsedPair
|
28
|
-
class IndexExtractor
|
29
|
-
def self.extract(pair, global)
|
30
|
-
item = pair.valueItem if pair.valueItem
|
31
|
-
item = pair.array if pair.array
|
32
|
-
|
33
|
-
# collect all values from the object
|
34
|
-
if item.is_a? Parsed::ParsedValueItem
|
35
|
-
if item&.value&.text
|
36
|
-
global.add_to_index(item.value.text)
|
37
|
-
elsif item&.value&.array
|
38
|
-
item.value.array.abstractArrayItems.each do |avi|
|
39
|
-
global.add_to_index(avi.arrayValueItem)
|
40
|
-
end
|
41
|
-
elsif item&.value&.nbArray
|
42
|
-
item.value.nbArray.arrayItems.each do |avi|
|
43
|
-
global.add_to_index(avi.arrayValueItem)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
elsif item.is_a? Parsed::ParsedArray
|
47
|
-
item.abstractArrayItems.each do |avi|
|
48
|
-
global.add_to_index(avi.arrayValueItem)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|