rupkl 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7731a56bb62b392639860c5e0f82c2175e8bca4ecd439e8ccffd05d9b223b0f
4
- data.tar.gz: 18487cb107c5a47212d185d782f4866d5fc5c0734b893986e4388c003728687d
3
+ metadata.gz: f84f197edd08a0aa623b11f6fd14c83e3fefaf880f0b70a8f6e84eb6599f4ad6
4
+ data.tar.gz: 9f3294541be5d4ea4ac6c71fe12f501752cf3b6c447194a8b6254723742c169b
5
5
  SHA512:
6
- metadata.gz: e9d8c2d0d8d9f4976ba804810285344b8f5a6cd308ce1eeff23eb3503feb365c2415d1876c8c879fdf38ca016b01dc849aaeb2e01ae502b9c0e0a44a1a2123ce
7
- data.tar.gz: 2bc34ee5b570519a913299dbe5415fe9a7e3dd406b5912f729127ce152c18fd6821f769f9c6df6e677c0c114de935f401584e67e5ae385133aef318810f57ce0
6
+ metadata.gz: a4ed0408a38e1db11008cd03922c295ac0e0fd42b22a2d9c6d47bd91e73f3de344aa2af1559d4e83d407a49cc51ec95e595da83ce0572d6b1ab86d17c4f79e05
7
+ data.tar.gz: a055b31ced095d7e8f851830c03daf63388d1ef23f343e7f1dd6292205e9a0a99a54bc2b5119e9489487084fe28b2d3a37af28c21197b0d0f7367e39446bffbb
@@ -25,13 +25,13 @@ module RuPkl
25
25
  .resolve_structure(context)
26
26
  t.respond_to?(:body) ||
27
27
  begin
28
- message = "cannot amend the target type #{t.class.basename}"
28
+ message = "cannot amend the target type #{t.class_name}"
29
29
  raise EvaluationError.new(message, position)
30
30
  end
31
31
  do_amend(t.copy(parent))
32
32
  end
33
33
 
34
- def copy(parent = nil)
34
+ def copy(parent = nil, position = @position)
35
35
  self.class.new(parent, target.copy, bodies.each(&:copy), position)
36
36
  end
37
37
 
@@ -15,15 +15,15 @@ module RuPkl
15
15
  end
16
16
 
17
17
  def class_name
18
- @class_name || basename.to_sym
18
+ @class_name ||= to_s.split('::').last.to_sym
19
19
  end
20
20
 
21
21
  def builtin_property(name)
22
- @builtin_properties&.[](name.id)
22
+ @builtin_properties&.[](name.to_sym)
23
23
  end
24
24
 
25
25
  def buildin_method(name)
26
- @builtin_methods&.[](name.id)
26
+ @builtin_methods&.[](name.to_sym)
27
27
  end
28
28
 
29
29
  private
@@ -64,6 +64,10 @@ module RuPkl
64
64
  false
65
65
  end
66
66
 
67
+ def class_name
68
+ self.class.class_name
69
+ end
70
+
67
71
  private
68
72
 
69
73
  def builtin_property(name)
@@ -88,12 +92,19 @@ module RuPkl
88
92
  nil
89
93
  end
90
94
 
91
- def check_positive_number(number)
95
+ def check_positive_number(number, position)
92
96
  return unless number.value.negative?
93
97
 
94
98
  m = "expected a positive number, but got '#{number.value}'"
95
99
  raise EvaluationError.new(m, position)
96
100
  end
101
+
102
+ protected
103
+
104
+ def execute_builtin_method(name, arguments, parent, position)
105
+ buildin_method(name)
106
+ .execute_method(self, arguments, parent, position)
107
+ end
97
108
  end
98
109
  end
99
110
  end
@@ -34,11 +34,41 @@ module RuPkl
34
34
  add_builtin_class PklModule
35
35
 
36
36
  define_builtin_property(:NaN) do
37
- Float.new(parent, ::Float::NAN, position)
37
+ Float.new(self, ::Float::NAN, position)
38
38
  end
39
39
 
40
40
  define_builtin_property(:Infinity) do
