kapusta 0.11.2 → 0.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ba2ee0fbbd336f3604e9c51014a458c0a54eefcb30939fc6f2a72ba25941fb6
4
- data.tar.gz: 687f46ff98b74d65d523404ba9350fd62921eada8e105f4fe0d9215eac036118
3
+ metadata.gz: d5e4a7dc8e3d044580b58064b4632706c2115964847d674c23bbe39a625e0b6e
4
+ data.tar.gz: b17a395b81ab568829022273e5df9ee5a186c052d6a1e4c843df631dfe1d6f76
5
5
  SHA512:
6
- metadata.gz: 070c9c5f4435f2e825f0bdb70ceb25f3cc5eba62745cae80f9d348aa4fc886d74a5f8ed06a93a62d572adbfadfbce5e93b3e37993a5d637e68d615af6e1ecfa7
7
- data.tar.gz: fc1697cfb31821c867c468666eee7bb3cd6af985c446cba8ea35e3c50c5928750a0989ce31c250d2c1d47f79b4f338e319a17cb00abb314c7213a1e3f2eb89e1
6
+ metadata.gz: d3e8ca629130a695a67a1c210ab06869518e2d232084e01a8cb6d180094e2b10b0cbc3f65c191a9a7a6b1e70727f1563f28e3637264cc7776a58c2e16e554991
7
+ data.tar.gz: 71695c0adf8e37705c9b9b85263e495578bcdd0d442c2d56ad09b1a6386640003164adf98d932c499472ae81d5c3d4a909898b907417e6d6463384b855b2fa33
data/README.md CHANGED
@@ -103,6 +103,7 @@ Kapusta keeps most core Fennel forms. The main differences come from Ruby's runt
103
103
  | `string.format`, `table.insert`, etc. | use Ruby methods and stdlib instead |
104
104
  | `values` uses Lua multiple returns | `values` lowers to a Ruby array, usually destructured |
105
105
  | `(print x)` is Lua's `print` (bare) | `(print x)` is Ruby's `p` (inspect-style) |
106
+ | `(.. "x: " nil)` errors at runtime | `(.. "x: " nil)` produces `"x: "` (Ruby `nil.to_s`) |
106
107
  | `with-open`, `tail!` | not provided |
107
108
 
108
109
  Kapusta-specific additions:
@@ -0,0 +1,32 @@
1
+ (fn arrange-coins [n]
2
+ (let [rows (faccumulate [acc {:sum 0 :rows 0} i 1 n]
3
+ (let [new-sum (+ (. acc :sum) i)]
4
+ (if (<= new-sum n)
5
+ {:sum new-sum :rows i}
6
+ acc)))
7
+ used (faccumulate [acc {:sum 0 :rows 0} i 1 n]
8
+ (let [new-sum (+ (. acc :sum) i)]
9
+ (if (<= new-sum n)
10
+ {:sum new-sum :rows i}
11
+ acc)))]
12
+ [(. rows :rows) (. used :sum)]))
13
+
14
+ (let [[r u] (arrange-coins 0)]
15
+ (print r)
16
+ (print u))
17
+
18
+ (let [[r u] (arrange-coins 1)]
19
+ (print r)
20
+ (print u))
21
+
22
+ (let [[r u] (arrange-coins 5)]
23
+ (print r)
24
+ (print u))
25
+
26
+ (let [[r u] (arrange-coins 8)]
27
+ (print r)
28
+ (print u))
29
+
30
+ (let [[r u] (arrange-coins 10)]
31
+ (print r)
32
+ (print u))
@@ -0,0 +1,24 @@
1
+ (fn sign [n]
2
+ (if (> n 0) 1
3
+ (< n 0) -1
4
+ 0))
5
+
6
+ (fn array-sign [nums]
7
+ (accumulate [acc 1 _ n (ipairs nums)]
8
+ (* acc (sign n))))
9
+
10
+ (fn join [tbl sep]
11
+ (var s "")
12
+ (each [_ x (ipairs tbl)]
13
+ (if (= s "")
14
+ (set s (.. x))
15
+ (set s (.. s sep x))))
16
+ s)
17
+
18
+ (fn debug-sign [label nums]
19
+ (local pretty #(.. "[" (join $ ", ") "]"))
20
+ (.. "case[" label "] in " (pretty nums) " out " (array-sign nums)))
21
+
22
+ (print (debug-sign "mixed" [-1 -2 -3 -4 3 2 1]))
23
+ (print (debug-sign "withzero" [1 5 0 2 -3]))
24
+ (print (debug-sign "allneg" [-1 1 -1 1 -1]))
@@ -0,0 +1,23 @@
1
+ (fn debug-data [packet seq]
2
+ (local no-nil #(or $ "nil"))
3
+ (let [[_ packet-seq] packet]
4
+ (.. "packet[:ping, " (no-nil packet-seq) "] seq " (no-nil seq))))
5
+
6
+ (fn show-case [packet seq]
7
+ (case packet
8
+ [:ping seq] (debug-data packet seq)
9
+ _ "other"))
10
+
11
+ (fn show-match [packet seq]
12
+ (match packet
13
+ [:ping seq] (debug-data packet seq)
14
+ _ "other"))
15
+
16
+ (print (.. "case: " (show-case [:ping 42] 7)))
17
+ (print (.. "case: " (show-case [:ping 42] nil)))
18
+ (print (.. "case: " (show-case [:ping nil] nil)))
19
+ (print (.. "case: " (show-case [:ping 42] 42)))
20
+ (print (.. "match: " (show-match [:ping 42] 7)))
21
+ (print (.. "match: " (show-match [:ping 42] nil)))
22
+ (print (.. "match: " (show-match [:ping nil] nil)))
23
+ (print (.. "match: " (show-match [:ping 42] 42)))
@@ -0,0 +1,16 @@
1
+ (fn divisibility-stats [n]
2
+ (let [threes (faccumulate [acc 0 i 1 n]
3
+ (let [step (if (= 0 (% i 3)) 1 0)]
4
+ (+ acc step)))
5
+ fives (faccumulate [acc 0 i 1 n]
6
+ (let [step (if (= 0 (% i 5)) 1 0)]
7
+ (+ acc step)))]
8
+ [threes fives]))
9
+
10
+ (let [[t f] (divisibility-stats 30)]
11
+ (print t)
12
+ (print f))
13
+
14
+ (let [[t f] (divisibility-stats 100)]
15
+ (print t)
16
+ (print f))
@@ -0,0 +1,7 @@
1
+ (fn equal-sums? [a b]
2
+ (= (accumulate [s 0 _ x (ipairs a)] (+ s x))
3
+ (accumulate [s 0 _ x (ipairs b)] (+ s x))))
4
+
5
+ (print (equal-sums? [1 2 3] [3 2 1]))
6
+ (print (equal-sums? [1 2 3] [4 5 6]))
7
+ (print (equal-sums? [0] [0]))
@@ -1,11 +1,16 @@
1
1
  ackermann
2
2
  anonymous-greeter
3
+ array-sign
4
+ arrange-coins
5
+ case-vs-match
3
6
  classify-wallet
4
7
  climbing-stairs
5
8
  convert-temperature
6
9
  count-effects
7
10
  describe
8
11
  destructure
12
+ divisibility-stats
13
+ equal-sums
9
14
  even-squares
10
15
  factorial
11
16
  falling-drops
@@ -15,9 +20,9 @@ gcd
15
20
  hashfn
16
21
  leap-year
17
22
  macros-dbg
23
+ macros-import
18
24
  macros-import-helpers
19
25
  macros-import-whole
20
- macros-import
21
26
  macros-multi
22
27
  macros-swap
23
28
  macros-thrice-if
@@ -26,10 +31,12 @@ macros-when-let
26
31
  match
27
32
  max-achievable
28
33
  min-max
34
+ nested-nil-pattern
35
+ non-constant-local
29
36
  or-patterns
30
- power-of-three
31
37
  packet-router
32
38
  points
39
+ power-of-three
33
40
  primes
34
41
  safe-lookup
35
42
  shapes
@@ -3,6 +3,7 @@ accumulator
3
3
  ackermann
4
4
  anagram
5
5
  anonymous-greeter
6
+ arrange-coins
6
7
  bank-account
7
8
  baseball-game
8
9
  best-time-to-buy-sell-stock
@@ -11,6 +12,7 @@ binary-to-decimal
11
12
  block-sort
12
13
  bst-iterator
13
14
  calc
15
+ case-vs-match
14
16
  circle
15
17
  classify-wallet
16
18
  climbing-stairs
@@ -20,8 +22,9 @@ count-effects
20
22
  counter
21
23
  describe
22
24
  destructure
23
- doto-hygiene
25
+ divisibility-stats
24
26
  doto
27
+ doto-hygiene
25
28
  egg-count
26
29
  even-squares
27
30
  exceptions
@@ -38,9 +41,9 @@ kwargs
38
41
  leap-year
39
42
  length-of-last-word
40
43
  macros-dbg
44
+ macros-import
41
45
  macros-import-helpers
42
46
  macros-import-whole
43
- macros-import
44
47
  macros-multi
45
48
  macros-swap
46
49
  macros-thrice-if
@@ -53,6 +56,7 @@ max-achievable
53
56
  maximum-subarray
54
57
  min-max
55
58
  module-header
59
+ nested-nil-pattern
56
60
  move-zeroes
57
61
  number-of-1-bits
58
62
  number-of-steps
@@ -84,8 +88,8 @@ thread-styles
84
88
  threading
85
89
  tic-tac-toe
86
90
  tset
87
- two-sum-hash
88
91
  two-sum
92
+ two-sum-hash
89
93
  ugly-number
90
94
  underscore-patterns
91
95
  valid-parentheses-1
@@ -0,0 +1,7 @@
1
+ (fn check [packet]
2
+ (case packet
3
+ [:ping seq] (.. "got " seq)
4
+ _ "other"))
5
+
6
+ (print (check [:ping 42]))
7
+ (print (check [:ping nil]))
@@ -0,0 +1,11 @@
1
+ (local hash-fn #(or $ "nil"))
2
+ (local regular-fn (fn [x] (+ x 1)))
3
+ (local lambda-fn (λ [x] (* x 2)))
4
+ (local vec-binding [10 20 30])
5
+ (local hash-binding {:a 1})
6
+
7
+ (print (hash-fn nil))
8
+ (print (regular-fn 5))
9
+ (print (lambda-fn 5))
10
+ (print (length vec-binding))
11
+ (print (. hash-binding :a))
@@ -57,7 +57,7 @@ module Kapusta
57
57
 
58
58
  def build_simple_block_parts(pattern, body, env, current_scope)
59
59
  body_env = env.child
60
- params = pattern.items.map { |sym| define_local(body_env, sym.name, shadow: true) }
60
+ params = pattern.items.map { |sym| define_local(body_env, sym, shadow: true) }
61
61
  body_code, = emit_sequence(body, body_env, current_scope,
62
62
  allow_method_definitions: false, result: false)
63
63
  [params, body_code]
@@ -296,7 +296,9 @@ module Kapusta
296
296
 
297
297
  if target.is_a?(Sym)
298
298
  validate_binding_symbol!(target)
299
- if allow_constant && form.head.name == 'local' && (constant_name = constant_name_for(target.name))
299
+ if allow_constant && form.head.name == 'local' &&
300
+ constant_value?(form.items[2]) &&
301
+ (constant_name = constant_name_for(target.name))
300
302
  env.define(target.name, constant_name)
301
303
  mark_mutability(env, target.name, mutable: false)
302
304
  return ["#{constant_name} = #{value_code}\nnil", env]
@@ -316,6 +318,13 @@ module Kapusta
316
318
  candidate if candidate.match?(/\A[A-Z][A-Z0-9_]*\z/)
317
319
  end
318
320
 
321
+ def constant_value?(value_form)
322
+ case value_form
323
+ when Numeric, String, ::Symbol, true, false, nil then true
324
+ else false
325
+ end
326
+ end
327
+
319
328
  def check_destructure_value!(pattern, value_form)
320
329
  return unless pattern.is_a?(Vec) || pattern.is_a?(HashLit)
321
330
 
@@ -111,30 +111,23 @@ module Kapusta
111
111
  bindings = args[0].items
112
112
  emit_error!(:accumulate_no_iterator) if bindings.length < 5
113
113
 
114
- acc_name = bindings[0]
115
- loop_name = bindings[2]
116
- loop_env = env.child
117
- acc_var = define_local(loop_env, acc_name.name)
118
- loop_var = define_local(loop_env, loop_name.name)
119
- body_code, = emit_sequence(args[1..], loop_env, current_scope, allow_method_definitions: false)
120
- accumulating_body = emit_sequence_value_assignment(acc_var, body_code)
121
- loop_code = emit_counted_loop(
122
- ruby_name: loop_var,
123
- start_code: emit_expr(bindings[3], env, current_scope),
124
- finish_code: emit_expr(bindings[4], env, current_scope),
125
- step_code: bindings[5] ? emit_expr(bindings[5], env, current_scope) : '1',
126
- until_form: nil,
127
- loop_env:,
128
- current_scope:,
129
- body_code: accumulating_body
130
- )
131
- [
132
- '(-> do',
133
- indent("#{acc_var} = #{emit_expr(bindings[1], env, current_scope)}"),
134
- indent(loop_code),
135
- indent(acc_var),
136
- 'end).call'
137
- ].join("\n")
114
+ body_env = env.child
115
+ acc_var = define_local(body_env, bindings[0].name)
116
+ loop_var = define_local(body_env, bindings[2].name)
117
+
118
+ init_code = emit_expr(bindings[1], env, current_scope)
119
+ start_code = emit_expr(bindings[3], env, current_scope)
120
+ finish_code = emit_expr(bindings[4], env, current_scope)
121
+ step_code = bindings[5] ? emit_expr(bindings[5], env, current_scope) : nil
122
+ body_code, = emit_sequence(args[1..], body_env, current_scope, allow_method_definitions: false)
123
+
124
+ receiver =
125
+ if step_code
126
+ "#{parenthesize(start_code)}.step(#{finish_code}, #{step_code})"
127
+ else
128
+ "(#{start_code}..#{finish_code})"
129
+ end
130
+ inject_block(receiver, "#{acc_var}, #{loop_var}", init_code, '', body_code)
138
131
  end
139
132
 
140
133
  def emit_hashfn(args, env, current_scope)
@@ -139,6 +139,8 @@ module Kapusta
139
139
 
140
140
  def doto(forms)
141
141
  value = forms.first
142
+ return value if forms[1..].empty?
143
+
142
144
  temp = gensym('doto')
143
145
  body = forms[1..].map do |form|
144
146
  if form.is_a?(List)
@@ -147,7 +149,8 @@ module Kapusta
147
149
  List.new([form, temp])
148
150
  end
149
151
  end
150
- List.new([Sym.new('let'), Vec.new([temp, value]), *body, temp])
152
+ fn = List.new([Sym.new('fn'), Vec.new([temp]), *body])
153
+ List.new([Sym.new(':'), value, :tap, fn])
151
154
  end
152
155
 
153
156
  def gensym(prefix)
@@ -555,30 +555,18 @@ module Kapusta
555
555
  lines = [base]
556
556
  args = list_raw_rest(list)
557
557
  semantic_length = semantic_items(args).length
558
+ hang_subsequent_args = hang_call_args?(list, indent)
558
559
 
559
560
  semantic_index = 0
561
+ hanging = nil
560
562
  args.each do |arg|
561
563
  if comment?(arg)
562
564
  lines << indent_block(render(arg, indent + INDENT), INDENT)
563
565
  next
564
- end
565
-
566
- if semantic_index.zero?
567
- first = render(
568
- arg,
569
- indent + base.length + 1,
570
- force_expand: semantic_length == 1 && fn_form?(arg)
571
- )
572
- first_line, *rest = first.lines(chomp: true)
573
- candidate = "#{base} #{first_line}"
574
-
575
- if lines.length == 1 && fits?(candidate, indent)
576
- lines[0] = candidate
577
- hanging = ' ' * (base.length + 1)
578
- rest.each { |line| lines << "#{hanging}#{line}" }
579
- else
580
- lines << indent_block(first, INDENT)
581
- end
566
+ elsif semantic_index.zero?
567
+ hanging = append_first_call_arg(lines, arg, base, indent, semantic_length)
568
+ elsif hanging && hang_subsequent_args
569
+ lines << prefix_continuation(hanging, render(arg, indent + hanging.length))
582
570
  else
583
571
  lines << indent_block(render(arg, indent + INDENT), INDENT)
584
572
  end
@@ -589,6 +577,48 @@ module Kapusta
589
577
  append_suffix(lines, ')')
590
578
  end
591
579
 
580
+ def append_first_call_arg(lines, arg, base, indent, semantic_length)
581
+ first = render(
582
+ arg,
583
+ indent + base.length + 1,
584
+ force_expand: semantic_length == 1 && fn_form?(arg)
585
+ )
586
+ first_line, *rest = first.lines(chomp: true)
587
+ candidate = "#{base} #{first_line}"
588
+
589
+ unless lines.length == 1 && fits?(candidate, indent)
590
+ lines << indent_block(first, INDENT)
591
+ return
592
+ end
593
+
594
+ hanging = ' ' * (base.length + 1)
595
+ lines[0] = candidate
596
+ rest.each { |line| lines << "#{hanging}#{line}" }
597
+ hanging
598
+ end
599
+
600
+ def hang_call_args?(list, indent)
601
+ return false unless operator_call?(list)
602
+
603
+ flat = flat_call_render(list)
604
+ flat && !fits?(flat, indent)
605
+ end
606
+
607
+ def operator_call?(list)
608
+ head = list_head(list)
609
+ head.is_a?(Sym) && head.name.match?(/\A[^\w.]+\z/)
610
+ end
611
+
612
+ def flat_call_render(list)
613
+ head = flat_render(list_head(list))
614
+ return unless head
615
+
616
+ rendered_args = semantic_items(list_raw_rest(list)).map { |arg| flat_render(arg) }
617
+ return if rendered_args.any?(&:nil?)
618
+
619
+ "(#{[head, *rendered_args].join(' ')})"
620
+ end
621
+
592
622
  def render_vec(vec, indent, layout: nil, top_level: false, force_expand: false)
593
623
  flat = flat_render(vec)
594
624
  return flat if !force_expand && flat && fits?(flat, indent) && allow_flat?(vec, top_level:, layout:)
@@ -800,8 +830,7 @@ module Kapusta
800
830
  'fn', 'lambda', 'λ', 'macro'
801
831
  true
802
832
  else
803
- flat = flat_render(form)
804
- flat && flat.length > 40
833
+ false
805
834
  end
806
835
  end
807
836
 
data/lib/kapusta/lsp.rb CHANGED
@@ -15,8 +15,38 @@ module Kapusta
15
15
  METHOD_NOT_FOUND = -32_601
16
16
  FULL_SYNC = 1
17
17
 
18
+ def self.debug?
19
+ %w[1 true yes on].include?(ENV['KAPUSTA_LS_DEBUG'].to_s.downcase)
20
+ end
21
+
18
22
  def self.start(input: $stdin, output: $stdout, log: $stderr)
19
- new(input:, output:, log:).run
23
+ server = new(input:, output:, log:)
24
+ install_signal_handlers(log)
25
+ server.run
26
+ debug_log(log, 'run returned, calling exit!(0)')
27
+ exit!(0)
28
+ end
29
+
30
+ def self.install_signal_handlers(log)
31
+ %w[TERM INT HUP].each do |sig|
32
+ Signal.trap(sig) do
33
+ debug_log(log, "signal #{sig} received, exiting")
34
+ exit!(0)
35
+ rescue StandardError
36
+ exit!(0)
37
+ end
38
+ rescue ArgumentError
39
+ nil
40
+ end
41
+ end
42
+
43
+ def self.debug_log(log, message)
44
+ return unless debug?
45
+
46
+ log.write("kapusta-ls[debug pid=#{Process.pid}]: #{message}\n")
47
+ log.flush
48
+ rescue StandardError
49
+ nil
20
50
  end
21
51
 
22
52
  def self.uri_to_path(uri)
@@ -34,7 +64,7 @@ module Kapusta
34
64
  @input = input.binmode
35
65
  @output = output.binmode
36
66
  @log = log
37
- @debug = %w[1 true yes on].include?(ENV['KAPUSTA_LS_DEBUG'].to_s.downcase)
67
+ @debug = LSP.debug?
38
68
  @sources = {}
39
69
  @workspace_index = WorkspaceIndex.new
40
70
  @initialized = false
@@ -42,9 +72,11 @@ module Kapusta
42
72
  end
43
73
 
44
74
  def run
75
+ debug('run loop start')
45
76
  until (message = read_message).nil?
46
77
  handle(message)
47
78
  end
79
+ debug('stdin EOF, run loop exiting')
48
80
  end
49
81
 
50
82
  private
@@ -83,8 +115,14 @@ module Kapusta
83
115
 
84
116
  def write_message(payload)
85
117
  body = JSON.generate(payload)
118
+ tag = payload[:id] ? "response id=#{payload[:id]}" : "notify #{payload[:method]}"
119
+ debug("write begin (#{tag}, #{body.bytesize} bytes)")
86
120
  @output.write("Content-Length: #{body.bytesize}\r\n\r\n#{body}")
87
121
  @output.flush
122
+ debug("write done (#{tag})")
123
+ rescue Errno::EPIPE, IOError => e
124
+ debug("write failed (#{e.class}: #{e.message}), exiting")
125
+ exit!(0)
88
126
  end
89
127
 
90
128
  def handle(message)
@@ -92,9 +130,11 @@ module Kapusta
92
130
  id = message['id']
93
131
  params = message['params'] || {}
94
132
 
133
+ debug("dispatch begin method=#{method.inspect} id=#{id.inspect}")
95
134
  return handle_pre_init(method, id, params) unless @initialized || method == 'initialize' || method == 'exit'
96
135
 
97
136
  dispatch(method, id, params)
137
+ debug("dispatch end method=#{method.inspect} id=#{id.inspect}")
98
138
  rescue StandardError => e
99
139
  log("#{e.class}: #{e.message}")
100
140
  log(e.backtrace.first(5).join("\n"))
@@ -116,8 +156,12 @@ module Kapusta
116
156
  when 'initialized' then nil
117
157
  when 'shutdown'
118
158
  @shutdown = true
159
+ debug('shutdown received, replying and arming watchdog')
119
160
  reply(id, nil)
120
- when 'exit' then exit(@shutdown ? 0 : 1)
161
+ arm_shutdown_watchdog
162
+ when 'exit'
163
+ debug("exit notification received (shutdown=#{@shutdown}), calling exit!")
164
+ exit!(@shutdown ? 0 : 1)
121
165
  when 'textDocument/didOpen' then on_did_open(params)
122
166
  when 'textDocument/didChange' then on_did_change(params)
123
167
  when 'textDocument/didSave' then on_did_save(params)
@@ -300,14 +344,28 @@ module Kapusta
300
344
  notify('textDocument/publishDiagnostics', params)
301
345
  end
302
346
 
347
+ def arm_shutdown_watchdog(seconds: 2)
348
+ Thread.new do
349
+ sleep seconds
350
+ debug("shutdown watchdog firing after #{seconds}s, forcing exit")
351
+ exit!(0)
352
+ end
353
+ end
354
+
303
355
  def log(message)
304
356
  @log.puts "kapusta-ls: #{message}"
357
+ @log.flush
358
+ rescue StandardError
359
+ nil
305
360
  end
306
361
 
307
362
  def debug(message)
308
363
  return unless @debug
309
364
 
310
- @log.puts "kapusta-ls[debug]: #{message}"
365
+ @log.write("kapusta-ls[debug pid=#{Process.pid}]: #{message}\n")
366
+ @log.flush
367
+ rescue StandardError
368
+ nil
311
369
  end
312
370
  end
313
371
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kapusta
4
- VERSION = '0.11.2'
4
+ VERSION = '0.12.0'
5
5
  end
@@ -76,6 +76,29 @@ RSpec.describe 'examples' do
76
76
  expect(run_example('ackermann.kap')).to eq("9\n61\n")
77
77
  end
78
78
 
79
+ it 'non-constant-local.kap' do
80
+ expect(run_example('non-constant-local.kap')).to eq(<<~OUT)
81
+ "nil"
82
+ 6
83
+ 10
84
+ 3
85
+ 1
86
+ OUT
87
+ end
88
+
89
+ it 'case-vs-match.kap' do
90
+ expect(run_example('case-vs-match.kap')).to eq(<<~OUT)
91
+ "case: packet[:ping, 42] seq 42"
92
+ "case: packet[:ping, 42] seq 42"
93
+ "case: other"
94
+ "case: packet[:ping, 42] seq 42"
95
+ "match: other"
96
+ "match: other"
97
+ "match: packet[:ping, nil] seq nil"
98
+ "match: packet[:ping, 42] seq 42"
99
+ OUT
100
+ end
101
+
79
102
  it 'accumulator.kap' do
80
103
  expect(run_example('accumulator.kap')).to eq("22\n")
81
104
  end
@@ -92,6 +115,30 @@ RSpec.describe 'examples' do
92
115
  expect(run_example('circle.kap')).to eq("78.53975\n31.4159\n")
93
116
  end
94
117
 
118
+ it 'arrange-coins.kap' do
119
+ expect(run_example('arrange-coins.kap')).to eq(<<~OUT)
120
+ 0
121
+ 0
122
+ 1
123
+ 1
124
+ 2
125
+ 3
126
+ 3
127
+ 6
128
+ 4
129
+ 10
130
+ OUT
131
+ end
132
+
133
+ it 'divisibility-stats.kap' do
134
+ expect(run_example('divisibility-stats.kap')).to eq(<<~OUT)
135
+ 10
136
+ 6
137
+ 33
138
+ 20
139
+ OUT
140
+ end
141
+
95
142
  it 'anagram.kap' do
96
143
  expect(run_example('anagram.kap')).to eq("true\ntrue\nfalse\n")
97
144
  end
@@ -444,15 +491,10 @@ RSpec.describe 'examples' do
444
491
  OUT
445
492
  end
446
493
 
447
- it 'underscore-patterns.kap on mruby keeps loose nil and strict fallback separate' do
448
- path = File.join(EXAMPLES_DIR, 'underscore-patterns.kap')
449
- ruby = compile_example('underscore-patterns.kap', target: :mruby3)
450
-
451
- expect(run_mruby_source(ruby, path:)).to eq(<<~OUT)
452
- 5
453
- nil
454
- 5
455
- "fallback"
494
+ it 'nested-nil-pattern.kap' do
495
+ expect(run_example('nested-nil-pattern.kap')).to eq(<<~OUT)
496
+ "got 42"
497
+ "other"
456
498
  OUT
457
499
  end
458
500
 
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.11.2
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgenii Morozov
@@ -31,6 +31,8 @@ files:
31
31
  - examples/ackermann.kap
32
32
  - examples/anagram.kap
33
33
  - examples/anonymous-greeter.kap
34
+ - examples/arrange-coins.kap
35
+ - examples/array-sign.kap
34
36
  - examples/bank-account.kap
35
37
  - examples/baseball-game.kap
36
38
  - examples/best-time-to-buy-sell-stock.kap
@@ -40,6 +42,7 @@ files:
40
42
  - examples/blocks-and-kwargs.kap
41
43
  - examples/bst-iterator.kap
42
44
  - examples/calc.kap
45
+ - examples/case-vs-match.kap
43
46
  - examples/circle.kap
44
47
  - examples/classify-wallet.kap
45
48
  - examples/climbing-stairs.kap
@@ -49,9 +52,11 @@ files:
49
52
  - examples/counter.kap
50
53
  - examples/describe.kap
51
54
  - examples/destructure.kap
55
+ - examples/divisibility-stats.kap
52
56
  - examples/doto-hygiene.kap
53
57
  - examples/doto.kap
54
58
  - examples/egg-count.kap
59
+ - examples/equal-sums.kap
55
60
  - examples/even-squares.kap
56
61
  - examples/exceptions.kap
57
62
  - examples/factorial.kap
@@ -87,6 +92,8 @@ files:
87
92
  - examples/module-header.kap
88
93
  - examples/move-zeroes.kap
89
94
  - examples/mruby-runtime-examples.txt
95
+ - examples/nested-nil-pattern.kap
96
+ - examples/non-constant-local.kap
90
97
  - examples/number-of-1-bits.kap
91
98
  - examples/number-of-steps.kap
92
99
  - examples/or-patterns.kap