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,184 +2,244 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- module OperationCommon
6
- def to_ruby(scopes)
7
- evaluate(scopes).to_ruby(nil)
5
+ module Operatable
6
+ def s_op(operator, key, context, position)
7
+ check_s_op(operator, position)
8
+
9
+ k = key.evaluate(context)
10
+ valid_key_operand?(k) ||
11
+ raise_invalid_key_error(operator, k, position)
12
+
13
+ (v = find_by_key(k)) ||
14
+ raise_no_key_found_error(k, context, position)
15
+
16
+ v.evaluate
8
17
  end
9
18
 
10
- def to_string(scopes)
11
- evaluate(scopes).to_string(nil)
19
+ def u_op(operator, position)
20
+ check_u_op(operator, position)
21
+ __send__(u_op_method(operator), position)
12
22
  end
13
23
 
14
- def to_pkl_string(scopes)
15
- evaluate(scopes).to_pkl_string(nil)
24
+ def b_op(operator, operand, context, position)
25
+ check_b_op(operator, position)
26
+ return self if short_circuit?(operator)
27
+
28
+ r_operand = operand.evaluate(context)
29
+ if valid_r_operand?(operator, r_operand)
30
+ __send__(b_op_method(operator), r_operand, position)
31
+ elsif [:==, :'!='].any?(operator)
32
+ Boolean.new(nil, operator != :==, position)
33
+ else
34
+ raise_invalid_r_operand_error(operator, r_operand, position)
35
+ end
36
+ end
37
+
38
+ def b_op_eq(r_operand, position)
39
+ result = self == r_operand
40
+ Boolean.new(nil, result, position)
41
+ end
42
+
43
+ def b_op_ne(r_operand, position)
44
+ result = self != r_operand
45
+ Boolean.new(nil, result, position)
16
46
  end
17
47
 
18
48
  private
19
49
 
20
- def s_op(scopes)
21
- r = receiver.evaluate(scopes)
22
- check_operator(r)
50
+ def check_s_op(operator, position)
51
+ check_operator(operator, position)
52
+ end
23
53
 
24
- k = key.evaluate(scopes)
25
- check_key_operand(r, k)
54
+ def valid_key_operand?(_key)
55
+ true
56
+ end
26
57
 
27
- r.find_by_key(k) ||
28
- begin
29
- message = "cannot find key '#{k.to_pkl_string(scopes)}'"
30
- raise EvaluationError.new(message, position)
31
- end
58
+ def raise_invalid_key_error(operator, key, position)
59
+ message =
60
+ "invalid key operand type #{key.class_name} is given " \
61
+ "for operator '#{operator}'"
62
+ raise EvaluationError.new(message, position)
32
63
  end
33
64
 
34
- def u_op(scopes)
35
- o = operand.evaluate(scopes)
36
- check_operator(o)
65
+ def raise_no_key_found_error(key, context, position)
66
+ message = "cannot find key '#{key.to_pkl_string(context)}'"
67
+ raise EvaluationError.new(message, position)
68
+ end
37
69
 
38
- result =
39
- if operator == :-
40
- -o.value
41
- else
42
- !o.value
43
- end
44
- create_op_result(result)
70
+ def check_u_op(operator, position)
71
+ op = :"#{operator}@"
72
+ check_operator(op, position)
45
73
  end
46
74
 
47
- def b_op(scopes)
48
- l = l_operand.evaluate(scopes)
49
- check_operator(l)
50
- return l if short_circuit?(l)
75
+ def u_op_method(operator)
76
+ { '-': :u_op_minus, '!': :u_op_negate }[operator]
77
+ end
51
78
 
52
- r = r_operand.evaluate(scopes)
53
- check_r_operand(l, r)
79
+ def check_b_op(operator, position)
80
+ check_operator(operator, position)
81
+ end
54
82
 
55
- l, r = l.coerce(operator, r)
56
- create_op_result(l.__send__(ruby_op, r))
83
+ def short_circuit?(_operator)
84
+ false
57
85
  end
58
86
 
