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.
@@ -2,6 +2,125 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
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
17
+ end
18
+
19
+ def u_op(operator, position)
20
+ check_u_op(operator, position)
21
+ __send__(u_op_method(operator), position)
22
+ end
23
+
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)
46
+ end
47
+
48
+ private
49
+
50
+ def check_s_op(operator, position)
51
+ check_operator(operator, position)
52
+ end
53
+
54
+ def valid_key_operand?(_key)
55
+ true
56
+ end
57
+
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)
63
+ end
64
+
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
69
+
70
+ def check_u_op(operator, position)
71
+ op = :"#{operator}@"
72
+ check_operator(op, position)
73
+ end
74
+
75
+ def u_op_method(operator)
76
+ { '-': :u_op_minus, '!': :u_op_negate }[operator]
77
+ end
78
+
79
+ def check_b_op(operator, position)
80
+ check_operator(operator, position)
81
+ end
82
+
83
+ def short_circuit?(_operator)
84
+ false
85
+ end
86
+
87
+ def valid_r_operand?(_operator, operand)
88
+ operand.is_a?(self.class)
89
+ end
90
+
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)
96
+ end
97
+
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]
109
+ end
110
+
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)
117
+ end
118
+
119
+ def defined_operator?(_operator)
120
+ false
121
+ end
122
+ end
123
+
5
124
  module OperationCommon
6
125
  include NodeCommon
7
126
 
@@ -14,7 +133,7 @@ module RuPkl
14
133
  attr_reader :operator
15
134
  attr_reader :operands
16
135
 
17
- def copy(parent = nil)
136
+ def copy(parent = nil, position = @position)
18
137
  copied_operands = operands.map(&:copy)
19
138
  self.class.new(parent, operator, *copied_operands, position)
20
139
  end
@@ -23,18 +142,7 @@ module RuPkl
23
142
 
24
143
  def s_op(context)
25
144
  r = receiver.evaluate(context)
26
- check_operator(r)
27
-
28
- k = key.evaluate(context)
29
- check_key_operand(r, k)
30
-
31
- (v = r.find_by_key(k)) ||
32
- begin
33
- message = "cannot find key '#{k.to_pkl_string(context)}'"
34
- raise EvaluationError.new(message, position)
35
- end
36
-
37
- v.evaluate
145
+ r.s_op(operator, key, context, position)
38
146
  end
39
147
 
40
148
  def non_null_op(context)
@@ -47,28 +155,12 @@ module RuPkl
47
155
 
48
156
  def u_op(context)
49
157
  o = operand.evaluate(context)
50
- check_operator(o)
51
-
52
- result =
53
- if operator == :-
54
- -o.value
55
- else
56
- !o.value
57
- end
58
- create_op_result(result)
158
+ o.u_op(operator, position)
59
159
  end
60
160
 
61
161
  def b_op(context)
62
162
  l = l_operand.evaluate(context)
63
- check_operator(l)
64
- return l if short_circuit?(l)
65
-
66
- r = r_operand.evaluate(context)
67
- check_r_operand(l, r)
68
- .then { return _1 if _1 }
69
-
70
- l, r = l.coerce(operator, r)
71
- create_op_result(l.__send__(ruby_op, r))
163
+ l.b_op(operator, r_operand, context, position)
72
164
  end
73
165
 
74
166
  def null_coalescing_op(context)
@@ -77,75 +169,6 @@ module RuPkl
77
169
 
78
170
  r_operand.evaluate(context)
79
171
  end
