rupkl 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/rupkl/node/amend_expression.rb +48 -0
  4. data/lib/rupkl/node/any.rb +99 -0
  5. data/lib/rupkl/node/base.rb +45 -0
  6. data/lib/rupkl/node/boolean.rb +12 -4
  7. data/lib/rupkl/node/context.rb +27 -0
  8. data/lib/rupkl/node/declared_type.rb +32 -0
  9. data/lib/rupkl/node/dynamic.rb +28 -59
  10. data/lib/rupkl/node/identifier.rb +16 -6
  11. data/lib/rupkl/node/listing.rb +61 -0
  12. data/lib/rupkl/node/mapping.rb +47 -0
  13. data/lib/rupkl/node/member_finder.rb +55 -0
  14. data/lib/rupkl/node/member_reference.rb +44 -21
  15. data/lib/rupkl/node/method_call.rb +64 -0
  16. data/lib/rupkl/node/method_definition.rb +143 -0
  17. data/lib/rupkl/node/node_common.rb +76 -0
  18. data/lib/rupkl/node/null.rb +27 -0
  19. data/lib/rupkl/node/number.rb +136 -6
  20. data/lib/rupkl/node/object.rb +369 -73
  21. data/lib/rupkl/node/operation.rb +97 -60
  22. data/lib/rupkl/node/pkl_module.rb +16 -28
  23. data/lib/rupkl/node/reference_resolver.rb +79 -0
  24. data/lib/rupkl/node/string.rb +388 -18
  25. data/lib/rupkl/node/struct_common.rb +119 -57
  26. data/lib/rupkl/node/this.rb +17 -0
  27. data/lib/rupkl/node/type_common.rb +34 -0
  28. data/lib/rupkl/node/value_common.rb +18 -9
  29. data/lib/rupkl/parser/expression.rb +158 -41
  30. data/lib/rupkl/parser/identifier.rb +2 -2
  31. data/lib/rupkl/parser/literal.rb +18 -12
  32. data/lib/rupkl/parser/method.rb +41 -0
  33. data/lib/rupkl/parser/misc.rb +4 -0
  34. data/lib/rupkl/parser/object.rb +57 -25
  35. data/lib/rupkl/parser/pkl_class.rb +28 -8
  36. data/lib/rupkl/parser/pkl_module.rb +5 -3
  37. data/lib/rupkl/parser/type.rb +28 -0
  38. data/lib/rupkl/parser.rb +8 -0
  39. data/lib/rupkl/pkl_object.rb +26 -6
  40. data/lib/rupkl/version.rb +1 -1
  41. data/lib/rupkl.rb +25 -4
  42. metadata +33 -3
  43. data/lib/rupkl/node/pkl_class.rb +0 -30
@@ -3,36 +3,50 @@
3
3
  module RuPkl
4
4
  module Node
5
5
  module OperationCommon
6
- def to_ruby(scopes)
7
- evaluate(scopes).to_ruby(nil)
8
- end
6
+ include NodeCommon
9
7
 
10
- def to_string(scopes)
11
- evaluate(scopes).to_string(nil)
8
+ def initialize(parent, operator, *operands, position)
9
+ super(parent, *operands, position)
10
+ @operator = operator
11
+ @operands = operands
12
12
  end
13
13
 
14
- def to_pkl_string(scopes)
15
- evaluate(scopes).to_pkl_string(nil)
14
+ attr_reader :operator
15
+ attr_reader :operands
16
+
17
+ def copy(parent = nil)
18
+ copied_operands = operands.map(&:copy)
19
+ self.class.new(parent, operator, *copied_operands, position)
16
20
  end
17
21
 
18
22
  private
19
23
 
20
- def s_op(scopes)
21
- r = receiver.evaluate(scopes)
24
+ def s_op(context)
25
+ r = receiver.evaluate(context)
22
26
  check_operator(r)
23
27
 
24
- k = key.evaluate(scopes)
28
+ k = key.evaluate(context)
25
29
  check_key_operand(r, k)
26
30
 
27
- r.find_by_key(k) ||
31
+ (v = r.find_by_key(k)) ||
28
32
  begin
