rupkl 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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