kapusta 0.13.2 → 0.15.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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -11
  3. data/bin/check-all +6 -1
  4. data/bin/compile-examples +7 -2
  5. data/examples/anagram.kap +3 -3
  6. data/examples/app/args.kap +9 -0
  7. data/examples/arrange-coins.kap +3 -3
  8. data/examples/baseball-game.kap +5 -5
  9. data/examples/best-time-to-buy-sell-stock.kap +2 -2
  10. data/examples/binary-search.kap +2 -2
  11. data/examples/binary-to-decimal.kap +1 -1
  12. data/examples/blocks-and-kwargs.kap +2 -2
  13. data/examples/count-effects.kap +1 -1
  14. data/examples/count-items-matching-rule.kap +18 -0
  15. data/examples/digit-tools.kap +24 -0
  16. data/examples/doto-hygiene.kap +2 -2
  17. data/examples/doto.kap +2 -2
  18. data/examples/egg-count.kap +1 -1
  19. data/examples/excel-column.kap +26 -0
  20. data/examples/exceptions.kap +1 -1
  21. data/examples/falling-drops.kap +7 -7
  22. data/examples/fennel-parity-examples.txt +3 -6
  23. data/examples/good-pairs.kap +18 -0
  24. data/examples/greet.kap +1 -1
  25. data/examples/happy-number.kap +2 -2
  26. data/examples/left-right-difference.kap +60 -0
  27. data/examples/length-of-last-word.kap +4 -4
  28. data/examples/logger-rate-limiter.kap +26 -0
  29. data/examples/manhattan-distance.kap +1 -1
  30. data/examples/maximum-subarray.kap +23 -7
  31. data/examples/minimum-start-value.kap +19 -0
  32. data/examples/move-zeroes.kap +2 -2
  33. data/examples/mruby-runtime-examples.txt +10 -2
  34. data/examples/non-constant-local.kap +1 -1
  35. data/examples/number-of-1-bits.kap +1 -1
  36. data/examples/number-of-steps.kap +1 -1
  37. data/examples/palindrome.kap +2 -2
  38. data/examples/pangram.kap +4 -4
  39. data/examples/pcall.kap +3 -3
  40. data/examples/pipeline.kap +4 -4
  41. data/examples/plus-one.kap +3 -3
  42. data/examples/raindrops.kap +1 -1
  43. data/examples/range-width.kap +14 -0
  44. data/examples/recent-counter.kap +6 -6
  45. data/examples/require-local-args.kap +9 -0
  46. data/examples/require-local.kap +7 -0
  47. data/examples/require-module-local.kap +4 -0
  48. data/examples/require-module.kap +4 -0
  49. data/examples/reverse-integer.kap +1 -1
  50. data/examples/roman-to-integer.kap +3 -3
  51. data/examples/running-sum.kap +20 -0
  52. data/examples/safe-lookup.kap +2 -2
  53. data/examples/single-number.kap +1 -1
  54. data/examples/stack.kap +14 -14
  55. data/examples/subtract-product-sum.kap +1 -1
  56. data/examples/summary-ranges.kap +45 -0
  57. data/examples/threading.kap +5 -5
  58. data/examples/tset.kap +1 -1
  59. data/examples/two-sum-hash.kap +3 -3
  60. data/examples/two-sum.kap +1 -1
  61. data/examples/ugly-number.kap +1 -1
  62. data/examples/underground-system.kap +39 -0
  63. data/examples/valid-parentheses-1.kap +6 -6
  64. data/exe/kapusta-ls +49 -2
  65. data/lib/kapusta/ast.rb +8 -0
  66. data/lib/kapusta/compiler/emitter/bindings.rb +111 -89
  67. data/lib/kapusta/compiler/emitter/collections.rb +32 -40
  68. data/lib/kapusta/compiler/emitter/control_flow.rb +33 -31
  69. data/lib/kapusta/compiler/emitter/expressions.rb +21 -5
  70. data/lib/kapusta/compiler/emitter/interop.rb +172 -48
  71. data/lib/kapusta/compiler/emitter/patterns.rb +12 -14
  72. data/lib/kapusta/compiler/emitter/support.rb +70 -81
  73. data/lib/kapusta/compiler/language.rb +533 -0
  74. data/lib/kapusta/compiler/lua_compat.rb +23 -28
  75. data/lib/kapusta/compiler/macro_expander.rb +30 -30
  76. data/lib/kapusta/compiler/macro_lowerer.rb +12 -24
  77. data/lib/kapusta/compiler/normalizer.rb +25 -17
  78. data/lib/kapusta/compiler.rb +3 -24
  79. data/lib/kapusta/env.rb +2 -2
  80. data/lib/kapusta/errors.rb +2 -1
  81. data/lib/kapusta/formatter/ast_helpers.rb +78 -0
  82. data/lib/kapusta/formatter/cli.rb +125 -0
  83. data/lib/kapusta/formatter/line_helpers.rb +44 -0
  84. data/lib/kapusta/formatter/validator.rb +32 -0
  85. data/lib/kapusta/formatter.rb +363 -325
  86. data/lib/kapusta/lsp/identifier.rb +1 -1
  87. data/lib/kapusta/lsp/rename.rb +21 -11
  88. data/lib/kapusta/lsp/scope_walker.rb +122 -212
  89. data/lib/kapusta/lsp/workspace_index.rb +17 -5
  90. data/lib/kapusta/reader.rb +4 -2
  91. data/lib/kapusta/version.rb +1 -1
  92. data/lib/kapusta.rb +39 -6
  93. data/spec/cli_spec.rb +13 -0
  94. data/spec/examples_errors_spec.rb +3 -1
  95. data/spec/examples_spec.rb +99 -15
  96. data/spec/formatter_spec.rb +246 -0
  97. data/spec/lsp_spec.rb +69 -0
  98. data/spec/require_spec.rb +294 -0
  99. metadata +23 -2
  100. data/examples/describe.kap +0 -9
