rupkl 0.1.0 → 0.2.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 (43) 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 +99 -0
  5. data/lib/rupkl/node/base.rb +45 -0
  6. data/lib/rupkl/node/boolean.rb +12 -4
  7. data/lib/rupkl/node/context.rb +27 -0
  8. data/lib/rupkl/node/declared_type.rb +32 -0
  9. data/lib/rupkl/node/dynamic.rb +28 -59
  10. data/lib/rupkl/node/identifier.rb +16 -6
  11. data/lib/rupkl/node/listing.rb +61 -0
  12. data/lib/rupkl/node/mapping.rb +47 -0
  13. data/lib/rupkl/node/member_finder.rb +55 -0
  14. data/lib/rupkl/node/member_reference.rb +44 -21
  15. data/lib/rupkl/node/method_call.rb +64 -0
  16. data/lib/rupkl/node/method_definition.rb +143 -0
  17. data/lib/rupkl/node/node_common.rb +76 -0
  18. data/lib/rupkl/node/null.rb +27 -0
  19. data/lib/rupkl/node/number.rb +136 -6
  20. data/lib/rupkl/node/object.rb +369 -73
  21. data/lib/rupkl/node/operation.rb +97 -60
  22. data/lib/rupkl/node/pkl_module.rb +16 -28
  23. data/lib/rupkl/node/reference_resolver.rb +79 -0
  24. data/lib/rupkl/node/string.rb +388 -18
  25. data/lib/rupkl/node/struct_common.rb +119 -57
  26. data/lib/rupkl/node/this.rb +17 -0
  27. data/lib/rupkl/node/type_common.rb +34 -0
  28. data/lib/rupkl/node/value_common.rb +18 -9
  29. data/lib/rupkl/parser/expression.rb +158 -41
  30. data/lib/rupkl/parser/identifier.rb +2 -2
  31. data/lib/rupkl/parser/literal.rb +18 -12
  32. data/lib/rupkl/parser/method.rb +41 -0
  33. data/lib/rupkl/parser/misc.rb +4 -0
  34. data/lib/rupkl/parser/object.rb +57 -25
  35. data/lib/rupkl/parser/pkl_class.rb +28 -8
  36. data/lib/rupkl/parser/pkl_module.rb +5 -3
  37. data/lib/rupkl/parser/type.rb +28 -0
  38. data/lib/rupkl/parser.rb +8 -0
  39. data/lib/rupkl/pkl_object.rb +26 -6
  40. data/lib/rupkl/version.rb +1 -1
  41. data/lib/rupkl.rb +25 -4
  42. metadata +33 -3
  43. data/lib/rupkl/node/pkl_class.rb +0 -30
@@ -2,64 +2,69 @@
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
+ private
25
+
26
+ def evaluate_value(evaluator, context)
27
+ @value_evaluated = value.__send__(evaluator, context)
28
+ value
32
29
  end
33
- end
34
30
 
35
- class ObjectProperty
36
- include PropertyEvaluator
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
+ end
37
39
 
38
- def initialize(name, value, objects, position)
40
+ class ObjectProperty < ObjectMember
41
+ def initialize(parent, name, value, position)
42
+ super
39
43
  @name = name
40
44
  @value = value
41
- @objects = objects
42
- @position = position
43
45
  end
44
46
 
45
47
  attr_reader :name
46
- attr_reader :value
47
- attr_reader :objects
48
- attr_reader :position
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
@@ -68,40 +73,52 @@ module RuPkl
68
73
  def ==(other)
69
74
  name.id == other.name.id && value == other.value
70
75
  end
71
- end
72
76
 
73
- class ObjectEntry
74
- include PropertyEvaluator
77
+ def copy(parent = nil)
78
+ self.class.new(parent, name.copy, copy_value, position)
79
+ end
75
80
 
76
- def initialize(key, value, objects, position)
81
+ private
82
+
83
+ def assign_evaluaed_value?
84
+ @name && @value
85
+ end
86
+ end
87
+
88
+ class ObjectEntry < ObjectMember
89
+ def initialize(parent, key, value, position)
90
+ super
77
91
  @key = key
78
92
  @value = value
79
- @objects = objects
80
- @position = position
81
93
  end
82
94
 
83
- attr_reader :key
84
- attr_reader :value
85
- attr_reader :objects
86
- attr_reader :position
95
+ def key
96
+ @key_evaluated || @key
97
+ end
98
+
99
+ def evaluate(context = nil)
100
+ evaluate_key(context)
101
+ evaluate_value(__method__, context)
102
+ self
103
+ end
87
104
 
88
- def evaluate(scopes)
89
- k = key.evaluate(scopes)
90
- v = evaluate_property(value, objects, scopes)
91
- self.class.new(k, v, nil, position)
105
+ def resolve_structure(context = nil)
106
+ evaluate_key(context)
107
+ evaluate_value(__method__, context)
108
+ self
92
109
  end
93
110
 
