rupkl 0.1.0 → 0.2.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.
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,43 +3,66 @@
3
3
  module RuPkl
4
4
  module Node
5
5
  class MemberReference
6
- def initialize(receiver, member, position)
6
+ include NodeCommon
7
+ include ReferenceResolver
8
+
9
+ def initialize(parent, receiver, member, nullable, position)
10
+ super(parent, receiver, member, position)
7
11
  @receiver = receiver
8
12
  @member = member
9
- @position = position
13
+ @nullable = nullable
10
14
  end
11
15
 
12
16
  attr_reader :receiver
13
17
  attr_reader :member
14
- attr_reader :position
15
18
 
16
- def evaluate(scopes)
17
- member_node =
18
- if receiver
19
- find_member([receiver.evaluate(scopes)])
20
- else
21
- find_member(scopes)
22
- end
23
- member_node.evaluate(scopes).value
19
+ def nullable?
20
+ @nullable
24
21
  end
25
22
 
26
- def to_string(scopes)
27
- evaluate(scopes).to_string(nil)
23
+ def evaluate(context = nil)
24
+ do_evaluate do
25
+ resolve_member_reference(context, member, receiver, nullable?).evaluate
26
+ end
28
27
  end
29
28
 
30
- def to_pkl_string(scopes)
31
- evaluate(scopes).to_pkl_string(nil)
29
+ def resolve_reference(context = nil)
30
+ do_evaluate do
31
+ resolve_member_reference(context, member, receiver, nullable?).resolve_reference
32
+ end
33
+ end
34
+
35
+ def copy(parent = nil)
36
+ self
37
+ .class.new(parent, receiver&.copy, member&.copy, nullable?, position)
38
+ .tap { copy_scope_index(_1) }
32
39
  end
33
40
 
34
41
  private
35
42
 
36
- def find_member(scopes)
37
- scopes.reverse_each do |scope|
38
- node = scope&.properties&.find { _1.name.id == member.id }
39
- return node if node
40
- end
43
+ def do_evaluate
44
+ @evaluating &&
45
+ (raise EvaluationError.new('circular reference is detected', position))
46
+
47
+ @evaluating = true
48
+ result = yield
49
+ @evaluating = false
50
+
51
+ result
52
+ end
53
+
54
+ def ifnone_value(receiver)
55
+ receiver
56
+ end
57
+
58
+ def get_member_node(scope, target)
59
+ return unless scope.respond_to?(:property)
60
+
61
+ scope.property(target)
62
+ end
41
63
 
42
- raise EvaluationError.new("cannot find property '#{member.id}'", position)
64
+ def unresolve_reference_error(target)
65
+ EvaluationError.new("cannot find property '#{target.id}'", position)
43
66
  end
44
67
  end
