rupkl 0.1.0 → 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 +4 -4
- data/README.md +1 -1
- data/lib/rupkl/node/amend_expression.rb +48 -0
- data/lib/rupkl/node/any.rb +110 -0
- data/lib/rupkl/node/base.rb +75 -0
- data/lib/rupkl/node/boolean.rb +30 -5
- data/lib/rupkl/node/collection.rb +176 -0
- data/lib/rupkl/node/context.rb +27 -0
- data/lib/rupkl/node/data_size.rb +254 -0
- data/lib/rupkl/node/declared_type.rb +32 -0
- data/lib/rupkl/node/duration.rb +266 -0
- data/lib/rupkl/node/dynamic.rb +33 -60
- data/lib/rupkl/node/identifier.rb +19 -5
- data/lib/rupkl/node/if_expression.rb +45 -0
- data/lib/rupkl/node/intseq.rb +84 -0
- data/lib/rupkl/node/listing.rb +68 -0
- data/lib/rupkl/node/map.rb +120 -0
- data/lib/rupkl/node/mapping.rb +54 -0
- data/lib/rupkl/node/member_finder.rb +49 -0
- data/lib/rupkl/node/member_reference.rb +46 -21
- data/lib/rupkl/node/method_call.rb +63 -0
- data/lib/rupkl/node/method_definition.rb +199 -0
- data/lib/rupkl/node/node_common.rb +76 -0
- data/lib/rupkl/node/null.rb +24 -0
- data/lib/rupkl/node/number.rb +228 -10
- data/lib/rupkl/node/object.rb +626 -74
- data/lib/rupkl/node/operation.rb +175 -115
- data/lib/rupkl/node/pair.rb +58 -0
- data/lib/rupkl/node/pkl_module.rb +16 -28
- data/lib/rupkl/node/reference_resolver.rb +79 -0
- data/lib/rupkl/node/regex.rb +196 -0
- data/lib/rupkl/node/string.rb +415 -23
- data/lib/rupkl/node/struct_common.rb +150 -53
- data/lib/rupkl/node/this.rb +17 -0
- data/lib/rupkl/node/type_common.rb +34 -0
- data/lib/rupkl/node/value_common.rb +18 -13
- data/lib/rupkl/parser/expression.rb +197 -43
- data/lib/rupkl/parser/identifier.rb +2 -2
- data/lib/rupkl/parser/literal.rb +18 -12
- data/lib/rupkl/parser/method.rb +41 -0
- data/lib/rupkl/parser/misc.rb +24 -0
- data/lib/rupkl/parser/object.rb +141 -26
- data/lib/rupkl/parser/pkl_class.rb +37 -10
- data/lib/rupkl/parser/pkl_module.rb +5 -3
- data/lib/rupkl/parser/type.rb +28 -0
- data/lib/rupkl/parser.rb +8 -0
- data/lib/rupkl/pkl_object.rb +11 -7
- data/lib/rupkl/version.rb +1 -1
- data/lib/rupkl.rb +35 -6
- metadata +45 -7
- data/lib/rupkl/node/pkl_class.rb +0 -30
data/lib/rupkl/node/object.rb
CHANGED
@@ -2,106 +2,131 @@
|
|
2
2
|
|
3
3
|
module RuPkl
|
4
4
|
module Node
|
5
|
-
|
6
|
-
|
5
|
+
class ObjectMember
|
6
|
+
include NodeCommon
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def value
|
9
|
+
@value_evaluated || @value
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
evaluate_objects(objects, scopes).to_ruby(nil)
|
17
|
-
end
|
12
|
+
def add_child(child)
|
13
|
+
super
|
14
|
+
assign_evaluaed_value? &&
|
15
|
+
(@value_evaluated = child)
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
21
|
-
|
22
|
-
value.to_pkl_string(scopes)
|
23
|
-
else
|
24
|
-
evaluate_objects(objects, scopes).to_pkl_string(nil)
|
25
|
-
end
|
18
|
+
def visibility
|
19
|
+
@visibility || :lexical
|
26
20
|
end
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
22
|
+
attr_writer :visibility
|
23
|
+
|
24
|
+
def generated?
|
25
|
+
@generated
|
32
26
|
end
|
33
|
-
end
|
34
27
|
|
35
|
-
|
36
|
-
include PropertyEvaluator
|
28
|
+
attr_writer :generated
|
37
29
|
|
38
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
def evaluate_value(evaluator, context)
|
33
|
+
@value_evaluated = value.__send__(evaluator, context)
|
34
|
+
value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ObjectProperty < ObjectMember
|
39
|
+
def initialize(parent, name, value, modifiers, position)
|
40
|
+
super(parent, name, value, position)
|
39
41
|
@name = name
|
40
42
|
@value = value
|
41
|
-
@
|
42
|
-
@position = position
|
43
|
+
@modifiers = modifiers
|
43
44
|
end
|
44
45
|
|
45
46
|
attr_reader :name
|
46
|
-
attr_reader :
|
47
|
-
attr_reader :objects
|
48
|
-
attr_reader :position
|
47
|
+
attr_reader :modifiers
|
49
48
|
|
50
|
-
def evaluate(
|
51
|
-
|
52
|
-
self
|
49
|
+
def evaluate(context = nil)
|
50
|
+
evaluate_value(__method__, context)
|
51
|
+
self
|
53
52
|
end
|
54
53
|
|
55
|
-
def
|
56
|
-
|
54
|
+
def resolve_structure(context = nil)
|
55
|
+
evaluate_value(__method__, context)
|
56
|
+
self
|
57
57
|
end
|
58
58
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
def to_ruby(context = nil)
|
60
|
+
[name.id, evaluate_value(:evaluate, context).to_ruby]
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_pkl_string(context = nil)
|
64
|
+
v = evaluate_value(:evaluate, context).to_pkl_string
|
65
|
+
|
66
|
+
if v.start_with?('new Dynamic')
|
67
|
+
"#{name.id}#{v.delete_prefix('new Dynamic')}"
|
63
68
|
else
|
64
69
|
"#{name.id} = #{v}"
|
65
70
|
end
|
66
71
|
end
|
67
72
|
|
68
73
|
def ==(other)
|
69
|
-
name
|
74
|
+
name == other.name && value == other.value
|
75
|
+
end
|
76
|
+
|
77
|
+
def copy(parent = nil, position = @position)
|
78
|
+
self.class.new(parent, name.copy, value.copy, modifiers, position)
|
79
|
+
end
|
80
|
+
|
81
|
+
def local?
|
82
|
+
@modifiers&.[](:local) || false
|
83
|
+
end
|
84
|
+
|
85
|
+
def coexistable?(other)
|
86
|
+
name != other.name || local? != other.local? && !parent.equal?(other.parent)
|
70
87
|
end
|
71
|
-
end
|
72
88
|
|
73
|
-
|
74
|
-
include PropertyEvaluator
|
89
|
+
private
|
75
90
|
|
76
|
-
def
|
91
|
+
def assign_evaluaed_value?
|
92
|
+
@name && @value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class ObjectEntry < ObjectMember
|
97
|
+
def initialize(parent, key, value, position)
|
98
|
+
super
|
77
99
|
@key = key
|
78
100
|
@value = value
|
79
|
-
@objects = objects
|
80
|
-
@position = position
|
81
101
|
end
|
82
102
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
attr_reader :position
|
103
|
+
def key
|
104
|
+
@key_evaluated || @key
|
105
|
+
end
|
87
106
|
|
88
|
-
def evaluate(
|
89
|
-
|
90
|
-
|
91
|
-
self
|
107
|
+
def evaluate(context = nil)
|
108
|
+
evaluate_key(context)
|
109
|
+
evaluate_value(__method__, context)
|
110
|
+
self
|
92
111
|
end
|
93
112
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
113
|
+
def resolve_structure(context = nil)
|
114
|
+
evaluate_key(context)
|
115
|
+
evaluate_value(__method__, context)
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_ruby(context = nil)
|
120
|
+
k = evaluate_key(context).to_ruby
|
121
|
+
v = evaluate_value(:evaluate, context).to_ruby
|
97
122
|
[k, v]
|
98
123
|
end
|
99
124
|
|
100
|
-
def to_pkl_string(
|
101
|
-
k =
|
102
|
-
v =
|
103
|
-
if v.start_with?('
|
104
|
-
"[#{k}]
|
125
|
+
def to_pkl_string(context = nil)
|
126
|
+
k = evaluate_key(context).to_pkl_string
|
127
|
+
v = evaluate_value(:evaluate, context).to_pkl_string
|
128
|
+
if v.start_with?('new Dynamic')
|
129
|
+
"[#{k}]#{v.delete_prefix('new Dynamic')}"
|
105
130
|
else
|
106
131
|
"[#{k}] = #{v}"
|
107
132
|
end
|
@@ -110,31 +135,558 @@ module RuPkl
|
|
110
135
|
def ==(other)
|
111
136
|
key == other.key && value == other.value
|
112
137
|
end
|
138
|
+
|
139
|
+
def copy(parent = nil, position = @position)
|
140
|
+
self.class.new(parent, key, value.copy, position)
|
141
|
+
end
|
142
|
+
|
143
|
+
def coexistable?(other)
|
144
|
+
key != other.key
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def evaluate_key(context)
|
150
|
+
@key_evaluated ||=
|
151
|
+
(context || current_context).pop.then do |c|
|
152
|
+
@key.evaluate(c)
|
153
|
+
end
|
154
|
+
@key_evaluated
|
155
|
+
end
|
156
|
+
|
157
|
+
def assign_evaluaed_value?
|
158
|
+
@value && @key && @key_evaluated
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class ObjectElement < ObjectMember
|
163
|
+
def initialize(parent, value, position)
|
164
|
+
super
|
165
|
+
@value = value
|
166
|
+
end
|
167
|
+
|
168
|
+
def evaluate(context = nil)
|
169
|
+
evaluate_value(__method__, context)
|
170
|
+
self
|
171
|
+
end
|
172
|
+
|
173
|
+
def resolve_structure(context = nil)
|
174
|
+
evaluate_value(__method__, context)
|
175
|
+
self
|
176
|
+
end
|
177
|
+
|
178
|
+
def to_ruby(context = nil)
|
179
|
+
evaluate_value(:evaluate, context).to_ruby
|
180
|
+
end
|
181
|
+
|
182
|
+
def to_pkl_string(context = nil)
|
183
|
+
evaluate_value(:evaluate, context).to_pkl_string
|
184
|
+
end
|
185
|
+
|
186
|
+
def ==(other)
|
187
|
+
value == other.value
|
188
|
+
end
|
189
|
+
|
190
|
+
def copy(parent = nil, position = @position)
|
191
|
+
self.class.new(parent, value.copy, position)
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
def assign_evaluaed_value?
|
197
|
+
@value
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class WhenGenerator
|
202
|
+
include NodeCommon
|
203
|
+
|
204
|
+
def initialize(parent, condition, when_body, else_body, result, position)
|
205
|
+
super
|
206
|
+
@condition = condition
|
207
|
+
@when_body = when_body
|
208
|
+
@else_body = else_body
|
209
|
+
@result = result if result
|
210
|
+
end
|
211
|
+
|
212
|
+
attr_reader :condition
|
213
|
+
attr_reader :when_body
|
214
|
+
attr_reader :else_body
|
215
|
+
|
216
|
+
def resolve_generator(context = nil)
|
217
|
+
unless instance_variable_defined?(:@result)
|
218
|
+
@result =
|
219
|
+
if evaluate_condition(context)
|
220
|
+
when_body.resolve_generator(context)
|
221
|
+
else
|
222
|
+
else_body&.resolve_generator(context)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
self
|
227
|
+
end
|
228
|
+
|
229
|
+
def copy(parent = nil, position = @position)
|
230
|
+
if result
|
231
|
+
self.class.new(parent, nil, nil, nil, result.copy, position)
|
232
|
+
else
|
233
|
+
copies = [condition, when_body, else_body].map { _1&.copy }
|
234
|
+
self.class.new(parent, *copies, nil, position)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def collect_members(klass)
|
239
|
+
result&.collect_members(klass)
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
attr_reader :result
|
245
|
+
|
246
|
+
def evaluate_condition(context)
|
247
|
+
result =
|
248
|
+
(context || current_context.pop).then do |c|
|
249
|
+
condition.evaluate(c)
|
250
|
+
end
|
251
|
+
return result.value if result.is_a?(Boolean)
|
252
|
+
|
253
|
+
message =
|
254
|
+
'expected type \'Boolean\', ' \
|
255
|
+
"but got type '#{result.class_name}'"
|
256
|
+
raise EvaluationError.new(message, position)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
class ForGenerator
|
261
|
+
include NodeCommon
|
262
|
+
|
263
|
+
def initialize(parent, key_name, value_name, iterable, body, results, position)
|
264
|
+
super(parent, key_name, value_name, iterable, body, *results, position)
|
265
|
+
@key_name = key_name
|
266
|
+
@value_name = value_name
|
267
|
+
@iterable = iterable
|
268
|
+
@body = body
|
269
|
+
@results = results&.map { _1.items.last }
|
270
|
+
end
|
271
|
+
|
272
|
+
attr_reader :key_name
|
273
|
+
attr_reader :value_name
|
274
|
+
attr_reader :iterable
|
275
|
+
attr_reader :body
|
276
|
+
|
277
|
+
def resolve_generator(context = nil)
|
278
|
+
@results ||= iterate_body(context)
|
279
|
+
self
|
280
|
+
end
|
281
|
+
|
282
|
+
def copy(parent = nil, position = @position)
|
283
|
+
if results
|
284
|
+
self.class.new(parent, key_name, value_name, nil, nil, copy_result, position)
|
285
|
+
else
|
286
|
+
copies = [iterable, body].map { _1&.copy }
|
287
|
+
self.class.new(parent, key_name, value_name, *copies, nil, position)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def collect_members(klass)
|
292
|
+
results
|
293
|
+
&.flat_map { collect_members_from_body(_1, klass) }
|
294
|
+
&.compact
|
295
|
+
end
|
296
|
+
|
297
|
+
private
|
298
|
+
|
299
|
+
attr_reader :results
|
300
|
+
|
301
|
+
def copy_result
|
302
|
+
results.map { _1.parent.copy }
|
303
|
+
end
|
304
|
+
|
305
|
+
ITERATION_METHODS = {
|
306
|
+
IntSeq => :iterate_intseq,
|
307
|
+
List => :iterate_collection,
|
308
|
+
Set => :iterate_collection,
|
309
|
+
Map => :iterate_map,
|
310
|
+
Listing => :iterate_listing,
|
311
|
+
Mapping => :iterate_mapping,
|
312
|
+
Dynamic => :iterate_dynamic
|
313
|
+
}.freeze
|
314
|
+
|
315
|
+
def iterate_body(context)
|
316
|
+
iterable_object = evaluate_iterable(context)
|
317
|
+
if (method = ITERATION_METHODS[iterable_object.class])
|
318
|
+
__send__(method, iterable_object)&.map do |(k, v)|
|
319
|
+
resolve_body(k, v)
|
320
|
+
end
|
321
|
+
else
|
322
|
+
message =
|
323
|
+
"cannot iterate over value of type '#{iterable_object.class_name}'"
|
324
|
+
raise EvaluationError.new(message, position)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def evaluate_iterable(context)
|
329
|
+
(context || current_context.pop).then do |c|
|
330
|
+
iterable.evaluate(c)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def iterate_intseq(intseq)
|
335
|
+
intseq.to_ruby.map.with_index do |v, i|
|
336
|
+
[Int.new(nil, i, nil), Int.new(nil, v, nil)]
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def iterate_collection(collection)
|
341
|
+
collection.elements.map.with_index do |e, i|
|
342
|
+
[Int.new(nil, i, nil), e]
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def iterate_map(map)
|
347
|
+
map.entries.map do |e|
|
348
|
+
[e.key, e.value]
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def iterate_listing(listing)
|
353
|
+
listing.elements&.map&.with_index do |e, i|
|
354
|
+
[Int.new(nil, i, nil), e.value]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
def iterate_mapping(mapping)
|
359
|
+
mapping.entries&.map do |e|
|
360
|
+
[e.key, e.value]
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def iterate_properties(dynamic)
|
365
|
+
dynamic.properties&.map do |p|
|
366
|
+
[String.new(nil, p.name.id.to_s, nil, nil), p.value]
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
def iterate_dynamic(dynamic)
|
371
|
+
[
|
372
|
+
*iterate_properties(dynamic),
|
373
|
+
*iterate_mapping(dynamic),
|
374
|
+
*iterate_listing(dynamic)
|
375
|
+
]
|
376
|
+
end
|
377
|
+
|
378
|
+
def resolve_body(key, value)
|
379
|
+
env = create_evaluation_env(key, value)
|
380
|
+
body
|
381
|
+
.copy(env)
|
382
|
+
.tap { _1.resolve_generator(_1.current_context) }
|
383
|
+
end
|
384
|
+
|
385
|
+
def create_evaluation_env(key, value)
|
386
|
+
iterators = []
|
387
|
+
iterators << create_iterator(key_name, key) if key_name
|
388
|
+
iterators << create_iterator(value_name, value)
|
389
|
+
ObjectBody.new(self, iterators, position)
|
390
|
+
end
|
391
|
+
|
392
|
+
def create_iterator(name, value)
|
393
|
+
ObjectProperty.new(nil, name, value, { local: true }, name.position)
|
394
|
+
end
|
395
|
+
|
396
|
+
def collect_members_from_body(body, klass)
|
397
|
+
body
|
398
|
+
.collect_members(klass)
|
399
|
+
&.tap { |members| check_no_properties(members, klass) }
|
400
|
+
end
|
401
|
+
|
402
|
+
def check_no_properties(members, klass)
|
403
|
+
return if members.empty? || klass != ObjectProperty
|
404
|
+
|
405
|
+
message = 'cannot generate object properties'
|
406
|
+
raise EvaluationError.new(message, position)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
class ObjectBody
|
411
|
+
include NodeCommon
|
412
|
+
include MemberFinder
|
413
|
+
|
414
|
+
def initialize(parent, items, position)
|
415
|
+
super(parent, *items, position)
|
416
|
+
end
|
417
|
+
|
418
|
+
attr_reader :pkl_classes
|
419
|
+
|
420
|
+
alias_method :items, :children
|
421
|
+
|
422
|
+
def properties(visibility: :lexical, all: false)
|
423
|
+
@properties ||= collect_members(ObjectProperty)
|
424
|
+
|
425
|
+
if all
|
426
|
+
@properties
|
427
|
+
elsif visibility == :lexical
|
428
|
+
@properties&.select { _1.visibility == :lexical || _1.parent.equal?(self) }
|
429
|
+
else
|
430
|
+
@properties&.select { !_1.local? }
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def entries
|
435
|
+
@entries ||= collect_members(ObjectEntry)
|
436
|
+
end
|
437
|
+
|
438
|
+
def elements
|
439
|
+
@elements ||= collect_members(ObjectElement)
|
440
|
+
end
|
441
|
+
|
442
|
+
def pkl_methods
|
443
|
+
@pkl_methods ||= collect_members(MethodDefinition)
|
444
|
+
end
|
445
|
+
|
446
|
+
def fields(visibility: :lexical)
|
447
|
+
[*properties(visibility: visibility), *entries, *elements]
|
448
|
+
end
|
449
|
+
|
450
|
+
def definitions
|
451
|
+
[*pkl_methods, *pkl_classes]
|
452
|
+
end
|
453
|
+
|
454
|
+
def members(visibility: :lexical)
|
455
|
+
[*fields(visibility: visibility), *definitions]
|
456
|
+
end
|
457
|
+
|
458
|
+
def evaluate(context = nil)
|
459
|
+
do_evaluation(__method__, context)
|
460
|
+
end
|
461
|
+
|
462
|
+
def resolve_structure(context = nil)
|
463
|
+
resolve_generator(context)
|
464
|
+
do_evaluation(__method__, context)
|
465
|
+
end
|
466
|
+
|
467
|
+
def copy(parent = nil, position = @position)
|
468
|
+
copied_members = items&.map(&:copy)
|
469
|
+
self.class.new(parent, copied_members, position)
|
470
|
+
end
|
471
|
+
|
472
|
+
def current_context
|
473
|
+
super&.push_scope(self)
|
474
|
+
end
|
475
|
+
|
476
|
+
def resolve_generator(context = nil)
|
477
|
+
generators&.each { _1.resolve_generator(context) }
|
478
|
+
self
|
479
|
+
end
|
480
|
+
|
481
|
+
def collect_members(klass)
|
482
|
+
items
|
483
|
+
&.each_with_object([], &member_collector(klass))
|
484
|
+
&.then { !_1.empty? && _1 || nil }
|
485
|
+
end
|
486
|
+
|
487
|
+
def merge!(*others)
|
488
|
+
others.each { do_merge(_1) }
|
489
|
+
self
|
490
|
+
end
|
491
|
+
|
492
|
+
private
|
493
|
+
|
494
|
+
GENERATOR_CLASSES = [
|
495
|
+
WhenGenerator,
|
496
|
+
ForGenerator
|
497
|
+
].freeze
|
498
|
+
|
499
|
+
def generator?(item)
|
500
|
+
GENERATOR_CLASSES.any? { item.is_a?(_1) }
|
501
|
+
end
|
502
|
+
|
503
|
+
def generators
|
504
|
+
items&.select { generator?(_1) }
|
505
|
+
end
|
506
|
+
|
507
|
+
def do_evaluation(evaluator, context)
|
508
|
+
(context&.push_scope(self) || current_context).then do |c|
|
509
|
+
fields&.each do |field|
|
510
|
+
if field.generated?
|
511
|
+
field.__send__(evaluator)
|
512
|
+
else
|
513
|
+
field.__send__(evaluator, c)
|
514
|
+
end
|
515
|
+
end
|
516
|
+
check_duplication
|
517
|
+
self
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
def check_duplication
|
522
|
+
check_duplication_members(properties(all: true))
|
523
|
+
check_duplication_members(entries)
|
524
|
+
check_duplication_members(pkl_methods)
|
525
|
+
end
|
526
|
+
|
527
|
+
def check_duplication_members(members)
|
528
|
+
members&.each do |member|
|
529
|
+
duplicate_member?(members, member) &&
|
530
|
+
(raise EvaluationError.new('duplicate definition of member', member.position))
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
def duplicate_member?(members, member)
|
535
|
+
count = members.count { !_1.coexistable?(member) }
|
536
|
+
count > 1
|
537
|
+
end
|
538
|
+
|
539
|
+
def member_collector(klass)
|
540
|
+
proc do |item, members|
|
541
|
+
if generator?(item)
|
542
|
+
items = item.collect_members(klass)
|
543
|
+
items && members.concat(items.each { _1.generated = true })
|
544
|
+
elsif item.is_a?(klass)
|
545
|
+
members << item
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
def do_merge(rhs)
|
551
|
+
rhs_properties = rhs.properties(visibility: :object)
|
552
|
+
rhs_entries, rhs_amend = split_entries(rhs.entries)
|
553
|
+
@properties = merge_hash_members(properties(all: true), rhs_properties)
|
554
|
+
@entries = merge_hash_members(entries, rhs_entries)
|
555
|
+
@elements = merge_array_members(elements, rhs.elements, rhs_amend, :key)
|
556
|
+
end
|
557
|
+
|
558
|
+
def split_entries(entries)
|
559
|
+
return [nil, nil] unless entries
|
560
|
+
|
561
|
+
elements_size = elements&.size || 0
|
562
|
+
grouped_entries =
|
563
|
+
entries
|
564
|
+
.group_by { index_node?(_1.key, elements_size) }
|
565
|
+
[grouped_entries[false], grouped_entries[true]]
|
566
|
+
end
|
567
|
+
|
568
|
+
def index_node?(node, elements_size)
|
569
|
+
node.instance_of?(Node::Int) && node.value < elements_size
|
570
|
+
end
|
571
|
+
|
572
|
+
def merge_hash_members(lhs, rhs)
|
573
|
+
return nil unless lhs || rhs
|
574
|
+
return rhs unless lhs
|
575
|
+
|
576
|
+
rhs&.each do |r|
|
577
|
+
if (index = find_member_index(lhs, r))
|
578
|
+
lhs[index] = merge_hash_value(lhs[index], r)
|
579
|
+
else
|
580
|
+
r.visibility = :object
|
581
|
+
lhs << r
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
lhs
|
586
|
+
end
|
587
|
+
|
588
|
+
def merge_hash_value(lhs, rhs)
|
589
|
+
if [lhs.value, rhs.value].all? { _1.respond_to?(:body) }
|
590
|
+
lhs.value.merge!(rhs.value.body)
|
591
|
+
lhs
|
592
|
+
else
|
593
|
+
rhs
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
def find_member_index(lhs, rhs)
|
598
|
+
lhs.find_index { !_1.coexistable?(rhs) }
|
599
|
+
end
|
600
|
+
|
601
|
+
def merge_array_members(lhs_array, rhs_array, rhs_hash, accessor)
|
602
|
+
return nil unless lhs_array || rhs_array
|
603
|
+
return rhs_array unless lhs_array
|
604
|
+
|
605
|
+
rhs_hash&.each do |r|
|
606
|
+
index = r.__send__(accessor).value
|
607
|
+
lhs_array[index] = merge_array_value(lhs_array[index], r)
|
608
|
+
end
|
609
|
+
|
610
|
+
concat_array_members(lhs_array, rhs_array)
|
611
|
+
end
|
612
|
+
|
613
|
+
def concat_array_members(lhs_array, rhs_array)
|
614
|
+
rhs_array
|
615
|
+
&.each { _1.visibility = :object }
|
616
|
+
&.then { lhs_array.concat(_1) }
|
617
|
+
lhs_array
|
618
|
+
end
|
619
|
+
|
620
|
+
def merge_array_value(lhs, rhs)
|
621
|
+
if [lhs.value, rhs.value].all? { _1.respond_to?(:body) }
|
622
|
+
lhs.value.merge!(rhs.value.body)
|
623
|
+
lhs
|
624
|
+
else
|
625
|
+
lhs.class.new(self, rhs.value, rhs.position)
|
626
|
+
end
|
627
|
+
end
|
113
628
|
end
|
114
629
|
|
115
630
|
class UnresolvedObject
|
116
|
-
|
117
|
-
|
118
|
-
|
631
|
+
include NodeCommon
|
632
|
+
|
633
|
+
def initialize(parent, type, bodies, position)
|
634
|
+
super(parent, type, *bodies, position)
|
635
|
+
@type = type
|
636
|
+
@bodies = bodies
|
637
|
+
end
|
638
|
+
|
639
|
+
attr_reader :type
|
640
|
+
attr_reader :bodies
|
641
|
+
|
642
|
+
def evaluate(context = nil)
|
643
|
+
resolve_structure(context).evaluate(context)
|
119
644
|
end
|
120
645
|
|
121
|
-
|
122
|
-
|
646
|
+
def resolve_structure(context = nil)
|
647
|
+
exec_on(context) do |c|
|
648
|
+
klass = find_class(c)
|
649
|
+
create_object(klass, c)
|
650
|
+
end
|
651
|
+
end
|
123
652
|
|
124
|
-
def
|
125
|
-
|
653
|
+
def structure?
|
654
|
+
true
|
126
655
|
end
|
127
656
|
|
128
|
-
def
|
129
|
-
|
657
|
+
def copy(parent = nil, position = @position)
|
658
|
+
self.class.new(parent, type, bodies, position)
|
659
|
+
end
|
660
|
+
|
661
|
+
private
|
662
|
+
|
663
|
+
def find_class(context)
|
664
|
+
type
|
665
|
+
&.find_class(context)
|
666
|
+
&.tap { |klass| check_class(klass) } || Dynamic
|
130
667
|
end
|
131
668
|
|
132
|
-
def
|
133
|
-
|
669
|
+
def check_class(klass)
|
670
|
+
message =
|
671
|
+
if klass.abstract?
|
672
|
+
"cannot instantiate abstract class '#{klass.class_name}'"
|
673
|
+
elsif !klass.instantiable?
|
674
|
+
"cannot instantiate class '#{klass.class_name}'"
|
675
|
+
else
|
676
|
+
return
|
677
|
+
end
|
678
|
+
raise EvaluationError.new(message, position)
|
134
679
|
end
|
135
680
|
|
136
|
-
def
|
137
|
-
|
681
|
+
def create_object(klass, context)
|
682
|
+
klass
|
683
|
+
.new(parent, bodies.first.copy, position)
|
684
|
+
.tap { _1.resolve_structure(context) }
|
685
|
+
.tap do |o|
|
686
|
+
bodies[1..]
|
687
|
+
.map { _1.copy(o).resolve_structure(context) }
|
688
|
+
.then { o.merge!(*_1) }
|
689
|
+
end
|
138
690
|
end
|
139
691
|
end
|
140
692
|
end
|