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,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
|