modl 0.3.26 → 0.3.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +272 -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,81 +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 KeylistExtractor
|
29
|
-
def self.extract(pair, item)
|
30
|
-
# the item must be an array of arrays
|
31
|
-
pair.key_lists = []
|
32
|
-
last_keylist_len = 0
|
33
|
-
if item.is_a?(Parsed::ParsedValueItem) && item.value.is_a?(Parsed::ParsedValue) && item.value.array
|
34
|
-
item.value.array.abstractArrayItems.each do |avi|
|
35
|
-
key_list = []
|
36
|
-
avi.arrayValueItem.array.abstractArrayItems.each do |key|
|
37
|
-
key_list << key.arrayValueItem.primitive.string.string if key.arrayValueItem.primitive.string
|
38
|
-
key_list << key.arrayValueItem.primitive.number.num if key.arrayValueItem.primitive.number
|
39
|
-
end
|
40
|
-
if key_list.length > last_keylist_len
|
41
|
-
last_keylist_len = key_list.length
|
42
|
-
else
|
43
|
-
raise InterpreterError, 'Error: Key lists in *assign are not in ascending order of list length: ' + key_list.to_s
|
44
|
-
end
|
45
|
-
pair.key_lists << key_list
|
46
|
-
end
|
47
|
-
elsif item.is_a?(Parsed::ParsedArray)
|
48
|
-
item.abstractArrayItems.each do |avi|
|
49
|
-
key_list = []
|
50
|
-
avi.arrayValueItem.array.abstractArrayItems.each do |key|
|
51
|
-
key_list << key.arrayValueItem.primitive.string.string if key.arrayValueItem.primitive.string
|
52
|
-
key_list << key.arrayValueItem.primitive.number.num if key.arrayValueItem.primitive.number
|
53
|
-
end
|
54
|
-
if key_list.length > last_keylist_len
|
55
|
-
last_keylist_len = key_list.length
|
56
|
-
else
|
57
|
-
raise InterpreterError, 'Error: Key lists in *assign are not in ascending order of list length.'
|
58
|
-
end
|
59
|
-
pair.key_lists << key_list
|
60
|
-
end
|
61
|
-
elsif item.is_a?(Parsed::ParsedValueItem) && !item.value.nbArray.nil?
|
62
|
-
item.value.nbArray.arrayItems.each do |avi|
|
63
|
-
key_list = []
|
64
|
-
avi.arrayValueItem.array.abstractArrayItems.each do |key|
|
65
|
-
key_list << key.arrayValueItem.primitive.string.string if key.arrayValueItem.primitive.string
|
66
|
-
key_list << key.arrayValueItem.primitive.number.num if key.arrayValueItem.primitive.number
|
67
|
-
end
|
68
|
-
if key_list.length > last_keylist_len
|
69
|
-
last_keylist_len = key_list.length
|
70
|
-
else
|
71
|
-
raise InterpreterError, 'Error: Key lists in *assign are not in ascending order of list length.'
|
72
|
-
end
|
73
|
-
pair.key_lists << key_list
|
74
|
-
end
|
75
|
-
else
|
76
|
-
raise InterpreterError, 'Array of arrays expected for: ' + pair.key
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,172 +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 *method defined by a MODL document.
|
28
|
-
class MODLMethod
|
29
|
-
attr_accessor :id
|
30
|
-
attr_accessor :name
|
31
|
-
attr_accessor :transform
|
32
|
-
|
33
|
-
def name_or_id
|
34
|
-
@name.nil? ? @id : @name
|
35
|
-
end
|
36
|
-
|
37
|
-
# There is a user-defined method transform to run on the str
|
38
|
-
def run(str)
|
39
|
-
# Consume the elements of the transform spec until there are none left.
|
40
|
-
transform = @transform
|
41
|
-
while transform && transform.length > 0
|
42
|
-
if transform.start_with?('replace<') || transform.start_with?('r<')
|
43
|
-
close_bracket = transform.index('>')
|
44
|
-
m = Sutil.head(transform, close_bracket + 1).sub!('replace', 'r')
|
45
|
-
str = StandardMethods.run_method(m, str)
|
46
|
-
# Consume the subst clause
|
47
|
-
close_bracket = transform.index('>')
|
48
|
-
transform = Sutil.tail(transform, close_bracket + 2)
|
49
|
-
elsif transform.start_with?('trim') || transform.start_with?('t<')
|
50
|
-
close_bracket = transform.index('>')
|
51
|
-
m = Sutil.head(transform, close_bracket + 1).sub!('trim', 't')
|
52
|
-
str = StandardMethods.run_method(m, str)
|
53
|
-
# Consume the trunc clause
|
54
|
-
close_bracket = transform.index('>')
|
55
|
-
transform = Sutil.tail(transform, close_bracket + 2)
|
56
|
-
elsif transform.start_with?('initcap') || transform.start_with?('i')
|
57
|
-
str = StandardMethods.run_method('i', str)
|
58
|
-
transform = Sutil.after(transform, '.')
|
59
|
-
elsif transform.start_with?('upcase') || transform.start_with?('u')
|
60
|
-
str = StandardMethods.run_method('u', str)
|
61
|
-
transform = Sutil.after(transform, '.')
|
62
|
-
elsif transform.start_with?('downcase') || transform.start_with?('d')
|
63
|
-
str = StandardMethods.run_method('d', str)
|
64
|
-
transform = Sutil.after(transform, '.')
|
65
|
-
elsif transform.start_with?('sentence') || transform.start_with?('s')
|
66
|
-
str = StandardMethods.run_method('s', str)
|
67
|
-
transform = Sutil.after(transform, '.')
|
68
|
-
elsif transform.start_with?('urlencode') || transform.start_with?('e')
|
69
|
-
str = StandardMethods.run_method('e', str)
|
70
|
-
transform = Sutil.after(transform, '.')
|
71
|
-
else
|
72
|
-
raise InterpreterError, 'NOT IMPLEMENTED'
|
73
|
-
end
|
74
|
-
end
|
75
|
-
str
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
# Extracts a method definition from a ParsedPair
|
81
|
-
class MethodExtractor
|
82
|
-
def self.extract(pair, global)
|
83
|
-
return unless pair.type == 'method'
|
84
|
-
|
85
|
-
mthd = MODLMethod.new
|
86
|
-
map = pair.map if pair.map
|
87
|
-
map = pair.valueItem&.value&.map if pair.valueItem&.value&.map
|
88
|
-
|
89
|
-
map.mapItems.each do |item|
|
90
|
-
next unless item&.pair&.type
|
91
|
-
|
92
|
-
case item&.pair&.type
|
93
|
-
when 'id'
|
94
|
-
mthd.id = item.pair.valueItem.value.primitive.string.string
|
95
|
-
when 'transform'
|
96
|
-
mthd.transform = item.pair.valueItem.value.primitive.string.string
|
97
|
-
when 'name'
|
98
|
-
mthd.name = item.pair.valueItem.value.primitive.string.string
|
99
|
-
else
|
100
|
-
raise InterpreterError, 'Invalid *method - only *id, *name, and *transform fields expected'
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
raise InterpreterError, 'Missing id for method' if mthd.id.nil?
|
105
|
-
raise InterpreterError, 'Missing name for method' if mthd.name.nil?
|
106
|
-
raise InterpreterError, 'Duplicate method name or id: ' + mthd.name if global.has_user_method?(mthd.name)
|
107
|
-
raise InterpreterError, 'Duplicate method name or id: ' + mthd.id if global.has_user_method?(mthd.id)
|
108
|
-
|
109
|
-
# store the methods by id and name to make them easier to find later
|
110
|
-
global.user_method_id(mthd.id, mthd)
|
111
|
-
global.user_method(mthd.name, mthd)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class StandardMethods
|
116
|
-
|
117
|
-
@@mthd_names = %w(u d i s e r t p upcase downcase initcap sentence urlencode replace trim punydecode)
|
118
|
-
|
119
|
-
def self.run_method(mthd, str)
|
120
|
-
m = mthd.match(/\w*/)[0]
|
121
|
-
case m
|
122
|
-
when 'u', 'upcase'
|
123
|
-
str.upcase
|
124
|
-
when 'd', 'downcase'
|
125
|
-
str.downcase
|
126
|
-
when 'i', 'initcap'
|
127
|
-
str.split.map(&:capitalize) * ' '
|
128
|
-
when 's', 'sentence'
|
129
|
-
split = str.split
|
130
|
-
split[0].capitalize!
|
131
|
-
split.join(' ')
|
132
|
-
when 'e', 'urlencode'
|
133
|
-
CGI.escape(str)
|
134
|
-
when 'r', 'replace'
|
135
|
-
s1, s2 = get_subst_parts(mthd)
|
136
|
-
str.gsub(s1, s2)
|
137
|
-
when 't', 'trim'
|
138
|
-
s1 = extract_params mthd
|
139
|
-
i = str.index(s1)
|
140
|
-
Sutil.head(str, i)
|
141
|
-
when 'p', 'punydecode'
|
142
|
-
Punycode.decode(str)
|
143
|
-
else
|
144
|
-
str.nil? ? '.' + mthd : str.to_s + '.' + mthd
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
# Extract the method parameters
|
149
|
-
def self.get_subst_parts(s)
|
150
|
-
# should be of the form .r(s1,s2)
|
151
|
-
result = extract_params(s).split(',')
|
152
|
-
result[0] = '' if result.length.zero? || result[0].nil?
|
153
|
-
result[1] = '' if result.length == 1 || result[1].nil?
|
154
|
-
result
|
155
|
-
end
|
156
|
-
|
157
|
-
# Extract the method parameter
|
158
|
-
def self.extract_params(str)
|
159
|
-
# should be of the form .r(s1,s2)
|
160
|
-
Sutil.between(str, '<', '>')
|
161
|
-
end
|
162
|
-
|
163
|
-
def self.valid_method?(mthd)
|
164
|
-
m = mthd
|
165
|
-
if m.include?('<')
|
166
|
-
m = Sutil.until(m, '<')
|
167
|
-
end
|
168
|
-
return @@mthd_names.include?(m)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
@@ -1,88 +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
|
-
# Store any files for up to 1 hour by default.
|
28
|
-
class ObjectCache
|
29
|
-
# A cache record to keep track of the time since an object was last cached.
|
30
|
-
class CacheEntry
|
31
|
-
TTL_ONE_HOUR = 3_600 # seconds
|
32
|
-
|
33
|
-
attr_reader :object
|
34
|
-
|
35
|
-
# Initialiase the CacheEntry with an object and an optional ttl in seconds (default 1 hour)
|
36
|
-
def initialize(object, ttl = nil)
|
37
|
-
ttl = TTL_ONE_HOUR if ttl.nil?
|
38
|
-
@object = object
|
39
|
-
@expiry_time = Time.now + ttl
|
40
|
-
end
|
41
|
-
|
42
|
-
# Check whether the CacheEntry is live
|
43
|
-
def expired?
|
44
|
-
@expiry_time < Time.now
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Set up and empty cache.
|
49
|
-
def initialize
|
50
|
-
@cache = {}
|
51
|
-
end
|
52
|
-
|
53
|
-
# Cache an object with the given key and optional ttl in seconds (default 1 hour)
|
54
|
-
def put(key, object, ttl = nil)
|
55
|
-
@cache[key] = CacheEntry.new(object, ttl) unless key.nil? || object.nil?
|
56
|
-
end
|
57
|
-
|
58
|
-
# Evict a cache entry
|
59
|
-
def evict(key)
|
60
|
-
@cache.delete(key) unless key.nil?
|
61
|
-
end
|
62
|
-
|
63
|
-
# Return the object with the given key if one exists and has not expired.
|
64
|
-
def get(key)
|
65
|
-
# Return nothing if not in the cache or it has expired.
|
66
|
-
return if key.nil?
|
67
|
-
|
68
|
-
entry = @cache[key]
|
69
|
-
return unless entry
|
70
|
-
return if entry.expired?
|
71
|
-
|
72
|
-
# Otherwise return the cached object.
|
73
|
-
# We don't delete the cached entry because we might need to force its use if its expired and offline
|
74
|
-
entry.object
|
75
|
-
end
|
76
|
-
|
77
|
-
# If the file is offline this can be used to retrieve the cached version if we have one.
|
78
|
-
def force_get(key)
|
79
|
-
# Return nothing if not in the cache or it has expired.
|
80
|
-
return if key.nil?
|
81
|
-
|
82
|
-
entry = @cache[key]
|
83
|
-
return unless entry
|
84
|
-
entry.object
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,98 +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
|
-
class OrphanHandler
|
28
|
-
#
|
29
|
-
# Return true if all strings start with '_'
|
30
|
-
#
|
31
|
-
def self.all_hidden(str_array)
|
32
|
-
if str_array && str_array.length > 0
|
33
|
-
str_array.each do |s|
|
34
|
-
return false unless s.start_with?('_')
|
35
|
-
end
|
36
|
-
end
|
37
|
-
true
|
38
|
-
end
|
39
|
-
|
40
|
-
#
|
41
|
-
# Look for any orphan pairs at the top level and adopt them into a map
|
42
|
-
# Its an error if there are duplicate keys or mixed types at the top.
|
43
|
-
#
|
44
|
-
def self.adopt(global, structures)
|
45
|
-
#
|
46
|
-
# Separate out any top-level pairs into a separate hash, checking for duplicates on the way.
|
47
|
-
#
|
48
|
-
if structures
|
49
|
-
pairs = Hash.new
|
50
|
-
|
51
|
-
# This will replace the existing structures array
|
52
|
-
new_structures = []
|
53
|
-
|
54
|
-
structures.each do |s|
|
55
|
-
if s.pair
|
56
|
-
# skip hidden pairs and instructions
|
57
|
-
if s.pair.key.start_with?('*') || s.pair.key.start_with?('_') || s.pair.key == '?'
|
58
|
-
new_structures.push(s)
|
59
|
-
next
|
60
|
-
end
|
61
|
-
|
62
|
-
if pairs.has_key?(s.pair.key)
|
63
|
-
raise InterpreterError, 'Duplicate top level keys are not allowed.'
|
64
|
-
else
|
65
|
-
pairs[s.pair.key] = s
|
66
|
-
end
|
67
|
-
else
|
68
|
-
if pairs.length > 0 && !all_hidden(pairs.keys) && !s.top_level_conditional
|
69
|
-
raise InterpreterError, 'Mixed top-level types are not allowed.'
|
70
|
-
else
|
71
|
-
new_structures.push(s)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
if pairs.length > 0
|
77
|
-
#
|
78
|
-
# Create a map for the pairs and insert them into it.
|
79
|
-
#
|
80
|
-
new_map = MODL::Parser::Parsed::ParsedMap.new(global)
|
81
|
-
pairs.values.each do |p|
|
82
|
-
new_map.mapItems.push p unless p.pair.key.start_with?('_')
|
83
|
-
end
|
84
|
-
|
85
|
-
# Add the map to a new structure and insert it at the front of the structures list
|
86
|
-
new_struct = MODL::Parser::Parsed::ParsedStructure.new(global)
|
87
|
-
new_struct.map = new_map
|
88
|
-
new_structures.unshift(new_struct)
|
89
|
-
|
90
|
-
# Replace the existing structures with the new structures.
|
91
|
-
return new_structures
|
92
|
-
end
|
93
|
-
end
|
94
|
-
structures
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|