29
- message = "cannot find key '#{k.to_pkl_string(scopes)}'"
33
+ message = "cannot find key '#{k.to_pkl_string(context)}'"
30
34
  raise EvaluationError.new(message, position)
31
35
  end
36
+
37
+ v.evaluate
32
38
  end
33
39
 
34
- def u_op(scopes)
35
- o = operand.evaluate(scopes)
40
+ def non_null_op(context)
41
+ o = operand.evaluate(context)
42
+ return o unless o.null?
43
+
44
+ m = "expected a non-null value but got '#{o.to_pkl_string(context)}'"
45
+ raise EvaluationError.new(m, position)
46
+ end
47
+
48
+ def u_op(context)
49
+ o = operand.evaluate(context)
36
50
  check_operator(o)
37
51
 
38
52
  result =
@@ -44,18 +58,26 @@ module RuPkl
44
58
  create_op_result(result)
45
59
  end
46
60
 
47
- def b_op(scopes)
48
- l = l_operand.evaluate(scopes)
61
+ def b_op(context)
62
+ l = l_operand.evaluate(context)
49
63
  check_operator(l)
50
64
  return l if short_circuit?(l)
51
65
 
52
- r = r_operand.evaluate(scopes)
66
+ r = r_operand.evaluate(context)
53
67
  check_r_operand(l, r)
68
+ .then { return _1 if _1 }
54
69
 
55
70
  l, r = l.coerce(operator, r)
56
71
  create_op_result(l.__send__(ruby_op, r))
57
72
  end
58
73
 
74
+ def null_coalescing_op(context)
75
+ l = l_operand.evaluate(context)
76
+ return l unless l.null?
77
+
78
+ r_operand.evaluate(context)
79
+ end
80
+
59
81
  def check_operator(operand)
60
82
  undefined_operator?(operand) &&
61
83
  begin
@@ -87,13 +109,16 @@ module RuPkl
87
109
  end
88
110
 
89
111
  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
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
97
122
  end
98
123
 
99
124
  def invalid_r_operand?(l_operand, r_operand)
@@ -115,10 +140,10 @@ module RuPkl
115
140
 
116
141
  def create_op_result(result)
117
142
  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)
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)
122
147
  end
123
148
  end
124
149
  end
@@ -126,60 +151,72 @@ module RuPkl
126
151
  class SubscriptOperation
127
152
  include OperationCommon
128
153
 
129
- def initialize(receiver, key, position)
130
- @receiver = receiver
131
- @key = key
132
- @position = position
154
+ def receiver
155
+ operands.first
156
+ end
157
+
158
+ def key
159
+ operands.last
133
160
  end
134
161
 
135
- attr_reader :receiver
136
- attr_reader :key
137
- attr_reader :position
162
+ def evaluate(context = nil)
163
+ s_op(context)
164
+ end
165
+ end
166
+
167
+ class NonNullOperation
168
+ include OperationCommon
138
169
 
139
- def operator
140
- :[]
170
+ def operand
171
+ operands.first
141
172
  end
142
173
 
143
- def evaluate(scopes)
144
- s_op(scopes)
174
+ def evaluate(context = nil)
175
+ non_null_op(context)
145
176
  end
146
177
  end
147
178
 
148
179
  class UnaryOperation
149
180
  include OperationCommon
150
181
 
151
- def initialize(operator, operand, position)
152
- @operator = operator
153
- @operand = operand
154
- @position = position
182
+ def operand
183
+ operands.first
155
184
  end
156
185
 
157
- attr_reader :operator
158
- attr_reader :operand
159
- attr_reader :position
160
-
161
- def evaluate(scopes)
162
- u_op(scopes)
186
+ def evaluate(context = nil)
187
+ u_op(context)
163
188
  end
164
189
  end
165
190
 
166
191
  class BinaryOperation
167
192
  include OperationCommon
168
193
 
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
194
+ def l_operand
195
+ operands.first
174
196
  end
175
197
 
