rupkl 0.2.0 → 0.3.0

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