80
-
81
- def check_operator(operand)
82
- undefined_operator?(operand) &&
83
- begin
84
- message =
85
- "operator '#{operator}' is not defined for " \
86
- "#{operand.class.basename} type"
87
- raise EvaluationError.new(message, position)
88
- end
89
- end
90
-
91
- def undefined_operator?(operand)
92
- !operand.respond_to?(:undefined_operator?) ||
93
- operand.undefined_operator?(operator)
94
- end
95
-
96
- def check_key_operand(receiver, key)
97
- invalid_key_operand?(receiver, key) &&
98
- begin
99
- message =
100
- "invalid key operand type #{key.class.basename} is given " \
101
- "for operator '#{operator}'"
102
- raise EvaluationError.new(message, position)
103
- end
104
- end
105
-
106
- def invalid_key_operand?(receiver, key)
107
- receiver.respond_to?(:invalid_key_operand?) &&
108
- receiver.invalid_key_operand?(key)
109
- end
110
-
111
- def check_r_operand(l_operand, r_operand)
112
- return unless invalid_r_operand?(l_operand, r_operand)
113
-
114
- if [:==, :'!='].include?(operator)
115
- create_op_result(operator != :==)
116
- else
117
- message =
118
- "invalid operand type #{r_operand.class.basename} is given " \
119
- "for operator '#{operator}'"
120
- raise EvaluationError.new(message, position)
121
- end
122
- end
123
-
124
- def invalid_r_operand?(l_operand, r_operand)
125
- if l_operand.respond_to?(:invalid_r_operand?)
126
- l_operand.invalid_r_operand?(r_operand)
127
- else
128
- !r_operand.is_a?(l_operand.class)
129
- end
130
- end
131
-
132
- def short_circuit?(l_operand)
133
- l_operand.respond_to?(:short_circuit?) &&
134
- l_operand.short_circuit?(operator)
135
- end
136
-
137
- def ruby_op
138
- { '&&': :&, '||': :|, '~/': :/ }.fetch(operator, operator)
139
- end
140
-
141
- def create_op_result(result)
142
- case result
143
- when ::Integer then Int.new(parent, result, position)
144
- when ::Float then Float.new(parent, result, position)
145
- when ::String then String.new(parent, result, nil, position)
146
- when true, false then Boolean.new(parent, result, position)
147
- end
148
- end
149
172
  end
150
173
 
151
174
  class SubscriptOperation
@@ -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
@@ -8,10 +8,6 @@ module RuPkl
8
8
  abstract_class
9
9
  klass_name :Module
10
10
 
11
- def properties
12
- @body&.properties(visibility: :object)
13
- end
14
-
15
11
  def pkl_methods
16
12
  @body&.pkl_methods
17
13
  end
@@ -25,6 +21,10 @@ module RuPkl
25
21
  super
26
22
  end
27
23
 
24
+ def to_ruby(context = nil)
25
+ to_pkl_object(context)
26
+ end
27
+
28
28
  private
29
29
 