59
- def check_operator(operand)
60
- undefined_operator?(operand) &&
61
- begin
62
- message =
63
- "operator '#{operator}' is not defined for " \
64
- "#{operand.class.basename} type"
65
- raise EvaluationError.new(message, position)
66
- end
87
+ def valid_r_operand?(_operator, operand)
88
+ operand.is_a?(self.class)
67
89
  end
68
90
 
69
- def undefined_operator?(operand)
70
- !operand.respond_to?(:undefined_operator?) ||
71
- operand.undefined_operator?(operator)
91
+ def raise_invalid_r_operand_error(operator, r_operand, position)
92
+ message =
93
+ "invalid operand type #{r_operand.class_name} is given " \
94
+ "for operator '#{operator}'"
95
+ raise EvaluationError.new(message, position)
72
96
  end
73
97
 
74
- def check_key_operand(receiver, key)
75
- invalid_key_operand?(receiver, key) &&
76
- begin
77
- message =
78
- "invalid key operand type #{key.class.basename} is given " \
79
- "for operator '#{operator}'"
80
- raise EvaluationError.new(message, position)
81
- end
98
+ def b_op_method(operator)
99
+ {
100
+ '**': :b_op_exp,
101
+ '*': :b_op_mul, '/': :b_op_div,
102
+ '~/': :b_op_truncating_div, '%': :b_op_rem,
103
+ '+': :b_op_add, '-': :b_op_sub,
104
+ '<': :b_op_lt, '>': :b_op_gt,
105
+ '<=': :b_op_le, '>=': :b_op_ge,
106
+ '==': :b_op_eq, '!=': :b_op_ne,
107
+ '&&': :b_op_and, '||': :b_op_or
108
+ }[operator]
82
109
  end
83
110
 
84
- def invalid_key_operand?(receiver, key)
85
- receiver.respond_to?(:invalid_key_operand?) &&
86
- receiver.invalid_key_operand?(key)
111
+ def check_operator(operator, position)
112
+ return if
113
+ [:==, :'!='].any?(operator) || defined_operator?(operator)
114
+
115
+ message = "operator '#{operator}' is not defined for #{class_name} type"
116
+ raise EvaluationError.new(message, position)
87
117
  end
88
118
 
89
- def check_r_operand(l_operand, r_operand)
90
- invalid_r_operand?(l_operand, r_operand) &&
91
- begin
92
- message =
93
- "invalid operand type #{r_operand.class.basename} is given " \
94
- "for operator '#{operator}'"
95
- raise EvaluationError.new(message, position)
96
- end
119
+ def defined_operator?(_operator)
120
+ false
97
121
  end
122
+ end
98
123
 
99
- def invalid_r_operand?(l_operand, r_operand)
100
- if l_operand.respond_to?(:invalid_r_operand?)
101
- l_operand.invalid_r_operand?(r_operand)
102
- else
103
- !r_operand.is_a?(l_operand.class)
104
- end
124
+ module OperationCommon
125
+ include NodeCommon
126
+
127
+ def initialize(parent, operator, *operands, position)
128
+ super(parent, *operands, position)
129
+ @operator = operator
130
+ @operands = operands
105
131
  end
106
132
 
107
- def short_circuit?(l_operand)
108
- l_operand.respond_to?(:short_circuit?) &&
109
- l_operand.short_circuit?(operator)
133
+ attr_reader :operator
134
+ attr_reader :operands
135
+
136
+ def copy(parent = nil, position = @position)
137
+ copied_operands = operands.map(&:copy)
138
+ self.class.new(parent, operator, *copied_operands, position)
110
139
  end
111
140
 
112
- def ruby_op
113
- { '&&': :&, '||': :|, '~/': :/ }.fetch(operator, operator)
141
+ private
142
+
143
+ def s_op(context)
144
+ r = receiver.evaluate(context)
145
+ r.s_op(operator, key, context, position)
114
146
  end
115
147
 
