rupkl 0.1.0 → 0.2.0

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