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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8b6a7346123ff0c771a201f1218f0c2d92e3c34a16e4fe0f668724eb53726ee
4
- data.tar.gz: 169990d7f909f37f72ea97ba2ff44c9634137fead23791ab6a80fddd9b3af109
3
+ metadata.gz: d7731a56bb62b392639860c5e0f82c2175e8bca4ecd439e8ccffd05d9b223b0f
4
+ data.tar.gz: 18487cb107c5a47212d185d782f4866d5fc5c0734b893986e4388c003728687d
5
5
  SHA512:
6
- metadata.gz: 50e6f855bec47026a3a6f4b8b61b9fd61ceafc7686bcd0a51f459a42ae88a97ee954fb362f3450c89d6499fe6e1d97f2b2350350a2820607c007bc7a8e8d8190
7
- data.tar.gz: ad63c41fa79cc9b487d6d3c7f4b129febbf914e564f15d9921072cf4680442dcc77c605d8d7cc283aa15662f15247f427ccbd218c2a1856681ca402500e2810f
6
+ metadata.gz: e9d8c2d0d8d9f4976ba804810285344b8f5a6cd308ce1eeff23eb3503feb365c2415d1876c8c879fdf38ca016b01dc849aaeb2e01ae502b9c0e0a44a1a2123ce
7
+ data.tar.gz: 2bc34ee5b570519a913299dbe5415fe9a7e3dd406b5912f729127ce152c18fd6821f769f9c6df6e677c0c114de935f401584e67e5ae385133aef318810f57ce0
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.basename}"
29
+ raise EvaluationError.new(message, position)
30
+ end
31
+ do_amend(t.copy(parent))
32
+ end
33
+
34
+ def copy(parent = nil)
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,99 @@
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 || basename.to_sym
19
+ end
20
+
21
+ def builtin_property(name)
22
+ @builtin_properties&.[](name.id)
23
+ end
24
+
25
+ def buildin_method(name)
26
+ @builtin_methods&.[](name.id)
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
+ private
68
+
69
+ def builtin_property(name)
70
+ self.class.ancestors.each do |klass|
71
+ next unless klass.respond_to?(:builtin_property)
72
+
73
+ body = klass.builtin_property(name)
74
+ return instance_exec(&body) if body
75
+ end
76
+
77
+ nil
78
+ end
79
+
80
+ def buildin_method(name)
81
+ self.class.ancestors.each do |klass|
82
+ next unless klass.respond_to?(:buildin_method)
83
+
84
+ method = klass.buildin_method(name)
85
+ return method if method
86
+ end
87
+
88
+ nil
89
+ end
90
+
91
+ def check_positive_number(number)
92
+ return unless number.value.negative?
93
+
94
+ m = "expected a positive number, but got '#{number.value}'"
95
+ raise EvaluationError.new(m, position)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,45 @@
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(parent, ::Float::NAN, position)
38
+ end
39
+
40
+ define_builtin_property(:Infinity) do
41
+ Float.new(parent, ::Float::INFINITY, position)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,12 +2,10 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- class Boolean
5
+ class Boolean < Any
6
6
  include ValueCommon
7
7
 
8
- def evaluate(_scopes)
9
- self
10
- end
8
+ uninstantiable_class
11
9
 
12
10
  def undefined_operator?(operator)
13
11
  [:!, :==, :'!=', :'&&', :'||'].none?(operator)
@@ -16,6 +14,16 @@ module RuPkl
16
14
  def short_circuit?(operator)
17
15
  [operator, value] in [:'&&', false] | [:'||', true]
18
16
  end
17
+
18
+ define_builtin_method(:xor, other: Boolean) do |other|
19
+ result = value ^ other.value
20
+ Boolean.new(nil, result, position)
21
+ end
22
+
23
+ define_builtin_method(:implies, other: Boolean) do |other|
24
+ result = !value || other.value
25
+ Boolean.new(nil, result, position)
26
+ end
19
27
  end
20
28
  end
21
29
  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
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class DeclaredType
6
+ include TypeCommon
7
+
8
+ def initialize(parent, type, position)
9
+ super(parent, *type, position)
10
+ @type = type
11
+ end
12
+
13
+ attr_reader :type
14
+
15
+ def find_class(context)
16
+ find_type(type, context)
17
+ end
18
+
19
+ def to_s
20
+ type.last.id.to_s
21
+ end
22
+
23
+ private
24
+
25
+ def match_type?(klass, context)
26
+ rhs = klass
27
+ lhs = find_class(context)
28
+ rhs <= lhs
29
+ end
30
+ end
31
+ end
32
+ end
@@ -2,36 +2,19 @@
2
2
 