@@ -19,26 +19,30 @@ climbing-stairs
19
19
  contains-duplicate
20
20
  convert-temperature
21
21
  count-effects
22
+ count-items-matching-rule
22
23
  counter
23
- describe
24
24
  destructure
25
+ digit-tools
25
26
  divisibility-stats
26
27
  doto
27
28
  doto-hygiene
28
29
  egg-count
29
30
  even-squares
31
+ excel-column
30
32
  exceptions
31
33
  factorial
32
34
  falling-drops
33
35
  fib
34
36
  fizzbuzz
35
37
  gcd
38
+ good-pairs
36
39
  greet
37
40
  happy-number
38
41
  hashfn
39
42
  hit-counter
40
43
  kwargs
41
44
  leap-year
45
+ left-right-difference
42
46
  length-of-last-word
43
47
  macros-dbg
44
48
  macros-import
@@ -55,9 +59,10 @@ match
55
59
  max-achievable
56
60
  maximum-subarray
57
61
  min-max
62
+ minimum-start-value
58
63
  module-header
59
- nested-nil-pattern
60
64
  move-zeroes
65
+ nested-nil-pattern
61
66
  number-of-1-bits
62
67
  number-of-steps
63
68
  or-patterns
@@ -70,11 +75,13 @@ points
70
75
  power-of-three
71
76
  primes
72
77
  raindrops
78
+ range-width
73
79
  recent-counter
74
80
  record
75
81
  reverse-integer
76
82
  roman-to-integer
77
83
  ruby-eval
84
+ running-sum
78
85
  safe-lookup
79
86
  scopes
80
87
  shapes
@@ -84,6 +91,7 @@ squares
84
91
  stack
85
92
  subtract-product-sum
86
93
  sum
94
+ summary-ranges
87
95
  thread-styles
88
96
  threading
89
97
  tic-tac-toe
@@ -8,4 +8,4 @@
8
8
  (print (regular-fn 5))
9
9
  (print (lambda-fn 5))
10
10
  (print (length vec-binding))
11
- (print (. hash-binding :a))
11
+ (print hash-binding:a)
@@ -5,7 +5,7 @@
5
5
  (var count 0)
6
6
  (for [_ 1 BIT-WIDTH]
7
7
  (set count (+ count (% x 2)))
8
- (set x (: (/ x 2) :floor)))
8
+ (set x (. (/ x 2) :floor)))
9
9
  count)
10
10
 
11
11
  (print (hamming-weight 11))
@@ -5,7 +5,7 @@
5
5
  (var steps 0)
