kapusta 0.2.2 → 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/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 +2 -2
- data/lib/kapusta/compiler/emitter/collections.rb +1 -1
- data/lib/kapusta/compiler/emitter/interop.rb +51 -2
- data/lib/kapusta/compiler/emitter/patterns.rb +1 -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/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
|
|
|
@@ -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
|
|
|
@@ -21,11 +21,17 @@ 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
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)
|
|
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
|
|
29
35
|
if literal_name && direct_method_name?(literal_name.to_s)
|
|
30
36
|
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(literal_name.to_s),
|
|
31
37
|
positional, kwargs, block_form, env, current_scope)
|
|
@@ -37,6 +43,15 @@ module Kapusta
|
|
|
37
43
|
"#{parenthesize(receiver)}.public_send(#{parts})"
|
|
38
44
|
end
|
|
39
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
|
+
|
|
40
55
|
def emit_require(arg, env, current_scope)
|
|
41
56
|
path_code =
|
|
42
57
|
case arg
|
|
@@ -218,6 +233,9 @@ module Kapusta
|
|
|
218
233
|
def emit_compare(args, env, current_scope, operator)
|
|
219
234
|
values = args.map { |arg| emit_expr(arg, env, current_scope) }
|
|
220
235
|
return 'true' if values.length <= 1
|
|
236
|
+
if (nil_pred = nil_predicate(args, values, operator, negate: false))
|
|
237
|
+
return nil_pred
|
|
238
|
+
end
|
|
221
239
|
|
|
222
240
|
(0...(values.length - 1)).map do |i|
|
|
223
241
|
"#{parenthesize(values[i])} #{operator} #{parenthesize(values[i + 1])}"
|
|
@@ -227,12 +245,27 @@ module Kapusta
|
|
|
227
245
|
def emit_compare_any(args, env, current_scope, operator)
|
|
228
246
|
values = args.map { |arg| emit_expr(arg, env, current_scope) }
|
|
229
247
|
return 'false' if values.length <= 1
|
|
248
|
+
if (nil_pred = nil_predicate(args, values, operator, negate: true))
|
|
249
|
+
return nil_pred
|
|
250
|
+
end
|
|
230
251
|
|
|
231
252
|
(0...(values.length - 1)).map do |i|
|
|
232
253
|
"#{parenthesize(values[i])} #{operator} #{parenthesize(values[i + 1])}"
|
|
233
254
|
end.join(' || ')
|
|
234
255
|
end
|
|
235
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
|
+
|
|
236
269
|
def emit_reduce(args, env, current_scope, empty_value, operator)
|
|
237
270
|
return empty_value if args.empty?
|
|
238
271
|
|
|
@@ -292,6 +325,9 @@ module Kapusta
|
|
|
292
325
|
else
|
|
293
326
|
receiver = emit_method_path(base_code, segments[0...-1])
|
|
294
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
|
|
295
331
|
if direct_method_name?(segments.last)
|
|
296
332
|
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(segments.last),
|
|
297
333
|
positional, kwargs, block_form, env, current_scope)
|
|
@@ -328,10 +364,23 @@ module Kapusta
|
|
|
328
364
|
|
|
329
365
|
def emit_self_call(name, args, env, current_scope)
|
|
330
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
|
+
|
|
331
372
|
block = emit_block_proc(block_form, env, current_scope)
|
|
332
|
-
method_name =
|
|
373
|
+
method_name = snake.to_sym.inspect
|
|
333
374
|
parts = build_call_args([method_name, *positional], kwargs, block)
|
|
334
|
-
"
|
|
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
|
|
335
384
|
end
|
|
336
385
|
|
|
337
386
|
def split_call_args(args, env, current_scope)
|
|
@@ -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]
|
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: []
|