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
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class MethodParam
6
+ include NodeCommon
7
+
8
+ def initialize(parent, name, type, position)
9
+ super
10
+ @name = name
11
+ @type = type
12
+ end
13
+
14
+ attr_reader :name
15
+ attr_reader :type
16
+
17
+ def check_type(value, context, position)
18
+ type&.check_type(value, context, position)
19
+ end
20
+
21
+ def varparam?
22
+ false
23
+ end
24
+ end
25
+
26
+ class VariadicMethodParam < MethodParam
27
+ def check_type(values, context, position)
28
+ values.each { |v| super(v, context, position) }
29
+ end
30
+
31
+ def varparam?
32
+ true
33
+ end
34
+ end
35
+
36
+ class MethodDefinition
37
+ include NodeCommon
38
+
39
+ def initialize(parent, name, params, type, body, position)
40
+ super(parent, name, *params, type, body, position)
41
+ @name = name
42
+ @params = params
43
+ @type = type
44
+ @body = body&.copy # reset `#parent` handle
45
+ end
46
+
47
+ attr_reader :name
48
+ attr_reader :params
49
+ attr_reader :type
50
+ attr_reader :body
51
+
52
+ def call(receiver, arguments, context, parent, position)
53
+ args = evaluate_arguments(arguments, context, position)
54
+ execute_method(receiver, args, parent, position)
55
+ end
56
+
57
+ def coexistable?(other)
58
+ name != other.name
59
+ end
60
+
61
+ private
62
+
63
+ def evaluate_arguments(arguments, context, position)
64
+ check_arity(arguments, position)
65
+
66
+ params&.each_with_index&.to_h do |param, i|
67
+ arg =
68
+ if param.varparam?
69
+ Array(arguments&.[](i..))
70
+ else
71
+ arguments&.[](i)
72
+ end
73
+ evaluate_argument(param, arg, context)
74
+ end
75
+ end
76
+
77
+ def check_arity(arguments, position)
78
+ n_args = arguments&.size || 0
79
+ n_params = n_params_range
80
+ return if n_args in ^n_params
81
+
82
+ m = "expected #{n_params} method arguments but got #{n_args}"
83
+ raise EvaluationError.new(m, position)
84
+ end
85
+
86
+ def n_params_range
87
+ n_params = params&.size || 0
88
+ params&.last&.varparam? && (n_params - 1..) || n_params
89
+ end
90
+
91
+ def evaluate_argument(param, arg, context)
92
+ value =
93
+ if param.varparam?
94
+ arg.map { _1.evaluate(context) }
95
+ else
96
+ arg.evaluate(context)
97
+ end
98
+ param.check_type(value, context, position)
99
+ [param.name, value]
100
+ end
101
+
102
+ def execute_method(receiver, arguments, parent, position)
103
+ context = create_call_context(receiver, arguments)
104
+ execute_body(context)
105
+ .copy(parent, position) # set parent and position given from the caller
106
+ end
107
+
108
+ def create_call_context(receiver, arguments)
109
+ local_context = MethodCallContext.new(arguments)
110
+ method_context = current_context
111
+ if receiver
112
+ Context.new([*method_context.scopes, local_context], [receiver])
113
+ else
114
+ method_context.push_scope(local_context)
115
+ end
116
+ end
117
+
118
+ def execute_body(context)
119
+ body
120
+ .evaluate(context)
121
+ .tap { type&.check_type(_1, context, position) }
122
+ end
123
+ end
124
+
125
+ class MethodCallContext
126
+ include NodeCommon
127
+ include MemberFinder
128
+
129
+ def initialize(arguments)
130
+ @properties =
131
+ arguments&.map do |(name, value)|
132
+ ObjectProperty.new(nil, name, value, nil, nil)
133
+ end
134
+ super(nil, *@properties, nil)
135
+ end
136
+
137
+ attr_reader :properties
138
+ end
139
+
140
+ class BuiltinMethodTypeChecker
141
+ include TypeCommon
142
+
143
+ def initialize(klass)
144
+ super(nil, nil)
145
+ @klass = klass
146
+ end
147
+
148
+ private
149
+
150
+ def match_type?(klass, _context)
151
+ klass <= @klass
152
+ end
153
+ end
154
+
155
+ class BuiltinMethodParams < MethodParam
156
+ def initialize(name, klass)
157
+ id = Identifier.new(nil, name, nil)
158
+ type = BuiltinMethodTypeChecker.new(klass)
159
+ super(nil, id, type, nil)
160
+ end
161
+ end
162
+
163
+ class BuiltinVariadicMethodParam < VariadicMethodParam
164
+ def initialize(name, klass)
165
+ id = Identifier.new(nil, name, nil)
166
+ type = BuiltinMethodTypeChecker.new(klass)
167
+ super(nil, id, type, nil)
168
+ end
169
+ end
170
+
171
+ class BuiltinMethodDefinition < MethodDefinition
172
+ def initialize(name, **params, &body)
173
+ id = Identifier.new(nil, name, nil)
174
+ list = param_list(params)
175
+ super(nil, id, list, nil, nil, nil)
176
+ @body = body
177
+ end
178
+
179
+ def execute_method(receiver, arguments, parent, position)
180
+ args = arguments&.transform_keys(&:to_sym)
181
+ receiver
182
+ .instance_exec(args, parent, position, &body)
183
+ end
184
+
185
+ private
186
+
187
+ def param_list(params)
188
+ params.map do |name, type|
189
+ case type
190
+ in [klass, { varparams: true }]
191
+ BuiltinVariadicMethodParam.new(name, klass)
192
+ else
193
+ BuiltinMethodParams.new(name, type)
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ module NodeCommon
6
+ def initialize(parent, *children, position)
7
+ @position = position
8
+ parent&.add_child(self)
9
+ children.each { add_child(_1) }
10
+ end
11
+
12
+ attr_reader :parent
13
+ attr_reader :children
14
+ attr_reader :position
15
+
16
+ def resolve_reference(_context = nil)
17
+ self
18
+ end
19
+
20
+ def resolve_structure(_context = nil)
21
+ self
22
+ end
23
+
24
+ def to_ruby(context = nil)
25
+ evaluate(context).to_ruby(context)
26
+ end
27
+
28
+ def to_string(context = nil)
29
+ evaluate(context).to_string(context)
30
+ end
31
+
32
+ def to_pkl_string(context = nil)
33
+ evaluate(context).to_pkl_string(context)
34
+ end
35
+
36
+ def add_child(child)
37
+ return unless child
38
+
39
+ child.parent ||
40
+ child.instance_exec(self) { @parent = _1 }
41
+
42
+ @children&.any? { _1.equal?(child) } ||
43
+ (@children ||= []) << child
44
+ end
45
+
46
+ def copy(parent = nil, position = @position)
47
+ copied_children = children&.map(&:copy)
48
+ self.class.new(parent, *copied_children, position)
49
+ end
50
+
51
+ def current_context
52
+ parent&.current_context
53
+ end
54
+
55
+ def structure?
56
+ false
57
+ end
58
+
59
+ private
60
+
61
+ INVALID_STRING = String.new('?').freeze
62
+
63
+ def invalid_string
64
+ INVALID_STRING
65
+ end
66
+
67
+ def invalid_string?(string)
68
+ string.equal?(INVALID_STRING)
69
+ end
70
+
71
+ def exec_on(context)
72
+ yield(context || current_context)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class Null < Any
6
+ include ValueCommon
7
+ include Operatable
8
+
9
+ uninstantiable_class
10
+
11
+ def initialize(parent, position)
12
+ super(parent, nil, position)
13
+ end
14
+
15
+ def to_string(_context = nil)
16
+ 'null'
17
+ end
18
+
19
+ def null?
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,19 +2,173 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- class Number
5
+ class Number < Any
6
6
  include ValueCommon