41
- Float.new(parent, ::Float::INFINITY, position)
41
+ Float.new(self, ::Float::INFINITY, position)
42
+ end
43
+
44
+ define_builtin_method(
45
+ :List, elements: [Any, varparams: true]
46
+ ) do |args, parent, position|
47
+ List.new(parent, args[:elements], position)
48
+ end
49
+
50
+ define_builtin_method(
51
+ :Set, elements: [Any, varparams: true]
52
+ ) do |args, parent, position|
53
+ Set.new(parent, args[:elements], position)
54
+ end
55
+
56
+ define_builtin_method(:Pair, first: Any, second: Any) do |args, parent, position|
57
+ Pair.new(parent, args[:first], args[:second], position)
58
+ end
59
+
60
+ define_builtin_method(
61
+ :Map, entries: [Any, varparams: true]
62
+ ) do |args, parent, position|
63
+ Map.new(parent, args[:entries], position)
64
+ end
65
+
66
+ define_builtin_method(:IntSeq, start: Int, last: Int) do |args, parent, position|
67
+ IntSeq.new(parent, args[:start], args[:last], nil, position)
68
+ end
69
+
70
+ define_builtin_method(:Regex, pattern: String) do |args, parent, position|
71
+ Regex.new(parent, args[:pattern], position)
42
72
  end
43
73
  end
44
74
  end
@@ -4,25 +4,42 @@ module RuPkl
4
4
  module Node
5
5
  class Boolean < Any
6
6
  include ValueCommon
7
+ include Operatable
7
8
 
8
9
  uninstantiable_class
9
10
 
10
- def undefined_operator?(operator)
11
- [:!, :==, :'!=', :'&&', :'||'].none?(operator)
11
+ def u_op_negate(position)
12
+ Boolean.new(nil, !value, position)
12
13
  end
13
14
 
14
- def short_circuit?(operator)
15
- [operator, value] in [:'&&', false] | [:'||', true]
15
+ def b_op_and(r_operand, position)
16
+ result = value && r_operand.value
17
+ Boolean.new(nil, result, position)
16
18
  end
17
19
 
18
- define_builtin_method(:xor, other: Boolean) do |other|
19
- result = value ^ other.value
20
+ def b_op_or(r_operand, position)
21
+ result = value || r_operand.value
20
22
  Boolean.new(nil, result, position)
21
23
  end
22
24
 
23
- define_builtin_method(:implies, other: Boolean) do |other|
24
- result = !value || other.value
25
- Boolean.new(nil, result, position)
25
+ define_builtin_method(:xor, other: Boolean) do |args, parent, position|
26
+ result = value ^ args[:other].value
27
+ Boolean.new(parent, result, position)
28
+ end
29
+
30
+ define_builtin_method(:implies, other: Boolean) do |args, parent, position|
31
+ result = !value || args[:other].value
32
+ Boolean.new(parent, result, position)
33
+ end
34
+
35
+ private
36
+
37
+ def defined_operator?(operator)
38
+ [:'!@', :'&&', :'||'].any?(operator)
39
+ end
40
+
41
+ def short_circuit?(operator)
42
+ [operator, value] in [:'&&', false] | [:'||', true]
26
43
  end
27
44
  end
28
45
  end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class Collection < Any
