kapusta 0.2.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee9b062de9860ef3b9f3cfcbac8503e69c1549f0f09af35b41e5eb13303c1ddb
4
- data.tar.gz: daa87e0b3b65dfc82f21ff47e88b41652d05f087e46320ca1c3f49bac2457b71
3
+ metadata.gz: 693c32746a17e6f3a2aa7ac2a2d23cd6e3b3d981f1ef9355a69c5cd14ea09bbe
4
+ data.tar.gz: 7a500a84cbb1c8e3c1937c1fb987aa14db1b835cd63416e2f2e1d9b18309324e
5
5
  SHA512:
6
- metadata.gz: 564c441ea9395cd4f28daaa631de6022e39125eede47032bf32bbc2a45f18979b7376f264b5302459b78403ef039ef8aca93e6f469cc0666b033f6e6717894a2
7
- data.tar.gz: 38479cb8d38b81df15697a56c1a14e63d4dda7a0dd793db4e121e06126395339d9c7676a4bb14411a6b43398b64196f877ce3126990eb07d24f2a0c769a577e2
6
+ metadata.gz: fb9f5ac51dbc88892e7d2b2527c6b94d13c972276899cdf86a76f6460e7073c0c4610cbaee2142e66638108226b9a66efe1415e42394e6c8c7abd74bd4ac0d2c
7
+ data.tar.gz: 53eac046879c094bd002cb6d0e9c199dfb39680d2140dde5699f62a36a26a8cc5d928ccc02315b1cad568e9b8f383cafeddf2e26cfaa4d07db3f53a29783de7e
data/README.md CHANGED
@@ -67,8 +67,8 @@ def ack(m, n)
67
67
  ack(m - 1, ack(m, n - 1))
68
68
  end
69
69
  end
70
- p(ack(2, 3))
71
- p(ack(3, 3))
70
+ p ack(2, 3)
71
+ p ack(3, 3)
72
72
  ```
73
73
 
74
74
  ## Comparison with Fennel
@@ -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
- <<~RUBY.chomp
217
- (-> do
218
- #{indent(join_code(binding_code, body_code))}
219
- end).call
220
- RUBY
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
- return <<~RUBY.chomp
117
- #{emit_expr(iter_expr.items[1], env, current_scope)}.each_with_index do |#{value_var}, #{index_var}|
118
- #{bind_code}
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
- return <<~RUBY.chomp
130
- #{emit_expr(iter_expr.items[1], env, current_scope)}.each do |#{key_var}, #{value_var}|
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
- <<~RUBY.chomp
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
- <<~RUBY.chomp
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|
@@ -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
- "p(#{args.map { |arg| emit_expr(arg, env, current_scope) }.join(', ')})"
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
- "(#{emit_expr(arg, env, current_scope)}).to_s"
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, block = split_call_args(args[2..], env, current_scope)
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 && !kwargs && !block && direct_method_name?(literal_name.to_s)
30
- return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(literal_name.to_s), positional)
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
- lines = ['begin', indent(emit_expr(args[0], env, current_scope))]
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, block = split_call_args(args, env, current_scope)
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, block = split_call_args(args, env, current_scope)
285
- if !kwargs && !block && direct_method_name?(segments.last)
286
- return emit_direct_method_call(receiver, Kapusta.kebab_to_snake(segments.last), positional)
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
- args = positional.join(', ')
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
- suffix = args.empty? ? method_name : "#{method_name}(#{args})"
310
- "#{rendered_receiver}.#{suffix}"
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, block = split_call_args(args, env, current_scope)
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
- block = nil
338
+ block_form = nil
322
339
  remaining = args
323
340
  if !remaining.empty? && block_form?(remaining.last)
324
- block = emit_expr(remaining.last, env, current_scope)
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, block]
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 |#{ruby_name}|",
271
+ "#{parenthesize(start_code)}.step(#{finish_code}#{step_part}) do#{block_args}",
271
272
  indent(body),
272
273
  'end'
273
274
  ].join("\n")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kapusta
4
- VERSION = '0.2.1'
4
+ VERSION = '0.2.2'
5
5
  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.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgenii Morozov