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,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