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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/rupkl/node/amend_expression.rb +48 -0
  4. data/lib/rupkl/node/any.rb +110 -0
  5. data/lib/rupkl/node/base.rb +75 -0
  6. data/lib/rupkl/node/boolean.rb +30 -5
  7. data/lib/rupkl/node/collection.rb +176 -0
  8. data/lib/rupkl/node/context.rb +27 -0
  9. data/lib/rupkl/node/data_size.rb +254 -0
  10. data/lib/rupkl/node/declared_type.rb +32 -0
  11. data/lib/rupkl/node/duration.rb +266 -0
  12. data/lib/rupkl/node/dynamic.rb +33 -60
  13. data/lib/rupkl/node/identifier.rb +19 -5
  14. data/lib/rupkl/node/if_expression.rb +45 -0
  15. data/lib/rupkl/node/intseq.rb +84 -0
  16. data/lib/rupkl/node/listing.rb +68 -0
  17. data/lib/rupkl/node/map.rb +120 -0
  18. data/lib/rupkl/node/mapping.rb +54 -0
  19. data/lib/rupkl/node/member_finder.rb +49 -0
  20. data/lib/rupkl/node/member_reference.rb +46 -21
  21. data/lib/rupkl/node/method_call.rb +63 -0
  22. data/lib/rupkl/node/method_definition.rb +199 -0
  23. data/lib/rupkl/node/node_common.rb +76 -0
  24. data/lib/rupkl/node/null.rb +24 -0
  25. data/lib/rupkl/node/number.rb +228 -10
  26. data/lib/rupkl/node/object.rb +626 -74
  27. data/lib/rupkl/node/operation.rb +175 -115
  28. data/lib/rupkl/node/pair.rb +58 -0
  29. data/lib/rupkl/node/pkl_module.rb +16 -28
  30. data/lib/rupkl/node/reference_resolver.rb +79 -0
  31. data/lib/rupkl/node/regex.rb +196 -0
  32. data/lib/rupkl/node/string.rb +415 -23
  33. data/lib/rupkl/node/struct_common.rb +150 -53
  34. data/lib/rupkl/node/this.rb +17 -0
  35. data/lib/rupkl/node/type_common.rb +34 -0
  36. data/lib/rupkl/node/value_common.rb +18 -13
  37. data/lib/rupkl/parser/expression.rb +197 -43
  38. data/lib/rupkl/parser/identifier.rb +2 -2
  39. data/lib/rupkl/parser/literal.rb +18 -12
  40. data/lib/rupkl/parser/method.rb +41 -0
  41. data/lib/rupkl/parser/misc.rb +24 -0
  42. data/lib/rupkl/parser/object.rb +141 -26
  43. data/lib/rupkl/parser/pkl_class.rb +37 -10
  44. data/lib/rupkl/parser/pkl_module.rb +5 -3
  45. data/lib/rupkl/parser/type.rb +28 -0
  46. data/lib/rupkl/parser.rb +8 -0
  47. data/lib/rupkl/pkl_object.rb +11 -7
  48. data/lib/rupkl/version.rb +1 -1
  49. data/lib/rupkl.rb +35 -6
  50. metadata +45 -7
  51. data/lib/rupkl/node/pkl_class.rb +0 -30
@@ -2,106 +2,131 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- module PropertyEvaluator
6
- private
5
+ class ObjectMember
6
+ include NodeCommon
7
7
 
8
- def evaluate_property(value, objects, scopes)
9
- value&.evaluate(scopes) || evaluate_objects(objects, scopes)
8
+ def value
9
+ @value_evaluated || @value
10
10
  end
11
11
 
12
- def property_to_ruby(value, objects, scopes)
13
- if value
14
- value.to_ruby(scopes)
15
- else
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 property_to_pkl_string(value, objects, scopes)
21
- if value
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
- def evaluate_objects(objects, scopes)
29
- objects
30
- .map { _1.evaluate(scopes) }
31
- .inject { |r, o| r.merge!(o) }
22
+ attr_writer :visibility
23
+
24
+ def generated?
25
+ @generated
32
26
  end
33
- end
34
27
 
35
- class ObjectProperty
36
- include PropertyEvaluator
28
+ attr_writer :generated
37
29
 
38
- def initialize(name, value, objects, position)
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
- @objects = objects
42
- @position = position
43
+ @modifiers = modifiers
43
44
  end
44
45
 
45
46
  attr_reader :name
46
- attr_reader :value
47
- attr_reader :objects
48
- attr_reader :position
47
+ attr_reader :modifiers
49
48
 
50
- def evaluate(scopes)
51
- v = evaluate_property(value, objects, scopes)
52
- self.class.new(name, v, nil, position)
49
+ def evaluate(context = nil)
50
+ evaluate_value(__method__, context)
51
+ self
53
52
  end
54
53
 
55
- def to_ruby(scopes)
56
- [name.id, property_to_ruby(value, objects, scopes)]
54
+ def resolve_structure(context = nil)
55
+ evaluate_value(__method__, context)
56
+ self
57
57
  end
58
58
 
59
- def to_pkl_string(scopes)
60
- v = property_to_pkl_string(value, objects, scopes)
61
- if v.start_with?('{')
62
- "#{name.id} #{v}"
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.id == other.name.id && value == other.value
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
- class ObjectEntry
74
- include PropertyEvaluator
89
+ private
75
90
 
76
- def initialize(key, value, objects, position)
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
- attr_reader :key
84
- attr_reader :value
85
- attr_reader :objects
86
- attr_reader :position
103
+ def key
104
+ @key_evaluated || @key
105
+ end
87
106
 
88
- def evaluate(scopes)
89
- k = key.evaluate(scopes)
90
- v = evaluate_property(value, objects, scopes)
91
- self.class.new(k, v, nil, position)
107
+ def evaluate(context = nil)
108
+ evaluate_key(context)
109
+ evaluate_value(__method__, context)
110
+ self
92
111
  end
93
112
 
94
- def to_ruby(scopes)
95
- k = key.to_ruby(scopes)
96
- v = property_to_ruby(value, objects, scopes)
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(scopes)
101
- k = key.to_pkl_string(scopes)
102
- v = property_to_pkl_string(value, objects, scopes)
103
- if v.start_with?('{')
104
- "[#{k}] #{v}"
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
- def initialize(members, position)
117
- @members = members
118
- @position = position
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
- attr_reader :members
122
- attr_reader :position
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 evaluate(scopes)
125
- Dynamic.new(members, scopes, position)
653
+ def structure?
654
+ true
126
655
  end
127
656
 
128
- def to_ruby(scopes)
129
- evaluate(scopes).to_ruby(nil)
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 to_string(scopes)
133
- evaluate(scopes).to_string(nil)
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 to_pkl_string(scopes)
137
- evaluate(scopes).to_pkl_string(nil)
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