3
3
  module RuPkl
4
4
  module Node
5
- class Dynamic
5
+ class Dynamic < Any
6
6
  include StructCommon
7
7
 
8
- def initialize(members, scopes, position)
9
- @position = position
10
- add_members(members, scopes)
8
+ def properties
9
+ @body&.properties(visibility: :object)
11
10
  end
12
11
 
13
- attr_reader :properties
14
- attr_reader :entries
15
- attr_reader :elements
16
- attr_reader :position
17
-
18
- def evaluate(_scopes)
19
- self
20
- end
21
-
22
- def to_ruby(_scopes)
23
- create_pkl_object(nil, properties, entries, elements)
12
+ def entries
13
+ @body&.entries
24
14
  end
25
15
 
26
- def to_pkl_string(_scopes)
27
- to_pkl_string_object(*properties, *entries, *elements)
28
- end
29
-
30
- def merge!(other)
31
- @properties = merge_hash_members(properties, other.properties, :name)
32
- @entries = merge_hash_members(entries, other.entries, :key)
33
- @elements = merge_array_members(elements, other.elements)
34
- self
16
+ def elements
17
+ @body&.elements
35
18
  end
36
19
 
37
20
  def ==(other)
@@ -41,58 +24,44 @@ module RuPkl
41
24
  match_members?(elements, other.elements, true)
42
25
  end
43
26
 
44
- def undefined_operator?(operator)
45
- [:[], :==, :'!='].none?(operator)
46
- end
47
-
48
27
  def find_by_key(key)
49
28
  find_entry(key) || find_element(key)
50
29
  end
51
30
 
52
- private
53
-
54
- def add_members(members, scopes)
55
- return unless members
31
+ define_builtin_method(:length) do
32
+ result = elements&.size || 0
33
+ Int.new(nil, result, position)
34
+ end
56
35
 
57
- push_scope(scopes) do |s|
58
- members.each { |m| add_member(m, s) }
59
- end
36
+ define_builtin_method(:hasProperty, name: String) do |name|
37
+ result = find_property(name.value.to_sym) && true || false
38
+ Boolean.new(nil, result, position)
60
39
  end
61
40
 
62
- def add_member(member, scopes)
63
- member.evaluate(scopes).then do |m|
64
- case member
65
- when ObjectProperty then add_property(m)
66
- when ObjectEntry then add_entry(m)
67
- else add_element(m)
41
+ define_builtin_method(:getProperty, name: String) do |name|
42
+ find_property(name.value.to_sym) ||
43
+ begin
44
+ m = "cannot find property '#{name.value}'"
45
+ raise EvaluationError.new(m, position)
68
46
  end
69
- end
70
47
  end
71
48
 
72
- def add_property(member)
73
- add_hash_member((@properties ||= []), member, :name)
49
+ define_builtin_method(:getPropertyOrNull, name: String) do |name|
50
+ find_property(name.value.to_sym) || Null.new(nil, position)
74
51
  end
75
52
 
76
- def add_entry(member)
77
- add_hash_member((@entries ||= []), member, :key)
78
- end
53
+ private
79
54
 
80
- def add_element(member)
81
- add_array_member((@elements ||= []), member)
55
+ def properties_not_allowed?
56
+ false
82
57
  end
83
58
 
84
- def find_entry(key)
85
- entries
86
- &.find { _1.key == key }
87
- &.then(&:value)
59
+ def entries_not_allowed?
60
+ false
88
61
  end
89
62
 
90
- def find_element(index)
91
- return nil unless elements
92
- return nil unless index.value.is_a?(::Integer)
93
-
94
- elements
95
- .find.with_index { |_, i| i == index.value }
63
+ def elements_not_allowed?
64
+ false
96
65
  end
97
66
  end
98
67
  end
@@ -3,17 +3,27 @@
3
3
  module RuPkl
4
4
  module Node
5
5
  class Identifier
6
- def initialize(id, position)
6
+ include NodeCommon
7
+
8
+ def initialize(parent, id, position)
9
+ super(parent, position)
7
10
  @id = id
8
- @position = position
9
11
  end
10
12
 
