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.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/examples/manhattan-distance.kap +9 -0
- data/examples/subtract-product-sum.kap +14 -0
- data/lib/kapusta/compiler/emitter/bindings.rb +18 -7
- data/lib/kapusta/compiler/emitter/collections.rb +69 -45
- data/lib/kapusta/compiler/emitter/control_flow.rb +39 -66
- data/lib/kapusta/compiler/emitter/interop.rb +65 -72
- data/lib/kapusta/compiler/emitter/patterns.rb +196 -109
- data/lib/kapusta/compiler/emitter/support.rb +2 -15
- data/lib/kapusta/compiler/emitter.rb +1 -3
- data/lib/kapusta/compiler/normalizer.rb +2 -2
- data/lib/kapusta/compiler.rb +0 -1
- data/lib/kapusta/version.rb +1 -1
- data/lib/kapusta.rb +28 -4
- data/spec/examples_spec.rb +8 -0
- metadata +3 -2
- data/lib/kapusta/compiler/runtime.rb +0 -226
|
@@ -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
|