6
6
  (while (not= x target)
7
7
  (if (= 0 (% x 2))
8
- (set x (: (/ x 2) :floor))
8
+ (set x (. (/ x 2) :floor))
9
9
  (set x (- x 1)))
10
10
  (set steps (+ steps 1)))
11
11
  steps)
@@ -1,6 +1,6 @@
1
1
  (fn palindrome? [s]
2
- (let [normalized (-> s (: :downcase) (: :gsub (ruby "/[^a-z]/") ""))]
3
- (= normalized (: normalized :reverse))))
2
+ (let [normalized (-> s (. :downcase) (. :gsub (ruby "/[^a-z]/") ""))]
3
+ (= normalized (. normalized :reverse))))
4
4
 
5
5
  (print (palindrome? "racecar"))
6
6
  (print (palindrome? "A man, a plan, a canal: Panama"))
data/examples/pangram.kap CHANGED
@@ -1,10 +1,10 @@
1
1
  (fn pangram? [s]
2
2
  (= 26
3
3
  (length (-> s
4
- (: :downcase)
5
- (: :gsub (ruby "/[^a-z]/") "")
6
- (: :chars)
7
- (: :uniq)))))
4
+ (. :downcase)
5
+ (. :gsub (ruby "/[^a-z]/") "")
6
+ (. :chars)
7
+ (. :uniq)))))
8
8
 
9
9
  (print (pangram? "The quick brown fox jumps over the lazy dog"))
10
10
  (print (pangram? "Hello, world"))
data/examples/pcall.kap CHANGED
@@ -1,12 +1,12 @@
1
1
  (fn parse-int [s]
2
- (: Kernel :Integer s))
2
+ (. Kernel :Integer s))
3
3
 
4
4
  (let [[ok value] (pcall parse-int "12")
5
5
  [bad-ok error] (pcall parse-int "oops")
6
- [handled-ok handled] (xpcall parse-int (fn [e] (e.message)) "oops")]
6
+ [handled-ok handled] (xpcall parse-int (fn [e] (. e :message)) "oops")]
7
7
  (print ok)
8
8
  (print value)
9
9
  (print bad-ok)
10
- (print (error.class))
10
+ (print (. error :class))
11
11
  (print handled-ok)
12
12
  (print handled))
@@ -3,7 +3,7 @@
3
3
  ; Filter first so later stages stay focused.
4
4
  (-> words
5
5
  ; Keep the shorter words before transforming them.
6
- (: :select (fn [w] (< (length w) 5)))
7
- (: :map (fn [w] (w.upcase)))
8
- (: :sort)
9
- (: :each (fn [w] (print w)))))
6
+ (. :select (fn [w] (< (length w) 5)))
7
+ (. :map (fn [w] (. w :upcase)))
8
+ (. :sort)
9
+ (. :each (fn [w] (print w)))))
@@ -2,11 +2,11 @@
2
2
  (var i (- (length digits) 1))
3
3
  (var carry 1)
4
4
  (while (and (>= i 0) (> carry 0))
5
- (let [total (+ (. digits i) carry)]
5
+ (let [total (+ (: digits i) carry)]
6
6
  (tset digits i (% total 10))
7
- (set carry (: (/ total 10) :floor)))
7
+ (set carry (. (/ total 10) :floor)))
8
8
  (set i (- i 1)))
9
- (if (> carry 0) (: digits :unshift carry) digits))
9
+ (if (> carry 0) (. digits :unshift carry) digits))
10
10
 
11
11
  (print (plus-one [1 2 3]))
12
12
  (print (plus-one [4 3 2 1]))
@@ -7,7 +7,7 @@
7
7
  (when (div? n 5) (add-drop "Plang"))
8
8
  (when (div? n 7) (add-drop "Plong"))
9
9
  (if (empty? drops)
10
- (: n :to-s)
10
+ n.to-s
11
11
  (drops.join)))
12
12
 
13
13
  (print (raindrops 15))