11
- def ==(other)
12
- other.instance_of?(self.class) && id == other.id
13
+ attr_reader :id
14
+
15
+ def copy(parent = nil)
16
+ self.class.new(parent, id, position)
13
17
  end
14
18
 
15
- attr_reader :id
16
- attr_reader :position
19
+ def ==(other)
20
+ id ==
21
+ if other.respond_to?(:id)
22
+ other.id
23
+ else
24
+ other
25
+ end
26
+ end
17
27
  end
18
28
  end
19
29
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class Listing < Any
6
+ include StructCommon
7
+
8
+ def elements
9
+ @body&.elements
10
+ end
11
+
12
+ def ==(other)
13
+ other.instance_of?(self.class) &&
14
+ match_members?(elements, other.elements, true)
15
+ end
16
+
17
+ def find_by_key(key)
18
+ find_element(key)
19
+ end
20
+
21
+ define_builtin_property(:isEmpty) do
22
+ result = elements.nil? || elements.empty?
23
+ Boolean.new(self, result, position)
24
+ end
25
+
26
+ define_builtin_property(:length) do
27
+ result = elements&.size || 0
28
+ Int.new(self, result, position)
29
+ end
30
+
31
+ define_builtin_property(:isDistinct) do
32
+ result =
33
+ elements.nil? ||
34
+ elements.all? { |lhs| elements.one? { |rhs| rhs == lhs } }
35
+ Boolean.new(self, result || elements.nil?, position)
36
+ end
37
+
38
+ define_builtin_property(:distinct) do
39
+ result =
40
+ elements
41
+ &.each_with_object([]) { |e, l| l << e unless l.include?(e) }
42
+ body = ObjectBody.new(nil, result, position)
43
+ Listing.new(self, body, position)
44
+ end
45
+
46
+ define_builtin_method(:join, separator: String) do |separator|
47
+ result =
48
+ elements
49
+ &.map { _1.value.to_string }
50
+ &.join(separator.value)
51
+ String.new(nil, result || '', nil, position)
52
+ end
53
+
54
+ private
55
+
56
+ def elements_not_allowed?
57
+ false
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ class Mapping < Any
6
+ include StructCommon
7
+
8
+ def entries
9
+ @body&.entries
10
+ end
11
+
12
+ def ==(other)
13
+ other.instance_of?(self.class) &&
14
+ match_members?(entries, other.entries, false)
15
+ end
16
+
17
+ def find_by_key(key)
18
+ find_entry(key)
19
+ end
20
+
21
+ define_builtin_property(:isEmpty) do
22
+ result = entries.nil? || entries.empty?
23
+ Boolean.new(self, result, position)
24
+ end
25
+
26
+ define_builtin_property(:length) do
27
+ result = entries&.size || 0
28
+ Int.new(self, result, position)
29
+ end
30
+
31
+ define_builtin_method(:containsKey, key: Any) do |key|
32
+ result = find_entry(key) && true || false
33
+ Boolean.new(nil, result, position)
34
+ end
35
+
36
+ define_builtin_method(:getOrNull, key: Any) do |key|
37
+ find_entry(key) || Null.new(nil, position)
38
+ end
39
+
40
+ private
41
+
42
+ def entries_not_allowed?
43
+ false
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuPkl
4
+ module Node
5
+ module MemberFinder
6
+ def property(name)
7
+ value = find_property(name)
8
+ return value if value
9
+
10
+ super if self.class <= Any
11
+ end
12
+
13
+ def pkl_method(name)
14
+ method = find_pkl_method(name)
15
+ return method if method
16
+
17
+ super if self.class <= Any
18
+ end
19
+
20
+ private
21
+
22
+ def find_property(name)
23
+ return unless respond_to?(:properties)
24
+
25
+ properties
26
+ &.find { _1.name == name }
27
+ &.value
28
+ end
29
+
30
+ def find_entry(key)
31
+ return unless respond_to?(:entries)
32
+
33
+ entries
34
+ &.find { _1.key == key }
35
+ &.value
36
+ end
37
+
38
+ def find_element(index)
39
+ return unless respond_to?(:elements)
40
+ return unless elements
41
+ return unless index.value.is_a?(::Integer)
42
+
43
+ elements
44
+ .find.with_index { |_, i| i == index.value }
45
+ &.value
46
+ end
47
+
48
+ def find_pkl_method(name)
49
+ return unless respond_to?(:pkl_methods)
50
+
51
+ pkl_methods&.find { _1.name == name }
52
+ end
53
+ end
54
+ end
55
+ end