176
- attr_reader :operator
177
- attr_reader :l_operand
178
- attr_reader :r_operand
179
- attr_reader :position
198
+ def r_operand
199
+ operands.last
200
+ end
201
+
202
+ def evaluate(context = nil)
203
+ b_op(context)
204
+ end
205
+ end
206
+
207
+ class NullCoalescingOperation
208
+ include OperationCommon
209
+
210
+ def l_operand
211
+ operands.first
212
+ end
213
+
214
+ def r_operand
215
+ operands.last
216
+ end
180
217
 
181
- def evaluate(scopes)
182
- b_op(scopes)
218
+ def evaluate(context = nil)
219
+ null_coalescing_op(context)
183
220
  end
184
221
  end
185
222
  end
@@ -2,45 +2,33 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- class PklModule
5
+ class PklModule < Any
6
6
  include StructCommon
7
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
8
+ abstract_class
9
+ klass_name :Module
10
+
11
+ def properties
12
+ @body&.properties(visibility: :object)
15
13
  end
16
14
 
17
- attr_reader :properties
18
- attr_reader :position
15
+ def pkl_methods
16
+ @body&.pkl_methods
17
+ end
19
18
 
20
- def evaluate(scopes)
21
- push_scope(scopes) do |s|
22
- self.class.new(evaluate_properties(s), position)
23
- end
19
+ def pkl_classes
20
+ @body&.pkl_classes
24
21
  end
25
22
 
26
- def to_ruby(scopes)
27
- push_scope(scopes) do |s|
28
- create_pkl_object(s, properties, nil, nil)
29
- end
23
+ def evaluate(context = nil)
24
+ resolve_structure(context)
25
+ super
30
26
  end
31
27
 
32
28
  private
33
29
 
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
30
+ def properties_not_allowed?
31
+ false
44
32
  end
45
33
  end
46
34
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ module ReferenceResolver
6
+ private
7
+
8
+ def resolve_member_reference(context, target, receiver, nullable)
9
+ scopes, raise_error, ifnone =
10
+ if receiver
11
+ evaluate_receiver(receiver, context)&.then do |r|
12
+ [[r], raise_error?(r, nullable), ifnone_value(r)]
13
+ end
14
+ else
15
+ exec_on(context) do |c|
16
+ [[c&.objects&.last, Base.instance, *c&.scopes], true]
17
+ end
18
+ end
19
+ find_member(scopes, target, raise_error, ifnone)
20
+ end
21
+
22
+ def raise_error?(receiver, nullable)
23
+ !(nullable && receiver&.null?)
24
+ end
25
+
26
+ def evaluate_receiver(receiver, context)
27
+ return unless receiver
28
+
29
+ if receiver.structure?
30
+ receiver
31
+ .resolve_reference(context)
32
+ .resolve_structure(context)
33
+ else
34
+ receiver.evaluate(context)
35
+ end
36
+ end
37
+
38
+ def find_member(scopes, target, raise_error, ifnone)
39
+ if scope_index.index
40
+ get_member_node(scopes[scope_index.index], target)
41
+ else
42
+ search_member(scopes, target, raise_error, ifnone)
43
+ end
44
+ end
45
+
46
+ def search_member(scopes, target, raise_error, ifnone)
47
+ node, index = search_member_from_scopes(scopes, target)
48
+ if node
49
+ scope_index.index = index
50
+ return node
51
+ end
52
+
53
+ raise_error &&
54
+ (raise unresolve_reference_error(target))
55
+
56
+ ifnone
57
+ end
58
+
59
+ def search_member_from_scopes(scopes, target)
60
+ scopes.reverse_each.with_index do |scope, i|
61
+ node = get_member_node(scope, target)
62
+ return [node, scopes.size - i - 1] if node
63
+ end
64
+
65
+ nil
66
+ end
67
+
68
+ ScopeIndex = Struct.new(:index)
69
+
70
+ def scope_index
71
+ @scope_index ||= ScopeIndex.new
72
+ end
73
+
74
+ def copy_scope_index(target)
75
+ target.instance_exec(scope_index) { @scope_index = _1 }
76
+ end
77
+ end
78
+ end
79
+ end