@@ -0,0 +1,14 @@
1
+ (fn range-width [lo hi]
2
+ (- hi lo))
3
+
4
+ (fn min-max-range [nums]
5
+ (var lo 1000000)
6
+ (var hi -1000000)
7
+ (each [_ n (ipairs nums)]
8
+ (when (< n lo) (set lo n))
9
+ (when (> n hi) (set hi n)))
10
+ (range-width (values lo hi)))
11
+
12
+ (print (min-max-range [4 2 9 1 7]))
13
+ (print (min-max-range [10 10 10]))
14
+ (print (min-max-range [-3 8 0 5]))
@@ -2,16 +2,16 @@
2
2
  (fn initialize [] (set @pings []))
3
3
  (fn ping [t]
4
4
  (let [pings @pings]
5
- (pings.push t)
6
- (while (< (. pings 0) (- t 3000))
7
- (pings.shift))
5
+ (. pings :push t)
6
+ (while (< (: pings 0) (- t 3000))
7
+ (. pings :shift))
8
8
  (length pings)))
9
9
  (defn warm [history]
10
10
  (let [c (RecentCounter.new)]
11
- (each [_ t (ipairs history)] (c.ping t))
11
+ (each [_ t (ipairs history)] (. c :ping t))
12
12
  c))
13
13
  (end)
14
14
 
15
15
  (let [c (RecentCounter.warm [100 200 300])]
16
- (print (c.ping 3001))
17
- (print (c.ping 3002)))
16
+ (print (. c :ping 3001))
17
+ (print (. c :ping 3002)))
@@ -0,0 +1,9 @@
1
+ (module RequireLocalArgs)
2
+
3
+ (defn parse [argv]
4
+ {:command (: argv 0) :options (. argv :drop 1)})
5
+
6
+ (defn usage []
7
+ "usage: kapusta <command> [options]")
8
+
9
+ (end)
@@ -0,0 +1,7 @@
1
+ (require "./require-local-args")
2
+
3
+ (let [parsed (RequireLocalArgs.parse ["serve" "--port" "3000"])
4
+ options parsed:options]
5
+ (print parsed:command)
6
+ (print (options.join " "))
7
+ (print (RequireLocalArgs.usage)))
@@ -0,0 +1,4 @@
1
+ (local args (require :app.args))
2
+
3
+ (let [parsed (args.parse ["deploy" "production"])]
4
+ (print (args.format-command parsed)))
@@ -0,0 +1,4 @@
1
+ (require :app.args)
2
+
3
+ (let [parsed (App.Args.parse ["deploy" "production"])]
4
+ (print (App.Args.format-command parsed)))
@@ -4,7 +4,7 @@
4
4
  (var result 0)
5
5
  (while (> remaining 0)
6
6
  (set result (+ (* result 10) (% remaining 10)))
7
- (set remaining (: (/ remaining 10) :floor)))
7
+ (set remaining (. (/ remaining 10) :floor)))
8
8
  (* result sign)))
9
9
 
10
10
  (print (reverse-integer 123))
