rupkl 0.2.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.
@@ -21,30 +21,30 @@ module RuPkl
21
21
 
22
22
  attr_writer :visibility
23
23
 
24
+ def generated?
25
+ @generated
26
+ end
27
+
28
+ attr_writer :generated
29
+
24
30
  private
25
31
 
26
32
  def evaluate_value(evaluator, context)
27
33
  @value_evaluated = value.__send__(evaluator, context)
28
34
  value
29
35
  end
30
-
31
- def copy_value
32
- if @value_evaluated.respond_to?(:body)
33
- @value_evaluated.copy
34
- else
35
- @value.copy
36
- end
37
- end
38
36
  end
39
37
 
40
38
  class ObjectProperty < ObjectMember
41
- def initialize(parent, name, value, position)
42
- super
39
+ def initialize(parent, name, value, modifiers, position)
40
+ super(parent, name, value, position)
43
41
  @name = name
44
42
  @value = value
43
+ @modifiers = modifiers
45
44
  end
46
45
 
47
46
  attr_reader :name
47
+ attr_reader :modifiers
48
48
 
49
49
  def evaluate(context = nil)
50
50
  evaluate_value(__method__, context)
@@ -71,11 +71,19 @@ module RuPkl
71
71
  end
72
72
 
73
73
  def ==(other)
74
- name.id == other.name.id && value == other.value
74
+ name == other.name && value == other.value
75
75
  end
76
76
 
77
- def copy(parent = nil)
78
- self.class.new(parent, name.copy, copy_value, position)
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)
79
87
  end
80
88
 
81
89
  private
@@ -128,8 +136,12 @@ module RuPkl
128
136
  key == other.key && value == other.value
129
137
  end
130
138
 
131
- def copy(parent = nil)
132
- self.class.new(parent, key, copy_value, position)
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
133
145
  end
134
146
 
135
147
  private
@@ -175,8 +187,8 @@ module RuPkl
175
187
  value == other.value
176
188
  end
177
189
 
178
- def copy(parent = nil)
179
- self.class.new(parent, copy_value, position)
190
+ def copy(parent = nil, position = @position)
191
+ self.class.new(parent, value.copy, position)
180
192
  end
181
193
 
182
194
  private
@@ -186,39 +198,261 @@ module RuPkl
186
198
  end
187
199
  end
188
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
+
189
410
  class ObjectBody
190
411
  include NodeCommon
191
412
  include MemberFinder
192
413
 
193
- def initialize(parent, members, position)
194
- super(parent, position)
195
- members&.each { add_member(_1) }
414
+ def initialize(parent, items, position)
415
+ super(parent, *items, position)
196
416
  end
197
417
 
198
- attr_reader :entries
199
- attr_reader :elements
200
- attr_reader :pkl_methods
201
418
  attr_reader :pkl_classes
202
419
 
203
- def properties(visibility: :lexical)
204
- if visibility == :lexical
420
+ alias_method :items, :children
421
+
422
+ def properties(visibility: :lexical, all: false)
423
+ @properties ||= collect_members(ObjectProperty)
424
+
425
+ if all
205
426
  @properties
206
- &.select { _1.visibility == :lexical || _1.parent.equal?(self) }
427
+ elsif visibility == :lexical
428
+ @properties&.select { _1.visibility == :lexical || _1.parent.equal?(self) }
207
429
  else
208
- @properties
430
+ @properties&.select { !_1.local? }
209
431
  end
210
432
  end
211
433
 
212
- def fields
213
- [*properties, *entries, *elements]
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]
214
448
  end
215
449
 
216
450
  def definitions
217
451
  [*pkl_methods, *pkl_classes]
218
452
  end
219
453
 
220
- def members
221
- [*fields, *definitions]
454
+ def members(visibility: :lexical)
455
+ [*fields(visibility: visibility), *definitions]
222
456
  end
223
457
 
224
458
  def evaluate(context = nil)
@@ -226,11 +460,12 @@ module RuPkl
226
460
  end
227
461
 
228
462
  def resolve_structure(context = nil)
463
+ resolve_generator(context)
229
464
  do_evaluation(__method__, context)
230
465
  end
231
466
 
232
- def copy(parent = nil)
233
- copied_members = members.map(&:copy)
467
+ def copy(parent = nil, position = @position)
468
+ copied_members = items&.map(&:copy)
234
469
  self.class.new(parent, copied_members, position)
235
470
  end
236
471
 
@@ -238,6 +473,17 @@ module RuPkl
238
473
  super&.push_scope(self)
239
474
  end
240
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
+
241
487
  def merge!(*others)
242
488
  others.each { do_merge(_1) }
