kapusta 0.2.1 → 0.2.3
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 +2 -2
- data/examples/anagram.kap +4 -4
- data/examples/baseball-game.kap +1 -1
- data/examples/exceptions.kap +1 -1
- data/examples/pcall.kap +6 -3
- data/examples/raindrops.kap +1 -1
- data/examples/single-number.kap +7 -0
- data/kapusta.gemspec +1 -1
- data/lib/kapusta/compiler/emitter/bindings.rb +7 -7
- data/lib/kapusta/compiler/emitter/collections.rb +12 -25
- data/lib/kapusta/compiler/emitter/expressions.rb +6 -2
- data/lib/kapusta/compiler/emitter/interop.rb +105 -18
- data/lib/kapusta/compiler/emitter/patterns.rb +1 -1
- data/lib/kapusta/compiler/emitter/support.rb +2 -1
- data/lib/kapusta/version.rb +1 -1
- data/spec/examples_spec.rb +4 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a5fcd922c54b5fa491785e6087c4fc2f8e6de1a8d94deab10fca3f775518b9b
|
|
4
|
+
data.tar.gz: d95f4bce9e6673104c44fc0ff281a705e796797490285cc50ef509b6b9fe5e97
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cb5ba4420166be83a152c22bf56a12563efdb8cc64e54f230f6d299051761c5abc2329ae42dfc5e6127a721f66250b9804d6ec86a9b053dc36282599b2f8c986
|
|
7
|
+
data.tar.gz: 334d34e9e47bdecf6a4aa35cc6e905770efb6913fa6c2e9f90b0f3b1a95915b9044c8e3f36c81778a865f91a6d43f675318bf1ae892e19292cb4a2d2de179685
|
data/README.md
CHANGED
data/examples/anagram.kap
CHANGED
data/examples/baseball-game.kap
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
(if (= op "C") (do (-?> (scores.pop) (: :abs)) nil)
|
|
5
5
|
(= op "D") (scores.push (* 2 (. scores -1)))
|
|
6
6
|
(= op "+") (scores.push (+ (. scores -1) (. scores -2)))
|
|
7
|
-
(scores.push (
|
|
7
|
+
(scores.push (: op :to-i))))
|
|
8
8
|
scores.sum))
|
|
9
9
|
|
|
10
10
|
(print (cal-points ["5" "2" "C" "D" "+"]))
|
data/examples/exceptions.kap
CHANGED
data/examples/pcall.kap
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
(
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
(fn parse-int [s]
|
|
2
|
+
(: Kernel :Integer s))
|
|
3
|
+
|
|
4
|
+
(let [[ok value] (pcall parse-int "12")
|
|
5
|
+
[bad-ok error] (pcall parse-int "oops")
|
|
6
|
+
[handled-ok handled] (xpcall parse-int (fn [e] (e.message)) "oops")]
|
|
4
7
|
(print ok)
|
|
5
8
|
(print value)
|
|
6
9
|
(print bad-ok)
|
data/examples/raindrops.kap
CHANGED
data/kapusta.gemspec
CHANGED
|
@@ -7,13 +7,13 @@ Gem::Specification.new do |spec|
|
|
|
7
7
|
spec.version = Kapusta::VERSION
|
|
8
8
|
spec.authors = ['Evgenii Morozov']
|
|
9
9
|
spec.homepage = 'https://github.com/evmorov/kapusta'
|
|
10
|
+
spec.license = 'MIT'
|
|
10
11
|
|
|
11
12
|
spec.summary = 'A Lisp for the Ruby runtime'
|
|
12
13
|
spec.description = 'Kapusta is a Lisp for the Ruby runtime.'
|
|
13
14
|
spec.required_ruby_version = '>= 3.1'
|
|
14
15
|
|
|
15
16
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
16
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
|
17
17
|
spec.metadata['source_code_uri'] = spec.homepage
|
|
18
18
|
spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
|
|
19
19
|
|
|
@@ -213,11 +213,11 @@ module Kapusta
|
|
|
213
213
|
|
|
214
214
|
def emit_let(args, env, current_scope)
|
|
215
215
|
binding_code, body_code = emit_let_parts(args, env, current_scope, result: true)
|
|
216
|
-
|
|
217
|
-
(-> do
|
|
218
|
-
|
|
219
|
-
end).call
|
|
220
|
-
|
|
216
|
+
[
|
|
217
|
+
'(-> do',
|
|
218
|
+
indent(join_code(binding_code, body_code)),
|
|
219
|
+
'end).call'
|
|
220
|
+
].join("\n")
|
|
221
221
|
end
|
|
222
222
|
|
|
223
223
|
def emit_let_statement(args, env, current_scope)
|
|
@@ -242,7 +242,7 @@ module Kapusta
|
|
|
242
242
|
body_code, = emit_sequence(body, child_env, current_scope,
|
|
243
243
|
allow_method_definitions: false,
|
|
244
244
|
result:)
|
|
245
|
-
[binding_codes.join("\n"), body_code]
|
|
245
|
+
[binding_codes.reject(&:empty?).join("\n"), body_code]
|
|
246
246
|
end
|
|
247
247
|
|
|
248
248
|
def join_code(*chunks)
|
|
@@ -258,7 +258,7 @@ module Kapusta
|
|
|
258
258
|
["#{ruby_name} = #{value_code}\nnil", env]
|
|
259
259
|
else
|
|
260
260
|
bind_code, env = emit_pattern_bind(target, value_code, env)
|
|
261
|
-
[
|
|
261
|
+
[join_code(bind_code, 'nil'), env]
|
|
262
262
|
end
|
|
263
263
|
end
|
|
264
264
|
|
|
@@ -113,12 +113,9 @@ module Kapusta
|
|
|
113
113
|
[[binding_pats[0], index_var], [binding_pats[1], value_var]], body_env
|
|
114
114
|
)
|
|
115
115
|
body_code = yield(body_env)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
#{body_code}
|
|
120
|
-
end
|
|
121
|
-
RUBY
|
|
116
|
+
header = "#{emit_expr(iter_expr.items[1], env, current_scope)}" \
|
|
117
|
+
".each_with_index do |#{value_var}, #{index_var}|"
|
|
118
|
+
return iteration_block(header, bind_code, body_code)
|
|
122
119
|
when 'pairs'
|
|
123
120
|
key_var = temp('key')
|
|
124
121
|
value_var = temp('value')
|
|
@@ -126,12 +123,8 @@ module Kapusta
|
|
|
126
123
|
bind_code, body_env = emit_iteration_bindings([[binding_pats[0], key_var], [binding_pats[1], value_var]],
|
|
127
124
|
body_env)
|
|
128
125
|
body_code = yield(body_env)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
#{bind_code}
|
|
132
|
-
#{body_code}
|
|
133
|
-
end
|
|
134
|
-
RUBY
|
|
126
|
+
header = "#{emit_expr(iter_expr.items[1], env, current_scope)}.each do |#{key_var}, #{value_var}|"
|
|
127
|
+
return iteration_block(header, bind_code, body_code)
|
|
135
128
|
end
|
|
136
129
|
end
|
|
137
130
|
|
|
@@ -141,27 +134,21 @@ module Kapusta
|
|
|
141
134
|
body_env = env.child
|
|
142
135
|
bind_code, body_env = emit_iteration_bindings([[binding_pats[0], value_var]], body_env)
|
|
143
136
|
body_code = yield(body_env)
|
|
144
|
-
|
|
145
|
-
#{coll_code}.each do |#{value_var}|
|
|
146
|
-
#{bind_code}
|
|
147
|
-
#{body_code}
|
|
148
|
-
end
|
|
149
|
-
RUBY
|
|
137
|
+
iteration_block("#{coll_code}.each do |#{value_var}|", bind_code, body_code)
|
|
150
138
|
else
|
|
151
139
|
parts_var = temp('parts')
|
|
152
140
|
body_env = env.child
|
|
153
141
|
pairs = binding_pats.each_with_index.map { |pattern, i| [pattern, "#{parts_var}[#{i}]"] }
|
|
154
142
|
bind_code, body_env = emit_iteration_bindings(pairs, body_env)
|
|
155
143
|
body_code = yield(body_env)
|
|
156
|
-
|
|
157
|
-
#{coll_code}.each do |*#{parts_var}|
|
|
158
|
-
#{bind_code}
|
|
159
|
-
#{body_code}
|
|
160
|
-
end
|
|
161
|
-
RUBY
|
|
144
|
+
iteration_block("#{coll_code}.each do |*#{parts_var}|", bind_code, body_code)
|
|
162
145
|
end
|
|
163
146
|
end
|
|
164
147
|
|
|
148
|
+
def iteration_block(header, bind_code, body_code)
|
|
149
|
+
[header, indent(join_code(bind_code, body_code)), 'end'].join("\n")
|
|
150
|
+
end
|
|
151
|
+
|
|
165
152
|
def emit_iteration_bindings(pairs, env)
|
|
166
153
|
current_env = env
|
|
167
154
|
codes = pairs.compact.map do |pattern, value_code|
|
|
@@ -169,7 +156,7 @@ module Kapusta
|
|
|
169
156
|
|
|
170
157
|
code, current_env = emit_pattern_bind(pattern, value_code, current_env)
|
|
171
158
|
code
|
|
172
|
-
end.compact
|
|
159
|
+
end.compact.reject(&:empty?)
|
|
173
160
|
[codes.join("\n"), current_env]
|
|
174
161
|
end
|
|
175
162
|
|
|
@@ -110,13 +110,17 @@ module Kapusta
|
|
|
110
110
|
def emit_print(args, env, current_scope)
|
|
111
111
|
return 'p' if args.empty?
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
rendered = args.map { |arg| emit_expr(arg, env, current_scope) }
|
|
114
|
+
return "p #{rendered[0]}" if rendered.length == 1 && simple_expression?(rendered[0])
|
|
115
|
+
|
|
116
|
+
"p(#{rendered.join(', ')})"
|
|
114
117
|
end
|
|
115
118
|
|
|
116
119
|
def emit_string_part(arg, env, current_scope)
|
|
117
120
|
return arg.inspect if arg.is_a?(String)
|
|
118
121
|
|
|
119
|
-
|
|
122
|
+
code = emit_expr(arg, env, current_scope)
|
|
123
|
+
"#{simple_expression?(code) ? code : "(#{code})"}.to_s"
|
|
120
124
|
end
|
|
121
125
|
end
|
|
122
126
|
end
|
|
@@ -21,20 +21,37 @@ module Kapusta
|
|
|
21
21
|
runtime_call(:qget_path, object_code, "[#{keys}]")
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
BINARY_OPERATOR_METHODS = %w[<=> ** << >> & | ^ === =~].freeze
|
|
25
|
+
private_constant :BINARY_OPERATOR_METHODS
|
|
26
|
+
|
|
24
27
|
def emit_colon(args, env, current_scope)
|
|
25
28
|
receiver = emit_expr(args[0], env, current_scope)
|
|
26
29
|
method_form = args[1]
|
|
27
|
-
positional, kwargs,
|
|
30
|
+
positional, kwargs, block_form = split_call_args(args[2..], env, current_scope)
|
|
28
31
|
literal_name = method_form if method_form.is_a?(Symbol) || method_form.is_a?(String)
|
|
29
|
-
if literal_name &&
|
|
30
|
-
return
|
|
32
|
+
if literal_name && binary_operator_call?(literal_name.to_s, positional, kwargs, block_form)
|
|
33
|
+
return emit_binary_operator_call(receiver, literal_name.to_s, positional[0])
|
|
34
|
+
end
|
|
35
|
+
if literal_name && direct_method_name?(literal_name.to_s)
|
|
36
|
+
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(literal_name.to_s),
|
|
37
|
+
positional, kwargs, block_form, env, current_scope)
|
|
31
38
|
end
|
|
32
39
|
|
|
33
40
|
method_name = emit_method_name(method_form, env, current_scope)
|
|
41
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
34
42
|
parts = build_call_args([method_name, *positional], kwargs, block)
|
|
35
43
|
"#{parenthesize(receiver)}.public_send(#{parts})"
|
|
36
44
|
end
|
|
37
45
|
|
|
46
|
+
def binary_operator_call?(name, positional, kwargs, block_form)
|
|
47
|
+
BINARY_OPERATOR_METHODS.include?(name) &&
|
|
48
|
+
positional.length == 1 && !kwargs && !block_form
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def emit_binary_operator_call(receiver, operator, arg_code)
|
|
52
|
+
"#{parenthesize(receiver)} #{operator} #{parenthesize(arg_code)}"
|
|
53
|
+
end
|
|
54
|
+
|
|
38
55
|
def emit_require(arg, env, current_scope)
|
|
39
56
|
path_code =
|
|
40
57
|
case arg
|
|
@@ -163,7 +180,14 @@ module Kapusta
|
|
|
163
180
|
end
|
|
164
181
|
end
|
|
165
182
|
|
|
166
|
-
|
|
183
|
+
body_form = args[0]
|
|
184
|
+
body_code =
|
|
185
|
+
if body_form.is_a?(List) && body_form.head.is_a?(Sym) && body_form.head.name == 'do'
|
|
186
|
+
emit_sequence(body_form.rest, env, current_scope, allow_method_definitions: false).first
|
|
187
|
+
else
|
|
188
|
+
emit_expr(body_form, env, current_scope)
|
|
189
|
+
end
|
|
190
|
+
lines = ['begin', indent(body_code)]
|
|
167
191
|
catches.each do |klass_form, bind_sym, body|
|
|
168
192
|
rescue_env = env.child
|
|
169
193
|
rescue_name = define_local(rescue_env, bind_sym.name)
|
|
@@ -209,6 +233,9 @@ module Kapusta
|
|
|
209
233
|
def emit_compare(args, env, current_scope, operator)
|
|
210
234
|
values = args.map { |arg| emit_expr(arg, env, current_scope) }
|
|
211
235
|
return 'true' if values.length <= 1
|
|
236
|
+
if (nil_pred = nil_predicate(args, values, operator, negate: false))
|
|
237
|
+
return nil_pred
|
|
238
|
+
end
|
|
212
239
|
|
|
213
240
|
(0...(values.length - 1)).map do |i|
|
|
214
241
|
"#{parenthesize(values[i])} #{operator} #{parenthesize(values[i + 1])}"
|
|
@@ -218,12 +245,27 @@ module Kapusta
|
|
|
218
245
|
def emit_compare_any(args, env, current_scope, operator)
|
|
219
246
|
values = args.map { |arg| emit_expr(arg, env, current_scope) }
|
|
220
247
|
return 'false' if values.length <= 1
|
|
248
|
+
if (nil_pred = nil_predicate(args, values, operator, negate: true))
|
|
249
|
+
return nil_pred
|
|
250
|
+
end
|
|
221
251
|
|
|
222
252
|
(0...(values.length - 1)).map do |i|
|
|
223
253
|
"#{parenthesize(values[i])} #{operator} #{parenthesize(values[i + 1])}"
|
|
224
254
|
end.join(' || ')
|
|
225
255
|
end
|
|
226
256
|
|
|
257
|
+
def nil_predicate(args, values, operator, negate:)
|
|
258
|
+
return unless args.length == 2
|
|
259
|
+
return unless (operator == '==' && !negate) || (operator == '!=' && negate)
|
|
260
|
+
|
|
261
|
+
nil_idx = args.find_index(&:nil?)
|
|
262
|
+
return unless nil_idx
|
|
263
|
+
|
|
264
|
+
other = values[1 - nil_idx]
|
|
265
|
+
receiver = simple_expression?(other) ? other : parenthesize(other)
|
|
266
|
+
"#{'!' if negate}#{receiver}.nil?"
|
|
267
|
+
end
|
|
268
|
+
|
|
227
269
|
def emit_reduce(args, env, current_scope, empty_value, operator)
|
|
228
270
|
return empty_value if args.empty?
|
|
229
271
|
|
|
@@ -246,7 +288,8 @@ module Kapusta
|
|
|
246
288
|
end
|
|
247
289
|
|
|
248
290
|
def emit_callable_call(callee_code, args, env, current_scope)
|
|
249
|
-
positional, kwargs,
|
|
291
|
+
positional, kwargs, block_form = split_call_args(args, env, current_scope)
|
|
292
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
250
293
|
rendered = build_call_args(positional, kwargs, block)
|
|
251
294
|
suffix = rendered.empty? ? '.call' : ".call(#{rendered})"
|
|
252
295
|
"#{parenthesize(callee_code)}#{suffix}"
|
|
@@ -281,12 +324,17 @@ module Kapusta
|
|
|
281
324
|
emit_callable_call(base_code, args, env, current_scope)
|
|
282
325
|
else
|
|
283
326
|
receiver = emit_method_path(base_code, segments[0...-1])
|
|
284
|
-
positional, kwargs,
|
|
285
|
-
if
|
|
286
|
-
return
|
|
327
|
+
positional, kwargs, block_form = split_call_args(args, env, current_scope)
|
|
328
|
+
if binary_operator_call?(segments.last, positional, kwargs, block_form)
|
|
329
|
+
return emit_binary_operator_call(receiver, segments.last, positional[0])
|
|
330
|
+
end
|
|
331
|
+
if direct_method_name?(segments.last)
|
|
332
|
+
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(segments.last),
|
|
333
|
+
positional, kwargs, block_form, env, current_scope)
|
|
287
334
|
end
|
|
288
335
|
|
|
289
336
|
method_name = Kapusta.kebab_to_snake(segments.last).to_sym.inspect
|
|
337
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
290
338
|
parts = build_call_args([method_name, *positional], kwargs, block)
|
|
291
339
|
"#{receiver}.public_send(#{parts})"
|
|
292
340
|
end
|
|
@@ -303,25 +351,43 @@ module Kapusta
|
|
|
303
351
|
end
|
|
304
352
|
end
|
|
305
353
|
|
|
306
|
-
def emit_direct_method_call(receiver, method_name, positional
|
|
307
|
-
|
|
354
|
+
def emit_direct_method_call(receiver, method_name, positional, kwargs = nil,
|
|
355
|
+
block_form = nil, env = nil, current_scope = nil)
|
|
356
|
+
attached = block_form && emit_attached_block(block_form, env, current_scope)
|
|
357
|
+
block = block_form && !attached ? emit_block_proc(block_form, env, current_scope) : nil
|
|
358
|
+
parts = build_call_args(positional, kwargs, block)
|
|
308
359
|
rendered_receiver = simple_expression?(receiver) ? receiver : parenthesize(receiver)
|
|
309
|
-
|
|
310
|
-
"#{
|
|
360
|
+
call = parts.empty? ? method_name : "#{method_name}(#{parts})"
|
|
361
|
+
call = "#{call} #{attached}" if attached
|
|
362
|
+
"#{rendered_receiver}.#{call}"
|
|
311
363
|
end
|
|
312
364
|
|
|
313
365
|
def emit_self_call(name, args, env, current_scope)
|
|
314
|
-
positional, kwargs,
|
|
315
|
-
|
|
366
|
+
positional, kwargs, block_form = split_call_args(args, env, current_scope)
|
|
367
|
+
snake = Kapusta.kebab_to_snake(name)
|
|
368
|
+
if direct_method_name?(snake)
|
|
369
|
+
return emit_direct_self_call(snake, positional, kwargs, block_form, env, current_scope)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
373
|
+
method_name = snake.to_sym.inspect
|
|
316
374
|
parts = build_call_args([method_name, *positional], kwargs, block)
|
|
317
|
-
"
|
|
375
|
+
"public_send(#{parts})"
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def emit_direct_self_call(method_name, positional, kwargs, block_form, env, current_scope)
|
|
379
|
+
attached = block_form && emit_attached_block(block_form, env, current_scope)
|
|
380
|
+
block = block_form && !attached ? emit_block_proc(block_form, env, current_scope) : nil
|
|
381
|
+
parts = build_call_args(positional, kwargs, block)
|
|
382
|
+
call = parts.empty? ? "#{method_name}()" : "#{method_name}(#{parts})"
|
|
383
|
+
attached ? "#{call} #{attached}" : call
|
|
318
384
|
end
|
|
319
385
|
|
|
320
386
|
def split_call_args(args, env, current_scope)
|
|
321
|
-
|
|
387
|
+
block_form = nil
|
|
322
388
|
remaining = args
|
|
323
389
|
if !remaining.empty? && block_form?(remaining.last)
|
|
324
|
-
|
|
390
|
+
block_form = remaining.last
|
|
325
391
|
remaining = remaining[0...-1]
|
|
326
392
|
end
|
|
327
393
|
|
|
@@ -332,7 +398,24 @@ module Kapusta
|
|
|
332
398
|
kwargs = nil
|
|
333
399
|
positional = remaining.map { |arg| emit_expr(arg, env, current_scope) }
|
|
334
400
|
end
|
|
335
|
-
[positional, kwargs,
|
|
401
|
+
[positional, kwargs, block_form]
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def emit_block_proc(block_form, env, current_scope)
|
|
405
|
+
block_form && emit_expr(block_form, env, current_scope)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def emit_attached_block(block_form, env, current_scope)
|
|
409
|
+
return unless block_form.is_a?(List) && block_form.head.is_a?(Sym)
|
|
410
|
+
return unless %w[fn lambda λ].include?(block_form.head.name)
|
|
411
|
+
|
|
412
|
+
pattern = block_form.items[1]
|
|
413
|
+
return unless pattern.is_a?(Vec) && simple_parameter_pattern?(pattern)
|
|
414
|
+
|
|
415
|
+
body = block_form.items[2..]
|
|
416
|
+
params, body_code = build_simple_block_parts(pattern, body, env, current_scope)
|
|
417
|
+
header = params.empty? ? 'do' : "do |#{params.join(', ')}|"
|
|
418
|
+
[header, indent(body_code), 'end'].join("\n")
|
|
336
419
|
end
|
|
337
420
|
|
|
338
421
|
def emit_method_name(form, env, current_scope)
|
|
@@ -404,13 +487,17 @@ module Kapusta
|
|
|
404
487
|
|
|
405
488
|
def simple_expression?(code)
|
|
406
489
|
code.match?(/\A[a-z_]\w*\z/) ||
|
|
490
|
+
code.match?(/\A@@?[a-z_]\w*\z/) ||
|
|
491
|
+
code.match?(/\A\$[a-zA-Z_]\w*\z/) ||
|
|
407
492
|
code.match?(/\A[A-Z]\w*(?:::[A-Z]\w*)*\z/) ||
|
|
408
493
|
code.match?(/\A[a-z_]\w*[!?=]?\([^()\n]*\)\z/) ||
|
|
409
494
|
code.match?(/\A\d+(?:\.\d+)?\z/) ||
|
|
410
495
|
code.match?(/\A[a-z_]\w*(?:\.[a-z_]\w*[!?=]?(?:\([^()\n]*\))?|\[[^\[\]]*\])+\z/) ||
|
|
496
|
+
code.match?(/\A[A-Z]\w*(?:::[A-Z]\w*)*(?:\.[a-z_]\w*[!?=]?(?:\([^()\n]*\))?|\[[^\[\]]*\])+\z/) ||
|
|
411
497
|
code.match?(/\A:[a-zA-Z_]\w*[!?=]?\z/) ||
|
|
412
498
|
code.match?(/\A"(?:[^"\\]|\\.)*"\z/) ||
|
|
413
499
|
code.match?(/\A'(?:[^'\\]|\\.)*'\z/) ||
|
|
500
|
+
code.match?(/\A\[[^\[\]\n]*\]\z/) ||
|
|
414
501
|
%w[nil true false self].include?(code) ||
|
|
415
502
|
negation_simple?(code)
|
|
416
503
|
end
|
|
@@ -8,7 +8,7 @@ module Kapusta
|
|
|
8
8
|
|
|
9
9
|
def emit_pattern_bind(pattern, value_code, env)
|
|
10
10
|
if pattern.is_a?(Sym)
|
|
11
|
-
return ['
|
|
11
|
+
return ['', env] if pattern.name == '_'
|
|
12
12
|
|
|
13
13
|
ruby_name = define_local(env, pattern)
|
|
14
14
|
["#{ruby_name} = #{value_code}", env]
|
|
@@ -266,8 +266,9 @@ module Kapusta
|
|
|
266
266
|
until_code = until_form ? "break if #{emit_expr(until_form, loop_env, current_scope)}" : nil
|
|
267
267
|
body = [until_code, body_code].compact.reject(&:empty?).join("\n")
|
|
268
268
|
step_part = step_code == '1' ? '' : ", #{step_code}"
|
|
269
|
+
block_args = ruby_name == '_' ? '' : " |#{ruby_name}|"
|
|
269
270
|
[
|
|
270
|
-
"#{parenthesize(start_code)}.step(#{finish_code}#{step_part}) do
|
|
271
|
+
"#{parenthesize(start_code)}.step(#{finish_code}#{step_part}) do#{block_args}",
|
|
271
272
|
indent(body),
|
|
272
273
|
'end'
|
|
273
274
|
].join("\n")
|
data/lib/kapusta/version.rb
CHANGED
data/spec/examples_spec.rb
CHANGED
|
@@ -399,6 +399,10 @@ RSpec.describe 'examples' do
|
|
|
399
399
|
expect(run_example('shapes.kap')).to eq("78.5\n9\n8\n0\n")
|
|
400
400
|
end
|
|
401
401
|
|
|
402
|
+
it 'single-number.kap' do
|
|
403
|
+
expect(run_example('single-number.kap')).to eq("1\n4\n1\n")
|
|
404
|
+
end
|
|
405
|
+
|
|
402
406
|
it 'squares.kap' do
|
|
403
407
|
expect(run_example('squares.kap')).to eq("1\n4\n9\n16\n25\n")
|
|
404
408
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kapusta
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Evgenii Morozov
|
|
@@ -80,6 +80,7 @@ files:
|
|
|
80
80
|
- examples/safe-lookup.kap
|
|
81
81
|
- examples/scopes.kap
|
|
82
82
|
- examples/shapes.kap
|
|
83
|
+
- examples/single-number.kap
|
|
83
84
|
- examples/squares.kap
|
|
84
85
|
- examples/stack.kap
|
|
85
86
|
- examples/sum.kap
|
|
@@ -123,10 +124,10 @@ files:
|
|
|
123
124
|
- spec/reader_spec.rb
|
|
124
125
|
- spec/spec_helper.rb
|
|
125
126
|
homepage: https://github.com/evmorov/kapusta
|
|
126
|
-
licenses:
|
|
127
|
+
licenses:
|
|
128
|
+
- MIT
|
|
127
129
|
metadata:
|
|
128
130
|
rubygems_mfa_required: 'true'
|
|
129
|
-
homepage_uri: https://github.com/evmorov/kapusta
|
|
130
131
|
source_code_uri: https://github.com/evmorov/kapusta
|
|
131
132
|
bug_tracker_uri: https://github.com/evmorov/kapusta/issues
|
|
132
133
|
rdoc_options: []
|