45
68
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class MethodCall
6
+ include NodeCommon
7
+ include ReferenceResolver
8
+
9
+ def initialize(parent, receiver, method_name, arguments, nullable, position)
10
+ super(parent, receiver, method_name, *arguments, position)
11
+ @receiver = receiver
12
+ @method_name = method_name
13
+ @arguments = arguments
14
+ @nullable = nullable
15
+ end
16
+
17
+ attr_reader :receiver
18
+ attr_reader :method_name
19
+ attr_reader :arguments
20
+
21
+ def nullable?
22
+ @nullable
23
+ end
24
+
25
+ def evaluate(context = nil)
26
+ exec_on(context) do |c|
27
+ r = evaluate_receiver(receiver, c)
28
+ m = resolve_member_reference(c, method_name, r, nullable?)
29
+ m && execute_method(m, r, c) || r
30
+ end
31
+ end
32
+
33
+ def copy(parent = nil)
34
+ copied_args = arguments&.map(&:copy)
35
+ self.class
36
+ .new(parent, receiver&.copy, method_name, copied_args, nullable?, position)
37
+ .tap { copy_scope_index(_1) }
38
+ end
39
+
40
+ private
41
+
42
+ def ifnone_value(_)
43
+ nil
44
+ end
45
+
46
+ def get_member_node(scope, target)
47
+ return unless scope.respond_to?(:pkl_method)
48
+
49
+ scope.pkl_method(target)
50
+ end
51
+
52
+ def unresolve_reference_error(target)
53
+ m = "cannot find method '#{target.id}'"
54
+ raise EvaluationError.new(m, position)
55
+ end
56
+
57
+ def execute_method(pkl_method, receiver, context)
58
+ pkl_method
59
+ .call(receiver, arguments, context, position)
60
+ .tap { parent&.add_child(_1) }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class MethodParam
6
+ include NodeCommon
7
+
8
+ def initialize(parent, name, type, position)
9
+ super
10
+ @name = name
11
+ @type = type
12
+ end
13
+
14
+ attr_reader :name
15
+ attr_reader :type
16
+
17
+ def check_type(value, context, position)
18
+ type&.check_type(value, context, position)
19
+ end
20
+ end
21
+
22
+ class MethodDefinition
23
+ include NodeCommon
24
+
25
+ def initialize(parent, name, params, type, body, position)
26
+ super(parent, name, *params, type, body, position)
27
+ @name = name
28
+ @params = params
29
+ @type = type
30
+ @body = body&.copy # reset `#parent` handle
31
+ end
32
+
33
+ attr_reader :name
34
+ attr_reader :params
35
+ attr_reader :type
36
+ attr_reader :body
37
+
38
+ def call(receiver, arguments, context, position)
39
+ args = evaluate_arguments(arguments, context, position)
40
+ execute_method(receiver, args)
41
+ end
42
+
43
+ private
44
+
45
+ def evaluate_arguments(arguments, context, position)
46
+ check_arity(arguments, position)
47
+
48
+ arguments&.zip(params)&.map do |arg, param|
49
+ evaluate_argument(arg, param, context)
50
+ end
51
+ end
52
+
53
+ def evaluate_argument(arg, param, context)
54
+ value = arg.evaluate(context)
55
+ param.check_type(value, context, position)
56
+ [param.name, value]
57
+ end
58
+
59
+ def check_arity(arguments, position)
60
+ n_args = arguments&.size || 0
61
+ n_params = params&.size || 0
62
+ return if n_args == n_params
63
+
64
+ m = "expected #{n_params} method arguments but got #{n_args}"
65
+ raise EvaluationError.new(m, position)
66
+ end
67
+
68
+ def execute_method(receiver, arguments)
69
+ context = create_call_context(receiver, arguments)
70
+ execute_body(context)
71
+ end
72
+
73
+ def create_call_context(receiver, arguments)
74
+ local_context = MethodCallContext.new(arguments)
75
+ method_context = current_context
76
+ if receiver
77
+ Context.new([*method_context.scopes, local_context], [receiver])
78
+ else
79
+ method_context.push_scope(local_context)
80
+ end
81
+ end
82
+
83
+ def execute_body(context)
84
+ body
85
+ .evaluate(context)
86
+ .tap { type&.check_type(_1, context, position) }
87
+ end
88
+ end
89
+
90
+ class MethodCallContext
91
+ include NodeCommon
92
+ include MemberFinder
93
+
94
+ def initialize(arguments)
95
+ @properties =
96
+ arguments&.map do |(name, value)|
97
+ ObjectProperty.new(nil, name, value, nil)
98
+ end
99
+ super(nil, *@properties, nil)
100
+ end
101
+
102
+ attr_reader :properties
103
+ end
104
+
105
+ class BuiltinMethodTypeChecker
106
+ include TypeCommon
107
+
108
+ def initialize(klass)
109
+ super(nil, nil)
110
+ @klass = klass
111
+ end
112
+
113
+ private
114
+
115
+ def match_type?(klass, _context)
116
+ klass <= @klass
117
+ end
118
+ end
119
+
120
+ class BuiltinMethodParams < MethodParam
121
+ def initialize(name, klass)
122
+ id = Identifier.new(nil, name, nil)
123
+ type = BuiltinMethodTypeChecker.new(klass)
124
+ super(nil, id, type, nil)
125
+ end
126
+ end
127
+
128
+ class BuiltinMethodDefinition < MethodDefinition
129
+ def initialize(name, **params, &body)
130
+ param_list = params.map { |n, t| BuiltinMethodParams.new(n, t) }
131
+ id = Identifier.new(nil, name, nil)
132
+ super(nil, id, param_list, nil, nil, nil)
133
+ @body = body
134
+ end
135
+
136
+ private
137
+
138
+ def execute_method(receiver, arguments)
139
+ receiver.instance_exec(*arguments&.map(&:last), &body)
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ module NodeCommon
6
+ def initialize(parent, *children, position)
7
+ @position = position
8
+ parent&.add_child(self)
9
+ children.each { add_child(_1) }
10
+ end
11
+
12
+ attr_reader :parent
13
+ attr_reader :children
14
+ attr_reader :position
15
+
16
+ def resolve_reference(_context = nil)
17
+ self
18
+ end
19
+
20
+ def resolve_structure(_context = nil)
21
+ self
22
+ end
23
+
24
+ def to_ruby(context = nil)
25
+ evaluate(context).to_ruby(context)
26
+ end
27
+
28
+ def to_string(context = nil)
29
+ evaluate(context).to_string(context)
30
+ end
31
+
32
+ def to_pkl_string(context = nil)
33
+ evaluate(context).to_pkl_string(context)
34
+ end
35
+
36
+ def add_child(child)
37
+ return unless child
38
+
39
+ child.parent ||
40
+ child.instance_exec(self) { @parent = _1 }
41
+
42
+ @children&.any? { _1.equal?(child) } ||
43
+ (@children ||= []) << child
44
+ end
45
+
46
+ def copy(parent = nil)
47
+ copied_children = children&.map(&:copy)
48
+ self.class.new(parent, *copied_children, position)
49
+ end
50
+
51
+ def current_context
52
+ parent&.current_context
53
+ end
54
+
55
+ def structure?
56
+ false
57
+ end
58
+
59
+ private
60
+
61
+ INVALID_STRING = String.new('?').freeze
62
+
63
+ def invalid_string
64
+ INVALID_STRING
65
+ end
66
+
67
+ def invalid_string?(string)
68
+ string.equal?(INVALID_STRING)
69
+ end
70
+
71
+ def exec_on(context)
72
+ yield(context || current_context)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class Null < Any
6
+ include ValueCommon
7
+
8
+ uninstantiable_class
9
+
10
+ def initialize(parent, position)
11
+ super(parent, nil, position)
12
+ end
13
+
14
+ def to_string(_context = nil)
15
+ 'null'
16
+ end
17
+
18
+ def undefined_operator?(operator)
19
+ [:==, :'!='].none?(operator)
20
+ end
21
+
22
+ def null?
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,13 +2,9 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- class Number
5
+ class Number < Any
6
6
  include ValueCommon