@@ -1,12 +1,12 @@
1
1
  (fn roman-to-integer [s]
2
2
  (let [value-map {"I" 1 "V" 5 "X" 10 "L" 50 "C" 100 "D" 500 "M" 1000}
3
- chars (s.chars)
3
+ chars (. s :chars)
4
4
  n (length chars)]
5
5
  (var total 0)
6
6
  (var i 0)
7
7
  (while (< i n)
8
- (let [curr (. value-map (. chars i))
9
- ahead (if (< (+ i 1) n) (. value-map (. chars (+ i 1))) 0)
8
+ (let [curr (: value-map (: chars i))
9
+ ahead (if (< (+ i 1) n) (: value-map (: chars (+ i 1))) 0)
10
10
  subtract? (< curr ahead)]
11
11
  (set total (+ total (if subtract? (- ahead curr) curr)))
12
12
  (set i (+ i (if subtract? 2 1)))))
@@ -0,0 +1,20 @@
1
+ (fn same-list? [a b]
2
+ (var ok (= (length a) (length b)))
3
+ (each [i value (ipairs a)]
4
+ (when (not (= value (: b i)))
5
+ (set ok false)))
6
+ ok)
7
+
8
+ (fn running-sum [nums]
9
+ (var total 0)
10
+ (icollect [_ n (ipairs nums)]
11
+ (do
12
+ (set total (+ total n))
13
+ total)))
14
+
15
+ (print (same-list? [1 3 6 10 15 21 28 36 45 55 66 78]
16
+ (running-sum [1 2 3 4 5 6 7 8 9 10 11 12])))
17
+
18
+ (print (same-list? [1 2 3 4 5] (running-sum [1 1 1 1 1])))
19
+
20
+ (print (same-list? [3 4 6 16 17] (running-sum [3 1 2 10 1])))
@@ -1,6 +1,6 @@
1
1
  (let [user {:profile {:name "Ada"}}
2
2
  missing {}
3
- name (?. user :profile :name)
4
- missing-name (?. missing :profile :name)]
3
+ name (?: user :profile :name)
4
+ missing-name (?: missing :profile :name)]
5
5
  (print name)
6
6
  (print missing-name))
@@ -1,6 +1,6 @@
1
1
  (fn single-number [nums]
2
2
  (accumulate [acc 0 _ n (ipairs nums)]
3
- (: acc :^ n)))
3
+ (. acc :^ n)))
4
4
 
5
5
  (print (single-number [2 2 1]))
6
6
  (print (single-number [4 1 2 1 2]))
data/examples/stack.kap CHANGED
@@ -7,32 +7,32 @@
7
7
  (fn push [x]
8
8
  (let [xs (ivar xs)
9
9
  mins (ivar mins)
10
- current-min (if (mins.empty?) x (< x (. mins -1)) x (. mins -1))]
11
- (xs.push x)
12
- (mins.push current-min))
10
+ current-min (if (. mins :empty?) x (< x (: mins -1)) x (: mins -1))]
11
+ (. xs :push x)
12
+ (. mins :push current-min))
13
13
  self)
14
14
 
15
15
  (fn pop []
16
16
  (let [mins (ivar mins)]
17
- (mins.pop))
17
+ (. mins :pop))
18
18
  (let [xs (ivar xs)]
19
- (xs.pop)))
19
+ (. xs :pop)))
20
20
 
21
21
  (fn top []
22
- (. (ivar xs) -1))
22
+ (: (ivar xs) -1))
23
23
 
24
24
  (fn get-min []
25
- (. (ivar mins) -1))
25
+ (: (ivar mins) -1))
26
26
 
27
27
  (end)
28
28
 
29
29
  (let [s (MinStack.new)]
30
- (s.push -2)
31
- (s.push 0)
32
- (s.push -3)
33
- (print (s.get-min))
34
- (s.pop)
35
- (print (s.top))
36
- (print (s.get-min)))
30
+ (. s :push -2)
31
+ (. s :push 0)
32
+ (. s :push -3)
33
+ (print (. s :get-min))
34
+ (. s :pop)
35
+ (print (. s :top))
36
+ (print (. s :get-min)))
37
37
 
38
38
  (print (= MinStack.superclass Object))
@@ -6,7 +6,7 @@
6
6
  (let [d (% x 10)]
7
7
  (set product (* product d))
8
8
  (set sum (+ sum d))
9
- (set x (: (/ x 10) :floor))))
9
+ (set x (. (/ x 10) :floor))))
10
10
  (- product sum))
11
11
 
12
12
  (print (subtract-product-sum 234))
@@ -0,0 +1,45 @@
1
+ (fn join [sep xs]
2
+ (var s "")
3
+ (each [_ x (ipairs xs)]
4
+ (if (= s "")
5
+ (set s (.. x))
6
+ (set s (.. s sep x))))
7
+ s)
8
+
9
+ (fn range-boundary->string [n]
10
+ (.. n))
11
+
12
+ (fn range-label [range-start range-end]
13
+ (if (= range-start range-end)
14
+ (range-boundary->string range-start)
15
+ (join "" [(range-boundary->string range-start)
16
+ "->"
17
+ (range-boundary->string range-end)])))
18
+
19
+ (fn append-range [out lo hi]
20
+ (let [label (range-label lo hi)
21
+ parts [out (if (= out "") "" "|") label]]
22
+ (join "" parts)))
23
+
24
+ (fn summary-ranges [nums]
25
+ (var started? false)
26
+ (var start 0)
27
+ (var prev 0)
28
+ (var out "")
29
+ (each [_ n (ipairs nums)]
30
+ (if started?
31
+ (if (= n (+ prev 1))
32
+ (set prev n)
33
+ (do
34
+ (set out (append-range out start prev))
35
+ (set start n)
36
+ (set prev n)))
37
+ (do
38
+ (set started? true)
39
+ (set start n)
40
+ (set prev n))))
41
+ (if started? (append-range out start prev) out))
42
+
43
+ (print (summary-ranges [0 1 2 4 5 7]))
44
+ (print (summary-ranges [0 2 3 4 6 8 9]))
45
+ (print (.. "empty=" (summary-ranges [])))
@@ -5,7 +5,7 @@
5
5
  (.. left value right))
