kapusta 0.2.0 → 0.2.2
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 +30 -4
- data/examples/best-time-to-buy-sell-stock.kap +12 -0
- data/examples/majority-element.kap +11 -0
- data/examples/plus-one.kap +14 -0
- data/examples/reverse-integer.kap +13 -0
- data/examples/roman-to-integer.kap +17 -0
- data/examples/zoo-animal-1.kap +5 -0
- data/examples/zoo-animal-inheritance-2.kap +8 -0
- data/lib/kapusta/compiler/emitter/bindings.rb +5 -5
- data/lib/kapusta/compiler/emitter/collections.rb +11 -24
- data/lib/kapusta/compiler/emitter/control_flow.rb +11 -3
- data/lib/kapusta/compiler/emitter/expressions.rb +6 -2
- data/lib/kapusta/compiler/emitter/interop.rb +54 -16
- data/lib/kapusta/compiler/emitter/support.rb +2 -1
- data/lib/kapusta/version.rb +1 -1
- data/spec/examples_spec.rb +31 -2
- metadata +8 -2
- data/examples/inheritance.kap +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 693c32746a17e6f3a2aa7ac2a2d23cd6e3b3d981f1ef9355a69c5cd14ea09bbe
|
|
4
|
+
data.tar.gz: 7a500a84cbb1c8e3c1937c1fb987aa14db1b835cd63416e2f2e1d9b18309324e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb9f5ac51dbc88892e7d2b2527c6b94d13c972276899cdf86a76f6460e7073c0c4610cbaee2142e66638108226b9a66efe1415e42394e6c8c7abd74bd4ac0d2c
|
|
7
|
+
data.tar.gz: 53eac046879c094bd002cb6d0e9c199dfb39680d2140dde5699f62a36a26a8cc5d928ccc02315b1cad568e9b8f383cafeddf2e26cfaa4d07db3f53a29783de7e
|
data/README.md
CHANGED
|
@@ -41,6 +41,36 @@ account = BankAccount.new('Ada', 100)
|
|
|
41
41
|
|
|
42
42
|
See `examples/bank-account.kap` and `examples/use_bank_account.rb`.
|
|
43
43
|
|
|
44
|
+
## Examples
|
|
45
|
+
|
|
46
|
+
See [`examples/`](https://github.com/evmorov/kapusta/tree/main/examples).
|
|
47
|
+
|
|
48
|
+
```fennel
|
|
49
|
+
(fn ack [m n]
|
|
50
|
+
(if (= m 0) (+ n 1)
|
|
51
|
+
(= n 0) (ack (- m 1) 1)
|
|
52
|
+
(ack (- m 1) (ack m (- n 1)))))
|
|
53
|
+
|
|
54
|
+
(print (ack 2 3))
|
|
55
|
+
(print (ack 3 3))
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Compiles to:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
def ack(m, n)
|
|
62
|
+
if m == 0
|
|
63
|
+
n + 1
|
|
64
|
+
elsif n == 0
|
|
65
|
+
ack(m - 1, 1)
|
|
66
|
+
else
|
|
67
|
+
ack(m - 1, ack(m, n - 1))
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
p ack(2, 3)
|
|
71
|
+
p ack(3, 3)
|
|
72
|
+
```
|
|
73
|
+
|
|
44
74
|
## Comparison with Fennel
|
|
45
75
|
|
|
46
76
|
Kapusta keeps most core Fennel forms. The main differences come from Ruby's runtime and object model.
|
|
@@ -65,10 +95,6 @@ Kapusta-specific additions:
|
|
|
65
95
|
- a trailing symbol-keyed hash is emitted as Ruby keyword arguments
|
|
66
96
|
- a final function literal argument is emitted as a Ruby block
|
|
67
97
|
|
|
68
|
-
## Examples
|
|
69
|
-
|
|
70
|
-
See `examples/`.
|
|
71
|
-
|
|
72
98
|
## Formatting
|
|
73
99
|
|
|
74
100
|
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
(fn max-profit [prices]
|
|
2
|
+
(var min-price (. prices 0))
|
|
3
|
+
(var best 0)
|
|
4
|
+
(for [i 1 (- (length prices) 1)]
|
|
5
|
+
(let [p (. prices i)]
|
|
6
|
+
(when (< p min-price) (set min-price p))
|
|
7
|
+
(when (> (- p min-price) best) (set best (- p min-price)))))
|
|
8
|
+
best)
|
|
9
|
+
|
|
10
|
+
(print (max-profit [7 1 5 3 6 4]))
|
|
11
|
+
(print (max-profit [7 6 4 3 1]))
|
|
12
|
+
(print (max-profit [2 4 1]))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
(fn majority [nums]
|
|
2
|
+
(var candidate nil)
|
|
3
|
+
(var count 0)
|
|
4
|
+
(each [n nums]
|
|
5
|
+
(when (= count 0) (set candidate n))
|
|
6
|
+
(if (= n candidate) (set count (+ count 1)) (set count (- count 1))))
|
|
7
|
+
candidate)
|
|
8
|
+
|
|
9
|
+
(print (majority [3 2 3]))
|
|
10
|
+
(print (majority [2 2 1 1 1 2 2]))
|
|
11
|
+
(print (majority [1]))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
(fn plus-one [digits]
|
|
2
|
+
(var i (- (length digits) 1))
|
|
3
|
+
(var carry 1)
|
|
4
|
+
(while (and (>= i 0) (> carry 0))
|
|
5
|
+
(let [total (+ (. digits i) carry)]
|
|
6
|
+
(tset digits i (% total 10))
|
|
7
|
+
(set carry (: (/ total 10) :floor)))
|
|
8
|
+
(set i (- i 1)))
|
|
9
|
+
(if (> carry 0) (: digits :unshift carry) digits))
|
|
10
|
+
|
|
11
|
+
(print (plus-one [1 2 3]))
|
|
12
|
+
(print (plus-one [4 3 2 1]))
|
|
13
|
+
(print (plus-one [9]))
|
|
14
|
+
(print (plus-one [9 9]))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
(fn reverse-integer [x]
|
|
2
|
+
(let [sign (if (< x 0) -1 1)]
|
|
3
|
+
(var remaining (* x sign))
|
|
4
|
+
(var result 0)
|
|
5
|
+
(while (> remaining 0)
|
|
6
|
+
(set result (+ (* result 10) (% remaining 10)))
|
|
7
|
+
(set remaining (: (/ remaining 10) :floor)))
|
|
8
|
+
(* result sign)))
|
|
9
|
+
|
|
10
|
+
(print (reverse-integer 123))
|
|
11
|
+
(print (reverse-integer -123))
|
|
12
|
+
(print (reverse-integer 120))
|
|
13
|
+
(print (reverse-integer 0))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
(fn roman-to-integer [s]
|
|
2
|
+
(let [values {"I" 1 "V" 5 "X" 10 "L" 50 "C" 100 "D" 500 "M" 1000}
|
|
3
|
+
chars (s.chars)
|
|
4
|
+
n (length chars)]
|
|
5
|
+
(var total 0)
|
|
6
|
+
(var i 0)
|
|
7
|
+
(while (< i n)
|
|
8
|
+
(let [curr (. values (. chars i))
|
|
9
|
+
ahead (if (< (+ i 1) n) (. values (. chars (+ i 1))) 0)
|
|
10
|
+
subtract? (< curr ahead)]
|
|
11
|
+
(set total (+ total (if subtract? (- ahead curr) curr)))
|
|
12
|
+
(set i (+ i (if subtract? 2 1)))))
|
|
13
|
+
total))
|
|
14
|
+
|
|
15
|
+
(print (roman-to-integer "III"))
|
|
16
|
+
(print (roman-to-integer "LVIII"))
|
|
17
|
+
(print (roman-to-integer "MCMXCIV"))
|
|
@@ -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)
|
|
@@ -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|
|
|
@@ -15,7 +15,7 @@ module Kapusta
|
|
|
15
15
|
return emit_expr(args[0], env, current_scope) if args.length == 1
|
|
16
16
|
|
|
17
17
|
cond = emit_expr(args[0], env, current_scope)
|
|
18
|
-
truthy =
|
|
18
|
+
truthy = emit_if_branch(args[1], env, current_scope)
|
|
19
19
|
lines = ["if #{cond}", indent(truthy)]
|
|
20
20
|
append_else_lines(lines, args[2..], env, current_scope)
|
|
21
21
|
lines << 'end'
|
|
@@ -31,7 +31,7 @@ module Kapusta
|
|
|
31
31
|
append_elsif_lines(lines, args, env, current_scope)
|
|
32
32
|
else
|
|
33
33
|
lines << 'else'
|
|
34
|
-
lines << indent(
|
|
34
|
+
lines << indent(emit_if_branch(args[0], env, current_scope))
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -39,10 +39,18 @@ module Kapusta
|
|
|
39
39
|
return append_else_lines(lines, args, env, current_scope) if args.length < 2
|
|
40
40
|
|
|
41
41
|
lines << "elsif #{emit_expr(args[0], env, current_scope)}"
|
|
42
|
-
lines << indent(
|
|
42
|
+
lines << indent(emit_if_branch(args[1], env, current_scope))
|
|
43
43
|
append_else_lines(lines, args[2..], env, current_scope)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
def emit_if_branch(form, env, current_scope)
|
|
47
|
+
return emit_expr(form, env, current_scope) unless do_form?(form)
|
|
48
|
+
|
|
49
|
+
emit_sequence(form.rest, env, current_scope,
|
|
50
|
+
allow_method_definitions: false,
|
|
51
|
+
result: true).first
|
|
52
|
+
end
|
|
53
|
+
|
|
46
54
|
def if_form?(form)
|
|
47
55
|
form.is_a?(List) && form.head.is_a?(Sym) && form.head.name == 'if'
|
|
48
56
|
end
|
|
@@ -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
|
|
@@ -24,13 +24,15 @@ module Kapusta
|
|
|
24
24
|
def emit_colon(args, env, current_scope)
|
|
25
25
|
receiver = emit_expr(args[0], env, current_scope)
|
|
26
26
|
method_form = args[1]
|
|
27
|
-
positional, kwargs,
|
|
27
|
+
positional, kwargs, block_form = split_call_args(args[2..], env, current_scope)
|
|
28
28
|
literal_name = method_form if method_form.is_a?(Symbol) || method_form.is_a?(String)
|
|
29
|
-
if literal_name &&
|
|
30
|
-
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(literal_name.to_s),
|
|
29
|
+
if literal_name && direct_method_name?(literal_name.to_s)
|
|
30
|
+
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(literal_name.to_s),
|
|
31
|
+
positional, kwargs, block_form, env, current_scope)
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
method_name = emit_method_name(method_form, env, current_scope)
|
|
35
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
34
36
|
parts = build_call_args([method_name, *positional], kwargs, block)
|
|
35
37
|
"#{parenthesize(receiver)}.public_send(#{parts})"
|
|
36
38
|
end
|
|
@@ -163,7 +165,14 @@ module Kapusta
|
|
|
163
165
|
end
|
|
164
166
|
end
|
|
165
167
|
|
|
166
|
-
|
|
168
|
+
body_form = args[0]
|
|
169
|
+
body_code =
|
|
170
|
+
if body_form.is_a?(List) && body_form.head.is_a?(Sym) && body_form.head.name == 'do'
|
|
171
|
+
emit_sequence(body_form.rest, env, current_scope, allow_method_definitions: false).first
|
|
172
|
+
else
|
|
173
|
+
emit_expr(body_form, env, current_scope)
|
|
174
|
+
end
|
|
175
|
+
lines = ['begin', indent(body_code)]
|
|
167
176
|
catches.each do |klass_form, bind_sym, body|
|
|
168
177
|
rescue_env = env.child
|
|
169
178
|
rescue_name = define_local(rescue_env, bind_sym.name)
|
|
@@ -246,7 +255,8 @@ module Kapusta
|
|
|
246
255
|
end
|
|
247
256
|
|
|
248
257
|
def emit_callable_call(callee_code, args, env, current_scope)
|
|
249
|
-
positional, kwargs,
|
|
258
|
+
positional, kwargs, block_form = split_call_args(args, env, current_scope)
|
|
259
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
250
260
|
rendered = build_call_args(positional, kwargs, block)
|
|
251
261
|
suffix = rendered.empty? ? '.call' : ".call(#{rendered})"
|
|
252
262
|
"#{parenthesize(callee_code)}#{suffix}"
|
|
@@ -281,12 +291,14 @@ module Kapusta
|
|
|
281
291
|
emit_callable_call(base_code, args, env, current_scope)
|
|
282
292
|
else
|
|
283
293
|
receiver = emit_method_path(base_code, segments[0...-1])
|
|
284
|
-
positional, kwargs,
|
|
285
|
-
if
|
|
286
|
-
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(segments.last),
|
|
294
|
+
positional, kwargs, block_form = split_call_args(args, env, current_scope)
|
|
295
|
+
if direct_method_name?(segments.last)
|
|
296
|
+
return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(segments.last),
|
|
297
|
+
positional, kwargs, block_form, env, current_scope)
|
|
287
298
|
end
|
|
288
299
|
|
|
289
300
|
method_name = Kapusta.kebab_to_snake(segments.last).to_sym.inspect
|
|
301
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
290
302
|
parts = build_call_args([method_name, *positional], kwargs, block)
|
|
291
303
|
"#{receiver}.public_send(#{parts})"
|
|
292
304
|
end
|
|
@@ -303,25 +315,30 @@ module Kapusta
|
|
|
303
315
|
end
|
|
304
316
|
end
|
|
305
317
|
|
|
306
|
-
def emit_direct_method_call(receiver, method_name, positional
|
|
307
|
-
|
|
318
|
+
def emit_direct_method_call(receiver, method_name, positional, kwargs = nil,
|
|
319
|
+
block_form = nil, env = nil, current_scope = nil)
|
|
320
|
+
attached = block_form && emit_attached_block(block_form, env, current_scope)
|
|
321
|
+
block = block_form && !attached ? emit_block_proc(block_form, env, current_scope) : nil
|
|
322
|
+
parts = build_call_args(positional, kwargs, block)
|
|
308
323
|
rendered_receiver = simple_expression?(receiver) ? receiver : parenthesize(receiver)
|
|
309
|
-
|
|
310
|
-
"#{
|
|
324
|
+
call = parts.empty? ? method_name : "#{method_name}(#{parts})"
|
|
325
|
+
call = "#{call} #{attached}" if attached
|
|
326
|
+
"#{rendered_receiver}.#{call}"
|
|
311
327
|
end
|
|
312
328
|
|
|
313
329
|
def emit_self_call(name, args, env, current_scope)
|
|
314
|
-
positional, kwargs,
|
|
330
|
+
positional, kwargs, block_form = split_call_args(args, env, current_scope)
|
|
331
|
+
block = emit_block_proc(block_form, env, current_scope)
|
|
315
332
|
method_name = Kapusta.kebab_to_snake(name).to_sym.inspect
|
|
316
333
|
parts = build_call_args([method_name, *positional], kwargs, block)
|
|
317
334
|
"send(#{parts})"
|
|
318
335
|
end
|
|
319
336
|
|
|
320
337
|
def split_call_args(args, env, current_scope)
|
|
321
|
-
|
|
338
|
+
block_form = nil
|
|
322
339
|
remaining = args
|
|
323
340
|
if !remaining.empty? && block_form?(remaining.last)
|
|
324
|
-
|
|
341
|
+
block_form = remaining.last
|
|
325
342
|
remaining = remaining[0...-1]
|
|
326
343
|
end
|
|
327
344
|
|
|
@@ -332,7 +349,24 @@ module Kapusta
|
|
|
332
349
|
kwargs = nil
|
|
333
350
|
positional = remaining.map { |arg| emit_expr(arg, env, current_scope) }
|
|
334
351
|
end
|
|
335
|
-
[positional, kwargs,
|
|
352
|
+
[positional, kwargs, block_form]
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def emit_block_proc(block_form, env, current_scope)
|
|
356
|
+
block_form && emit_expr(block_form, env, current_scope)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def emit_attached_block(block_form, env, current_scope)
|
|
360
|
+
return unless block_form.is_a?(List) && block_form.head.is_a?(Sym)
|
|
361
|
+
return unless %w[fn lambda λ].include?(block_form.head.name)
|
|
362
|
+
|
|
363
|
+
pattern = block_form.items[1]
|
|
364
|
+
return unless pattern.is_a?(Vec) && simple_parameter_pattern?(pattern)
|
|
365
|
+
|
|
366
|
+
body = block_form.items[2..]
|
|
367
|
+
params, body_code = build_simple_block_parts(pattern, body, env, current_scope)
|
|
368
|
+
header = params.empty? ? 'do' : "do |#{params.join(', ')}|"
|
|
369
|
+
[header, indent(body_code), 'end'].join("\n")
|
|
336
370
|
end
|
|
337
371
|
|
|
338
372
|
def emit_method_name(form, env, current_scope)
|
|
@@ -404,13 +438,17 @@ module Kapusta
|
|
|
404
438
|
|
|
405
439
|
def simple_expression?(code)
|
|
406
440
|
code.match?(/\A[a-z_]\w*\z/) ||
|
|
441
|
+
code.match?(/\A@@?[a-z_]\w*\z/) ||
|
|
442
|
+
code.match?(/\A\$[a-zA-Z_]\w*\z/) ||
|
|
407
443
|
code.match?(/\A[A-Z]\w*(?:::[A-Z]\w*)*\z/) ||
|
|
408
444
|
code.match?(/\A[a-z_]\w*[!?=]?\([^()\n]*\)\z/) ||
|
|
409
445
|
code.match?(/\A\d+(?:\.\d+)?\z/) ||
|
|
410
446
|
code.match?(/\A[a-z_]\w*(?:\.[a-z_]\w*[!?=]?(?:\([^()\n]*\))?|\[[^\[\]]*\])+\z/) ||
|
|
447
|
+
code.match?(/\A[A-Z]\w*(?:::[A-Z]\w*)*(?:\.[a-z_]\w*[!?=]?(?:\([^()\n]*\))?|\[[^\[\]]*\])+\z/) ||
|
|
411
448
|
code.match?(/\A:[a-zA-Z_]\w*[!?=]?\z/) ||
|
|
412
449
|
code.match?(/\A"(?:[^"\\]|\\.)*"\z/) ||
|
|
413
450
|
code.match?(/\A'(?:[^'\\]|\\.)*'\z/) ||
|
|
451
|
+
code.match?(/\A\[[^\[\]\n]*\]\z/) ||
|
|
414
452
|
%w[nil true false self].include?(code) ||
|
|
415
453
|
negation_simple?(code)
|
|
416
454
|
end
|
|
@@ -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
|
@@ -239,8 +239,12 @@ RSpec.describe 'examples' do
|
|
|
239
239
|
expect(run_example('hashfn.kap')).to eq("5\n21\n")
|
|
240
240
|
end
|
|
241
241
|
|
|
242
|
-
it '
|
|
243
|
-
expect(run_example('
|
|
242
|
+
it 'zoo-animal-1.kap' do
|
|
243
|
+
expect(run_example('zoo-animal-1.kap')).to eq('')
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it 'zoo-animal-inheritance-2.kap' do
|
|
247
|
+
expect(run_example('zoo-animal-inheritance-2.kap')).to eq(<<~OUT)
|
|
244
248
|
true
|
|
245
249
|
"animalia"
|
|
246
250
|
"Poppy the dog"
|
|
@@ -455,4 +459,29 @@ RSpec.describe 'examples' do
|
|
|
455
459
|
"draw"
|
|
456
460
|
OUT
|
|
457
461
|
end
|
|
462
|
+
|
|
463
|
+
it 'reverse-integer.kap' do
|
|
464
|
+
expect(run_example('reverse-integer.kap')).to eq("321\n-321\n21\n0\n")
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
it 'roman-to-integer.kap' do
|
|
468
|
+
expect(run_example('roman-to-integer.kap')).to eq("3\n58\n1994\n")
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
it 'best-time-to-buy-sell-stock.kap' do
|
|
472
|
+
expect(run_example('best-time-to-buy-sell-stock.kap')).to eq("5\n0\n2\n")
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
it 'majority-element.kap' do
|
|
476
|
+
expect(run_example('majority-element.kap')).to eq("3\n2\n1\n")
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
it 'plus-one.kap' do
|
|
480
|
+
expect(run_example('plus-one.kap')).to eq(<<~OUT)
|
|
481
|
+
[1, 2, 4]
|
|
482
|
+
[4, 3, 2, 2]
|
|
483
|
+
[1, 0]
|
|
484
|
+
[1, 0, 0]
|
|
485
|
+
OUT
|
|
486
|
+
end
|
|
458
487
|
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.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Evgenii Morozov
|
|
@@ -29,6 +29,7 @@ files:
|
|
|
29
29
|
- examples/anonymous-greeter.kap
|
|
30
30
|
- examples/bank-account.kap
|
|
31
31
|
- examples/baseball-game.kap
|
|
32
|
+
- examples/best-time-to-buy-sell-stock.kap
|
|
32
33
|
- examples/binary-search.kap
|
|
33
34
|
- examples/binary-to-decimal.kap
|
|
34
35
|
- examples/block-sort.kap
|
|
@@ -52,10 +53,10 @@ files:
|
|
|
52
53
|
- examples/greet.kap
|
|
53
54
|
- examples/happy-number.kap
|
|
54
55
|
- examples/hashfn.kap
|
|
55
|
-
- examples/inheritance.kap
|
|
56
56
|
- examples/kwargs.kap
|
|
57
57
|
- examples/leap-year.kap
|
|
58
58
|
- examples/length-of-last-word.kap
|
|
59
|
+
- examples/majority-element.kap
|
|
59
60
|
- examples/match.kap
|
|
60
61
|
- examples/maximum-subarray.kap
|
|
61
62
|
- examples/min-max.kap
|
|
@@ -67,11 +68,14 @@ files:
|
|
|
67
68
|
- examples/pangram.kap
|
|
68
69
|
- examples/pcall.kap
|
|
69
70
|
- examples/pipeline.kap
|
|
71
|
+
- examples/plus-one.kap
|
|
70
72
|
- examples/points.kap
|
|
71
73
|
- examples/primes.kap
|
|
72
74
|
- examples/raindrops.kap
|
|
73
75
|
- examples/record.kap
|
|
74
76
|
- examples/regex.kap
|
|
77
|
+
- examples/reverse-integer.kap
|
|
78
|
+
- examples/roman-to-integer.kap
|
|
75
79
|
- examples/ruby-eval.kap
|
|
76
80
|
- examples/safe-lookup.kap
|
|
77
81
|
- examples/scopes.kap
|
|
@@ -88,6 +92,8 @@ files:
|
|
|
88
92
|
- examples/use_bank_account.rb
|
|
89
93
|
- examples/valid-parentheses-1.kap
|
|
90
94
|
- examples/valid-parentheses-2.kap
|
|
95
|
+
- examples/zoo-animal-1.kap
|
|
96
|
+
- examples/zoo-animal-inheritance-2.kap
|
|
91
97
|
- exe/kapfmt
|
|
92
98
|
- exe/kapusta
|
|
93
99
|
- kapusta.gemspec
|
data/examples/inheritance.kap
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
(let [animal-class (class Zoo.Animal
|
|
2
|
-
(fn initialize [name] (set (ivar name) name))
|
|
3
|
-
(fn name [] (ivar name))
|
|
4
|
-
(fn kingdom [] "animalia")
|
|
5
|
-
(fn label [] (.. (self.name) " the animal")))
|
|
6
|
-
dog-class (class Zoo.Dog [Zoo.Animal]
|
|
7
|
-
(fn label [] (.. (self.name) " the dog"))
|
|
8
|
-
(fn bark [] "woof"))
|
|
9
|
-
dog (dog-class.new "Poppy")]
|
|
10
|
-
(print (= dog-class.superclass animal-class)
|
|
11
|
-
(dog.kingdom)
|
|
12
|
-
(dog.label)
|
|
13
|
-
(dog.bark)))
|