7
7
 
8
- def evaluate(_scopes)
9
- self
10
- end
11
-
12
8
  def undefined_operator?(operator)
13
9
  [:[], :!, :'&&', :'||'].include?(operator)
14
10
  end
@@ -29,12 +25,146 @@ module RuPkl
29
25
  operator == :/ ||
30
26
  operator != :'~/' && [self, r_operand].any?(Float)
31
27
  end
28
+
29
+ abstract_class
30
+ uninstantiable_class
31
+
32
+ define_builtin_property(:sign) do
33
+ result =
34
+ case value
35
+ when :positive?.to_proc then 1
36
+ when :negative?.to_proc then -1
37
+ else value
38
+ end
39
+ self.class.new(self, result, position)
40
+ end
41
+
42
+ define_builtin_property(:abs) do
43
+ self.class.new(self, value.abs, position)
44
+ end
45
+
46
+ define_builtin_property(:ceil) do
47
+ result = value.finite? && value.ceil || value
48
+ self.class.new(self, result, position)
49
+ end
50
+
51
+ define_builtin_property(:floor) do
52
+ result = value.finite? && value.floor || value
53
+ self.class.new(self, result, position)
54
+ end
55
+
56
+ define_builtin_property(:isPositive) do
57
+ result = value.zero? || value.positive?
58
+ Boolean.new(self, result, position)
59
+ end
60
+
61
+ define_builtin_property(:isFinite) do
62
+ Boolean.new(self, value.finite?, position)
63
+ end
64
+
65
+ define_builtin_property(:isInfinite) do
66
+ result = value.infinite? && true || false
67
+ Boolean.new(self, result, position)
68
+ end
69
+
70
+ define_builtin_property(:isNaN) do
71
+ result = !value.integer? && value.nan?
72
+ Boolean.new(self, result, position)
73
+ end
74
+
75
+ define_builtin_property(:isNonZero) do
76
+ Boolean.new(self, !value.zero?, position)
77
+ end
78
+
79
+ define_builtin_method(:toString) do
80
+ String.new(nil, value.to_s, nil, position)
81
+ end
82
+
83
+ define_builtin_method(:toInt) do
84
+ Int.new(nil, value.to_i, position)
85
+ end
86
+
87
+ define_builtin_method(:toFloat) do
88
+ Float.new(nil, value.to_f, position)
89
+ end
90
+
91
+ define_builtin_method(:round) do
92
+ result = value.finite? && value.round || value
93
+ self.class.new(nil, result, position)
94
+ end
95
+
96
+ define_builtin_method(:truncate) do
97
+ result = value.finite? && value.truncate || value
98
+ self.class.new(nil, result, position)
99
+ end
100
+
101
+ define_builtin_method(:isBetween, first: Number, last: Number) do |f, l|
102
+ result =
103
+ [f.value, l.value, value].all? { _1.finite? || _1.infinite? } &&
104
+ (f.value..l.value).include?(value)
105
+ Boolean.new(nil, result, position)
106
+ end
32
107
  end