6
6
 
7
7
  (fn fetch-name [user]
8
- (?. user :profile :name))
8
+ (?: user :profile :name))
9
9
 
10
10
  (let [thread-last (->> "Ada"
11
11
  (append " Lovelace")
@@ -20,9 +20,9 @@
20
20
  (append "!")
21
21
  (wrap "<" ">"))
22
22
  thread-first (-?> "kapusta"
23
- (: :upcase)
24
- (: :reverse))
23
+ (. :upcase)
24
+ (. :reverse))
25
25
  missing-first (-?> nil
26
- (: :upcase)
27
- (: :reverse))]
26
+ (. :upcase)
27
+ (. :reverse))]
28
28
  (print thread-last maybe-name missing-name thread-first missing-first))
data/examples/tset.kap CHANGED
@@ -1,4 +1,4 @@
1
1
  (let [person {:name "Ada"}]
2
2
  (tset person :city "Amsterdam")
3
3
  (print person)
4
- (print (. person :city)))
4
+ (print person:city))
@@ -2,10 +2,10 @@
2
2
  (var i 0)
3
3
  (var answer nil)
4
4
  (while (and (< i (length nums)) (= answer nil))
5
- (let [n (. nums i)
5
+ (let [n (: nums i)
6
6
  complement (- target n)]
7
- (if (seen.key? complement)
8
- (set answer [(. seen complement) i])
7
+ (if (. seen :key? complement)
8
+ (set answer [(: seen complement) i])
9
9
  (tset seen n i)))
10
10
  (set i (+ i 1)))
11
11
  answer)]
data/examples/two-sum.kap CHANGED
@@ -4,7 +4,7 @@
4
4
  (while (and (< i (length xs)) (= answer nil))
5
5
  (var j (+ i 1))
6
6
  (while (and (< j (length xs)) (= answer nil))
7
- (when (= (+ (. xs i) (. xs j)) target) (set answer [i j]))
7
+ (when (= (+ (: xs i) (: xs j)) target) (set answer [i j]))
8
8
  (set j (+ j 1)))
9
9
  (set i (+ i 1)))
10
10
  answer)
@@ -1,5 +1,5 @@
1
1
  (macro floor-div [a b]
2
- `(: (/ ,a ,b) :floor))
2
+ `(. (/ ,a ,b) :floor))
3
3
 
