rupkl 0.1.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 +7 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +123 -0
- data/lib/rupkl/exception.rb +26 -0
- data/lib/rupkl/node/boolean.rb +21 -0
- data/lib/rupkl/node/dynamic.rb +99 -0
- data/lib/rupkl/node/identifier.rb +19 -0
- data/lib/rupkl/node/member_reference.rb +46 -0
- data/lib/rupkl/node/number.rb +40 -0
- data/lib/rupkl/node/object.rb +141 -0
- data/lib/rupkl/node/operation.rb +186 -0
- data/lib/rupkl/node/pkl_class.rb +30 -0
- data/lib/rupkl/node/pkl_module.rb +47 -0
- data/lib/rupkl/node/string.rb +66 -0
- data/lib/rupkl/node/struct_common.rb +102 -0
- data/lib/rupkl/node/value_common.rb +35 -0
- data/lib/rupkl/parser/expression.rb +120 -0
- data/lib/rupkl/parser/identifier.rb +58 -0
- data/lib/rupkl/parser/literal.rb +309 -0
- data/lib/rupkl/parser/misc.rb +50 -0
- data/lib/rupkl/parser/object.rb +72 -0
- data/lib/rupkl/parser/pkl_class.rb +29 -0
- data/lib/rupkl/parser/pkl_module.rb +32 -0
- data/lib/rupkl/parser.rb +138 -0
- data/lib/rupkl/pkl_object.rb +150 -0
- data/lib/rupkl/version.rb +5 -0
- data/lib/rupkl.rb +48 -0
- metadata +101 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
module OperationCommon
|
6
|
+
def to_ruby(scopes)
|
7
|
+
evaluate(scopes).to_ruby(nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_string(scopes)
|
11
|
+
evaluate(scopes).to_string(nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_pkl_string(scopes)
|
15
|
+
evaluate(scopes).to_pkl_string(nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def s_op(scopes)
|
21
|
+
r = receiver.evaluate(scopes)
|
22
|
+
check_operator(r)
|
23
|
+
|
24
|
+
k = key.evaluate(scopes)
|
25
|
+
check_key_operand(r, k)
|
26
|
+
|
27
|
+
r.find_by_key(k) ||
|
28
|
+
begin
|
29
|
+
message = "cannot find key '#{k.to_pkl_string(scopes)}'"
|
30
|
+
raise EvaluationError.new(message, position)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def u_op(scopes)
|
35
|
+
o = operand.evaluate(scopes)
|
36
|
+
check_operator(o)
|
37
|
+
|
38
|
+
result =
|
39
|
+
if operator == :-
|
40
|
+
-o.value
|
41
|
+
else
|
42
|
+
!o.value
|
43
|
+
end
|
44
|
+
create_op_result(result)
|
45
|
+
end
|
46
|
+
|
47
|
+
def b_op(scopes)
|
48
|
+
l = l_operand.evaluate(scopes)
|
49
|
+
check_operator(l)
|
50
|
+
return l if short_circuit?(l)
|
51
|
+
|
52
|
+
r = r_operand.evaluate(scopes)
|
53
|
+
check_r_operand(l, r)
|
54
|
+
|
55
|
+
l, r = l.coerce(operator, r)
|
56
|
+
create_op_result(l.__send__(ruby_op, r))
|
57
|
+
end
|
58
|
+
|
59
|
+
def check_operator(operand)
|
60
|
+
undefined_operator?(operand) &&
|
61
|
+
begin
|
62
|
+
message =
|
63
|
+
"operator '#{operator}' is not defined for " \
|
64
|
+
"#{operand.class.basename} type"
|
65
|
+
raise EvaluationError.new(message, position)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def undefined_operator?(operand)
|
70
|
+
!operand.respond_to?(:undefined_operator?) ||
|
71
|
+
operand.undefined_operator?(operator)
|
72
|
+
end
|
73
|
+
|
74
|
+
def check_key_operand(receiver, key)
|
75
|
+
invalid_key_operand?(receiver, key) &&
|
76
|
+
begin
|
77
|
+
message =
|
78
|
+
"invalid key operand type #{key.class.basename} is given " \
|
79
|
+
"for operator '#{operator}'"
|
80
|
+
raise EvaluationError.new(message, position)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def invalid_key_operand?(receiver, key)
|
85
|
+
receiver.respond_to?(:invalid_key_operand?) &&
|
86
|
+
receiver.invalid_key_operand?(key)
|
87
|
+
end
|
88
|
+
|
89
|
+
def check_r_operand(l_operand, r_operand)
|
90
|
+
invalid_r_operand?(l_operand, r_operand) &&
|
91
|
+
begin
|
92
|
+
message =
|
93
|
+
"invalid operand type #{r_operand.class.basename} is given " \
|
94
|
+
"for operator '#{operator}'"
|
95
|
+
raise EvaluationError.new(message, position)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def invalid_r_operand?(l_operand, r_operand)
|
100
|
+
if l_operand.respond_to?(:invalid_r_operand?)
|
101
|
+
l_operand.invalid_r_operand?(r_operand)
|
102
|
+
else
|
103
|
+
!r_operand.is_a?(l_operand.class)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def short_circuit?(l_operand)
|
108
|
+
l_operand.respond_to?(:short_circuit?) &&
|
109
|
+
l_operand.short_circuit?(operator)
|
110
|
+
end
|
111
|
+
|
112
|
+
def ruby_op
|
113
|
+
{ '&&': :&, '||': :|, '~/': :/ }.fetch(operator, operator)
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_op_result(result)
|
117
|
+
case result
|
118
|
+
when ::Integer then Integer.new(result, position)
|
119
|
+
when ::Float then Float.new(result, position)
|
120
|
+
when ::String then String.new(result, nil, position)
|
121
|
+
when ::TrueClass, ::FalseClass then Boolean.new(result, position)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class SubscriptOperation
|
127
|
+
include OperationCommon
|
128
|
+
|
129
|
+
def initialize(receiver, key, position)
|
130
|
+
@receiver = receiver
|
131
|
+
@key = key
|
132
|
+
@position = position
|
133
|
+
end
|
134
|
+
|
135
|
+
attr_reader :receiver
|
136
|
+
attr_reader :key
|
137
|
+
attr_reader :position
|
138
|
+
|
139
|
+
def operator
|
140
|
+
:[]
|
141
|
+
end
|
142
|
+
|
143
|
+
def evaluate(scopes)
|
144
|
+
s_op(scopes)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class UnaryOperation
|
149
|
+
include OperationCommon
|
150
|
+
|
151
|
+
def initialize(operator, operand, position)
|
152
|
+
@operator = operator
|
153
|
+
@operand = operand
|
154
|
+
@position = position
|
155
|
+
end
|
156
|
+
|
157
|
+
attr_reader :operator
|
158
|
+
attr_reader :operand
|
159
|
+
attr_reader :position
|
160
|
+
|
161
|
+
def evaluate(scopes)
|
162
|
+
u_op(scopes)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
class BinaryOperation
|
167
|
+
include OperationCommon
|
168
|
+
|
169
|
+
def initialize(operator, l_operand, r_operand, position)
|
170
|
+
@operator = operator
|
171
|
+
@l_operand = l_operand
|
172
|
+
@r_operand = r_operand
|
173
|
+
@position = position
|
174
|
+
end
|
175
|
+
|
176
|
+
attr_reader :operator
|
177
|
+
attr_reader :l_operand
|
178
|
+
attr_reader :r_operand
|
179
|
+
attr_reader :position
|
180
|
+
|
181
|
+
def evaluate(scopes)
|
182
|
+
b_op(scopes)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
class PklClassProperty
|
6
|
+
include PropertyEvaluator
|
7
|
+
|
8
|
+
def initialize(name, value, objects, position)
|
9
|
+
@name = name
|
10
|
+
@value = value
|
11
|
+
@objects = objects
|
12
|
+
@position = position
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :name
|
16
|
+
attr_reader :value
|
17
|
+
attr_reader :objects
|
18
|
+
attr_reader :position
|
19
|
+
|
20
|
+
def evaluate(scopes)
|
21
|
+
v = evaluate_property(value, objects, scopes)
|
22
|
+
self.class.new(name, v, nil, position)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_ruby(scopes)
|
26
|
+
[name.id, property_to_ruby(value, objects, scopes)]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
class PklModule
|
6
|
+
include StructCommon
|
7
|
+
|
8
|
+
def initialize(items, position)
|
9
|
+
@position = position
|
10
|
+
items&.each do |item|
|
11
|
+
case item
|
12
|
+
when PklClassProperty then add_property(item)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :properties
|
18
|
+
attr_reader :position
|
19
|
+
|
20
|
+
def evaluate(scopes)
|
21
|
+
push_scope(scopes) do |s|
|
22
|
+
self.class.new(evaluate_properties(s), position)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_ruby(scopes)
|
27
|
+
push_scope(scopes) do |s|
|
28
|
+
create_pkl_object(s, properties, nil, nil)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def add_property(property)
|
35
|
+
(@properties ||= []) << property
|
36
|
+
end
|
37
|
+
|
38
|
+
def evaluate_properties(scopes)
|
39
|
+
properties&.each_with_object([]) do |property, result|
|
40
|
+
property
|
41
|
+
.evaluate(scopes)
|
42
|
+
.then { add_hash_member(result, _1, :name) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
class String
|
6
|
+
include ValueCommon
|
7
|
+
|
8
|
+
def initialize(value, portions, position)
|
9
|
+
super(value, position)
|
10
|
+
@portions = portions
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :portions
|
14
|
+
|
15
|
+
def evaluate(scopes)
|
16
|
+
s = value || evaluate_portions(scopes) || ''
|
17
|
+
self.class.new(s, nil, position)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_pkl_string(scopes)
|
21
|
+
super(scopes)
|
22
|
+
.then { |s| escape(s) }
|
23
|
+
.then { |s| "\"#{s}\"" }
|
24
|
+
end
|
25
|
+
|
26
|
+
def undefined_operator?(operator)
|
27
|
+
[:[], :==, :'!=', :+].none?(operator)
|
28
|
+
end
|
29
|
+
|
30
|
+
def invalid_key_operand?(key)
|
31
|
+
!key.is_a?(Integer)
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_by_key(key)
|
35
|
+
index = key.value
|
36
|
+
return nil unless (0...value.length).include?(index)
|
37
|
+
|
38
|
+
self.class.new(value[index], nil, portions)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def evaluate_portions(scopes)
|
44
|
+
portions
|
45
|
+
&.map { evaluate_portion(scopes, _1) }
|
46
|
+
&.join
|
47
|
+
end
|
48
|
+
|
49
|
+
def evaluate_portion(scopes, portion)
|
50
|
+
if portion.respond_to?(:to_string)
|
51
|
+
portion.to_string(scopes)
|
52
|
+
else
|
53
|
+
portion
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def escape(string)
|
58
|
+
replace = {
|
59
|
+
"\t" => '\t', "\n" => '\n', "\r" => '\r',
|
60
|
+
'"' => '\"', '\\' => '\\\\'
|
61
|
+
}
|
62
|
+
string.gsub(/([\t\n\r"\\])/) { replace[_1] }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
module StructCommon
|
6
|
+
def to_string(_scopes)
|
7
|
+
"new #{self.class.basename} #{to_pkl_string(nil)}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def coerce(_operator, r_operand)
|
11
|
+
[self, r_operand]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def push_scope(scopes)
|
17
|
+
yield([*scopes, self])
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_hash_member(members, member, accessor)
|
21
|
+
duplicate_member?(members, member, accessor) &&
|
22
|
+
begin
|
23
|
+
message = 'duplicate definition of member'
|
24
|
+
raise EvaluationError.new(message, member.position)
|
25
|
+
end
|
26
|
+
members << member
|
27
|
+
end
|
28
|
+
|
29
|
+
def duplicate_member?(members, member, accessor)
|
30
|
+
members
|
31
|
+
.any? { _1.__send__(accessor) == member.__send__(accessor) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_array_member(members, member)
|
35
|
+
members << member
|
36
|
+
end
|
37
|
+
|
38
|
+
def match_members?(lhs, rhs, match_order)
|
39
|
+
if !match_order && [lhs, rhs].all?(Array)
|
40
|
+
lhs.size == rhs.size &&
|
41
|
+
lhs.all? { rhs.include?(_1) } && rhs.all? { lhs.include?(_1) }
|
42
|
+
else
|
43
|
+
lhs == rhs
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def merge_hash_members(lhs, rhs, accessor)
|
48
|
+
return nil unless lhs || rhs
|
49
|
+
return rhs unless lhs
|
50
|
+
|
51
|
+
rhs&.each do |r|
|
52
|
+
if (index = find_index(lhs, r, accessor))
|
53
|
+
lhs[index] = r
|
54
|
+
else
|
55
|
+
lhs << r
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
lhs
|
60
|
+
end
|
61
|
+
|
62
|
+
def find_index(lhs, rhs, accessor)
|
63
|
+
lhs.find_index { _1.__send__(accessor) == rhs.__send__(accessor) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def merge_array_members(lhs, rhs)
|
67
|
+
return nil unless lhs || rhs
|
68
|
+
return rhs unless lhs
|
69
|
+
return lhs unless rhs
|
70
|
+
|
71
|
+
lhs.concat(rhs)
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_pkl_object(scopes, properties, entries, elements)
|
75
|
+
RuPkl::PklObject.new(
|
76
|
+
to_ruby_hash_members(scopes, properties),
|
77
|
+
to_ruby_hash_members(scopes, entries),
|
78
|
+
to_ruby_array_members(scopes, elements)
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_ruby_hash_members(scopes, members)
|
83
|
+
members
|
84
|
+
&.to_h { _1.to_ruby(scopes) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_ruby_array_members(scopes, members)
|
88
|
+
members
|
89
|
+
&.map { _1.to_ruby(scopes) }
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_pkl_string_object(*members)
|
93
|
+
return '{}' if members.empty?
|
94
|
+
|
95
|
+
members
|
96
|
+
.map { _1.to_pkl_string(nil) }
|
97
|
+
.join('; ')
|
98
|
+
.then { "{ #{_1} }" }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
module ValueCommon
|
6
|
+
def initialize(value, position)
|
7
|
+
@value = value
|
8
|
+
@position = position
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :value
|
12
|
+
attr_reader :position
|
13
|
+
|
14
|
+
def to_ruby(scopes)
|
15
|
+
evaluate(scopes).value
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_string(scopes)
|
19
|
+
to_ruby(scopes).to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_pkl_string(scopes)
|
23
|
+
to_string(scopes)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ==(other)
|
27
|
+
other.instance_of?(self.class) && value == other.value
|
28
|
+
end
|
29
|
+
|
30
|
+
def coerce(_operator, r_operand)
|
31
|
+
[value, r_operand.value]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
class Parser
|
5
|
+
define_parser do
|
6
|
+
rule(:unqualified_member_ref) do
|
7
|
+
id.as(:unqualified_member_ref)
|
8
|
+
end
|
9
|
+
|
10
|
+
rule(:primary) do
|
11
|
+
[
|
12
|
+
float_literal, integer_literal, boolean_literal, string_literal,
|
13
|
+
unqualified_member_ref, bracketed(expression)
|
14
|
+
].inject(:|)
|
15
|
+
end
|
16
|
+
|
17
|
+
rule(:qualified_member_ref) do
|
18
|
+
(
|
19
|
+
primary.as(:receiver) >>
|
20
|
+
(ws? >> str('.') >> ws? >> id).repeat(1).as(:member)
|
21
|
+
).as(:qualified_member_ref) | primary
|
22
|
+
end
|
23
|
+
|
24
|
+
rule(:subscript_operation) do
|
25
|
+
(
|
26
|
+
qualified_member_ref.as(:receiver) >>
|
27
|
+
(
|
28
|
+
pure_ws? >> bracketed(expression, '[', ']') >>
|
29
|
+
(ws? >> str('=')).absent?
|
30
|
+
).repeat(1).as(:key)
|
31
|
+
).as(:subscript_operation) | qualified_member_ref
|
32
|
+
end
|
33
|
+
|
34
|
+
rule(:unary_operation) do
|
35
|
+
(
|
36
|
+
(str(:-) | str(:!)).as(:unary_operator) >>
|
37
|
+
ws? >> subscript_operation.as(:operand)
|
38
|
+
) | subscript_operation
|
39
|
+
end
|
40
|
+
|
41
|
+
rule(:binary_operation) do
|
42
|
+
expression = unary_operation
|
43
|
+
operators = binary_operators
|
44
|
+
reducer = proc { |l, o, r| { binary_operator: o, l_operand: l, r_operand: r } }
|
45
|
+
infix_expression(expression, *operators, &reducer) | unary_operation
|
46
|
+
end
|
47
|
+
|
48
|
+
rule(:expression) do
|
49
|
+
binary_operation
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def binary_operators
|
55
|
+
operators = {
|
56
|
+
'||': 1, '&&': 2,
|
57
|
+
'==': 3, '!=': 3,
|
58
|
+
'<': 4, '>': 4, '<=': 4, '>=': 4,
|
59
|
+
'+': 5, '-': 5,
|
60
|
+
'*': 6, '/': 6, '~/': 6, '%': 6,
|
61
|
+
'**': 7
|
62
|
+
}
|
63
|
+
operators
|
64
|
+
.sort_by { |op, _| op.length }.reverse
|
65
|
+
.map { |op, priority| binary_operator_element(op, priority) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def binary_operator_element(operator, priority)
|
69
|
+
atom =
|
70
|
+
if operator == :-
|
71
|
+
pure_ws? >> str(operator) >> ws?
|
72
|
+
else
|
73
|
+
ws? >> str(operator) >> ws?
|
74
|
+
end
|
75
|
+
if operator == :**
|
76
|
+
[atom, priority, :right]
|
77
|
+
else
|
78
|
+
[atom, priority, :left]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
define_transform do
|
84
|
+
rule(unqualified_member_ref: simple(:member)) do
|
85
|
+
Node::MemberReference.new(nil, member, member.position)
|
86
|
+
end
|
87
|
+
|
88
|
+
rule(
|
89
|
+
qualified_member_ref:
|
90
|
+
{ receiver: simple(:receiver), member: sequence(:member) }
|
91
|
+
) do
|
92
|
+
member.inject(receiver) do |r, m|
|
93
|
+
Node::MemberReference.new(r, m, r.position)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
rule(
|
98
|
+
subscript_operation:
|
99
|
+
{ receiver: simple(:receiver), key: sequence(:key) }
|
100
|
+
) do
|
101
|
+
key.inject(receiver) do |r, k|
|
102
|
+
Node::SubscriptOperation.new(r, k, r.position)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
rule(unary_operator: simple(:operator), operand: simple(:operand)) do
|
107
|
+
Node::UnaryOperation.new(operator.to_sym, operand, node_position(operator))
|
108
|
+
end
|
109
|
+
|
110
|
+
rule(
|
111
|
+
binary_operator: simple(:operator),
|
112
|
+
l_operand: simple(:l_operand), r_operand: simple(:r_operand)
|
113
|
+
) do
|
114
|
+
Node::BinaryOperation.new(
|
115
|
+
operator.to_sym, l_operand, r_operand, l_operand.position
|
116
|
+
)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
class Parser
|
5
|
+
KEYWORDS = [
|
6
|
+
'abstract', 'amends', 'as', 'class', 'const', 'else', 'extends',
|
7
|
+
'external', 'false', 'fixed', 'for', 'function', 'hidden', 'if',
|
8
|
+
'import', 'import*', 'in', 'is', 'let', 'local', 'module', 'new',
|
9
|
+
'nothing', 'null', 'open', 'out', 'outer', 'read', 'read*', 'read?',
|
10
|
+
'super', 'this', 'throw', 'trace', 'true', 'typealias', 'unknown', 'when'
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
RESERVED_KEYWORDS = [
|
14
|
+
'protected', 'override', 'record', 'delete', 'case', 'switch', 'vararg'
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
define_parser do
|
18
|
+
[*KEYWORDS, *RESERVED_KEYWORDS].each do |kw|
|
19
|
+
rule(:"kw_#{kw}") do
|
20
|
+
str(kw) >> match('\\w').absent?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
rule(:regular_identifier) do
|
25
|
+
(str('_') | str('$') | match('\p{XID_Start}')) >> match('\p{XID_Continue}').repeat
|
26
|
+
end
|
27
|
+
|
28
|
+
rule(:quoted_identifier) do
|
29
|
+
str('`') >> (str('`').absent? >> any).repeat(1) >> str('`')
|
30
|
+
end
|
31
|
+
|
32
|
+
rule(:id) do
|
33
|
+
regular_identifier.as(:regular_id) | quoted_identifier.as(:quoted_id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
define_transform do
|
38
|
+
rule(regular_id: simple(:id)) do
|
39
|
+
if keyword?(id)
|
40
|
+
message = "keyword '#{id}' is not allowed for identifier"
|
41
|
+
parse_error(message, node_position(id))
|
42
|
+
end
|
43
|
+
|
44
|
+
Node::Identifier.new(id.to_sym, node_position(id))
|
45
|
+
end
|
46
|
+
|
47
|
+
rule(quoted_id: simple(:id)) do
|
48
|
+
Node::Identifier.new(id.to_s[1..-2].to_sym, node_position(id))
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def keyword?(id)
|
54
|
+
KEYWORDS.any?(id) || RESERVED_KEYWORDS.any?(id)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|