kapusta 0.2.4 → 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.
@@ -1,226 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kapusta
4
- module Compiler
5
- module Runtime
6
- HELPER_DEPENDENCIES = {
7
- destructure: %i[destructure_into],
8
- match_pattern: %i[match_pattern_into]
9
- }.freeze
10
-
11
- HELPER_SOURCES = {
12
- qget_path: <<~RUBY.chomp,
13
- def kap_qget_path(obj, keys)
14
- keys.each do |key|
15
- return if obj.nil?
16
-
17
- obj = obj[key]
18
- end
19
- obj
20
- end
21
- RUBY
22
- ensure_module: <<~RUBY.chomp,
23
- def kap_ensure_module(holder, path)
24
- segments = path.split('.')
25
- last = segments.pop
26
- scope = holder.is_a?(Module) ? holder : Object
27
- segments.each do |segment|
28
- scope =
29
- if scope.const_defined?(segment, false)
30
- scope.const_get(segment, false)
31
- else
32
- mod = Module.new
33
- scope.const_set(segment, mod)
34
- mod
35
- end
36
- end
37
- if scope.const_defined?(last, false)
38
- scope.const_get(last, false)
39
- else
40
- mod = Module.new
41
- scope.const_set(last, mod)
42
- mod
43
- end
44
- end
45
- RUBY
46
- ensure_class: <<~RUBY.chomp,
47
- def kap_ensure_class(holder, path, super_class)
48
- segments = path.split('.')
49
- last = segments.pop
50
- scope = holder.is_a?(Module) ? holder : Object
51
- segments.each do |segment|
52
- scope =
53
- if scope.const_defined?(segment, false)
54
- scope.const_get(segment, false)
55
- else
56
- mod = Module.new
57
- scope.const_set(segment, mod)
58
- mod
59
- end
60
- end
61
- if scope.const_defined?(last, false)
62
- scope.const_get(last, false)
63
- else
64
- klass = Class.new(super_class)
65
- scope.const_set(last, klass)
66
- klass
67
- end
68
- end
69
- RUBY
70
- destructure: <<~RUBY.chomp,
71
- def kap_destructure(pattern, value)
72
- bindings = {}
73
- kap_destructure_into(pattern, value, bindings)
74
- bindings
75
- end
76
- RUBY
77
- destructure_into: <<~'RUBY'.chomp,
78
- def kap_destructure_into(pattern, value, bindings)
79
- case pattern[0]
80
- when :sym
81
- name = pattern[1]
82
- bindings[name] = value unless name == '_'
83
- when :vec
84
- items = pattern[1]
85
- rest_idx = items.index { |item| item.is_a?(Array) && item[0] == :rest }
86
- if rest_idx
87
- before = items[0...rest_idx]
88
- rest_pattern = items[rest_idx][1]
89
- before.each_with_index do |item, i|
90
- kap_destructure_into(item, value ? value[i] : nil, bindings)
91
- end
92
- rest_value = value ? (value[rest_idx..] || []) : []
93
- kap_destructure_into(rest_pattern, rest_value, bindings)
94
- else
95
- items.each_with_index do |item, i|
96
- kap_destructure_into(item, value ? value[i] : nil, bindings)
97
- end
98
- end
99
- when :hash
100
- pattern[1].each do |key, subpattern|
101
- kap_destructure_into(subpattern, value ? value[key] : nil, bindings)
102
- end
103
- when :ignore
104
- nil
105
- else
106
- raise "unknown destructure pattern: #{pattern.inspect}"
107
- end
108
- end
109
- RUBY
110
- match_pattern: <<~RUBY.chomp,
111
- def kap_match_pattern(pattern, value)
112
- bindings = {}
113
- [kap_match_pattern_into(pattern, value, bindings), bindings]
114
- end
115
- RUBY
116
- match_pattern_into: <<~'RUBY'.chomp
117
- def kap_match_pattern_into(pattern, value, bindings)
118
- case pattern[0]
119
- when :bind
120
- name = pattern[1]
121
- allow_nil = pattern[2]
122
- return false if value.nil? && !allow_nil
123
-
124
- bindings[name] = value
125
- true
126
- when :ref
127
- bindings.key?(pattern[1]) && bindings[pattern[1]] == value
128
- when :wild
129
- true
130
- when :vec
131
- return false unless value.is_a?(Array) || value.respond_to?(:to_ary)
132
-
133
- array = value.is_a?(Array) ? value : value.to_ary
134
- items = pattern[1]
135
- rest_idx = items.index { |item| item.is_a?(Array) && item[0] == :rest }
136
- if rest_idx
137
- before = items[0...rest_idx]
138
- rest_pattern = items[rest_idx][1]
139
- return false if array.length < before.length
140
-
141
- before.each_with_index do |item, i|
142
- return false unless kap_match_pattern_into(item, array[i], bindings)
143
- end
144
- kap_match_pattern_into(rest_pattern, array[rest_idx..], bindings)
145
- else
146
- return false unless array.length >= items.length
147
-
148
- items.each_with_index do |item, i|
149
- return false unless kap_match_pattern_into(item, array[i], bindings)
150
- end
151
- true
152
- end
153
- when :hash
154
- return false unless value.is_a?(Hash)
155
-
156
- pattern[1].each do |key, subpattern|
157
- return false unless value.key?(key)
158
- return false unless kap_match_pattern_into(subpattern, value[key], bindings)
159
- end
160
- true
161
- when :lit
162
- value == pattern[1]
163
- when :pin
164
- value == pattern[1]
165
- when :or
166
- pattern[1].any? do |option|
167
- option_bindings = bindings.dup
168
- next false unless kap_match_pattern_into(option, value, option_bindings)
169
-
170
- bindings.replace(option_bindings)
171
- true
172
- end
173
- else
174
- raise "bad pattern: #{pattern.inspect}"
175
- end
176
- end
177
- RUBY
178
- }.transform_values(&:freeze).freeze
179
-
180
- module_function
181
-
182
- def helper_name(name)
183
- "kap_#{name}"
184
- end
185
-
186
- def helper_source(helpers)
187
- ordered = []
188
- seen = {}
189
- helpers.each { |name| append_helper_source(name.to_sym, ordered, seen) }
190
- return '' if ordered.empty?
191
-
192
- [
193
- ordered.map { |name| HELPER_SOURCES.fetch(name) }.join("\n\n"),
194
- "private #{ordered.map { |name| ":#{helper_name(name)}" }.join(', ')}"
195
- ].join("\n\n")
196
- end
197
-
198
- def append_helper_source(name, ordered, seen)
199
- return if seen[name]
200
-
201
- HELPER_DEPENDENCIES.fetch(name, []).each do |dependency|
202
- append_helper_source(dependency, ordered, seen)
203
- end
204
- ordered << name
205
- seen[name] = true
206
- end
207
-
208
- HELPER_SOURCES.each_value do |source|
209
- module_eval(source, __FILE__, __LINE__)
210
- end
211
-
212
- helper_methods = []
213
-
214
- HELPER_SOURCES.each_key do |name|
215
- helper_method = :"kap_#{name}"
216
- body = instance_method(helper_method)
217
- define_singleton_method(helper_method, body)
218
- define_singleton_method(name, body)
219
- helper_methods << helper_method
220
- end
221
-
222
- private_class_method(*helper_methods)
223
- send(:private, *helper_methods)
224
- end
225
- end
226
- end