rupkl 0.1.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/README.md +1 -1
- data/lib/rupkl/node/amend_expression.rb +48 -0
- data/lib/rupkl/node/any.rb +110 -0
- data/lib/rupkl/node/base.rb +75 -0
- data/lib/rupkl/node/boolean.rb +30 -5
- data/lib/rupkl/node/collection.rb +176 -0
- data/lib/rupkl/node/context.rb +27 -0
- data/lib/rupkl/node/data_size.rb +254 -0
- data/lib/rupkl/node/declared_type.rb +32 -0
- data/lib/rupkl/node/duration.rb +266 -0
- data/lib/rupkl/node/dynamic.rb +33 -60
- data/lib/rupkl/node/identifier.rb +19 -5
- data/lib/rupkl/node/if_expression.rb +45 -0
- data/lib/rupkl/node/intseq.rb +84 -0
- data/lib/rupkl/node/listing.rb +68 -0
- data/lib/rupkl/node/map.rb +120 -0
- data/lib/rupkl/node/mapping.rb +54 -0
- data/lib/rupkl/node/member_finder.rb +49 -0
- data/lib/rupkl/node/member_reference.rb +46 -21
- data/lib/rupkl/node/method_call.rb +63 -0
- data/lib/rupkl/node/method_definition.rb +199 -0
- data/lib/rupkl/node/node_common.rb +76 -0
- data/lib/rupkl/node/null.rb +24 -0
- data/lib/rupkl/node/number.rb +228 -10
- data/lib/rupkl/node/object.rb +626 -74
- data/lib/rupkl/node/operation.rb +175 -115
- data/lib/rupkl/node/pair.rb +58 -0
- data/lib/rupkl/node/pkl_module.rb +16 -28
- data/lib/rupkl/node/reference_resolver.rb +79 -0
- data/lib/rupkl/node/regex.rb +196 -0
- data/lib/rupkl/node/string.rb +415 -23
- data/lib/rupkl/node/struct_common.rb +150 -53
- data/lib/rupkl/node/this.rb +17 -0
- data/lib/rupkl/node/type_common.rb +34 -0
- data/lib/rupkl/node/value_common.rb +18 -13
- data/lib/rupkl/parser/expression.rb +197 -43
- data/lib/rupkl/parser/identifier.rb +2 -2
- data/lib/rupkl/parser/literal.rb +18 -12
- data/lib/rupkl/parser/method.rb +41 -0
- data/lib/rupkl/parser/misc.rb +24 -0
- data/lib/rupkl/parser/object.rb +141 -26
- data/lib/rupkl/parser/pkl_class.rb +37 -10
- data/lib/rupkl/parser/pkl_module.rb +5 -3
- data/lib/rupkl/parser/type.rb +28 -0
- data/lib/rupkl/parser.rb +8 -0
- data/lib/rupkl/pkl_object.rb +11 -7
- data/lib/rupkl/version.rb +1 -1
- data/lib/rupkl.rb +35 -6
- metadata +45 -7
- data/lib/rupkl/node/pkl_class.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f84f197edd08a0aa623b11f6fd14c83e3fefaf880f0b70a8f6e84eb6599f4ad6
|
4
|
+
data.tar.gz: 9f3294541be5d4ea4ac6c71fe12f501752cf3b6c447194a8b6254723742c169b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4ed0408a38e1db11008cd03922c295ac0e0fd42b22a2d9c6d47bd91e73f3de344aa2af1559d4e83d407a49cc51ec95e595da83ce0572d6b1ab86d17c4f79e05
|
7
|
+
data.tar.gz: a055b31ced095d7e8f851830c03daf63388d1ef23f343e7f1dd6292205e9a0a99a54bc2b5119e9489487084fe28b2d3a37af28c21197b0d0f7367e39446bffbb
|
data/README.md
CHANGED
@@ -116,7 +116,7 @@ Pkl code snippets used for RSpec examples are originaly from:
|
|
116
116
|
## Copyright & License
|
117
117
|
|
118
118
|
Copyright © 2024 Taichi Ishitani.
|
119
|
-
RuPkl is licensed under the terms of the [MIT License](https://opensource.org/licenses/MIT), see [LICENSE](LICENSE) for further details.
|
119
|
+
RuPkl is licensed under the terms of the [MIT License](https://opensource.org/licenses/MIT), see [LICENSE.txt](LICENSE.txt) for further details.
|
120
120
|
|
121
121
|
## Code of Conduct
|
122
122
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
class AmendExpression
|
6
|
+
include NodeCommon
|
7
|
+
|
8
|
+
def initialize(parent, target, bodies, position)
|
9
|
+
super(parent, target, *bodies, position)
|
10
|
+
@target = target
|
11
|
+
@bodies = bodies
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :target
|
15
|
+
attr_reader :bodies
|
16
|
+
|
17
|
+
def evaluate(context = nil)
|
18
|
+
resolve_structure(context).evaluate(context)
|
19
|
+
end
|
20
|
+
|
21
|
+
def resolve_structure(context = nil)
|
22
|
+
t =
|
23
|
+
target
|
24
|
+
.resolve_reference(context)
|
25
|
+
.resolve_structure(context)
|
26
|
+
t.respond_to?(:body) ||
|
27
|
+
begin
|
28
|
+
message = "cannot amend the target type #{t.class_name}"
|
29
|
+
raise EvaluationError.new(message, position)
|
30
|
+
end
|
31
|
+
do_amend(t.copy(parent))
|
32
|
+
end
|
33
|
+
|
34
|
+
def copy(parent = nil, position = @position)
|
35
|
+
self.class.new(parent, target.copy, bodies.each(&:copy), position)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def do_amend(target)
|
41
|
+
bodies
|
42
|
+
.map { _1.copy(target).resolve_structure }
|
43
|
+
.then { target.merge!(*_1) }
|
44
|
+
target
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
class Any
|
6
|
+
include NodeCommon
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def abstract?
|
10
|
+
@abstract || false
|
11
|
+
end
|
12
|
+
|
13
|
+
def instantiable?
|
14
|
+
!@uninstantiable
|
15
|
+
end
|
16
|
+
|
17
|
+
def class_name
|
18
|
+
@class_name ||= to_s.split('::').last.to_sym
|
19
|
+
end
|
20
|
+
|
21
|
+
def builtin_property(name)
|
22
|
+
@builtin_properties&.[](name.to_sym)
|
23
|
+
end
|
24
|
+
|
25
|
+
def buildin_method(name)
|
26
|
+
@builtin_methods&.[](name.to_sym)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def abstract_class
|
32
|
+
@abstract = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def uninstantiable_class
|
36
|
+
@uninstantiable = true
|
37
|
+
end
|
38
|
+
|
39
|
+
def klass_name(name)
|
40
|
+
@class_name = name
|
41
|
+
end
|
42
|
+
|
43
|
+
def define_builtin_property(name, &body)
|
44
|
+
(@builtin_properties ||= {})[name] = body
|
45
|
+
end
|
46
|
+
|
47
|
+
def define_builtin_method(name, ...)
|
48
|
+
(@builtin_methods ||= {})[name] = BuiltinMethodDefinition.new(name, ...)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
abstract_class
|
53
|
+
uninstantiable_class
|
54
|
+
|
55
|
+
def property(name)
|
56
|
+
builtin_property(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def pkl_method(name)
|
60
|
+
buildin_method(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def null?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def class_name
|
68
|
+
self.class.class_name
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def builtin_property(name)
|
74
|
+
self.class.ancestors.each do |klass|
|
75
|
+
next unless klass.respond_to?(:builtin_property)
|
76
|
+
|
77
|
+
body = klass.builtin_property(name)
|
78
|
+
return instance_exec(&body) if body
|
79
|
+
end
|
80
|
+
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def buildin_method(name)
|
85
|
+
self.class.ancestors.each do |klass|
|
86
|
+
next unless klass.respond_to?(:buildin_method)
|
87
|
+
|
88
|
+
method = klass.buildin_method(name)
|
89
|
+
return method if method
|
90
|
+
end
|
91
|
+
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def check_positive_number(number, position)
|
96
|
+
return unless number.value.negative?
|
97
|
+
|
98
|
+
m = "expected a positive number, but got '#{number.value}'"
|
99
|
+
raise EvaluationError.new(m, position)
|
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
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
class Base < PklModule
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super(nil, nil, nil)
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :pkl_classes
|
13
|
+
|
14
|
+
class << self
|
15
|
+
private
|
16
|
+
|
17
|
+
def add_builtin_class(klass)
|
18
|
+
instance.instance_eval do
|
19
|
+
name = klass.class_name
|
20
|
+
(@pkl_classes ||= {})[name] = klass
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
add_builtin_class Any
|
26
|
+
add_builtin_class Boolean
|
27
|
+
add_builtin_class Number
|
28
|
+
add_builtin_class Int
|
29
|
+
add_builtin_class Float
|
30
|
+
add_builtin_class String
|
31
|
+
add_builtin_class Dynamic
|
32
|
+
add_builtin_class Mapping
|
33
|
+
add_builtin_class Listing
|
34
|
+
add_builtin_class PklModule
|
35
|
+
|
36
|
+
define_builtin_property(:NaN) do
|
37
|
+
Float.new(self, ::Float::NAN, position)
|
38
|
+
end
|
39
|
+
|
40
|
+
define_builtin_property(:Infinity) do
|
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)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/rupkl/node/boolean.rb
CHANGED
@@ -2,15 +2,40 @@
|
|
2
2
|
|
3
3
|
module RuPkl
|
4
4
|
module Node
|
5
|
-
class Boolean
|
5
|
+
class Boolean < Any
|
6
6
|
include ValueCommon
|
7
|
+
include Operatable
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
uninstantiable_class
|
10
|
+
|
11
|
+
def u_op_negate(position)
|
12
|
+
Boolean.new(nil, !value, position)
|
13
|
+
end
|
14
|
+
|
15
|
+
def b_op_and(r_operand, position)
|
16
|
+
result = value && r_operand.value
|
17
|
+
Boolean.new(nil, result, position)
|
18
|
+
end
|
19
|
+
|
20
|
+
def b_op_or(r_operand, position)
|
21
|
+
result = value || r_operand.value
|
22
|
+
Boolean.new(nil, result, position)
|
10
23
|
end
|
11
24
|
|
12
|
-
|
13
|
-
|
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)
|
14
39
|
end
|
15
40
|
|
16
41
|
def short_circuit?(operator)
|
@@ -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,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuPkl
|
4
|
+
module Node
|
5
|
+
class Context
|
6
|
+
def initialize(scopes, objects)
|
7
|
+
@scopes = scopes
|
8
|
+
@objects = objects
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :scopes
|
12
|
+
attr_reader :objects
|
13
|
+
|
14
|
+
def push_scope(scope)
|
15
|
+
Context.new([*scopes, scope], objects)
|
16
|
+
end
|
17
|
+
|
18
|
+
def push_object(object)
|
19
|
+
Context.new(scopes, [*objects, object])
|
20
|
+
end
|
21
|
+
|
22
|
+
def pop
|
23
|
+
Context.new(scopes&.slice(..-2), objects&.slice(..-2))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|