33
108
 
34
- class Integer < Number
109
+ class Int < Number
110
+ def initialize(parent, value, position)
111
+ super(parent, value.to_i, position)
112
+ end
113
+
114
+ uninstantiable_class
115
+
116
+ define_builtin_property(:isEven) do
117
+ Boolean.new(self, value.even?, position)
118
+ end
119
+
120
+ define_builtin_property(:isOdd) do
121
+ Boolean.new(self, value.odd?, position)
122
+ end
123
+
124
+ define_builtin_property(:inv) do
125
+ self.class.new(self, ~value, position)
126
+ end
127
+
128
+ define_builtin_method(:shl, n: Int) do |n|
129
+ result = value << n.value
130
+ self.class.new(self, result, position)
131
+ end
132
+
133
+ define_builtin_method(:shr, n: Int) do |n|
134
+ result = value >> n.value
135
+ self.class.new(self, result, position)
136
+ end
137
+
138
+ define_builtin_method(:ushr, n: Int) do |n|
139
+ result =
140
+ if value.negative?
141
+ mask = (1 << 63) - 1
142
+ n.value.times.inject(value) { |v, _| (v >> 1) & mask }
143
+ else
144
+ value >> n.value
145
+ end
146
+ self.class.new(self, result, position)
147
+ end
148
+
149
+ define_builtin_method(:and, n: Int) do |n|
150
+ self.class.new(nil, value & n.value, position)
151
+ end
152
+
153
+ define_builtin_method(:or, n: Int) do |n|
154
+ self.class.new(nil, value | n.value, position)
155
+ end
156
+
157
+ define_builtin_method(:xor, n: Int) do |n|
158
+ self.class.new(nil, value ^ n.value, position)
159
+ end
35
160
  end
36
161
 
37
162
  class Float < Number
163
+ def initialize(parent, value, position)
164
+ super(parent, value.to_f, position)
165
+ end
166
+
167
+ uninstantiable_class
38
168
  end
39
169
  end
40
170
  end