30
30
  def properties_not_allowed?
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class Regex < Any
6
+ include Operatable
7
+
8
+ uninstantiable_class
9
+
10
+ def initialize(parent, pattern, position)
11
+ super
12
+ @pattern = Regexp.new(pattern.value)
13
+ end
14
+
15
+ attr_reader :pattern
16
+
17
+ def evaluate(_context = nil)
18
+ self
19
+ end
20
+
21
+ def to_ruby(_context = nil)
22
+ pattern
23
+ end
24
+
25
+ def to_pkl_string(context = nil)
26
+ to_string(context)
27
+ end
28
+
29
+ def to_string(context = nil)
30
+ source_string = source.to_pkl_string(context)
31
+ "Regex(#{source_string})"
32
+ end
33
+
34
+ def ==(other)
35
+ other.is_a?(self.class) && pattern == other.pattern
36
+ end
37
+
38
+ define_builtin_property(:pattern) do
39
+ source
40
+ end
41
+
42
+ define_builtin_property(:groupCount) do
43
+ Int.new(nil, group_count, position)
44
+ end
45
+
46
+ define_builtin_method(:findMatchesIn, input: String) do |args, parent, position|
47
+ find_matches(args[:input].value, parent, position)
48
+ end
49
+
50
+ define_builtin_method(:matchEntire, input: String) do |args, parent, position|
51
+ match_entire(args[:input].value, parent, position)
52
+ end
53
+
54
+ private
55
+
56
+ def source
57
+ @children[0]
58
+ end
59
+
60
+ def group_count
61
+ Regexp::Parser
62
+ .parse(pattern)
63
+ .each_expression.count { |exp, _| exp.capturing? }
64
+ end
65
+
66
+ def find_matches(string, parent, position)
67
+ matches = []
68
+ offset = 0
69
+ while (match_data = match_pattern(string, offset))
70
+ matches << RegexMatch.create(match_data, nil, position)
71
+ offset = calc_next_offset(match_data, offset)
72
+ end
73
+ List.new(parent, matches, position)
74
+ end
75
+
76
+ def match_entire(string, parent, position)
77
+ match_pattern(string, 0).then do |m|
78
+ if m && m.end(0) == string.size
79
+ RegexMatch.create(m, parent, position)
80
+ else
81
+ Null.new(parent, position)
82
+ end
83
+ end
84
+ end
85
+
86
+ def match_pattern(string, offset)
87
+ return if offset > string.size
88
+
89
+ pattern.match(string, offset)
90
+ end
91
+
92
+ def calc_next_offset(match_data, offset)
93
+ if match_data[0].empty?
94
+ offset + 1
95
+ else
96
+ match_data.end(0)
97
+ end
98
+ end
99
+ end
100
+
101
+ class RegexMatch < Any
102
+ include Operatable
103
+
104
+ uninstantiable_class
105
+
106
+ class << self
107
+ def create(match_data, parent, position)
108
+ groups = Array.new(match_data.size) do |i|
109
+ if match_data[i]
110
+ create_regex_match(
111
+ match_data[i], match_data.begin(i),
112
+ match_data.end(i), nil, nil, position
113
+ )
114
+ else
115
+ Null.new(nil, position)
116
+ end
117
+ end
118
+ create_regex_match(
119
+ match_data[0], match_data.begin(0),
120
+ match_data.end(0), groups, parent, position
121
+ )
122
+ end
123
+
124
+ private
125
+
126
+ def create_regex_match(value, start_offset, end_offset, groups, parent, position)
127
+ v = String.new(nil, value, nil, position)
128
+ s = Int.new(nil, start_offset, position)
129
+ e = Int.new(nil, end_offset, position)
130
+ g = List.new(nil, groups, position)
131
+ new(parent, v, s, e, g, position)
132
+ end
133
+ end
134
+
135
+ def value
136
+ @children[0]
137
+ end
138
+
139
+ def start
140
+ @children[1]
141
+ end
142
+
143
+ alias_method :start_offset, :start
144
+
145
+ def end
146
+ @children[2]
147
+ end
148
+
149
+ alias_method :end_offset, :end
150
+
151
+ def groups
152
+ @children[3]
153
+ end
154
+
155
+ def evaluate(_context = nil)
156
+ self
157
+ end
158
+
159
+ def to_ruby(context = nil)
160
+ {
161
+ value: value, start: start_offset, end: end_offset, groups: groups
162
+ }.transform_values { |v| v.to_ruby(context) }
163
+ end
164
+
165
+ def to_pkl_string(context = nil)
166
+ to_string(context)
167
+ end
168
+
169
+ def to_string(context)
170
+ value.to_string(context)
171
+ end
172
+
173
+ def ==(other)
174
+ other.is_a?(self.class) &&
175
+ value == other.value && start_offset == other.start &&
176
+ end_offset == other.end && groups == other.groups
177
+ end
178
+
179
+ define_builtin_property(:value) do
180
+ value
181
+ end
182
+
183
+ define_builtin_property(:start) do
184
+ start_offset
185
+ end
186
+
187
+ define_builtin_property(:end) do
188
+ end_offset
189
+ end
190
+
191
+ define_builtin_property(:groups) do
192
+ groups
193
+ end
194
+ end
195
+ end
196
+ end