94
- def to_ruby(scopes)
95
- k = key.to_ruby(scopes)
96
- v = property_to_ruby(value, objects, scopes)
111
+ def to_ruby(context = nil)
112
+ k = evaluate_key(context).to_ruby
113
+ v = evaluate_value(:evaluate, context).to_ruby
97
114
  [k, v]
98
115
  end
99
116
 
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}"
117
+ def to_pkl_string(context = nil)
118
+ k = evaluate_key(context).to_pkl_string
119
+ v = evaluate_value(:evaluate, context).to_pkl_string
120
+ if v.start_with?('new Dynamic')
121
+ "[#{k}]#{v.delete_prefix('new Dynamic')}"
105
122
  else
106
123
  "[#{k}] = #{v}"
107
124
  end
@@ -110,31 +127,310 @@ module RuPkl
110
127
  def ==(other)
111
128
  key == other.key && value == other.value
112
129
  end
130
+
131
+ def copy(parent = nil)
132
+ self.class.new(parent, key, copy_value, position)
133
+ end
134
+
135
+ private
136
+
137
+ def evaluate_key(context)
138
+ @key_evaluated ||=
139
+ (context || current_context).pop.then do |c|
140
+ @key.evaluate(c)
141
+ end
142
+ @key_evaluated
143
+ end
144
+
145
+ def assign_evaluaed_value?
146
+ @value && @key && @key_evaluated
147
+ end
148
+ end
149
+
150
+ class ObjectElement < ObjectMember
151
+ def initialize(parent, value, position)
152
+ super
153
+ @value = value
154
+ end
155
+
156
+ def evaluate(context = nil)
157
+ evaluate_value(__method__, context)
158
+ self
159
+ end
160
+
161
+ def resolve_structure(context = nil)
162
+ evaluate_value(__method__, context)
163
+ self
164
+ end
165
+
166
+ def to_ruby(context = nil)
167
+ evaluate_value(:evaluate, context).to_ruby
168
+ end
169
+
170
+ def to_pkl_string(context = nil)
171
+ evaluate_value(:evaluate, context).to_pkl_string
172
+ end
173
+
174
+ def ==(other)
175
+ value == other.value
176
+ end
177
+
178
+ def copy(parent = nil)
179
+ self.class.new(parent, copy_value, position)
180
+ end
181
+
182
+ private
183
+
184
+ def assign_evaluaed_value?
185
+ @value
186
+ end
187
+ end
188
+
189
+ class ObjectBody
190
+ include NodeCommon
191
+ include MemberFinder
192
+
193
+ def initialize(parent, members, position)
194
+ super(parent, position)
195
+ members&.each { add_member(_1) }
196
+ end
197
+
198
+ attr_reader :entries
199
+ attr_reader :elements
200
+ attr_reader :pkl_methods
201
+ attr_reader :pkl_classes
202
+
203
+ def properties(visibility: :lexical)
204
+ if visibility == :lexical
205
+ @properties
206
+ &.select { _1.visibility == :lexical || _1.parent.equal?(self) }
207
+ else
208
+ @properties
209
+ end
210
+ end
211
+
212
+ def fields
213
+ [*properties, *entries, *elements]
214
+ end
215
+
216
+ def definitions
217
+ [*pkl_methods, *pkl_classes]
218
+ end
219
+
220
+ def members
221
+ [*fields, *definitions]
222
+ end
223
+
224
+ def evaluate(context = nil)
225
+ do_evaluation(__method__, context)
226
+ end
227
+
228
+ def resolve_structure(context = nil)
229
+ do_evaluation(__method__, context)
230
+ end
231
+
232
+ def copy(parent = nil)
233
+ copied_members = members.map(&:copy)
234
+ self.class.new(parent, copied_members, position)
235
+ end
236
+
237
+ def current_context
238
+ super&.push_scope(self)
239
+ end
240
+
241
+ def merge!(*others)
242
+ others.each { do_merge(_1) }
243
+ self
244
+ end
245
+
246
+ private
247
+
248
+ def add_member(member)
249
+ add_child(member)
250
+
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
256
+ end
257
+
258
+ def member_variable_name(member)
259
+ {
260
+ ObjectProperty => :@properties,
261
+ ObjectEntry => :@entries,
262
+ ObjectElement => :@elements,
263
+ MethodDefinition => :@pkl_methods
264
+ }[member.class]
265
+ end
266
+
267
+ def do_evaluation(evaluator, context)
268
+ (context&.push_scope(self) || current_context).then do |c|
269
+ fields.each { |f| f.__send__(evaluator, c) }
270
+ check_duplication
271
+ self
272
+ end
273
+ end
274
+
275
+ def check_duplication
276
+ check_duplication_members(@properties, :name)
277
+ check_duplication_members(@entries, :key)
278
+ check_duplication_members(@pkl_methods, :name)
279
+ end
280
+
281
+ def check_duplication_members(members, accessor)
282
+ members&.each do |member|
283
+ duplicate_member?(members, member, accessor) &&
284
+ (raise EvaluationError.new('duplicate definition of member', member.position))
285
+ end
286
+ end
287
+
288
+ def duplicate_member?(members, member, accessor)
289
+ count =
290
+ members
291
+ .count { _1.__send__(accessor) == member.__send__(accessor) }
292
+ count > 1
293
+ end
294
+
295
+ def do_merge(rhs)
296
+ 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)
300
+ end
301
+
302
+ def split_entries(entries)
303
+ return [nil, nil] unless entries
304
+
305
+ elements_size = elements&.size || 0
306
+ grouped_entries =
307
+ entries
308
+ .group_by { index_node?(_1.key, elements_size) }
309
+ [grouped_entries[false], grouped_entries[true]]
310
+ end
311
+
312
+ def index_node?(node, elements_size)
313
+ node.instance_of?(Node::Int) && node.value < elements_size
314
+ end
315
+
316
+ def merge_hash_members(lhs, rhs, accessor)
317
+ return nil unless lhs || rhs
318
+ return rhs unless lhs
319
+
320
+ rhs&.each do |r|
321
+ if (index = find_member_index(lhs, r, accessor))
322
+ lhs[index] = merge_hash_value(lhs[index], r)
323
+ else
324
+ r.visibility = :object
325
+ lhs << r
326
+ end
327
+ end
328
+
329
+ lhs
330
+ end
331
+
332
+ def merge_hash_value(lhs, rhs)
333
+ if [lhs.value, rhs.value].all? { _1.respond_to?(:body) }
334
+ lhs.value.merge!(rhs.value)
335
+ lhs
336
+ else
337
+ rhs
338
+ end
339
+ end
340
+
341
+ def find_member_index(lhs, rhs, accessor)
342
+ lhs.find_index { _1.__send__(accessor) == rhs.__send__(accessor) }
343
+ end
344
+
345
+ def merge_array_members(lhs_array, rhs_array, rhs_hash, accessor)
346
+ return nil unless lhs_array || rhs_array
347
+ return rhs_array unless lhs_array
348
+
349
+ rhs_hash&.each do |r|
350
+ index = r.__send__(accessor).value
351
+ lhs_array[index] = merge_array_value(lhs_array[index], r)
352
+ end
353
+
354
+ concat_array_members(lhs_array, rhs_array)
355
+ end
356
+
357
+ def concat_array_members(lhs_array, rhs_array)
358
+ rhs_array
359
+ &.each { _1.visibility = :object }
360
+ &.then { lhs_array.concat(_1) }
361
+ lhs_array
362
+ end
363
+
364
+ def merge_array_value(lhs, rhs)
365
+ if [lhs.value, rhs.value].all? { _1.respond_to?(:body) }
366
+ lhs.value.merge!(rhs.value.body)
367
+ lhs
368
+ else
369
+ lhs.class.new(self, rhs.value, rhs.position)
370
+ end
371
+ end
113
372
  end