4
4
  (macro divide-out! [v d]
5
5
  `(while (= 0 (% ,v ,d))
@@ -0,0 +1,39 @@
1
+ (fn underground-system []
2
+ (let [active []
3
+ routes {:leyton-waterloo {:total 0 :count 0}
4
+ :paradise-cambridge {:total 0 :count 0}}
5
+ route-stat (fn [start end]
6
+ (case [start end]
7
+ ["Leyton" "Waterloo"] routes:leyton-waterloo
8
+ ["Paradise" "Cambridge"] routes:paradise-cambridge))
9
+ find-trip (fn [id]
10
+ (var found nil)
11
+ (each [_ trip (ipairs active)]
12
+ (when (= trip:id id)
13
+ (set found trip)))
14
+ found)
15
+ ops {:check-in (fn [id station time]
16
+ (active.push {: id : station : time}))
17
+ :check-out (fn [id station time]
18
+ (let [trip (find-trip id)
19
+ start trip:station
20
+ duration (- time trip:time)
21
+ stat (route-stat start station)]
22
+ (tset stat :total (+ stat:total duration))
23
+ (tset stat :count (+ stat:count 1))))
24
+ :average-time (fn [start end]
25
+ (let [stat (route-stat start end)]
26
+ (/ stat:total stat:count)))}]
27
+ {:active active :ops ops :routes routes}))
28
+
29
+ (local system (underground-system))
30
+
31
+ (system:ops:check-in 45 "Leyton" 3)
32
+ (system:ops:check-in 32 "Paradise" 8)
33
+ (system:ops:check-in 27 "Leyton" 10)
34
+ (system:ops:check-out 45 "Waterloo" 15)
35
+ (system:ops:check-out 27 "Waterloo" 20)
36
+ (system:ops:check-out 32 "Cambridge" 22)
37
+
38
+ (print (system:ops:average-time "Leyton" "Waterloo"))
39
+ (print (system:ops:average-time "Paradise" "Cambridge"))
@@ -7,15 +7,15 @@
7
7
  (fn valid? [s]
8
8
  (let [pairs (ivar pairs)
9
9
  stack []
10
- chars (s.chars)]
10
+ chars (. s :chars)]
11
11
  (var i 0)
12
12
  (var ok true)
13
13
  (while (and ok (< i (length chars)))
14
- (let [ch (. chars i)]
15
- (if (pairs.key? ch)
16
- (if (-?> (stack.pop) (= (. pairs ch))) nil (set ok false))
17
- (stack.push ch)))
14
+ (let [ch (: chars i)]
15
+ (if (. pairs :key? ch)
16
+ (if (-?> (. stack :pop) (= (: pairs ch))) nil (set ok false))
17
+ (. stack :push ch)))
18
18
  (set i (+ i 1)))
19
- (and ok (stack.empty?))))
19
+ (and ok (. stack :empty?))))
20
20
 
21
21
  (end)
data/exe/kapusta-ls CHANGED
@@ -3,12 +3,59 @@
3
3
 
4
4
  require_relative '../lib/kapusta/lsp'
5
5
 
6
+ def check_paths(args)
7
+ paths = args.flat_map do |arg|
8
+ if File.directory?(arg)
9
+ Dir[File.join(arg, '**', '*.kap')]
10
+ else
11
+ arg
12
+ end
13
+ end.uniq.sort
14
+
15
+ if paths.empty?
16
+ warn 'kapusta-ls: no .kap files found'
17
+ return 1
18
+ end
19
+
20
+ failures = []
21
+ paths.each do |path|
22
+ Kapusta.compile(File.read(path), path:)
23
+ rescue Kapusta::Error => e
24
+ failures << e.formatted
25
+ rescue SystemCallError => e
26
+ failures << "#{path}: #{e.message}"
27
+ end
28
+
29
+ if failures.empty?
30
+ puts "kapusta-ls checked #{paths.length} files"
31
+ 0
32
+ else
33
+ warn "#{failures.length} files reported kapusta-ls diagnostics:"
34
+ failures.each { |failure| warn " #{failure}" }
35
+ 1
36
+ end
37
+ end
38
+
6
39
  case ARGV.first
7
40
  when '--version', '-v'
8
41
  puts "kapusta-ls #{Kapusta::VERSION}"
9
42
  when '--help', '-h'
10
- puts 'usage: kapusta-ls # speak LSP over stdio'
43
+ puts 'usage: kapusta-ls # speak LSP over stdio'
44
+ puts ' kapusta-ls FILES... # check files or directories'
45
+ puts ' kapusta-ls --lint FILES...'
11
46
  puts ' kapusta-ls --version'
12
- else
47
+ when '--server'
13
48
  Kapusta::LSP.start
49
+ when '--lint'
50
+ exit check_paths(ARGV[1..])
51
+ else
52
+ if ARGV.empty?
53
+ Kapusta::LSP.start
54
+ elsif ARGV.first.start_with?('-')
55
+ warn "kapusta-ls: unknown option #{ARGV.first}"
56
+ warn 'usage: kapusta-ls [--lint] FILES...'
57
+ exit 1
58
+ else
59
+ exit check_paths(ARGV)
60
+ end
14
61
  end
data/lib/kapusta/ast.rb CHANGED
@@ -47,6 +47,14 @@ module Kapusta
47
47
  def segments
48
48
  @name.split('.')
49
49
  end
50
+
51
+ def colonized?
52
+ @name != ':' && !@name.start_with?(':') && @name.include?(':')
53
+ end
54
+
55
+ def colon_segments
56
+ @name.split(':')
57
+ end
50
58
  end
51
59
 
52
60
  class GeneratedSym < Sym