7
+ include Operatable
7
8
 
8
- def evaluate(_scopes)
9
- self
9
+ abstract_class
10
+ uninstantiable_class
11
+
12
+ def u_op_minus(position)
13
+ self.class.new(nil, -value, position)
14
+ end
15
+
16
+ {
17
+ b_op_exp: [:**, false], b_op_div: [:/, false],
18
+ b_op_truncating_div: [:/, true], b_op_rem: [:%, false],
19
+ b_op_add: [:+, false], b_op_sub: [:-, false]
20
+ }.each do |method_name, (op, result_int)|
21
+ class_eval(<<~M, __FILE__, __LINE__ + 1)
22
+ # def b_op_exp(r_operand, position)
23
+ # b_op_arithmetic(:'**', r_operand, false, position)
24
+ # end
25
+ def #{method_name}(r_operand, position)
26
+ b_op_arithmetic(:'#{op}', r_operand, #{result_int}, position)
27
+ end
28
+ M
29
+ end
30
+
31
+ def b_op_mul(r_operand, position)
32
+ case r_operand
33
+ when Number then b_op_arithmetic(:*, r_operand, false, position)
34
+ else r_operand.b_op_mul(self, position)
35
+ end
36
+ end
37
+
38
+ {
39
+ b_op_lt: :<, b_op_gt: :>,
40
+ b_op_le: :<=, b_op_ge: :>=,
41
+ b_op_eq: :==, b_op_ne: :'!='
42
+ }.each do |method_name, op|
43
+ class_eval(<<~M, __FILE__, __LINE__ + 1)
44
+ # def b_op_lt(r_operand, position)
45
+ # l, r = coerce(:'<', r_operand)
46
+ # result = l < r
47
+ # Boolean.new(nil, result, position)
48
+ # end
49
+ def #{method_name}(r_operand, position)
50
+ l, r = coerce(:'#{op}', r_operand)
51
+ result = l #{op} r
52
+ Boolean.new(nil, result, position)
53
+ end
54
+ M
55
+ end
56
+
57
+ define_builtin_property(:sign) do
58
+ result =
59
+ case value
60
+ when :positive?.to_proc then 1
61
+ when :negative?.to_proc then -1
62
+ else value
63
+ end
64
+ self.class.new(self, result, position)
65
+ end
66
+
67
+ [
68
+ :b, :kb, :kib, :mb, :mib, :gb, :gib, :tb, :tib, :pb, :pib
69
+ ].each do |unit|
70
+ class_eval(<<~P, __FILE__, __LINE__ + 1)
71
+ # define_builtin_property(:b) do
72
+ # DataSize.new(self, self, :b, position)
73
+ # end
74
+ define_builtin_property(:#{unit}) do
75
+ DataSize.new(self, self, :#{unit}, position)
76
+ end
77
+ P
78
+ end
79
+
80
+ [:ns, :us, :ms, :s, :min, :h, :d].each do |unit|
81
+ class_eval(<<~P, __FILE__, __LINE__ + 1)
82
+ # define_builtin_property(:ns) do
83
+ # Duration.new(self, self, :ns, position)
84
+ # end
85
+ define_builtin_property(:#{unit}) do
86
+ Duration.new(self, self, :#{unit}, position)
87
+ end
88
+ P
89
+ end
90
+
91
+ define_builtin_property(:abs) do
92
+ self.class.new(self, value.abs, position)
93
+ end
94
+
95
+ define_builtin_property(:ceil) do
96
+ result = value.finite? && value.ceil || value
97
+ self.class.new(self, result, position)
98
+ end
99
+
100
+ define_builtin_property(:floor) do
101
+ result = value.finite? && value.floor || value
102
+ self.class.new(self, result, position)
103
+ end
104
+
105
+ define_builtin_property(:isPositive) do
106
+ result = value.zero? || value.positive?
107
+ Boolean.new(self, result, position)
108
+ end
109
+
110
+ define_builtin_property(:isFinite) do
111
+ Boolean.new(self, value.finite?, position)
112
+ end
113
+
114
+ define_builtin_property(:isInfinite) do
115
+ result = value.infinite? && true || false
116
+ Boolean.new(self, result, position)
117
+ end
118
+
119
+ define_builtin_property(:isNaN) do
120
+ result = !value.integer? && value.nan?
121
+ Boolean.new(self, result, position)
122
+ end
123
+
124
+ define_builtin_property(:isNonZero) do
125
+ Boolean.new(self, !value.zero?, position)
126
+ end
127
+
128
+ define_builtin_method(:toString) do |_, parent, position|
129
+ String.new(parent, value.to_s, nil, position)
130
+ end
131
+
132
+ define_builtin_method(:toInt) do |_, parent, position|
133
+ Int.new(parent, value.to_i, position)
134
+ end
135
+
136
+ define_builtin_method(:toFloat) do |_, parent, position|
137
+ Float.new(parent, value.to_f, position)
138
+ end
139
+
140
+ define_builtin_method(:round) do |_, parent, position|
141
+ result = value.finite? && value.round || value
142
+ self.class.new(parent, result, position)
143
+ end
144
+
145
+ define_builtin_method(:truncate) do |_, parent, position|
146
+ result = value.finite? && value.truncate || value
147
+ self.class.new(parent, result, position)
10
148
  end
11
149
 
12
- def undefined_operator?(operator)
13
- [:[], :!, :'&&', :'||'].include?(operator)
150
+ define_builtin_method(
151
+ :isBetween, first: Number, last: Number
152
+ ) do |args, parent, position|
153
+ f = args[:first].value
154
+ l = args[:last].value
155
+ result =
156
+ [f, l, value].all? { _1.finite? || _1.infinite? } &&
157
+ (f..l).include?(value)
158
+ Boolean.new(parent, result, position)
14
159
  end
15
160
 
16
- def invalid_r_operand?(operand)
17
- !operand.is_a?(Number)
161
+ private
162
+
163
+ def defined_operator?(operator)
164
+ [:[], :'!@', :'&&', :'||'].none?(operator)
165
+ end
166
+
167
+ def valid_r_operand?(operator, operand)
168
+ case operator
169
+ when :* then operand in Number | DataSize | Duration
170
+ else operand in Number
171
+ end
18
172
  end
19
173
 
20
174
  def coerce(operator, r_operand)
@@ -26,15 +180,79 @@ module RuPkl
26
180
  end
27
181
 
28
182
  def force_float?(operator, r_operand)
29
- operator == :/ ||
30
- operator != :'~/' && [self, r_operand].any?(Float)
183
+ operator == :/ || [self, r_operand].any?(Float)
184
+ end
185
+
186
+ def b_op_arithmetic(operator, r_operand, result_int, position)
187
+ l, r = coerce(operator, r_operand)
188
+ result = l.__send__(operator, r)
189
+ if result_int || result.integer?
190
+ Int.new(nil, result, position)
191
+ else
192
+ Float.new(nil, result, position)
193
+ end
31
194
  end
32
195
  end
33
196
 
34
- class Integer < Number
197
+ class Int < Number
198
+ def initialize(parent, value, position)
199
+ super(parent, value.to_i, position)
200
+ end
201
+
202
+ uninstantiable_class
203
+
204
+ define_builtin_property(:isEven) do
205
+ Boolean.new(self, value.even?, position)
206
+ end
207
+
208
+ define_builtin_property(:isOdd) do
209
+ Boolean.new(self, value.odd?, position)
210
+ end
211
+
212
+ define_builtin_property(:inv) do
213
+ self.class.new(self, ~value, position)
214
+ end
215
+
216
+ define_builtin_method(:shl, n: Int) do |args, parent, position|
217
+ result = value << args[:n].value
218
+ self.class.new(parent, result, position)
219
+ end
220
+
221
+ define_builtin_method(:shr, n: Int) do |args, parent, position|
222
+ result = value >> args[:n].value
223
+ self.class.new(parent, result, position)
224
+ end
225
+
226
+ define_builtin_method(:ushr, n: Int) do |args, parent, position|
227
+ result =
228
+ if value.negative?
229
+ mask = (1 << 63) - 1
230
+ args[:n].value.times.inject(value) { |v, _| (v >> 1) & mask }
231
+ else
232
+ value >> args[:n].value
233
+ end
234
+ self.class.new(parent, result, position)
235
+ end
236
+
237
+ define_builtin_method(:and, n: Int) do |args, parent, position|
238
+ self.class.new(parent, value & args[:n].value, position)
239
+ end
240
+
241
+ define_builtin_method(:or, n: Int) do |args, parent, position|
242
+ self.class.new(parent, value | args[:n].value, position)
243
+ end
244
+
245
+ define_builtin_method(:xor, n: Int) do |args, parent, position|
246
+ self.class.new(parent, value ^ args[:n].value, position)
247
+ end
35
248
  end
36
249
 
37
250
  class Float < Number
251
+ def initialize(parent, value, position)
252
+ super(parent, value.to_f, position)
253
+ end
254
+
255
+ uninstantiable_class
38
256
  end
39
257
  end
40
258
  end