243
489
  self
@@ -245,58 +491,68 @@ module RuPkl
245
491
 
246
492
  private
247
493
 
248
- def add_member(member)
249
- add_child(member)
494
+ GENERATOR_CLASSES = [
495
+ WhenGenerator,
496
+ ForGenerator
497
+ ].freeze
250
498
 
251
- varialbe_name = member_variable_name(member)
252
- unless instance_variable_defined?(varialbe_name)
253
- instance_variable_set(varialbe_name, [])
254
- end
255
- instance_variable_get(varialbe_name) << member
499
+ def generator?(item)
500
+ GENERATOR_CLASSES.any? { item.is_a?(_1) }
256
501
  end
257
502
 
258
- def member_variable_name(member)
259
- {
260
- ObjectProperty => :@properties,
261
- ObjectEntry => :@entries,
262
- ObjectElement => :@elements,
263
- MethodDefinition => :@pkl_methods
264
- }[member.class]
503
+ def generators
504
+ items&.select { generator?(_1) }
265
505
  end
266
506
 
267
507
  def do_evaluation(evaluator, context)
268
508
  (context&.push_scope(self) || current_context).then do |c|
269
- fields.each { |f| f.__send__(evaluator, 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
270
516
  check_duplication
271
517
  self
272
518
  end
273
519
  end
274
520
 
275
521
  def check_duplication
276
- check_duplication_members(@properties, :name)
277
- check_duplication_members(@entries, :key)
278
- check_duplication_members(@pkl_methods, :name)
522
+ check_duplication_members(properties(all: true))
523
+ check_duplication_members(entries)
524
+ check_duplication_members(pkl_methods)
279
525
  end
280
526
 
281
- def check_duplication_members(members, accessor)
527
+ def check_duplication_members(members)
282
528
  members&.each do |member|
283
- duplicate_member?(members, member, accessor) &&
529
+ duplicate_member?(members, member) &&
284
530
  (raise EvaluationError.new('duplicate definition of member', member.position))
285
531
  end
286
532
  end
287
533
 
288
- def duplicate_member?(members, member, accessor)
289
- count =
290
- members
291
- .count { _1.__send__(accessor) == member.__send__(accessor) }
534
+ def duplicate_member?(members, member)
535
+ count = members.count { !_1.coexistable?(member) }
292
536
  count > 1
293
537
  end
294
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
+
295
550
  def do_merge(rhs)
551
+ rhs_properties = rhs.properties(visibility: :object)
296
552
  rhs_entries, rhs_amend = split_entries(rhs.entries)
297
- @properties = merge_hash_members(@properties, rhs.properties, :name)
298
- @entries = merge_hash_members(@entries, rhs_entries, :key)
299
- @elements = merge_array_members(@elements, rhs.elements, rhs_amend, :key)
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)
300
556
  end
301
557
 
302
558
  def split_entries(entries)
@@ -313,12 +569,12 @@ module RuPkl
313
569
  node.instance_of?(Node::Int) && node.value < elements_size
314
570
  end
315
571
 
316
- def merge_hash_members(lhs, rhs, accessor)
572
+ def merge_hash_members(lhs, rhs)
317
573
  return nil unless lhs || rhs
318
574
  return rhs unless lhs
319
575
 
320
576
  rhs&.each do |r|
321
- if (index = find_member_index(lhs, r, accessor))
577
+ if (index = find_member_index(lhs, r))
322
578
  lhs[index] = merge_hash_value(lhs[index], r)
323
579
  else
324
580
  r.visibility = :object
@@ -331,15 +587,15 @@ module RuPkl
331
587
 
332
588
  def merge_hash_value(lhs, rhs)
333
589
  if [lhs.value, rhs.value].all? { _1.respond_to?(:body) }
334
- lhs.value.merge!(rhs.value)
590
+ lhs.value.merge!(rhs.value.body)
335
591
  lhs
336
592
  else
337
593
  rhs
338
594
  end
339
595
  end
340
596
 
341
- def find_member_index(lhs, rhs, accessor)
342
- lhs.find_index { _1.__send__(accessor) == rhs.__send__(accessor) }
597
+ def find_member_index(lhs, rhs)
598
+ lhs.find_index { !_1.coexistable?(rhs) }
343
599
  end
344
600
 
345
601
  def merge_array_members(lhs_array, rhs_array, rhs_hash, accessor)
@@ -398,7 +654,7 @@ module RuPkl
398
654
  true
399
655
  end
400
656
 
401
- def copy(parent = nil)
657
+ def copy(parent = nil, position = @position)
402
658
  self.class.new(parent, type, bodies, position)
403
659
  end
404
660