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 +4 -4
- data/lib/rupkl/node/amend_expression.rb +2 -2
- data/lib/rupkl/node/any.rb +15 -4
- data/lib/rupkl/node/base.rb +32 -2
- data/lib/rupkl/node/boolean.rb +26 -9
- data/lib/rupkl/node/collection.rb +176 -0
- data/lib/rupkl/node/data_size.rb +254 -0
- data/lib/rupkl/node/duration.rb +266 -0
- data/lib/rupkl/node/dynamic.rb +19 -15
- data/lib/rupkl/node/identifier.rb +5 -1
- data/lib/rupkl/node/if_expression.rb +45 -0
- data/lib/rupkl/node/intseq.rb +84 -0
- data/lib/rupkl/node/listing.rb +11 -4
- data/lib/rupkl/node/map.rb +120 -0
- data/lib/rupkl/node/mapping.rb +13 -6
- data/lib/rupkl/node/member_finder.rb +4 -10
- data/lib/rupkl/node/member_reference.rb +5 -3
- data/lib/rupkl/node/method_call.rb +2 -3
- data/lib/rupkl/node/method_definition.rb +74 -18
- data/lib/rupkl/node/node_common.rb +1 -1
- data/lib/rupkl/node/null.rb +1 -4
- data/lib/rupkl/node/number.rb +133 -45
- data/lib/rupkl/node/object.rb +322 -66
- data/lib/rupkl/node/operation.rb +123 -100
- data/lib/rupkl/node/pair.rb +58 -0
- data/lib/rupkl/node/pkl_module.rb +4 -4
- data/lib/rupkl/node/regex.rb +196 -0
- data/lib/rupkl/node/string.rb +155 -133
- data/lib/rupkl/node/struct_common.rb +70 -35
- data/lib/rupkl/node/value_common.rb +1 -5
- data/lib/rupkl/parser/expression.rb +43 -6
- data/lib/rupkl/parser/misc.rb +20 -0
- data/lib/rupkl/parser/object.rb +96 -13
- data/lib/rupkl/parser/pkl_class.rb +12 -5
- data/lib/rupkl/pkl_object.rb +2 -18
- data/lib/rupkl/version.rb +1 -1
- data/lib/rupkl.rb +10 -2
- metadata +17 -9
data/lib/rupkl/node/operation.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|