6
+ include Operatable
7
+
8
+ abstract_class
9
+ uninstantiable_class
10
+
11
+ def initialize(parent, elements, position)
12
+ super(parent, *elements, position)
13
+ end
14
+
15
+ alias_method :elements, :children
16
+
17
+ def evaluate(_context = nil)
18
+ self
19
+ end
20
+
21
+ def to_ruby(context = nil)
22
+ elements&.map { _1.to_ruby(context) } || []
23
+ end
24
+
25
+ def to_pkl_string(context = nil)
26
+ to_string(context)
27
+ end
28
+
29
+ def to_string(context = nil)
30
+ element_string =
31
+ elements
32
+ &.map { _1.to_pkl_string(context) }
33
+ &.join(', ')
34
+ "#{class_name}(#{element_string})"
35
+ end
36
+
37
+ def ==(other)
38
+ other.instance_of?(self.class) && elements == other.elements
39
+ end
40
+
41
+ def b_op_add(r_operand, position)
42
+ result =
43
+ if elements && r_operand.elements
44
+ elements + r_operand.elements
45
+ else
46
+ elements || r_operand.elements
47
+ end
48
+ self.class.new(nil, result, position)
49
+ end
50
+
51
+ define_builtin_property(:length) do
52
+ result = elements&.size || 0
53
+ Int.new(self, result, position)
54
+ end
55
+
56
+ define_builtin_property(:isEmpty) do
57
+ result = elements.nil? || elements.empty?
58
+ Boolean.new(self, result, position)
59
+ end
60
+
61
+ define_builtin_property(:first) do
62
+ elements&.first || raise_wrong_collection_size_error
63
+ end
64
+
65
+ define_builtin_property(:firstOrNull) do
66
+ elements&.first || Null.new(parent, position)
67
+ end
68
+
69
+ define_builtin_property(:rest) do
70
+ if (result = elements&.[](1..))
71
+ self.class.new(parent, result, position)
72
+ else
73
+ raise_wrong_collection_size_error
74
+ end
75
+ end
76
+
77
+ define_builtin_property(:restOrNull) do
78
+ if (result = elements&.[](1..))
79
+ self.class.new(parent, result, position)
80
+ else
81
+ Null.new(parent, position)
82
+ end
83
+ end
84
+
85
+ define_builtin_property(:last) do
86
+ elements&.last || raise_wrong_collection_size_error
87
+ end
88
+
89
+ define_builtin_property(:lastOrNull) do
90
+ elements&.last || Null.new(parent, position)
91
+ end
92
+
93
+ define_builtin_property(:single) do
94
+ size = elements&.size || 0
95
+ size == 1 && elements.first ||
96
+ raise_wrong_collection_size_error { 'expected a single-element collection' }
97
+ end
98
+
99
+ define_builtin_property(:singleOrNull) do
100
+ size = elements&.size || 0
101
+ size == 1 && elements.first || Null.new(parent, position)
102
+ end
103
+
104
+ define_builtin_property(:lastIndex) do
105
+ result = (elements&.size || 0) - 1
106
+ Int.new(parent, result, position)
107
+ end
108
+
109
+ private
110
+
111
+ def remove_duplicate_elements(elements)
112
+ elements
113
+ &.each_with_object([]) { |e, a| a.include?(e) || (a << e) }
114
+ end
115
+
116
+ def raise_wrong_collection_size_error
117
+ message =
118
+ if block_given?
119
+ yield
120
+ else
121
+ 'expected a non-empty collection'
122
+ end
123
+ raise EvaluationError.new(message, position)
124
+ end
125
+
126
+ def valid_r_operand?(operator, operand)
127
+ operand.is_a?(self.class) ||
128
+ operator == :+ && (operand in List | Set)
129
+ end
130
+ end
131
+
132
+ class List < Collection
133
+ include MemberFinder
134
+ undef_method :pkl_method
135
+
136
+ uninstantiable_class
137
+
138
+ def find_by_key(key)
139
+ find_element(key)
140
+ end
141
+
142
+ define_builtin_property(:isDistinct) do
143
+ result =
144
+ elements.nil? ||
145
+ elements.all? { |e| elements.one?(e) }
146
+ Boolean.new(parent, result, position)
147
+ end
148
+
149
+ define_builtin_property(:distinct) do
150
+ result = remove_duplicate_elements(elements)
151
+ List.new(parent, result, position)
152
+ end
153
+
154
+ private
155
+
156
+ def defined_operator?(operator)
157
+ [:[], :+].any?(operator)
158
+ end
159
+ end
160
+
161
+ class Set < Collection
162
+ uninstantiable_class
163
+
164
+ def initialize(parent, elements, position)
165
+ unique_elements = remove_duplicate_elements(elements)
166
+ super(parent, unique_elements, position)
167
+ end
168
+
169
+ private
170
+
171
+ def defined_operator?(operator)
172
+ operator == :+
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,254 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class DataSize < Any
6
+ include Operatable
7
+
8
+ uninstantiable_class
9
+
10
+ def initialize(parent, value, unit, position)
11
+ super(parent, value, position)
12
+ @unit = unit
13
+ end
14
+
15
+ attr_reader :unit
16
+
17
+ def value
18
+ @children[0]
19
+ end
20
+
21
+ def evaluate(_context = nil)
22
+ self
23
+ end
24
+
25
+ def to_ruby(context = nil)
26
+ value.to_ruby(context) * unit_factor(unit)
27
+ end
28
+
29
+ def to_pkl_string(context = nil)
30
+ to_string(context)
31
+ end
32
+
33
+ def to_string(context = nil)
34
+ "#{value.to_pkl_string(context)}.#{unit}"
35
+ end
36
+
37
+ def u_op_minus(position)
38
+ DataSize.new(nil, value.u_op_minus(position), unit, position)
39
+ end
40
+
41
+ def ==(other)
42
+ other.is_a?(DataSize) &&
43
+ calc_byte_size(self).value == calc_byte_size(other).value
44
+ end
45
+
46
+ [:b_op_lt, :b_op_gt, :b_op_le, :b_op_ge].each do |method_name|
47
+ class_eval(<<~M, __FILE__, __LINE__ + 1)
48
+ # def b_op_lt(r_operand, position)
49
+ # l = calc_byte_size(self)
50
+ # r = calc_byte_size(r_operand)
51
+ # l.b_op_lt(r, position)
52
+ # end
53
+ def #{method_name}(r_operand, position)
54
+ l = calc_byte_size(self)
55
+ r = calc_byte_size(r_operand)
56
+ l.#{method_name}(r, position)
57
+ end
58
+ M
59
+ end
60
+
61
+ [:b_op_add, :b_op_sub].each do |method_name|
62
+ class_eval(<<~M, __FILE__, __LINE__ + 1)
63
+ # def b_op_add(r_operand, position)
64
+ # l, r, u = align_unit(self, r_operand)
65
+ # result = l.b_op_add(r, position)
66
+ # DataSize.new(nil, result, u, position)
67
+ # end
68
+ def #{method_name}(r_operand, position)
69
+ l, r, u = align_unit(self, r_operand)
70
+ result = l.#{method_name}(r, position)
71
+ DataSize.new(nil, result, u, position)
72
+ end
73
+ M
74
+ end
75
+
76
+ [:b_op_mul, :b_op_rem, :b_op_exp].each do |method_name|
77
+ class_eval(<<~M, __FILE__, __LINE__ + 1)
78
+ # def b_op_mul(r_operand, position)
79
+ # result = value.b_op_mul(r_operand, position)
80
+ # DataSize.new(nil, result, unit, position)
81
+ # end
82
+ def #{method_name}(r_operand, position)
83
+ result = value.#{method_name}(r_operand, position)
84
+ DataSize.new(nil, result, unit, position)
85
+ end
86
+ M
87
+ end
88
+
89
+ [:b_op_div, :b_op_truncating_div].each do |method_name|
90
+ class_eval(<<~M, __FILE__, __LINE__ + 1)
91
+ # def b_op_div(r_operand, position)
92
+ # if r_operand.is_a?(DataSize)
93
+ # l = calc_byte_size(self)
94
+ # r = calc_byte_size(r_operand)
95
+ # l.b_op_div(r, position)
96
+ # else
97
+ # result = value.b_op_div(r_operand, position)
98
+ # DataSize.new(nil, result, unit, position)
99
+ # end
100
+ # end
101
+ def #{method_name}(r_operand, position)
102
+ if r_operand.is_a?(DataSize)
103
+ l = calc_byte_size(self)
104
+ r = calc_byte_size(r_operand)
105
+ l.#{method_name}(r, position)
106
+ else
107
+ result = value.#{method_name}(r_operand, position)
108
+ DataSize.new(nil, result, unit, position)
109
+ end
110
+ end
111
+ M
112
+ end
113
+
114
+ define_builtin_property(:value) do
115
+ value
116
+ end
117
+
118
+ define_builtin_property(:unit) do
119
+ String.new(self, unit.to_s, nil, position)
120
+ end
121
+
122
+ define_builtin_property(:isPositive) do
123
+ result = value.value.zero? || value.value.positive?
124
+ Boolean.new(self, result, position)
125
+ end
126
+
127
+ define_builtin_property(:isBinaryUnit) do
128
+ result = [:b, :kib, :mib, :gib, :tib, :pib].include?(unit)
129
+ Boolean.new(self, result, position)
130
+ end
131
+
132
+ define_builtin_property(:isDecimalUnit) do
133
+ result = [:b, :kb, :mb, :gb, :tb, :pb].include?(unit)
134
+ Boolean.new(self, result, position)
135
+ end
136
+
137
+ define_builtin_method(
138
+ :isBetween, first: DataSize, last: DataSize
139
+ ) do |args, parent, position|
140
+ r = calc_byte_size(self)
141
+ f = calc_byte_size(args[:first])
142
+ l = calc_byte_size(args[:last])
143
+ r.execute_builtin_method(:isBetween, { first: f, last: l }, parent, position)
144
+ end
145
+
146
+ define_builtin_method(:toUnit, unit: String) do |args, parent, position|
147
+ unit = unit_symbol(args[:unit], position)
148
+ value = convert_unit(self, unit, position)
149
+ DataSize.new(parent, value, unit, position)
150
+ end
151
+
152
+ define_builtin_method(:toBinaryUnit) do |_args, parent, position|
153
+ if (unit = to_binary_unit)
154
+ value = convert_unit(self, unit, position)
155
+ DataSize.new(parent, value, unit, position)
156
+ else
157
+ self
158
+ end
159
+ end
160
+
161
+ define_builtin_method(:toDecimalUnit) do |_args, parent, position|
162
+ if (unit = to_decimal_unit)
163
+ value = convert_unit(self, unit, position)
164
+ DataSize.new(parent, value, unit, position)
165
+ else
166
+ self
167
+ end
168
+ end
169
+
170
+ private
171
+
172
+ UNIT_FACTOR = {
173
+ b: 1000**0,
174
+ kb: 1000**1, mb: 1000**2, gb: 1000**3,
175
+ tb: 1000**4, pb: 1000**5,
176
+ kib: 1024**1, mib: 1024**2, gib: 1024**3,
177
+ tib: 1024**4, pib: 1024**5
178
+ }.freeze
179
+
180
+ def unit_factor(unit)
181
+ UNIT_FACTOR[unit]
182
+ end
183
+
184
+ def defined_operator?(operator)
185
+ [:[], :'!@', :'&&', :'||'].none?(operator)
186
+ end
187
+
188
+ def valid_r_operand?(operator, operand)
189
+ case operator
190
+ when :*, :%, :** then operand in Number
191
+ when :/, :'~/' then operand in Number | DataSize
192
+ else super
193
+ end
194
+ end
195
+
196
+ def calc_byte_size(data_size)
197
+ factor = Int.new(nil, unit_factor(data_size.unit), nil)
198
+ data_size.value.b_op_mul(factor, nil)
199
+ end
200
+
201
+ def align_unit(l_operand, r_operand)
202
+ unit =
203
+ if unit_factor(l_operand.unit) >= unit_factor(r_operand.unit)
204
+ l_operand.unit
205
+ else
206
+ r_operand.unit
207
+ end
208
+
209
+ [
210
+ convert_unit(l_operand, unit, position),
211
+ convert_unit(r_operand, unit, position),
212
+ unit
213
+ ]
214
+ end
215
+
216
+ def convert_unit(data_size, unit, position)
217
+ return data_size.value if data_size.unit == unit
218
+
219
+ byte_size = calc_byte_size(data_size)
220
+ factor = Int.new(nil, unit_factor(unit), nil)
221
+ if (byte_size.value % factor.value).zero?
222
+ byte_size.b_op_truncating_div(factor, position)
223
+ else
224
+ byte_size.b_op_div(factor, position)
225
+ end
226
+ end
227
+
228
+ def unit_symbol(string, position)
229
+ symbol = string.value.to_sym
230
+ return symbol if UNIT_FACTOR.key?(symbol)
231
+
232
+ message =
233
+ 'expected value of type ' \
234
+ '"b"|"kb"|"kib"|"mb"|"mib"|"gb"|"gib"|"tb"|"tib"|"pb"|"pib", ' \
235
+ "but got #{string.to_pkl_string(nil)}"
236
+ raise EvaluationError.new(message, position)
237
+ end
238
+
239
+ def to_binary_unit
240
+ {
241
+ kb: :kib, mb: :mib, gb: :gib,
242
+ tb: :tib, pb: :pib
243
+ }[unit]
244
+ end
245
+
246
+ def to_decimal_unit
247
+ {
248
+ kib: :kb, mib: :mb, gib: :gb,
249
+ tib: :tb, pib: :pb
250
+ }[unit]
251
+ end
252
+ end
253
+ end
254
+ end