116
- def create_op_result(result)
117
- case result
118
- when ::Integer then Integer.new(result, position)
119
- when ::Float then Float.new(result, position)
120
- when ::String then String.new(result, nil, position)
121
- when ::TrueClass, ::FalseClass then Boolean.new(result, position)
122
- end
148
+ def non_null_op(context)
149
+ o = operand.evaluate(context)
150
+ return o unless o.null?
151
+
152
+ m = "expected a non-null value but got '#{o.to_pkl_string(context)}'"
153
+ raise EvaluationError.new(m, position)
154
+ end
155
+
156
+ def u_op(context)
157
+ o = operand.evaluate(context)
158
+ o.u_op(operator, position)
159
+ end
160
+
161
+ def b_op(context)
162
+ l = l_operand.evaluate(context)
163
+ l.b_op(operator, r_operand, context, position)
164
+ end
165
+
166
+ def null_coalescing_op(context)
167
+ l = l_operand.evaluate(context)
168
+ return l unless l.null?
169
+
170
+ r_operand.evaluate(context)
123
171
  end
124
172
  end
125
173
 
126
174
  class SubscriptOperation
127
175
  include OperationCommon
128
176
 
129
- def initialize(receiver, key, position)
130
- @receiver = receiver
131
- @key = key
132
- @position = position
177
+ def receiver
178
+ operands.first
133
179
  end
134
180
 
135
- attr_reader :receiver
136
- attr_reader :key
137
- attr_reader :position
181
+ def key
182
+ operands.last
183
+ end
138
184
 
139
- def operator
140
- :[]
185
+ def evaluate(context = nil)
186
+ s_op(context)
141
187
  end
188
+ end
189
+
190
+ class NonNullOperation
191
+ include OperationCommon
142
192
 
143
- def evaluate(scopes)
144
- s_op(scopes)
193
+ def operand
194
+ operands.first
195
+ end
196
+
197
+ def evaluate(context = nil)
198
+ non_null_op(context)
145
199
  end
146
200
  end
147
201
 
148
202
  class UnaryOperation
149
203
  include OperationCommon
150
204
 
151
- def initialize(operator, operand, position)
152
- @operator = operator
153
- @operand = operand
154
- @position = position
205
+ def operand
206
+ operands.first
155
207
  end
156
208
 
157
- attr_reader :operator
158
- attr_reader :operand
159
- attr_reader :position
160
-
161
- def evaluate(scopes)
162
- u_op(scopes)
209
+ def evaluate(context = nil)
210
+ u_op(context)
163
211
  end
164
212
  end
165
213
 
166
214
  class BinaryOperation
167
215
  include OperationCommon
168
216
 
169
- def initialize(operator, l_operand, r_operand, position)
170
- @operator = operator
171
- @l_operand = l_operand
172
- @r_operand = r_operand
173
- @position = position
217
+ def l_operand
218
+ operands.first
174
219
  end
175
220
 
176
- attr_reader :operator
177
- attr_reader :l_operand
178
- attr_reader :r_operand
179
- attr_reader :position
221
+ def r_operand
222
+ operands.last
223
+ end
224
+
225
+ def evaluate(context = nil)
226
+ b_op(context)
227
+ end
228
+ end
229
+
230
+ class NullCoalescingOperation
231
+ include OperationCommon
232
+
233
+ def l_operand
234
+ operands.first
235
+ end
236
+
237
+ def r_operand
238
+ operands.last
239
+ end
180
240
 
181
- def evaluate(scopes)
182
- b_op(scopes)
241
+ def evaluate(context = nil)
242
+ null_coalescing_op(context)
183
243
  end
184
244
  end
185
245
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class Pair < Any
6
+ include Operatable
7
+
8
+ uninstantiable_class
9
+
10
+ def first
11
+ @children[0]
12
+ end
13
+
14
+ def second
15
+ @children[1]
16
+ end
17
+
18
+ def evaluate(_context = nil)
19
+ self
20
+ end
21
+
22
+ def to_ruby(context = nil)
23
+ [first, second].map { _1.to_ruby(context) }
24
+ end
25
+
26
+ def to_pkl_string(context = nil)
27
+ to_string(context)
28
+ end
29
+
30
+ def to_string(context = nil)
31
+ element_strings =
32
+ [first, second].map { _1.to_pkl_string(context) }
33
+ "Pair(#{element_strings[0]}, #{element_strings[1]})"
34
+ end
35
+
36
+ def ==(other)
37
+ other.is_a?(self.class) &&
38
+ first == other.first && second == other.second
39
+ end
40
+
41
+ define_builtin_property(:first) do
42
+ first
43
+ end
44
+
45
+ define_builtin_property(:key) do
46
+ first
47
+ end
48
+
49
+ define_builtin_property(:second) do
50
+ second
51
+ end
52
+
53
+ define_builtin_property(:value) do
54
+ second
55
+ end
56
+ end
57
+ end
58
+ end
@@ -2,45 +2,33 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- class PklModule
5
+ class PklModule < Any
6
6
  include StructCommon