114
373
 
115
374
  class UnresolvedObject
116
- def initialize(members, position)
117
- @members = members
118
- @position = position
375
+ include NodeCommon
376
+
377
+ def initialize(parent, type, bodies, position)
378
+ super(parent, type, *bodies, position)
379
+ @type = type
380
+ @bodies = bodies
119
381
  end
120
382
 
121
- attr_reader :members
122
- attr_reader :position
383
+ attr_reader :type
384
+ attr_reader :bodies
123
385
 
124
- def evaluate(scopes)
125
- Dynamic.new(members, scopes, position)
386
+ def evaluate(context = nil)
387
+ resolve_structure(context).evaluate(context)
126
388
  end
127
389
 
128
- def to_ruby(scopes)
129
- evaluate(scopes).to_ruby(nil)
390
+ def resolve_structure(context = nil)
391
+ exec_on(context) do |c|
392
+ klass = find_class(c)
393
+ create_object(klass, c)
394
+ end
395
+ end
396
+
397
+ def structure?
398
+ true
399
+ end
400
+
401
+ def copy(parent = nil)
402
+ self.class.new(parent, type, bodies, position)
403
+ end
404
+
405
+ private
406
+
407
+ def find_class(context)
408
+ type
409
+ &.find_class(context)
410
+ &.tap { |klass| check_class(klass) } || Dynamic
130
411
  end
131
412
 
132
- def to_string(scopes)
133
- evaluate(scopes).to_string(nil)
413
+ def check_class(klass)
414
+ message =
415
+ if klass.abstract?
416
+ "cannot instantiate abstract class '#{klass.class_name}'"
417
+ elsif !klass.instantiable?
418
+ "cannot instantiate class '#{klass.class_name}'"
419
+ else
420
+ return
421
+ end
422
+ raise EvaluationError.new(message, position)
134
423
  end
135
424
 
136
- def to_pkl_string(scopes)
137
- evaluate(scopes).to_pkl_string(nil)
425
+ def create_object(klass, context)
426
+ klass
427
+ .new(parent, bodies.first.copy, position)
428
+ .tap { _1.resolve_structure(context) }
429
+ .tap do |o|
430
+ bodies[1..]
431
+ .map { _1.copy(o).resolve_structure(context) }
432
+ .then { o.merge!(*_1) }
433
+ end
138
434
  end
139
435
  end
140
436
  end