kapusta 0.13.2 → 0.14.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 +50 -11
- data/bin/check-all +6 -1
- data/bin/compile-examples +7 -2
- data/examples/anagram.kap +3 -3
- data/examples/app/args.kap +9 -0
- data/examples/arrange-coins.kap +3 -3
- data/examples/baseball-game.kap +5 -5
- data/examples/best-time-to-buy-sell-stock.kap +2 -2
- data/examples/binary-search.kap +2 -2
- data/examples/binary-to-decimal.kap +1 -1
- data/examples/blocks-and-kwargs.kap +2 -2
- data/examples/count-effects.kap +1 -1
- data/examples/count-items-matching-rule.kap +18 -0
- data/examples/doto-hygiene.kap +2 -2
- data/examples/doto.kap +2 -2
- data/examples/egg-count.kap +1 -1
- data/examples/exceptions.kap +1 -1
- data/examples/falling-drops.kap +7 -7
- data/examples/fennel-parity-examples.txt +3 -6
- data/examples/good-pairs.kap +18 -0
- data/examples/greet.kap +1 -1
- data/examples/happy-number.kap +2 -2
- data/examples/left-right-difference.kap +60 -0
- data/examples/length-of-last-word.kap +4 -4
- data/examples/manhattan-distance.kap +1 -1
- data/examples/maximum-subarray.kap +23 -7
- data/examples/minimum-start-value.kap +19 -0
- data/examples/move-zeroes.kap +2 -2
- data/examples/mruby-runtime-examples.txt +8 -2
- data/examples/non-constant-local.kap +1 -1
- data/examples/number-of-1-bits.kap +1 -1
- data/examples/number-of-steps.kap +1 -1
- data/examples/palindrome.kap +2 -2
- data/examples/pangram.kap +4 -4
- data/examples/pcall.kap +3 -3
- data/examples/pipeline.kap +4 -4
- data/examples/plus-one.kap +3 -3
- data/examples/raindrops.kap +1 -1
- data/examples/range-width.kap +14 -0
- data/examples/recent-counter.kap +6 -6
- data/examples/require-local-args.kap +9 -0
- data/examples/require-local.kap +7 -0
- data/examples/require-module-local.kap +4 -0
- data/examples/require-module.kap +4 -0
- data/examples/reverse-integer.kap +1 -1
- data/examples/roman-to-integer.kap +3 -3
- data/examples/running-sum.kap +20 -0
- data/examples/safe-lookup.kap +2 -2
- data/examples/single-number.kap +1 -1
- data/examples/stack.kap +14 -14
- data/examples/subtract-product-sum.kap +1 -1
- data/examples/summary-ranges.kap +45 -0
- data/examples/threading.kap +5 -5
- data/examples/tset.kap +1 -1
- data/examples/two-sum-hash.kap +3 -3
- data/examples/two-sum.kap +1 -1
- data/examples/ugly-number.kap +1 -1
- data/examples/underground-system.kap +39 -0
- data/examples/valid-parentheses-1.kap +6 -6
- data/exe/kapusta-ls +49 -2
- data/lib/kapusta/ast.rb +8 -0
- data/lib/kapusta/compiler/emitter/bindings.rb +111 -89
- data/lib/kapusta/compiler/emitter/collections.rb +32 -40
- data/lib/kapusta/compiler/emitter/control_flow.rb +33 -31
- data/lib/kapusta/compiler/emitter/expressions.rb +21 -5
- data/lib/kapusta/compiler/emitter/interop.rb +168 -48
- data/lib/kapusta/compiler/emitter/patterns.rb +12 -14
- data/lib/kapusta/compiler/emitter/support.rb +63 -81
- data/lib/kapusta/compiler/language.rb +522 -0
- data/lib/kapusta/compiler/lua_compat.rb +23 -28
- data/lib/kapusta/compiler/macro_expander.rb +30 -30
- data/lib/kapusta/compiler/macro_lowerer.rb +12 -24
- data/lib/kapusta/compiler/normalizer.rb +25 -17
- data/lib/kapusta/compiler.rb +3 -24
- data/lib/kapusta/env.rb +2 -2
- data/lib/kapusta/errors.rb +2 -1
- data/lib/kapusta/formatter/ast_helpers.rb +78 -0
- data/lib/kapusta/formatter/cli.rb +125 -0
- data/lib/kapusta/formatter/line_helpers.rb +44 -0
- data/lib/kapusta/formatter/validator.rb +32 -0
- data/lib/kapusta/formatter.rb +354 -325
- data/lib/kapusta/lsp/identifier.rb +1 -1
- data/lib/kapusta/lsp/rename.rb +21 -11
- data/lib/kapusta/lsp/scope_walker.rb +122 -212
- data/lib/kapusta/lsp/workspace_index.rb +17 -5
- data/lib/kapusta/reader.rb +4 -2
- data/lib/kapusta/version.rb +1 -1
- data/lib/kapusta.rb +39 -6
- data/spec/cli_spec.rb +13 -0
- data/spec/examples_errors_spec.rb +3 -1
- data/spec/examples_spec.rb +67 -15
- data/spec/formatter_spec.rb +246 -0
- data/spec/lsp_spec.rb +69 -0
- data/spec/require_spec.rb +294 -0
- metadata +20 -2
- data/examples/describe.kap +0 -9
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kapusta
|
|
4
|
+
module Compiler
|
|
5
|
+
module Language
|
|
6
|
+
FunctionForm = Struct.new(:head, :name, :params, :body, :prefix_length, keyword_init: true) do
|
|
7
|
+
def named? = !name.nil?
|
|
8
|
+
|
|
9
|
+
def anonymous? = name.nil?
|
|
10
|
+
end
|
|
11
|
+
ModuleForm = Struct.new(:name, :body, :prefix_length, keyword_init: true)
|
|
12
|
+
ClassForm = Struct.new(:name, :supers, :body, :prefix_length, keyword_init: true)
|
|
13
|
+
TryForm = Struct.new(:body, :clauses, keyword_init: true)
|
|
14
|
+
CatchClause = Struct.new(:klass, :bind_sym, :body, keyword_init: true)
|
|
15
|
+
FinallyClause = Struct.new(:body, keyword_init: true)
|
|
16
|
+
BindingForm = Struct.new(:head, :target, :value, keyword_init: true) do
|
|
17
|
+
def mutable? = head == 'var'
|
|
18
|
+
end
|
|
19
|
+
GlobalForm = Struct.new(:name, :value, keyword_init: true)
|
|
20
|
+
SetForm = Struct.new(:target, :value, keyword_init: true)
|
|
21
|
+
DotTarget = Struct.new(:object, :keys, keyword_init: true)
|
|
22
|
+
TsetForm = Struct.new(:table, :key, :value, keyword_init: true)
|
|
23
|
+
ConditionalBodyForm = Struct.new(:condition, :body, keyword_init: true) do
|
|
24
|
+
def body? = !body.empty?
|
|
25
|
+
end
|
|
26
|
+
ValuesForm = Struct.new(:key, :value, keyword_init: true)
|
|
27
|
+
LuaIteratorForm = Struct.new(:head, :collection, keyword_init: true) do
|
|
28
|
+
def name = head.name
|
|
29
|
+
end
|
|
30
|
+
LuaPcallForm = Struct.new(:callable, :args, keyword_init: true)
|
|
31
|
+
LuaXpcallForm = Struct.new(:callable, :handler, :args, keyword_init: true)
|
|
32
|
+
SigilForm = Struct.new(:head, :name, keyword_init: true) do
|
|
33
|
+
def kind = head.to_sym
|
|
34
|
+
end
|
|
35
|
+
MacroDefinitionForm = Struct.new(:name, :params, :body, keyword_init: true)
|
|
36
|
+
ImportMacrosForm = Struct.new(:destructure, :module_arg, keyword_init: true)
|
|
37
|
+
LetForm = Struct.new(:bindings, :body, keyword_init: true) do
|
|
38
|
+
def binding_pairs
|
|
39
|
+
return [] unless bindings.is_a?(Vec)
|
|
40
|
+
|
|
41
|
+
bindings.items.each_slice(2).map { |pattern, value| [pattern, value] }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
CaseForm = Struct.new(:subject, :clauses, keyword_init: true) do
|
|
45
|
+
def arm_pairs
|
|
46
|
+
clauses.each_slice(2).to_a
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def complete_arms
|
|
50
|
+
arm_pairs.select { |pair| pair.length == 2 }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
WherePattern = Struct.new(:inner, :guards, keyword_init: true)
|
|
54
|
+
OrPattern = Struct.new(:alternatives, keyword_init: true)
|
|
55
|
+
PinPattern = Struct.new(:name, keyword_init: true)
|
|
56
|
+
UnpackCall = Struct.new(:value, keyword_init: true)
|
|
57
|
+
HashFnForm = Struct.new(:body, keyword_init: true)
|
|
58
|
+
IterationForm = Struct.new(:bindings, :body, keyword_init: true) do
|
|
59
|
+
def items = bindings.is_a?(Vec) ? bindings.items : []
|
|
60
|
+
|
|
61
|
+
def iter_expr = items.last
|
|
62
|
+
|
|
63
|
+
def binding_pats = items[0...-1] || []
|
|
64
|
+
end
|
|
65
|
+
AccumulateForm = Struct.new(:bindings, :body, keyword_init: true) do
|
|
66
|
+
def items = bindings.is_a?(Vec) ? bindings.items : []
|
|
67
|
+
|
|
68
|
+
def acc_name = items[0]
|
|
69
|
+
|
|
70
|
+
def initial = items[1]
|
|
71
|
+
|
|
72
|
+
def iter_items = items[2..] || []
|
|
73
|
+
|
|
74
|
+
def iter_expr = iter_items.last
|
|
75
|
+
|
|
76
|
+
def binding_pats = iter_items[0...-1] || []
|
|
77
|
+
end
|
|
78
|
+
FaccumulateForm = Struct.new(:bindings, :body, keyword_init: true) do
|
|
79
|
+
def items = bindings.is_a?(Vec) ? bindings.items : []
|
|
80
|
+
|
|
81
|
+
def acc_name = items[0]
|
|
82
|
+
|
|
83
|
+
def initial = items[1]
|
|
84
|
+
|
|
85
|
+
def counter = items[2]
|
|
86
|
+
|
|
87
|
+
def start = items[3]
|
|
88
|
+
|
|
89
|
+
def finish = items[4]
|
|
90
|
+
|
|
91
|
+
def step = items[5]
|
|
92
|
+
end
|
|
93
|
+
CountedForForm = Struct.new(:bindings, :body, keyword_init: true) do
|
|
94
|
+
def items = bindings.is_a?(Vec) ? bindings.items : []
|
|
95
|
+
|
|
96
|
+
def counter = items[0]
|
|
97
|
+
|
|
98
|
+
def start = items[1]
|
|
99
|
+
|
|
100
|
+
def finish = items[2]
|
|
101
|
+
|
|
102
|
+
def extras = items[3..] || []
|
|
103
|
+
|
|
104
|
+
def each_extra
|
|
105
|
+
i = 0
|
|
106
|
+
while i < extras.length
|
|
107
|
+
item = extras[i]
|
|
108
|
+
if item.is_a?(Sym) && item.name == '&until'
|
|
109
|
+
yield :until, extras[i + 1]
|
|
110
|
+
i += 2
|
|
111
|
+
else
|
|
112
|
+
yield :step, item
|
|
113
|
+
i += 1
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
FUNCTION_HEADS = %w[fn lambda λ].freeze
|
|
120
|
+
FUNCTION_DEFINITION_HEADS = (FUNCTION_HEADS + %w[defn]).freeze
|
|
121
|
+
MACRO_FUNCTION_HEADS = (FUNCTION_HEADS + %w[macro]).freeze
|
|
122
|
+
BINDING_HEADS = %w[local var].freeze
|
|
123
|
+
HEADER_HEADS = %w[class module].freeze
|
|
124
|
+
HEADER_SCOPES = %i[module class].freeze
|
|
125
|
+
DEFINITION_SCOPES = ([:toplevel] + HEADER_SCOPES).freeze
|
|
126
|
+
THREAD_HEADS = %w[-> ->> -?> -?>>].freeze
|
|
127
|
+
PIPELINE_HEADS = (THREAD_HEADS + %w[doto]).freeze
|
|
128
|
+
SHORT_PIPELINE_HEADS = %w[-?> -?>>].freeze
|
|
129
|
+
THREAD_FIRST_HEADS = %w[-> -?>].freeze
|
|
130
|
+
SEQUENCE_STATEMENT_HEADS = %w[let while for each case match].freeze
|
|
131
|
+
MULTILINE_BODY_HEADS = %w[
|
|
132
|
+
if case match let try catch finally do for -> ->> -?> -?>> doto
|
|
133
|
+
fn lambda λ macro
|
|
134
|
+
].freeze
|
|
135
|
+
FLAT_BODY_HEADS = %w[
|
|
136
|
+
fn lambda λ macro when unless for each icollect collect fcollect
|
|
137
|
+
accumulate faccumulate
|
|
138
|
+
].freeze
|
|
139
|
+
NEVER_FLAT_HEADS = %w[let case match try catch finally do -> ->> -?> -?>> doto].freeze
|
|
140
|
+
QUASI_HEADS = %w[
|
|
141
|
+
quasi-sym quasi-list quasi-list-tail quasi-vec quasi-vec-tail
|
|
142
|
+
quasi-hash quasi-gensym
|
|
143
|
+
].freeze
|
|
144
|
+
CORE_SPECIAL_FORMS = %w[
|
|
145
|
+
fn defn lambda λ let local var global set if when unless case match
|
|
146
|
+
while for each do values
|
|
147
|
+
-> ->> -?> -?>> doto
|
|
148
|
+
icollect collect fcollect accumulate faccumulate
|
|
149
|
+
hashfn
|
|
150
|
+
. ?: :
|
|
151
|
+
..
|
|
152
|
+
length
|
|
153
|
+
require
|
|
154
|
+
module class end
|
|
155
|
+
try catch finally
|
|
156
|
+
raise
|
|
157
|
+
ivar cvar gvar
|
|
158
|
+
ruby
|
|
159
|
+
tset
|
|
160
|
+
and or not
|
|
161
|
+
= not= < <= > >=
|
|
162
|
+
+ - * / %
|
|
163
|
+
print
|
|
164
|
+
macro macros import-macros
|
|
165
|
+
quasi-sym quasi-list quasi-list-tail quasi-vec quasi-vec-tail quasi-hash quasi-gensym
|
|
166
|
+
].freeze
|
|
167
|
+
SPECIAL_FORMS = (CORE_SPECIAL_FORMS + LuaCompat::SPECIAL_FORMS).freeze
|
|
168
|
+
|
|
169
|
+
module_function
|
|
170
|
+
|
|
171
|
+
def list_head(form)
|
|
172
|
+
return unless form.is_a?(List) && !form.empty?
|
|
173
|
+
|
|
174
|
+
form.head
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def list_head_name(form)
|
|
178
|
+
head = list_head(form)
|
|
179
|
+
head.name if head.is_a?(Sym)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def list_head?(form, *names)
|
|
183
|
+
name = list_head_name(form)
|
|
184
|
+
!name.nil? && names.flatten.include?(name)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def end_form?(form) = list_head?(form, 'end')
|
|
188
|
+
|
|
189
|
+
def do_form?(form) = list_head?(form, 'do')
|
|
190
|
+
|
|
191
|
+
def defn_form?(form) = list_head?(form, 'defn')
|
|
192
|
+
|
|
193
|
+
def header_form?(form)
|
|
194
|
+
name = list_head_name(form)
|
|
195
|
+
!name.nil? && header_head?(name)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def sequence_statement_form?(form)
|
|
199
|
+
name = list_head_name(form)
|
|
200
|
+
!name.nil? && sequence_statement_head?(name)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def binding_form?(form)
|
|
204
|
+
name = list_head_name(form)
|
|
205
|
+
!name.nil? && binding_head?(name)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def special_form?(name) = SPECIAL_FORMS.include?(name)
|
|
209
|
+
|
|
210
|
+
def function_head?(name) = FUNCTION_HEADS.include?(name)
|
|
211
|
+
|
|
212
|
+
def function_definition_head?(name) = FUNCTION_DEFINITION_HEADS.include?(name)
|
|
213
|
+
|
|
214
|
+
def macro_function_head?(name) = MACRO_FUNCTION_HEADS.include?(name)
|
|
215
|
+
|
|
216
|
+
def binding_head?(name) = BINDING_HEADS.include?(name)
|
|
217
|
+
|
|
218
|
+
def header_head?(name) = HEADER_HEADS.include?(name)
|
|
219
|
+
|
|
220
|
+
def header_scope?(scope) = HEADER_SCOPES.include?(scope)
|
|
221
|
+
|
|
222
|
+
def definition_scope?(scope) = DEFINITION_SCOPES.include?(scope)
|
|
223
|
+
|
|
224
|
+
def pipeline_head?(name) = PIPELINE_HEADS.include?(name)
|
|
225
|
+
|
|
226
|
+
def short_pipeline_head?(name) = SHORT_PIPELINE_HEADS.include?(name)
|
|
227
|
+
|
|
228
|
+
def thread_first_head?(name) = THREAD_FIRST_HEADS.include?(name)
|
|
229
|
+
|
|
230
|
+
def sequence_statement_head?(name) = SEQUENCE_STATEMENT_HEADS.include?(name)
|
|
231
|
+
|
|
232
|
+
def multiline_body_head?(name) = MULTILINE_BODY_HEADS.include?(name)
|
|
233
|
+
|
|
234
|
+
def flat_body_head?(name) = FLAT_BODY_HEADS.include?(name)
|
|
235
|
+
|
|
236
|
+
def never_flat_head?(name) = NEVER_FLAT_HEADS.include?(name)
|
|
237
|
+
|
|
238
|
+
def quasi_head?(name) = QUASI_HEADS.include?(name)
|
|
239
|
+
|
|
240
|
+
def bodyless_header?(form)
|
|
241
|
+
return false unless header_form?(form)
|
|
242
|
+
|
|
243
|
+
case form.head.name
|
|
244
|
+
when 'module'
|
|
245
|
+
parsed = parse_module_form(form)
|
|
246
|
+
parsed.body.empty? || (parsed.body.length == 1 && bodyless_header?(parsed.body[0]))
|
|
247
|
+
when 'class'
|
|
248
|
+
parse_class_form(form).body.empty?
|
|
249
|
+
else
|
|
250
|
+
false
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def function_form?(form, heads: FUNCTION_HEADS)
|
|
255
|
+
!parse_function_form(form, heads:).nil?
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def parse_function_form(form, heads: FUNCTION_HEADS)
|
|
259
|
+
return unless list_head?(form, heads)
|
|
260
|
+
|
|
261
|
+
parse_function_args(form.rest, head: form.head)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def parse_function_args(args, head: nil)
|
|
265
|
+
if args[0].is_a?(Vec)
|
|
266
|
+
FunctionForm.new(head:, name: nil, params: args[0], body: args[1..] || [], prefix_length: 1)
|
|
267
|
+
elsif args[0].is_a?(Sym) && args[1].is_a?(Vec)
|
|
268
|
+
FunctionForm.new(head:, name: args[0], params: args[1], body: args[2..] || [], prefix_length: 2)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def parse_class_form(form)
|
|
273
|
+
return unless list_head?(form, 'class')
|
|
274
|
+
|
|
275
|
+
parse_class_args(form.rest)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def parse_module_form(form)
|
|
279
|
+
return unless list_head?(form, 'module')
|
|
280
|
+
|
|
281
|
+
parse_module_args(form.rest)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def parse_module_args(args)
|
|
285
|
+
ModuleForm.new(name: args[0], body: args[1..] || [], prefix_length: 1)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def parse_class_args(args)
|
|
289
|
+
if args[1].is_a?(Vec)
|
|
290
|
+
ClassForm.new(name: args[0], supers: args[1], body: args[2..] || [], prefix_length: 2)
|
|
291
|
+
else
|
|
292
|
+
ClassForm.new(name: args[0], supers: nil, body: args[1..] || [], prefix_length: 1)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def parse_try_args(args)
|
|
297
|
+
TryForm.new(body: args[0], clauses: (args[1..] || []).filter_map { |clause| parse_try_clause(clause) })
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def parse_try_clause(clause)
|
|
301
|
+
return unless list_head_name(clause)
|
|
302
|
+
|
|
303
|
+
case clause.head.name
|
|
304
|
+
when 'catch' then parse_catch_clause(clause.rest)
|
|
305
|
+
when 'finally' then FinallyClause.new(body: clause.rest)
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def parse_catch_clause(args)
|
|
310
|
+
if exception_class_form?(args[0])
|
|
311
|
+
CatchClause.new(klass: args[0], bind_sym: args[1], body: args[2..] || [])
|
|
312
|
+
else
|
|
313
|
+
CatchClause.new(klass: nil, bind_sym: args[0], body: args[1..] || [])
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def exception_class_form?(form)
|
|
318
|
+
form.is_a?(Sym) && (form.name.match?(/\A[A-Z]/) || form.dotted?)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def parse_binding_form(form)
|
|
322
|
+
return unless binding_form?(form)
|
|
323
|
+
|
|
324
|
+
parse_binding_args(form.head.name, form.rest)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def parse_binding_args(head, args)
|
|
328
|
+
return unless args.length == 2
|
|
329
|
+
|
|
330
|
+
BindingForm.new(head:, target: args[0], value: args[1])
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def parse_global_args(args)
|
|
334
|
+
return unless args.length == 2
|
|
335
|
+
|
|
336
|
+
GlobalForm.new(name: args[0], value: args[1])
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def parse_global_form(form)
|
|
340
|
+
return unless list_head?(form, 'global')
|
|
341
|
+
|
|
342
|
+
parse_global_args(form.rest)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def parse_set_form(form)
|
|
346
|
+
return unless list_head?(form, 'set')
|
|
347
|
+
|
|
348
|
+
parse_set_args(form.rest)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def parse_set_args(args)
|
|
352
|
+
SetForm.new(target: args[0], value: args[1])
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def parse_dot_target(form)
|
|
356
|
+
return unless list_head?(form, ':')
|
|
357
|
+
|
|
358
|
+
DotTarget.new(object: form.items[1], keys: form.items[2..] || [])
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def parse_tset_args(args)
|
|
362
|
+
return unless args.length >= 3
|
|
363
|
+
|
|
364
|
+
TsetForm.new(table: args[0], key: args[1], value: args[2])
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def parse_conditional_body_args(args)
|
|
368
|
+
ConditionalBodyForm.new(condition: args[0], body: args[1..] || [])
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def parse_values_form(form)
|
|
372
|
+
return unless list_head?(form, 'values') && form.items.length == 3
|
|
373
|
+
|
|
374
|
+
ValuesForm.new(key: form.items[1], value: form.items[2])
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def parse_lua_iterator_form(form)
|
|
378
|
+
head = list_head(form)
|
|
379
|
+
return unless head.is_a?(Sym) && LuaCompat.iterator_form?(head.name)
|
|
380
|
+
|
|
381
|
+
LuaIteratorForm.new(head:, collection: form.items[1])
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def parse_lua_pcall_args(args)
|
|
385
|
+
LuaPcallForm.new(callable: args[0], args: args[1..] || [])
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def parse_lua_xpcall_args(args)
|
|
389
|
+
LuaXpcallForm.new(callable: args[0], handler: args[1], args: args[2..] || [])
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def parse_sigil_form(form)
|
|
393
|
+
head = list_head_name(form)
|
|
394
|
+
return unless head
|
|
395
|
+
|
|
396
|
+
parse_sigil_args(head, form.rest)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def parse_sigil_args(head, args)
|
|
400
|
+
return unless %w[ivar cvar gvar].include?(head)
|
|
401
|
+
|
|
402
|
+
SigilForm.new(head:, name: args[0])
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def parse_hashfn_form(form)
|
|
406
|
+
return unless list_head?(form, 'hashfn')
|
|
407
|
+
|
|
408
|
+
HashFnForm.new(body: form.rest)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def parse_macro_definition_args(args)
|
|
412
|
+
MacroDefinitionForm.new(name: args[0], params: args[1], body: args[2..] || [])
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def parse_macro_definition_form(form)
|
|
416
|
+
return unless list_head?(form, 'macro')
|
|
417
|
+
|
|
418
|
+
parse_macro_definition_args(form.rest)
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def parse_import_macros_args(args)
|
|
422
|
+
ImportMacrosForm.new(destructure: args[0], module_arg: args[1])
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def parse_import_macros_form(form)
|
|
426
|
+
return unless list_head?(form, 'import-macros')
|
|
427
|
+
|
|
428
|
+
parse_import_macros_args(form.rest)
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def parse_let_args(args)
|
|
432
|
+
LetForm.new(bindings: args[0], body: args[1..] || [])
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def parse_let_form(form)
|
|
436
|
+
return unless list_head?(form, 'let')
|
|
437
|
+
|
|
438
|
+
parse_let_args(form.rest)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def parse_case_args(args)
|
|
442
|
+
CaseForm.new(subject: args[0], clauses: args[1..] || [])
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def parse_case_form(form)
|
|
446
|
+
return unless list_head?(form, %w[case match])
|
|
447
|
+
|
|
448
|
+
parse_case_args(form.rest)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def parse_try_form(form)
|
|
452
|
+
return unless list_head?(form, 'try')
|
|
453
|
+
|
|
454
|
+
parse_try_args(form.rest)
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def parse_where_pattern(pattern)
|
|
458
|
+
return unless list_head?(pattern, 'where')
|
|
459
|
+
|
|
460
|
+
WherePattern.new(inner: pattern.items[1], guards: pattern.items[2..] || [])
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def parse_or_pattern(pattern)
|
|
464
|
+
return unless list_head?(pattern, 'or')
|
|
465
|
+
|
|
466
|
+
OrPattern.new(alternatives: pattern.items[1..] || [])
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def parse_pin_pattern(pattern)
|
|
470
|
+
return unless list_head?(pattern, '=') && pattern.items.length == 2
|
|
471
|
+
|
|
472
|
+
PinPattern.new(name: pattern.items[1])
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def parse_unpack_call(form)
|
|
476
|
+
return unless list_head?(form, 'unpack')
|
|
477
|
+
|
|
478
|
+
UnpackCall.new(value: form.items[1])
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
def parse_iteration_args(args)
|
|
482
|
+
IterationForm.new(bindings: args[0], body: args[1..] || [])
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
def parse_iteration_form(form)
|
|
486
|
+
return unless list_head?(form, %w[each collect icollect])
|
|
487
|
+
|
|
488
|
+
parse_iteration_args(form.rest)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def parse_accumulate_args(args)
|
|
492
|
+
AccumulateForm.new(bindings: args[0], body: args[1..] || [])
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def parse_accumulate_form(form)
|
|
496
|
+
return unless list_head?(form, 'accumulate')
|
|
497
|
+
|
|
498
|
+
parse_accumulate_args(form.rest)
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def parse_faccumulate_args(args)
|
|
502
|
+
FaccumulateForm.new(bindings: args[0], body: args[1..] || [])
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def parse_faccumulate_form(form)
|
|
506
|
+
return unless list_head?(form, 'faccumulate')
|
|
507
|
+
|
|
508
|
+
parse_faccumulate_args(form.rest)
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
def parse_counted_for_args(args)
|
|
512
|
+
CountedForForm.new(bindings: args[0], body: args[1..] || [])
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def parse_counted_for_form(form)
|
|
516
|
+
return unless list_head?(form, %w[for fcollect])
|
|
517
|
+
|
|
518
|
+
parse_counted_for_args(form.rest)
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
end
|
|
@@ -25,25 +25,22 @@ module Kapusta
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def normalize_lua_pcall(items)
|
|
28
|
-
|
|
29
|
-
args = items[2..]
|
|
28
|
+
parsed = Language.parse_lua_pcall_args(items[1..] || [])
|
|
30
29
|
List.new([
|
|
31
30
|
Sym.new('try'),
|
|
32
|
-
List.new([Sym.new('values'), true, List.new([
|
|
31
|
+
List.new([Sym.new('values'), true, List.new([parsed.callable, *parsed.args])]),
|
|
33
32
|
List.new([Sym.new('catch'), Sym.new('StandardError'), Sym.new('e'),
|
|
34
33
|
List.new([Sym.new('values'), false, Sym.new('e')])])
|
|
35
34
|
])
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
def normalize_lua_xpcall(items)
|
|
39
|
-
|
|
40
|
-
handler = items[2]
|
|
41
|
-
args = items[3..]
|
|
38
|
+
parsed = Language.parse_lua_xpcall_args(items[1..] || [])
|
|
42
39
|
List.new([
|
|
43
40
|
Sym.new('try'),
|
|
44
|
-
List.new([Sym.new('values'), true, List.new([
|
|
41
|
+
List.new([Sym.new('values'), true, List.new([parsed.callable, *parsed.args])]),
|
|
45
42
|
List.new([Sym.new('catch'), Sym.new('StandardError'), Sym.new('e'),
|
|
46
|
-
List.new([Sym.new('values'), false, List.new([handler, Sym.new('e')])])])
|
|
43
|
+
List.new([Sym.new('values'), false, List.new([parsed.handler, Sym.new('e')])])])
|
|
47
44
|
])
|
|
48
45
|
end
|
|
49
46
|
end
|
|
@@ -53,39 +50,37 @@ module Kapusta
|
|
|
53
50
|
|
|
54
51
|
def emit_lua_compat_inject(iter_expr, binding_pats, body_env, env, current_scope, acc_var,
|
|
55
52
|
init_code, body_forms)
|
|
56
|
-
|
|
53
|
+
parsed = Language.parse_lua_iterator_form(iter_expr)
|
|
54
|
+
return unless parsed
|
|
57
55
|
|
|
58
|
-
case
|
|
56
|
+
case parsed.name
|
|
59
57
|
when 'ipairs'
|
|
60
|
-
emit_lua_ipairs_inject(
|
|
58
|
+
emit_lua_ipairs_inject(parsed, binding_pats, body_env, env, current_scope,
|
|
61
59
|
acc_var, init_code, body_forms)
|
|
62
60
|
when 'pairs'
|
|
63
|
-
emit_lua_pairs_inject(
|
|
61
|
+
emit_lua_pairs_inject(parsed, binding_pats, body_env, env, current_scope,
|
|
64
62
|
acc_var, init_code, body_forms)
|
|
65
63
|
end
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
def emit_lua_compat_iteration(iter_expr, binding_pats, env, current_scope, method:,
|
|
69
67
|
extra_block_param: nil, &block)
|
|
70
|
-
|
|
68
|
+
parsed = Language.parse_lua_iterator_form(iter_expr)
|
|
69
|
+
return unless parsed
|
|
71
70
|
|
|
72
|
-
case
|
|
71
|
+
case parsed.name
|
|
73
72
|
when 'ipairs'
|
|
74
|
-
emit_lua_ipairs_iteration(
|
|
73
|
+
emit_lua_ipairs_iteration(parsed, binding_pats, env, current_scope,
|
|
75
74
|
method:, extra_block_param:, &block)
|
|
76
75
|
when 'pairs'
|
|
77
|
-
emit_lua_pairs_iteration(
|
|
76
|
+
emit_lua_pairs_iteration(parsed, binding_pats, env, current_scope,
|
|
78
77
|
method:, extra_block_param:, &block)
|
|
79
78
|
end
|
|
80
79
|
end
|
|
81
80
|
|
|
82
|
-
def
|
|
83
|
-
expr.is_a?(List) && expr.head.is_a?(Sym) && LuaCompat.iterator_form?(expr.head.name)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def emit_lua_ipairs_inject(iter_expr, binding_pats, body_env, env, current_scope, acc_var,
|
|
81
|
+
def emit_lua_ipairs_inject(iter_form, binding_pats, body_env, env, current_scope, acc_var,
|
|
87
82
|
init_code, body_forms)
|
|
88
|
-
coll_code = emit_expr(
|
|
83
|
+
coll_code = emit_expr(iter_form.collection, env, current_scope)
|
|
89
84
|
value_var, value_bind = bind_iteration_param(binding_pats[1], 'value', body_env)
|
|
90
85
|
if ignored_pattern?(binding_pats[0])
|
|
91
86
|
body_code, = emit_sequence(body_forms, body_env, current_scope, allow_method_definitions: false)
|
|
@@ -99,22 +94,22 @@ module Kapusta
|
|
|
99
94
|
init_code, bind_code, body_code)
|
|
100
95
|
end
|
|
101
96
|
|
|
102
|
-
def emit_lua_pairs_inject(
|
|
97
|
+
def emit_lua_pairs_inject(iter_form, binding_pats, body_env, env, current_scope, acc_var,
|
|
103
98
|
init_code, body_forms)
|
|
104
99
|
key_var, key_bind = bind_iteration_param(binding_pats[0], 'key', body_env)
|
|
105
100
|
value_var, value_bind = bind_iteration_param(binding_pats[1], 'value', body_env)
|
|
106
101
|
bind_code = [key_bind, value_bind].compact.join("\n")
|
|
107
102
|
body_code, = emit_sequence(body_forms, body_env, current_scope, allow_method_definitions: false)
|
|
108
|
-
coll_code = emit_expr(
|
|
103
|
+
coll_code = emit_expr(iter_form.collection, env, current_scope)
|
|
109
104
|
inject_block(coll_code, "#{acc_var}, (#{key_var}, #{value_var})",
|
|
110
105
|
init_code, bind_code, body_code)
|
|
111
106
|
end
|
|
112
107
|
|
|
113
|
-
def emit_lua_ipairs_iteration(
|
|
108
|
+
def emit_lua_ipairs_iteration(iter_form, binding_pats, env, current_scope, method:,
|
|
114
109
|
extra_block_param: nil, &block)
|
|
115
110
|
body_env = env.child
|
|
116
111
|
value_var, value_bind = bind_iteration_param(binding_pats[1], 'value', body_env)
|
|
117
|
-
coll_code = emit_expr(
|
|
112
|
+
coll_code = emit_expr(iter_form.collection, env, current_scope)
|
|
118
113
|
if ignored_pattern?(binding_pats[0])
|
|
119
114
|
bind_code = value_bind || ''
|
|
120
115
|
body_code = block.call(body_env)
|
|
@@ -131,14 +126,14 @@ module Kapusta
|
|
|
131
126
|
iteration_block("#{receiver} do |#{params}|", bind_code, body_code)
|
|
132
127
|
end
|
|
133
128
|
|
|
134
|
-
def emit_lua_pairs_iteration(
|
|
129
|
+
def emit_lua_pairs_iteration(iter_form, binding_pats, env, current_scope, method:,
|
|
135
130
|
extra_block_param: nil, &block)
|
|
136
131
|
body_env = env.child
|
|
137
132
|
key_var, key_bind = bind_iteration_param(binding_pats[0], 'key', body_env)
|
|
138
133
|
value_var, value_bind = bind_iteration_param(binding_pats[1], 'value', body_env)
|
|
139
134
|
bind_code = [key_bind, value_bind].compact.join("\n")
|
|
140
135
|
body_code = block.call(body_env)
|
|
141
|
-
coll_code = emit_expr(
|
|
136
|
+
coll_code = emit_expr(iter_form.collection, env, current_scope)
|
|
142
137
|
inner_params = "#{key_var}, #{value_var}"
|
|
143
138
|
params = extra_block_param ? "(#{inner_params}), #{extra_block_param}" : inner_params
|
|
144
139
|
iteration_block("#{coll_code}.#{method} do |#{params}|", bind_code, body_code)
|