7
7
 
8
- def initialize(items, position)
9
- @position = position
10
- items&.each do |item|
11
- case item
12
- when PklClassProperty then add_property(item)
13
- end
14
- end
8
+ abstract_class
9
+ klass_name :Module
10
+
11
+ def pkl_methods
12
+ @body&.pkl_methods
15
13
  end
16
14
 
17
- attr_reader :properties
18
- attr_reader :position
15
+ def pkl_classes
16
+ @body&.pkl_classes
17
+ end
19
18
 
20
- def evaluate(scopes)
21
- push_scope(scopes) do |s|
22
- self.class.new(evaluate_properties(s), position)
23
- end
19
+ def evaluate(context = nil)
20
+ resolve_structure(context)
21
+ super
24
22
  end
25
23
 
26
- def to_ruby(scopes)
27
- push_scope(scopes) do |s|
28
- create_pkl_object(s, properties, nil, nil)
29
- end
24
+ def to_ruby(context = nil)
25
+ to_pkl_object(context)
30
26
  end
31
27
 
32
28
  private
33
29
 
34
- def add_property(property)
35
- (@properties ||= []) << property
36
- end
37
-
38
- def evaluate_properties(scopes)
39
- properties&.each_with_object([]) do |property, result|
40
- property
41
- .evaluate(scopes)
42
- .then { add_hash_member(result, _1, :name) }
43
- end
30
+ def properties_not_allowed?
31
+ false
44
32
  end
45
33
  end
46
34
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ module ReferenceResolver
6
+ private
7
+
8
+ def resolve_member_reference(context, target, receiver, nullable)
9
+ scopes, raise_error, ifnone =
10
+ if receiver
11
+ evaluate_receiver(receiver, context)&.then do |r|
12
+ [[r], raise_error?(r, nullable), ifnone_value(r)]
13
+ end
14
+ else
15
+ exec_on(context) do |c|
16
+ [[c&.objects&.last, Base.instance, *c&.scopes], true]
17
+ end
18
+ end
19
+ find_member(scopes, target, raise_error, ifnone)
20
+ end
21
+
22
+ def raise_error?(receiver, nullable)
23
+ !(nullable && receiver&.null?)
24
+ end
25
+
26
+ def evaluate_receiver(receiver, context)
27
+ return unless receiver
28
+
29
+ if receiver.structure?
30
+ receiver
31
+ .resolve_reference(context)
32
+ .resolve_structure(context)
33
+ else
34
+ receiver.evaluate(context)
35
+ end
36
+ end
37
+
38
+ def find_member(scopes, target, raise_error, ifnone)
39
+ if scope_index.index
40
+ get_member_node(scopes[scope_index.index], target)
41
+ else
42
+ search_member(scopes, target, raise_error, ifnone)
43
+ end
44
+ end
45
+
46
+ def search_member(scopes, target, raise_error, ifnone)
47
+ node, index = search_member_from_scopes(scopes, target)
48
+ if node
49
+ scope_index.index = index
50
+ return node
51
+ end
52
+
53
+ raise_error &&
54
+ (raise unresolve_reference_error(target))
55
+
56
+ ifnone
57
+ end
58
+
59
+ def search_member_from_scopes(scopes, target)
60
+ scopes.reverse_each.with_index do |scope, i|
61
+ node = get_member_node(scope, target)
62
+ return [node, scopes.size - i - 1] if node
63
+ end
64
+
65
+ nil
66
+ end
67
+
68
+ ScopeIndex = Struct.new(:index)
69
+
70
+ def scope_index
71
+ @scope_index ||= ScopeIndex.new
72
+ end
73
+
74
+ def copy_scope_index(target)
75
+ target.instance_exec(scope_index) { @scope_index = _1 }
76
+ end
77
+ end
78
+ end
79
+ end