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
|
@@ -15,7 +15,7 @@ module Kapusta
|
|
|
15
15
|
return false if name.match?(/[#{Regexp.escape(DELIM_CHARS)}]/o)
|
|
16
16
|
return false if name.match?(/\A-?\d/)
|
|
17
17
|
return false if name.include?('.')
|
|
18
|
-
return false if Kapusta::Compiler::
|
|
18
|
+
return false if Kapusta::Compiler::Language.special_form?(name)
|
|
19
19
|
|
|
20
20
|
true
|
|
21
21
|
end
|
data/lib/kapusta/lsp/rename.rb
CHANGED
|
@@ -64,7 +64,7 @@ module Kapusta
|
|
|
64
64
|
return if synthetic?(sym)
|
|
65
65
|
|
|
66
66
|
seg = segment_at_column(sym, col)
|
|
67
|
-
return unless seg && seg[:index] != :
|
|
67
|
+
return unless seg && seg[:index] != :on_delimiter
|
|
68
68
|
|
|
69
69
|
binding = walker.bindings.find { |b| b.sym.equal?(sym) }
|
|
70
70
|
reference = walker.references.find { |r| r.sym.equal?(sym) }
|
|
@@ -98,7 +98,7 @@ module Kapusta
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def segment_at_column(sym, col)
|
|
101
|
-
unless sym
|
|
101
|
+
unless path_sym?(sym)
|
|
102
102
|
start_col = sym.column
|
|
103
103
|
end_col = sym.column + sym.name.length
|
|
104
104
|
return unless col.between?(start_col, end_col)
|
|
@@ -107,14 +107,14 @@ module Kapusta
|
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
pos = sym.column
|
|
110
|
-
segments = sym
|
|
110
|
+
segments = path_segments(sym)
|
|
111
111
|
segments.each_with_index do |seg, k|
|
|
112
112
|
seg_start = pos
|
|
113
113
|
seg_end = pos + seg.length
|
|
114
114
|
return { index: k, start: seg_start, end: seg_end } if col >= seg_start && col < seg_end
|
|
115
115
|
|
|
116
116
|
if k < segments.length - 1
|
|
117
|
-
return { index: :
|
|
117
|
+
return { index: :on_delimiter, start: seg_end, end: seg_end + 1 } if col == seg_end
|
|
118
118
|
elsif col == seg_end
|
|
119
119
|
return { index: k, start: seg_start, end: seg_end }
|
|
120
120
|
end
|
|
@@ -124,13 +124,15 @@ module Kapusta
|
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
def classify(walker, sym, binding, reference, seg)
|
|
127
|
+
return if sym.colonized? && seg[:index].positive?
|
|
128
|
+
|
|
127
129
|
if sym.dotted? && seg[:index].positive?
|
|
128
130
|
segment_text = sym.segments[seg[:index]]
|
|
129
131
|
return if segment_text.match?(/\A[a-z]/)
|
|
130
132
|
end
|
|
131
133
|
|
|
132
134
|
if binding
|
|
133
|
-
return constant_target(walker, binding, seg) if
|
|
135
|
+
return constant_target(walker, binding, seg) if Compiler::Language.header_scope?(binding.kind)
|
|
134
136
|
|
|
135
137
|
return local_target(walker, binding, seg)
|
|
136
138
|
end
|
|
@@ -138,17 +140,17 @@ module Kapusta
|
|
|
138
140
|
if reference
|
|
139
141
|
target = reference.target
|
|
140
142
|
if target
|
|
141
|
-
return constant_target(walker, target, seg, sym:) if
|
|
143
|
+
return constant_target(walker, target, seg, sym:) if Compiler::Language.header_scope?(target.kind)
|
|
142
144
|
|
|
143
145
|
return local_target(walker, target, seg, sym:)
|
|
144
146
|
end
|
|
145
147
|
end
|
|
146
148
|
|
|
147
|
-
first_seg = sym
|
|
149
|
+
first_seg = path_sym?(sym) ? path_segments(sym).first : sym.name
|
|
148
150
|
if first_seg.match?(/\A[A-Z]/)
|
|
149
151
|
Target.new(
|
|
150
152
|
kind: :free_constant, sym:, name: sym.name,
|
|
151
|
-
segment_index: seg[:index], segment_prefix: (sym.dotted? ? sym.segments[0..seg[:index]] : [
|
|
153
|
+
segment_index: seg[:index], segment_prefix: (sym.dotted? ? sym.segments[0..seg[:index]] : [first_seg]),
|
|
152
154
|
seg_start: seg[:start], seg_end: seg[:end], walker:
|
|
153
155
|
)
|
|
154
156
|
else
|
|
@@ -392,9 +394,9 @@ module Kapusta
|
|
|
392
394
|
end
|
|
393
395
|
|
|
394
396
|
def segment_range(sym, segment_index)
|
|
395
|
-
return [sym.column, sym.column + sym.name.length] unless sym
|
|
397
|
+
return [sym.column, sym.column + sym.name.length] unless path_sym?(sym)
|
|
396
398
|
|
|
397
|
-
segments = sym
|
|
399
|
+
segments = path_segments(sym)
|
|
398
400
|
prior = segments[0...segment_index].sum { |s| s.length + 1 }
|
|
399
401
|
start_col = sym.column + prior
|
|
400
402
|
[start_col, start_col + segments[segment_index].length]
|
|
@@ -415,7 +417,7 @@ module Kapusta
|
|
|
415
417
|
|
|
416
418
|
def text_edit_first_segment(occurrence, new_name)
|
|
417
419
|
sym = occurrence.sym
|
|
418
|
-
return text_edit_full(occurrence, new_name) unless sym.is_a?(Sym) && sym
|
|
420
|
+
return text_edit_full(occurrence, new_name) unless sym.is_a?(Sym) && path_sym?(sym)
|
|
419
421
|
|
|
420
422
|
seg_start, seg_end = segment_range(sym, 0)
|
|
421
423
|
{
|
|
@@ -430,6 +432,14 @@ module Kapusta
|
|
|
430
432
|
def error(message)
|
|
431
433
|
{ error: { code: RESPONSE_REQUEST_FAILED, message: } }
|
|
432
434
|
end
|
|
435
|
+
|
|
436
|
+
def path_sym?(sym)
|
|
437
|
+
sym.dotted? || sym.colonized?
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def path_segments(sym)
|
|
441
|
+
sym.dotted? ? sym.segments : sym.colon_segments
|
|
442
|
+
end
|
|
433
443
|
end
|
|
434
444
|
end
|
|
435
445
|
end
|
|
@@ -19,22 +19,12 @@ module Kapusta
|
|
|
19
19
|
|
|
20
20
|
DISPATCHERS = {
|
|
21
21
|
'macros' => :skip,
|
|
22
|
-
|
|
23
|
-
'quasi-list' => :skip,
|
|
24
|
-
'quasi-list-tail' => :skip,
|
|
25
|
-
'quasi-vec' => :skip,
|
|
26
|
-
'quasi-vec-tail' => :skip,
|
|
27
|
-
'quasi-hash' => :skip,
|
|
28
|
-
'quasi-gensym' => :skip,
|
|
22
|
+
**Compiler::Language::QUASI_HEADS.to_h { |head| [head, :skip] },
|
|
29
23
|
'let' => :walk_let,
|
|
30
|
-
|
|
31
|
-
'var' => :walk_local_var,
|
|
24
|
+
**Compiler::Language::BINDING_HEADS.to_h { |head| [head, :walk_local_var] },
|
|
32
25
|
'global' => :walk_global,
|
|
33
26
|
'set' => :walk_set,
|
|
34
|
-
|
|
35
|
-
'defn' => :walk_fn,
|
|
36
|
-
'lambda' => :walk_fn,
|
|
37
|
-
'λ' => :walk_fn,
|
|
27
|
+
**Compiler::Language::FUNCTION_DEFINITION_HEADS.to_h { |head| [head, :walk_fn] },
|
|
38
28
|
'for' => :walk_for,
|
|
39
29
|
'each' => :walk_each_like,
|
|
40
30
|
'collect' => :walk_each_like,
|
|
@@ -98,7 +88,7 @@ module Kapusta
|
|
|
98
88
|
return i + 1
|
|
99
89
|
end
|
|
100
90
|
|
|
101
|
-
if bodyless_header?(form)
|
|
91
|
+
if Compiler::Language.bodyless_header?(form)
|
|
102
92
|
i = walk_bodyless_header(form, forms, i + 1, scope)
|
|
103
93
|
next
|
|
104
94
|
end
|
|
@@ -122,7 +112,7 @@ module Kapusta
|
|
|
122
112
|
end
|
|
123
113
|
|
|
124
114
|
def end_form?(form)
|
|
125
|
-
|
|
115
|
+
Compiler::Language.end_form?(form)
|
|
126
116
|
end
|
|
127
117
|
|
|
128
118
|
def binding_at(line, column)
|
|
@@ -150,39 +140,23 @@ module Kapusta
|
|
|
150
140
|
Scope.new(@scope_seq, parent, {}, kind)
|
|
151
141
|
end
|
|
152
142
|
|
|
153
|
-
def bodyless_header?(form)
|
|
154
|
-
return false unless form.is_a?(List) && !form.empty? && form.head.is_a?(Sym)
|
|
155
|
-
|
|
156
|
-
case form.head.name
|
|
157
|
-
when 'module'
|
|
158
|
-
body = form.items[2..] || []
|
|
159
|
-
body.empty? || (body.length == 1 && bodyless_header?(body[0]))
|
|
160
|
-
when 'class'
|
|
161
|
-
_name_sym, _supers, body = split_class_args(form.items[1..] || [])
|
|
162
|
-
body.empty?
|
|
163
|
-
else
|
|
164
|
-
false
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
143
|
def walk_bodyless_header(form, forms, body_start, scope)
|
|
169
144
|
case form.head.name
|
|
170
145
|
when 'module'
|
|
171
|
-
|
|
172
|
-
binding =
|
|
173
|
-
body = form.items[2..] || []
|
|
146
|
+
parsed = Compiler::Language.parse_module_form(form)
|
|
147
|
+
binding = parsed.name.is_a?(Sym) ? add_constant_binding(parsed.name, scope, :module) : nil
|
|
174
148
|
inside_module_or_class do
|
|
175
|
-
if body.length == 1 && bodyless_header?(body[0])
|
|
176
|
-
walk_bodyless_header(body[0], forms, body_start, scope)
|
|
149
|
+
if parsed.body.length == 1 && Compiler::Language.bodyless_header?(parsed.body[0])
|
|
150
|
+
walk_bodyless_header(parsed.body[0], forms, body_start, scope)
|
|
177
151
|
else
|
|
178
152
|
body_scope = make_scope(scope, :module)
|
|
179
153
|
walk_form_run(forms, body_start, body_scope, header_target: binding)
|
|
180
154
|
end
|
|
181
155
|
end
|
|
182
156
|
when 'class'
|
|
183
|
-
|
|
184
|
-
supers&.items&.each { |item| walk_form(item, scope) }
|
|
185
|
-
binding =
|
|
157
|
+
parsed = Compiler::Language.parse_class_form(form)
|
|
158
|
+
parsed.supers&.items&.each { |item| walk_form(item, scope) }
|
|
159
|
+
binding = parsed.name.is_a?(Sym) ? add_constant_binding(parsed.name, scope, :class) : nil
|
|
186
160
|
inside_class do
|
|
187
161
|
body_scope = make_scope(scope, :class)
|
|
188
162
|
walk_form_run(forms, body_start, body_scope, header_target: binding)
|
|
@@ -190,15 +164,6 @@ module Kapusta
|
|
|
190
164
|
end
|
|
191
165
|
end
|
|
192
166
|
|
|
193
|
-
def split_class_args(args)
|
|
194
|
-
name_sym = args[0]
|
|
195
|
-
if args[1].is_a?(Vec)
|
|
196
|
-
[name_sym, args[1], args[2..] || []]
|
|
197
|
-
else
|
|
198
|
-
[name_sym, nil, args[1..] || []]
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
|
|
202
167
|
def inside_module_or_class
|
|
203
168
|
@in_module_or_class += 1
|
|
204
169
|
yield
|
|
@@ -275,62 +240,51 @@ module Kapusta
|
|
|
275
240
|
end
|
|
276
241
|
|
|
277
242
|
def walk_let(list, scope)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return unless bindings_vec.is_a?(Vec)
|
|
243
|
+
parsed = Compiler::Language.parse_let_form(list)
|
|
244
|
+
return unless parsed.bindings.is_a?(Vec)
|
|
281
245
|
|
|
282
246
|
let_scope = make_scope(scope, :let)
|
|
283
|
-
|
|
284
|
-
i = 0
|
|
285
|
-
while i < items.length
|
|
286
|
-
name_pat = items[i]
|
|
287
|
-
value = items[i + 1]
|
|
247
|
+
parsed.binding_pairs.each do |name_pat, value|
|
|
288
248
|
walk_form(value, let_scope) if value
|
|
289
249
|
bind_pattern(name_pat, let_scope, :let)
|
|
290
|
-
i += 2
|
|
291
250
|
end
|
|
292
|
-
body
|
|
251
|
+
parsed.body.each { |form| walk_form(form, let_scope) }
|
|
293
252
|
end
|
|
294
253
|
|
|
295
254
|
def walk_local_var(list, scope)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
walk_form(value, scope)
|
|
300
|
-
bind_pattern(target, scope,
|
|
255
|
+
parsed = Compiler::Language.parse_binding_form(list)
|
|
256
|
+
return unless parsed
|
|
257
|
+
|
|
258
|
+
walk_form(parsed.value, scope)
|
|
259
|
+
bind_pattern(parsed.target, scope, parsed.mutable? ? :var : :local)
|
|
301
260
|
end
|
|
302
261
|
|
|
303
262
|
def walk_global(list, _scope)
|
|
304
|
-
|
|
305
|
-
value
|
|
306
|
-
walk_form(value, @root_scope) if value
|
|
263
|
+
parsed = Compiler::Language.parse_global_form(list)
|
|
264
|
+
walk_form(parsed.value, @root_scope) if parsed
|
|
307
265
|
end
|
|
308
266
|
|
|
309
267
|
def walk_hashfn(list, scope)
|
|
310
|
-
list.
|
|
268
|
+
Compiler::Language.parse_hashfn_form(list).body.each { |form| walk_form(form, scope) }
|
|
311
269
|
end
|
|
312
270
|
|
|
313
271
|
def walk_macro_def(list, scope)
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
params = items[2]
|
|
317
|
-
body = items[3..] || []
|
|
318
|
-
return unless name_sym.is_a?(Sym) && params.is_a?(Vec)
|
|
272
|
+
parsed = Compiler::Language.parse_macro_definition_form(list)
|
|
273
|
+
return unless parsed.name.is_a?(Sym) && parsed.params.is_a?(Vec)
|
|
319
274
|
|
|
320
|
-
add_binding(
|
|
275
|
+
add_binding(parsed.name, @root_scope, :macro)
|
|
321
276
|
fn_scope = make_scope(scope, :fn)
|
|
322
|
-
bind_param_vec(params, fn_scope)
|
|
323
|
-
body.each { |form| walk_form(form, fn_scope) }
|
|
277
|
+
bind_param_vec(parsed.params, fn_scope)
|
|
278
|
+
parsed.body.each { |form| walk_form(form, fn_scope) }
|
|
324
279
|
end
|
|
325
280
|
|
|
326
281
|
def walk_import_macros(list, scope)
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return unless
|
|
330
|
-
return unless module_arg.is_a?(Symbol) || module_arg.is_a?(String)
|
|
282
|
+
parsed = Compiler::Language.parse_import_macros_form(list)
|
|
283
|
+
return unless parsed.destructure.is_a?(HashLit)
|
|
284
|
+
return unless parsed.module_arg.is_a?(Symbol) || parsed.module_arg.is_a?(String)
|
|
331
285
|
|
|
332
|
-
module_label = module_arg.to_s.tr('_', '-')
|
|
333
|
-
destructure.pairs.each do |key, target|
|
|
286
|
+
module_label = parsed.module_arg.to_s.tr('_', '-')
|
|
287
|
+
parsed.destructure.pairs.each do |key, target|
|
|
334
288
|
next unless target.is_a?(Sym) && key.is_a?(Symbol)
|
|
335
289
|
|
|
336
290
|
add_import_macro_binding(target, scope, module_label, key)
|
|
@@ -357,9 +311,9 @@ module Kapusta
|
|
|
357
311
|
end
|
|
358
312
|
|
|
359
313
|
def walk_set(list, scope)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
walk_form(value, scope) if value
|
|
314
|
+
parsed = Compiler::Language.parse_set_form(list)
|
|
315
|
+
target = parsed.target
|
|
316
|
+
walk_form(parsed.value, scope) if parsed.value
|
|
363
317
|
if target.is_a?(List)
|
|
364
318
|
walk_form(target, scope)
|
|
365
319
|
return
|
|
@@ -375,18 +329,15 @@ module Kapusta
|
|
|
375
329
|
end
|
|
376
330
|
|
|
377
331
|
def walk_sigil_form(list, _scope)
|
|
378
|
-
|
|
332
|
+
parsed = Compiler::Language.parse_sigil_form(list)
|
|
333
|
+
return unless parsed&.name.is_a?(Sym)
|
|
379
334
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
kind = list.head.name.to_sym
|
|
384
|
-
target_scope = sigil_target_scope(kind)
|
|
385
|
-
existing = target_scope.bindings[inner.name]
|
|
335
|
+
target_scope = sigil_target_scope(parsed.kind)
|
|
336
|
+
existing = target_scope.bindings[parsed.name.name]
|
|
386
337
|
if existing
|
|
387
|
-
add_reference(
|
|
338
|
+
add_reference(parsed.name, target_scope, existing)
|
|
388
339
|
else
|
|
389
|
-
add_binding(
|
|
340
|
+
add_binding(parsed.name, target_scope, parsed.kind)
|
|
390
341
|
end
|
|
391
342
|
end
|
|
392
343
|
|
|
@@ -398,32 +349,24 @@ module Kapusta
|
|
|
398
349
|
end
|
|
399
350
|
|
|
400
351
|
def walk_fn(list, scope)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
params = items[1]
|
|
405
|
-
body = items[2..]
|
|
406
|
-
elsif items[1].is_a?(Sym) && items[2].is_a?(Vec)
|
|
407
|
-
name_sym = items[1]
|
|
408
|
-
params = items[2]
|
|
409
|
-
body = items[3..]
|
|
410
|
-
else
|
|
411
|
-
items[1..]&.each { |item| walk_form(item, scope) }
|
|
352
|
+
parsed = Compiler::Language.parse_function_form(list, heads: Compiler::Language::FUNCTION_DEFINITION_HEADS)
|
|
353
|
+
unless parsed
|
|
354
|
+
list.items[1..]&.each { |item| walk_form(item, scope) }
|
|
412
355
|
return
|
|
413
356
|
end
|
|
414
357
|
|
|
415
358
|
fn_scope = make_scope(scope, :fn)
|
|
416
|
-
if
|
|
359
|
+
if parsed.named?
|
|
417
360
|
kind = if method_definition_context?
|
|
418
361
|
:method
|
|
419
362
|
else
|
|
420
363
|
(scope == @root_scope ? :toplevel_fn : :fn_local)
|
|
421
364
|
end
|
|
422
|
-
binding = add_binding(
|
|
423
|
-
fn_scope.bindings[
|
|
365
|
+
binding = add_binding(parsed.name, scope, kind, lexical: true)
|
|
366
|
+
fn_scope.bindings[parsed.name.name] = binding unless kind == :method
|
|
424
367
|
end
|
|
425
|
-
bind_param_vec(params, fn_scope)
|
|
426
|
-
body.each { |form| walk_form(form, fn_scope) }
|
|
368
|
+
bind_param_vec(parsed.params, fn_scope)
|
|
369
|
+
parsed.body.each { |form| walk_form(form, fn_scope) }
|
|
427
370
|
end
|
|
428
371
|
|
|
429
372
|
def method_definition_context?
|
|
@@ -431,94 +374,70 @@ module Kapusta
|
|
|
431
374
|
end
|
|
432
375
|
|
|
433
376
|
def walk_for(list, scope)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
return unless bindings_vec.is_a?(Vec)
|
|
377
|
+
parsed = Compiler::Language.parse_counted_for_form(list)
|
|
378
|
+
return unless parsed.bindings.is_a?(Vec)
|
|
437
379
|
|
|
438
380
|
for_scope = make_scope(scope, :for)
|
|
439
|
-
items = bindings_vec.items
|
|
440
|
-
counter = items[0]
|
|
441
|
-
i = 1
|
|
442
381
|
until_forms = []
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
else
|
|
449
|
-
walk_form(item, scope)
|
|
450
|
-
i += 1
|
|
451
|
-
end
|
|
382
|
+
[parsed.start, parsed.finish].compact.each { |form| walk_form(form, scope) }
|
|
383
|
+
parsed.each_extra do |kind, form|
|
|
384
|
+
next unless form
|
|
385
|
+
|
|
386
|
+
kind == :until ? until_forms << form : walk_form(form, scope)
|
|
452
387
|
end
|
|
453
|
-
bind_pattern(counter, for_scope, :for_counter) if counter
|
|
388
|
+
bind_pattern(parsed.counter, for_scope, :for_counter) if parsed.counter
|
|
454
389
|
until_forms.each { |form| walk_form(form, for_scope) }
|
|
455
|
-
body
|
|
390
|
+
parsed.body.each { |form| walk_form(form, for_scope) }
|
|
456
391
|
end
|
|
457
392
|
|
|
458
393
|
def walk_for_like(list, scope) = walk_for(list, scope)
|
|
459
394
|
|
|
460
395
|
def walk_each_like(list, scope)
|
|
461
|
-
|
|
462
|
-
|
|
396
|
+
parsed = Compiler::Language.parse_iteration_form(list)
|
|
397
|
+
bindings_vec = parsed.bindings
|
|
463
398
|
return unless bindings_vec.is_a?(Vec)
|
|
464
399
|
|
|
465
|
-
|
|
466
|
-
return if items.empty?
|
|
400
|
+
return if parsed.items.empty?
|
|
467
401
|
|
|
468
402
|
each_scope = make_scope(scope, :each)
|
|
469
|
-
iter_expr
|
|
470
|
-
|
|
471
|
-
walk_form(
|
|
472
|
-
binders.each { |b| bind_pattern(b, each_scope, :each_var) }
|
|
473
|
-
body&.each { |form| walk_form(form, each_scope) }
|
|
403
|
+
walk_form(parsed.iter_expr, scope)
|
|
404
|
+
parsed.binding_pats.each { |b| bind_pattern(b, each_scope, :each_var) }
|
|
405
|
+
parsed.body.each { |form| walk_form(form, each_scope) }
|
|
474
406
|
end
|
|
475
407
|
|
|
476
408
|
def walk_accumulate(list, scope)
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
return unless bindings_vec.is_a?(Vec)
|
|
409
|
+
parsed = Compiler::Language.parse_accumulate_form(list)
|
|
410
|
+
return unless parsed.bindings.is_a?(Vec)
|
|
480
411
|
|
|
481
|
-
|
|
482
|
-
return if items.length < 4
|
|
412
|
+
return if parsed.items.length < 4
|
|
483
413
|
|
|
484
414
|
acc_scope = make_scope(scope, :accumulate)
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
walk_form(acc_init, scope)
|
|
491
|
-
bind_pattern(acc_name, acc_scope, :accumulator)
|
|
492
|
-
walk_form(iter_expr, scope)
|
|
493
|
-
binders.each { |b| bind_pattern(b, acc_scope, :each_var) }
|
|
494
|
-
body&.each { |form| walk_form(form, acc_scope) }
|
|
415
|
+
walk_form(parsed.initial, scope)
|
|
416
|
+
bind_pattern(parsed.acc_name, acc_scope, :accumulator)
|
|
417
|
+
walk_form(parsed.iter_expr, scope)
|
|
418
|
+
parsed.binding_pats.each { |b| bind_pattern(b, acc_scope, :each_var) }
|
|
419
|
+
parsed.body.each { |form| walk_form(form, acc_scope) }
|
|
495
420
|
end
|
|
496
421
|
|
|
497
422
|
def walk_faccumulate(list, scope)
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
return unless bindings_vec.is_a?(Vec)
|
|
423
|
+
parsed = Compiler::Language.parse_faccumulate_form(list)
|
|
424
|
+
return unless parsed.bindings.is_a?(Vec)
|
|
501
425
|
|
|
502
|
-
|
|
503
|
-
return if items.length < 5
|
|
426
|
+
return if parsed.items.length < 5
|
|
504
427
|
|
|
505
428
|
acc_scope = make_scope(scope, :faccumulate)
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
bind_pattern(acc_name, acc_scope, :accumulator)
|
|
512
|
-
bind_pattern(counter, acc_scope, :for_counter)
|
|
513
|
-
body&.each { |form| walk_form(form, acc_scope) }
|
|
429
|
+
walk_form(parsed.initial, scope)
|
|
430
|
+
[parsed.start, parsed.finish, parsed.step].compact.each { |form| walk_form(form, scope) }
|
|
431
|
+
bind_pattern(parsed.acc_name, acc_scope, :accumulator)
|
|
432
|
+
bind_pattern(parsed.counter, acc_scope, :for_counter)
|
|
433
|
+
parsed.body.each { |form| walk_form(form, acc_scope) }
|
|
514
434
|
end
|
|
515
435
|
|
|
516
436
|
def walk_case_match(list, scope)
|
|
517
|
-
mode = list
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
arms.each_slice(2) do |pattern, body|
|
|
437
|
+
mode = Compiler::Language.list_head_name(list) == 'match' ? :match : :case
|
|
438
|
+
parsed = Compiler::Language.parse_case_form(list)
|
|
439
|
+
walk_form(parsed.subject, scope)
|
|
440
|
+
parsed.arm_pairs.each do |pattern, body|
|
|
522
441
|
arm_scope = make_scope(scope, :case_arm)
|
|
523
442
|
walk_pattern(pattern, arm_scope, scope, mode)
|
|
524
443
|
walk_form(body, arm_scope) if body
|
|
@@ -526,51 +445,39 @@ module Kapusta
|
|
|
526
445
|
end
|
|
527
446
|
|
|
528
447
|
def walk_try(list, scope)
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
next unless head.is_a?(Sym)
|
|
537
|
-
|
|
538
|
-
if head.name == 'catch'
|
|
539
|
-
walk_catch(clause, scope)
|
|
540
|
-
elsif head.name == 'finally'
|
|
541
|
-
clause.items[1..]&.each { |form| walk_form(form, scope) }
|
|
448
|
+
parsed = Compiler::Language.parse_try_form(list)
|
|
449
|
+
walk_form(parsed.body, scope)
|
|
450
|
+
parsed.clauses.each do |clause|
|
|
451
|
+
case clause
|
|
452
|
+
when Compiler::Language::CatchClause then walk_catch(clause, scope)
|
|
453
|
+
when Compiler::Language::FinallyClause
|
|
454
|
+
clause.body.each { |form| walk_form(form, scope) }
|
|
542
455
|
end
|
|
543
456
|
end
|
|
544
457
|
end
|
|
545
458
|
|
|
546
459
|
def walk_catch(clause, scope)
|
|
547
|
-
|
|
548
|
-
if rest[0].is_a?(Sym) && (rest[0].name.match?(/\A[A-Z]/) || rest[0].dotted?)
|
|
549
|
-
klass = rest[0]
|
|
550
|
-
bind_sym = rest[1]
|
|
551
|
-
body = rest[2..]
|
|
552
|
-
walk_form(klass, scope)
|
|
553
|
-
else
|
|
554
|
-
bind_sym = rest[0]
|
|
555
|
-
body = rest[1..]
|
|
556
|
-
end
|
|
460
|
+
walk_form(clause.klass, scope) if clause.klass
|
|
557
461
|
catch_scope = make_scope(scope, :catch)
|
|
558
|
-
bind_pattern(bind_sym, catch_scope, :catch) if bind_sym.is_a?(Sym)
|
|
559
|
-
body
|
|
462
|
+
bind_pattern(clause.bind_sym, catch_scope, :catch) if clause.bind_sym.is_a?(Sym)
|
|
463
|
+
clause.body.each { |form| walk_form(form, catch_scope) }
|
|
560
464
|
end
|
|
561
465
|
|
|
562
466
|
def walk_module_class(list, scope)
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
467
|
+
if (module_form = Compiler::Language.parse_module_form(list))
|
|
468
|
+
kind = :module
|
|
469
|
+
name_sym = module_form.name
|
|
470
|
+
body = module_form.body
|
|
471
|
+
else
|
|
472
|
+
kind = :class
|
|
473
|
+
parsed = Compiler::Language.parse_class_form(list)
|
|
474
|
+
name_sym = parsed.name
|
|
475
|
+
parsed.supers&.items&.each { |item| walk_form(item, scope) }
|
|
476
|
+
body = parsed.body
|
|
569
477
|
end
|
|
570
478
|
|
|
571
479
|
add_constant_binding(name_sym, scope, kind) if name_sym.is_a?(Sym)
|
|
572
480
|
|
|
573
|
-
body = list.items[body_start..] || []
|
|
574
481
|
body_scope = make_scope(scope, kind)
|
|
575
482
|
if kind == :class
|
|
576
483
|
inside_class { body.each { |form| walk_form(form, body_scope) } }
|
|
@@ -583,11 +490,17 @@ module Kapusta
|
|
|
583
490
|
return if hashfn_synthetic?(sym.name)
|
|
584
491
|
return if sym.is_a?(MacroSym) || sym.is_a?(AutoGensym)
|
|
585
492
|
|
|
586
|
-
target_name = sym.dotted?
|
|
493
|
+
target_name = if sym.dotted?
|
|
494
|
+
sym.segments.first
|
|
495
|
+
elsif sym.colonized?
|
|
496
|
+
sym.colon_segments.first
|
|
497
|
+
else
|
|
498
|
+
sym.name
|
|
499
|
+
end
|
|
587
500
|
return if target_name.nil? || target_name.empty?
|
|
588
501
|
|
|
589
502
|
target = scope.lookup(target_name)
|
|
590
|
-
return if target.nil? && Compiler::
|
|
503
|
+
return if target.nil? && Compiler::Language.special_form?(sym.name)
|
|
591
504
|
|
|
592
505
|
add_reference(sym, scope, target)
|
|
593
506
|
end
|
|
@@ -602,7 +515,7 @@ module Kapusta
|
|
|
602
515
|
return if pattern.name == '_'
|
|
603
516
|
|
|
604
517
|
add_binding(pattern, scope, kind)
|
|
605
|
-
when Vec
|
|
518
|
+
when Vec, List
|
|
606
519
|
bind_vec_pattern(pattern, scope, kind)
|
|
607
520
|
when HashLit
|
|
608
521
|
bind_hash_pattern(pattern, scope, kind)
|
|
@@ -670,16 +583,13 @@ module Kapusta
|
|
|
670
583
|
end
|
|
671
584
|
|
|
672
585
|
def walk_pattern_list(list, scope, outer_scope, mode)
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
walk_pattern(
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
list.items[1..]&.each { |alt| walk_pattern(alt, scope, outer_scope, mode) }
|
|
681
|
-
elsif head.is_a?(Sym) && head.name == '=' && list.items.length == 2
|
|
682
|
-
name_sym = list.items[1]
|
|
586
|
+
if (where = Compiler::Language.parse_where_pattern(list))
|
|
587
|
+
walk_pattern(where.inner, scope, outer_scope, mode)
|
|
588
|
+
where.guards.each { |guard| walk_form(guard, scope) }
|
|
589
|
+
elsif (or_pattern = Compiler::Language.parse_or_pattern(list))
|
|
590
|
+
or_pattern.alternatives.each { |alt| walk_pattern(alt, scope, outer_scope, mode) }
|
|
591
|
+
elsif (pin = Compiler::Language.parse_pin_pattern(list))
|
|
592
|
+
name_sym = pin.name
|
|
683
593
|
if name_sym.is_a?(Sym) && (existing = outer_scope.lookup(name_sym.name))
|
|
684
594
|
add_reference(name_sym, outer_scope, existing)
|
|
685
595
|
end
|