kapusta 0.3.0 → 0.5.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.
@@ -6,8 +6,8 @@ module Kapusta
6
6
  class Reader
7
7
  class Error < Kapusta::Error; end
8
8
 
9
- WHITESPACE = [' ', "\t", "\n", "\r", "\f", "\v", ','].freeze
10
- DELIMS = ['(', ')', '[', ']', '{', '}', '"', ';'].freeze
9
+ WHITESPACE = [' ', "\t", "\n", "\r", "\f", "\v"].freeze
10
+ DELIMS = ['(', ')', '[', ']', '{', '}', '"', ';', '`', ','].freeze
11
11
  CLOSING_DELIMS = [')', ']', '}'].freeze
12
12
 
13
13
  def self.read_all(source, preserve_comments: false)
@@ -23,9 +23,10 @@ module Kapusta
23
23
  def read_all
24
24
  forms = []
25
25
  loop do
26
- skip_ws
26
+ had_blank = skip_ws
27
27
  break if eof?
28
28
 
29
+ forms << BlankLine.new if @preserve_comments && had_blank && !forms.empty?
29
30
  forms << read_next_item
30
31
  end
31
32
  forms
@@ -47,10 +48,14 @@ module Kapusta
47
48
  char
48
49
  end
49
50
 
50
- def skip_ws
51
+ def skip_ws # rubocop:disable Naming/PredicateMethod
52
+ newlines = 0
51
53
  until eof?
52
54
  char = peek
53
- if WHITESPACE.include?(char)
55
+ if char == "\n"
56
+ newlines += 1
57
+ advance
58
+ elsif WHITESPACE.include?(char)
54
59
  advance
55
60
  elsif !@preserve_comments && char == ';'
56
61
  advance until eof? || peek == "\n"
@@ -58,6 +63,7 @@ module Kapusta
58
63
  break
59
64
  end
60
65
  end
66
+ newlines >= 2
61
67
  end
62
68
 
63
69
  def delim?(char)
@@ -66,7 +72,7 @@ module Kapusta
66
72
 
67
73
  def read_next_item
68
74
  skip_ws
69
- raise Error, 'unexpected eof' if eof?
75
+ raise reader_error(:unexpected_eof, source_position) if eof?
70
76
 
71
77
  return read_comment if @preserve_comments && peek == ';'
72
78
 
@@ -75,10 +81,11 @@ module Kapusta
75
81
 
76
82
  def read_form
77
83
  skip_ws
78
- raise Error, 'unexpected eof' if eof?
84
+ raise reader_error(:unexpected_eof, source_position) if eof?
79
85
 
80
86
  return read_comment if @preserve_comments && peek == ';'
81
87
 
88
+ position = source_position
82
89
  form =
83
90
  case peek
84
91
  when '(' then read_list
@@ -86,27 +93,59 @@ module Kapusta
86
93
  when '{' then read_hash
87
94
  when '"' then read_string
88
95
  when '#' then read_hashfn
96
+ when '`' then read_quasiquote
97
+ when ',' then read_unquote
89
98
  when *CLOSING_DELIMS then raise unexpected_closing_delim(peek)
90
99
  else
91
100
  read_atom
92
101
  end
93
102
 
103
+ attach_position(form, position)
94
104
  read_postfix(form)
95
105
  end
96
106
 
107
+ def attach_position(form, position)
108
+ return form unless form.respond_to?(:line=)
109
+
110
+ form.line ||= position[0]
111
+ form.column ||= position[1]
112
+ form
113
+ end
114
+
115
+ def read_quasiquote
116
+ advance
117
+ Quasiquote.new(read_form)
118
+ end
119
+
120
+ def read_unquote
121
+ advance
122
+ if peek == '@'
123
+ advance
124
+ UnquoteSplice.new(read_form)
125
+ else
126
+ Unquote.new(read_form)
127
+ end
128
+ end
129
+
97
130
  def read_list
98
131
  opening_position = source_position
99
132
  advance
100
133
  items = []
101
134
  loop do
102
- skip_ws
135
+ had_blank = skip_ws
103
136
  raise unclosed_opening_delim('(', opening_position) if eof?
104
137
  break if peek == ')'
105
138
 
139
+ items << BlankLine.new if @preserve_comments && had_blank && !items.empty?
106
140
  items << read_next_item
107
141
  end
142
+ closing_position = source_position
108
143
  advance
109
- List.new(items)
144
+ list = List.new(items)
145
+ list.multiline_source = closing_position[0] != opening_position[0]
146
+ list.line = opening_position[0]
147
+ list.column = opening_position[1]
148
+ list
110
149
  end
111
150
 
112
151
  def read_vec
@@ -114,14 +153,20 @@ module Kapusta
114
153
  advance
115
154
  items = []
116
155
  loop do
117
- skip_ws
156
+ had_blank = skip_ws
118
157
  raise unclosed_opening_delim('[', opening_position) if eof?
119
158
  break if peek == ']'
120
159
 
160
+ items << BlankLine.new if @preserve_comments && had_blank && !items.empty?
121
161
  items << read_next_item
122
162
  end
163
+ closing_position = source_position
123
164
  advance
124
- Vec.new(items)
165
+ vec = Vec.new(items)
166
+ vec.multiline_source = closing_position[0] != opening_position[0]
167
+ vec.line = opening_position[0]
168
+ vec.column = opening_position[1]
169
+ vec
125
170
  end
126
171
 
127
172
  def read_hash
@@ -146,14 +191,20 @@ module Kapusta
146
191
  entries << normalize_hash_pair(pending[0], pending[1])
147
192
  pending.clear
148
193
  end
194
+ closing_position = source_position
149
195
  advance
150
196
 
151
- raise Error, 'odd number of forms in hash' unless pending.empty?
197
+ raise reader_error(:odd_forms_in_hash, opening_position) unless pending.empty?
152
198
 
153
- HashLit.new(entries)
199
+ hash = HashLit.new(entries)
200
+ hash.multiline_source = closing_position[0] != opening_position[0]
201
+ hash.line = opening_position[0]
202
+ hash.column = opening_position[1]
203
+ hash
154
204
  end
155
205
 
156
206
  def read_string
207
+ opening_position = source_position
157
208
  advance
158
209
  buffer = +''
159
210
  until eof? || peek == '"'
@@ -177,7 +228,7 @@ module Kapusta
177
228
  buffer << advance
178
229
  end
179
230
  end
180
- raise Error, 'unterminated string' if eof?
231
+ raise reader_error(:unterminated_string, opening_position) if eof?
181
232
 
182
233
  advance
183
234
  buffer
@@ -215,22 +266,25 @@ module Kapusta
215
266
  end
216
267
 
217
268
  def read_atom
269
+ position = source_position
218
270
  start = @pos
219
271
  advance until delim?(peek)
220
272
  token = @src[start...@pos]
221
- raise Error, 'empty token' if token.empty?
273
+ raise reader_error(:empty_token, position) if token.empty?
222
274
 
223
- parse_atom(token)
275
+ parse_atom(token, position)
224
276
  end
225
277
 
226
278
  def unexpected_closing_delim(char)
227
- line, column = source_position
228
- Error.new("unexpected closing delimiter '#{char}' at line #{line}, column #{column}")
279
+ reader_error(:unexpected_closing_delimiter, source_position, char:)
229
280
  end
230
281
 
231
282
  def unclosed_opening_delim(char, position)
232
- line, column = position
233
- Error.new("unclosed opening delimiter '#{char}' at line #{line}, column #{column}")
283
+ reader_error(:unclosed_delimiter, position, char:)
284
+ end
285
+
286
+ def reader_error(code, position, **args)
287
+ Error.new(Kapusta::Errors.format(code, **args), line: position[0], column: position[1])
234
288
  end
235
289
 
236
290
  def source_position
@@ -242,15 +296,19 @@ module Kapusta
242
296
  [line, column]
243
297
  end
244
298
 
245
- def parse_atom(token)
299
+ def parse_atom(token, position)
246
300
  return true if token == 'true'
247
301
  return false if token == 'false'
248
302
  return if token == 'nil'
249
303
  return Integer(token, 10) if token.match?(/\A-?\d+\z/)
250
304
  return Float(token) if token.match?(/\A-?\d+\.\d+\z/)
251
305
 
306
+ raise reader_error(:could_not_read_number, position, token:) if token.match?(/\A-?\d/)
307
+
252
308
  if token.start_with?(':') && token.length > 1
253
309
  Kapusta.kebab_to_snake(token[1..]).to_sym
310
+ elsif token.length > 1 && token.end_with?('#') && !token[0..-2].include?('#')
311
+ AutoGensym.new(token.chomp('#'))
254
312
  else
255
313
  Sym.new(token)
256
314
  end
@@ -258,7 +316,7 @@ module Kapusta
258
316
 
259
317
  def normalize_hash_pair(item, value)
260
318
  if item.is_a?(Sym) && item.name == ':'
261
- raise Error, 'bad shorthand' unless value.is_a?(Sym)
319
+ raise reader_error(:bad_shorthand, source_position) unless value.is_a?(Sym)
262
320
 
263
321
  key = Kapusta.kebab_to_snake(value.name).to_sym
264
322
  [key, value]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kapusta
4
- VERSION = '0.3.0'
4
+ VERSION = '0.5.0'
5
5
  end
data/lib/kapusta.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'kapusta/version'
4
4
  require_relative 'kapusta/error'
5
+ require_relative 'kapusta/errors'
5
6
  require_relative 'kapusta/support'
6
7
  require_relative 'kapusta/ast'
7
8
  require_relative 'kapusta/reader'
@@ -42,14 +43,14 @@ module Kapusta
42
43
 
43
44
  @installed = true
44
45
  Kernel.module_eval do
45
- alias_method :__kapusta_original_require_relative, :require_relative
46
- private :__kapusta_original_require_relative
47
-
48
46
  def require_relative(path)
49
- kap_path = Kapusta.send(:resolve_kap_relative, path, caller_locations(1, 1).first)
47
+ location = caller_locations(1, 1).first
48
+ kap_path = Kapusta.send(:resolve_kap_relative, path, location)
50
49
  return Kapusta.send(:require_kapusta_file, kap_path) if kap_path
51
50
 
52
- __kapusta_original_require_relative(path)
51
+ base_file = location&.absolute_path || location&.path
52
+ target = base_file ? File.expand_path(path, File.dirname(base_file)) : path
53
+ Kernel.require(target)
53
54
  end
54
55
  end
55
56
  end
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'open3'
5
+ require 'rbconfig'
6
+
7
+ ERRORS_DIR = File.expand_path('../examples-errors', __dir__)
8
+ KAPUSTA_BIN = File.expand_path('../exe/kapusta', __dir__)
9
+ KAPFMT_BIN = File.expand_path('../exe/kapfmt', __dir__)
10
+
11
+ def run_error_example(name)
12
+ k_out, k_err, k_status = Open3.capture3(RbConfig.ruby, KAPUSTA_BIN, name, chdir: ERRORS_DIR)
13
+ f_out, f_err, f_status = Open3.capture3(RbConfig.ruby, KAPFMT_BIN, name, chdir: ERRORS_DIR)
14
+
15
+ raise "kapusta unexpectedly succeeded for #{name}" if k_status.success?
16
+ raise "kapfmt unexpectedly succeeded for #{name}" if f_status.success?
17
+ raise "kapusta wrote to stdout for #{name}: #{k_out.inspect}" unless k_out.empty?
18
+ raise "kapfmt wrote to stdout for #{name}: #{f_out.inspect}" unless f_out.empty?
19
+ raise "kapusta and kapfmt disagree for #{name}:\n kapusta: #{k_err} kapfmt: #{f_err}" unless k_err == f_err
20
+
21
+ k_err
22
+ end
23
+
24
+ RSpec.describe 'examples-errors' do
25
+ it 'accumulate-missing-iterator.kap' do
26
+ expect(run_error_example('accumulate-missing-iterator.kap'))
27
+ .to eq("accumulate-missing-iterator.kap:5:3: expected initial value and iterator binding table\n")
28
+ end
29
+
30
+ it 'call-empty-form.kap' do
31
+ expect(run_error_example('call-empty-form.kap'))
32
+ .to eq("call-empty-form.kap:7:8: expected a function, macro, or special to call\n")
33
+ end
34
+
35
+ it 'call-literal-number.kap' do
36
+ expect(run_error_example('call-literal-number.kap'))
37
+ .to eq("call-literal-number.kap:6:14: cannot call literal value 1\n")
38
+ end
39
+
40
+ it 'case-no-patterns.kap' do
41
+ expect(run_error_example('case-no-patterns.kap'))
42
+ .to eq("case-no-patterns.kap:3:5: expected at least one pattern/body pair\n")
43
+ end
44
+
45
+ it 'case-odd-pattern-body.kap' do
46
+ expect(run_error_example('case-odd-pattern-body.kap'))
47
+ .to eq("case-odd-pattern-body.kap:2:3: expected even number of pattern/body pairs\n")
48
+ end
49
+
50
+ it 'destructure-literal-number.kap' do
51
+ expect(run_error_example('destructure-literal-number.kap'))
52
+ .to eq("destructure-literal-number.kap:5:3: could not destructure literal\n")
53
+ end
54
+
55
+ it 'destructure-literal-table.kap' do
56
+ expect(run_error_example('destructure-literal-table.kap'))
57
+ .to eq("destructure-literal-table.kap:4:1: could not destructure literal\n")
58
+ end
59
+
60
+ it 'destructure-rest-as-table.kap' do
61
+ expect(run_error_example('destructure-rest-as-table.kap'))
62
+ .to eq("destructure-rest-as-table.kap:6:3: unable to bind table ...\n")
63
+ end
64
+
65
+ it 'dot-without-table.kap' do
66
+ expect(run_error_example('dot-without-table.kap'))
67
+ .to eq("dot-without-table.kap:5:15: expected table argument\n")
68
+ end
69
+
70
+ it 'each-not-binding-table.kap' do
71
+ expect(run_error_example('each-not-binding-table.kap'))
72
+ .to eq("each-not-binding-table.kap:6:3: expected binding table\n")
73
+ end
74
+
75
+ it 'faccumulate-missing-iterator.kap' do
76
+ expect(run_error_example('faccumulate-missing-iterator.kap'))
77
+ .to eq("faccumulate-missing-iterator.kap:7:3: expected initial value and iterator binding table\n")
78
+ end
79
+
80
+ it 'fcollect-missing-range.kap' do
81
+ expect(run_error_example('fcollect-missing-range.kap'))
82
+ .to eq("fcollect-missing-range.kap:6:3: expected range to include start and stop\n")
83
+ end
84
+
85
+ it 'fn-non-symbol-param.kap' do
86
+ expect(run_error_example('fn-non-symbol-param.kap'))
87
+ .to eq("fn-non-symbol-param.kap:4:1: destructure pattern this compiler cannot translate: [1 2]\n")
88
+ end
89
+
90
+ it 'fn-without-params.kap' do
91
+ expect(run_error_example('fn-without-params.kap'))
92
+ .to eq("fn-without-params.kap:4:11: expected parameters table\n")
93
+ end
94
+
95
+ it 'for-missing-stop.kap' do
96
+ expect(run_error_example('for-missing-stop.kap'))
97
+ .to eq("for-missing-stop.kap:6:3: expected range to include start and stop\n")
98
+ end
99
+
100
+ it 'global-non-symbol-name.kap' do
101
+ expect(run_error_example('global-non-symbol-name.kap'))
102
+ .to eq("global-non-symbol-name.kap:6:1: unable to bind integer 1\n")
103
+ end
104
+
105
+ it 'global-without-value.kap' do
106
+ expect(run_error_example('global-without-value.kap'))
107
+ .to eq("global-without-value.kap:6:1: expected name and value\n")
108
+ end
109
+
110
+ it 'icollect-missing-iterator.kap' do
111
+ expect(run_error_example('icollect-missing-iterator.kap'))
112
+ .to eq("icollect-missing-iterator.kap:6:3: expected iterator binding table\n")
113
+ end
114
+
115
+ it 'if-no-body.kap' do
116
+ expect(run_error_example('if-no-body.kap'))
117
+ .to eq("if-no-body.kap:8:5: expected condition and body\n")
118
+ end
119
+
120
+ it 'import-macros-missing-module.kap' do
121
+ expect(run_error_example('import-macros-missing-module.kap'))
122
+ .to eq("import-macros-missing-module.kap:4:1: import-macros is not yet supported\n")
123
+ end
124
+
125
+ it 'let-odd-bindings.kap' do
126
+ expect(run_error_example('let-odd-bindings.kap'))
127
+ .to eq("let-odd-bindings.kap:2:3: expected even number of name/value bindings\n")
128
+ end
129
+
130
+ it 'let-without-body-form.kap' do
131
+ expect(run_error_example('let-without-body-form.kap'))
132
+ .to eq("let-without-body-form.kap:4:5: expected body expression\n")
133
+ end
134
+
135
+ it 'local-with-extra-args.kap' do
136
+ expect(run_error_example('local-with-extra-args.kap'))
137
+ .to eq("local-with-extra-args.kap:6:3: local: expected name and value\n")
138
+ end
139
+
140
+ it 'local-without-value.kap' do
141
+ expect(run_error_example('local-without-value.kap'))
142
+ .to eq("local-without-value.kap:6:3: local: expected name and value\n")
143
+ end
144
+
145
+ it 'macro-unsafe-bind.kap' do
146
+ expect(run_error_example('macro-unsafe-bind.kap'))
147
+ .to eq("macro-unsafe-bind.kap:13:8: macro tried to bind unsafe without gensym\n")
148
+ end
149
+
150
+ it 'macro-vararg-with-operator.kap' do
151
+ expect(run_error_example('macro-vararg-with-operator.kap'))
152
+ .to eq("macro-vararg-with-operator.kap:5:3: tried to use vararg with operator\n")
153
+ end
154
+
155
+ it 'match-no-patterns.kap' do
156
+ expect(run_error_example('match-no-patterns.kap'))
157
+ .to eq("match-no-patterns.kap:3:5: expected at least one pattern/body pair\n")
158
+ end
159
+
160
+ it 'mismatched-brackets.kap' do
161
+ expect(run_error_example('mismatched-brackets.kap'))
162
+ .to eq("mismatched-brackets.kap:4:19: unexpected closing delimiter ')'\n")
163
+ end
164
+
165
+ it 'only-rest-param.kap' do
166
+ expect(run_error_example('only-rest-param.kap'))
167
+ .to eq("only-rest-param.kap:4:1: expected rest argument before last parameter\n")
168
+ end
169
+
170
+ it 'quote-runtime.kap' do
171
+ expect(run_error_example('quote-runtime.kap'))
172
+ .to eq("quote-runtime.kap:6:1: cannot emit form: `hello\n")
173
+ end
174
+
175
+ it 'rest-not-last.kap' do
176
+ expect(run_error_example('rest-not-last.kap'))
177
+ .to eq("rest-not-last.kap:6:3: expected rest argument before last parameter\n")
178
+ end
179
+
180
+ it 'set-immutable-local.kap' do
181
+ expect(run_error_example('set-immutable-local.kap'))
182
+ .to eq("set-immutable-local.kap:8:3: expected var counter\n")
183
+ end
184
+
185
+ it 'shadow-special-fn.kap' do
186
+ expect(run_error_example('shadow-special-fn.kap'))
187
+ .to eq("shadow-special-fn.kap:6:3: local fn was overshadowed by a special form or macro\n")
188
+ end
189
+
190
+ it 'shadow-special-if.kap' do
191
+ expect(run_error_example('shadow-special-if.kap'))
192
+ .to eq("shadow-special-if.kap:4:1: local if was overshadowed by a special form or macro\n")
193
+ end
194
+
195
+ it 'symbol-starting-with-digit.kap' do
196
+ expect(run_error_example('symbol-starting-with-digit.kap'))
197
+ .to eq("symbol-starting-with-digit.kap:6:10: could not read number \"5var\"\n")
198
+ end
199
+
200
+ it 'tset-missing-value.kap' do
201
+ expect(run_error_example('tset-missing-value.kap'))
202
+ .to eq("tset-missing-value.kap:5:5: tset: expected table, key, and value arguments\n")
203
+ end
204
+
205
+ it 'unbalanced-parens.kap' do
206
+ expect(run_error_example('unbalanced-parens.kap'))
207
+ .to eq("unbalanced-parens.kap:4:1: unclosed opening delimiter '('\n")
208
+ end
209
+
210
+ it 'unclosed-table.kap' do
211
+ expect(run_error_example('unclosed-table.kap'))
212
+ .to eq("unclosed-table.kap:4:21: unexpected closing delimiter ']'\n")
213
+ end
214
+
215
+ it 'unquote-outside-quote.kap' do
216
+ expect(run_error_example('unquote-outside-quote.kap'))
217
+ .to eq("unquote-outside-quote.kap:5:10: cannot emit form: ,x\n")
218
+ end
219
+
220
+ it 'var-without-value.kap' do
221
+ expect(run_error_example('var-without-value.kap'))
222
+ .to eq("var-without-value.kap:6:3: var: expected name and value\n")
223
+ end
224
+
225
+ it 'when-no-body.kap' do
226
+ expect(run_error_example('when-no-body.kap'))
227
+ .to eq("when-no-body.kap:4:3: when: expected body\n")
228
+ end
229
+ end
@@ -500,4 +500,55 @@ RSpec.describe 'examples' do
500
500
  it 'subtract-product-sum.kap' do
501
501
  expect(run_example('subtract-product-sum.kap')).to eq("15\n21\n0\n")
502
502
  end
503
+
504
+ it 'ugly-number.kap' do
505
+ expect(run_example('ugly-number.kap')).to eq("true\ntrue\nfalse\nfalse\ntrue\n")
506
+ end
507
+
508
+ it 'macros-unless.kap' do
509
+ expect(run_example('macros-unless.kap')).to eq(<<~OUT)
510
+ "shown"
511
+ "also shown"
512
+ OUT
513
+ end
514
+
515
+ it 'macros-swap.kap' do
516
+ expect(run_example('macros-swap.kap')).to eq("2\n1\n")
517
+ end
518
+
519
+ it 'macros-when-let.kap' do
520
+ expect(run_example('macros-when-let.kap')).to eq(<<~OUT)
521
+ "got"
522
+ 3
523
+ "done"
524
+ OUT
525
+ end
526
+
527
+ it 'macros-multi.kap' do
528
+ expect(run_example('macros-multi.kap')).to eq("10\n20\n7\n")
529
+ end
530
+
531
+ it 'macros-thrice-if.kap' do
532
+ expect(run_example('macros-thrice-if.kap')).to eq(<<~OUT)
533
+ "tick"
534
+ 1
535
+ "tick"
536
+ 2
537
+ "tick"
538
+ 3
539
+ "final"
540
+ 3
541
+ OUT
542
+ end
543
+
544
+ it 'macros-dbg.kap' do
545
+ expect(run_example('macros-dbg.kap')).to eq(<<~OUT)
546
+ "dbg"
547
+ 6
548
+ "result"
549
+ 6
550
+ "dbg"
551
+ 50
552
+ OUT
553
+ end
503
554
  end
@@ -43,7 +43,7 @@ RSpec.describe Kapusta::Formatter do
43
43
  Dir.mktmpdir do |dir|
44
44
  path = File.join(dir, 'sample.kap')
45
45
  File.write(path, <<~KAP)
46
- (let [uri (URI.join (ivar base-uri) (.. "/posts/" id)) body (Net.HTTP.get uri) post (JSON.parse body {:symbolize-names true}) {: title : author} post] (values title author))
46
+ (fn fetch-post [id] (let [uri (URI.join (ivar base-uri) (.. "/posts/" id)) body (Net.HTTP.get uri) post (JSON.parse body {:symbolize-names true}) {: title : author} post] (values title author)))
47
47
  KAP
48
48
 
49
49
  previous_path = ENV.fetch('PATH', nil)
@@ -54,11 +54,12 @@ RSpec.describe Kapusta::Formatter do
54
54
  end
55
55
 
56
56
  expect(output).to eq(<<~KAP)
57
- (let [uri (URI.join (ivar base-uri) (.. "/posts/" id))
58
- body (Net.HTTP.get uri)
59
- post (JSON.parse body {:symbolize-names true})
60
- {: title : author} post]
61
- (values title author))
57
+ (fn fetch-post [id]
58
+ (let [uri (URI.join (ivar base-uri) (.. "/posts/" id))
59
+ body (Net.HTTP.get uri)
60
+ post (JSON.parse body {:symbolize-names true})
61
+ {: title : author} post]
62
+ (values title author)))
62
63
  KAP
63
64
  ensure
64
65
  ENV['PATH'] = previous_path
@@ -210,16 +211,14 @@ RSpec.describe Kapusta::Formatter do
210
211
  end
211
212
 
212
213
  expect(output).to eq(<<~KAP)
213
- (let
214
- [
215
- profile
216
- {
217
- :name "Ada"
218
- ; active user
219
- :active true}
220
- ; next binding
221
- role
222
- "Engineer"]
214
+ (let [
215
+ profile
216
+ {:name "Ada"
217
+ ; active user
218
+ :active true}
219
+ ; next binding
220
+ role
221
+ "Engineer"]
223
222
  (print profile role))
224
223
  KAP
225
224
  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.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgenii Morozov
@@ -20,8 +20,10 @@ files:
20
20
  - Gemfile
21
21
  - README.md
22
22
  - Rakefile
23
+ - bin/check-all
23
24
  - bin/compile-examples
24
25
  - bin/console
26
+ - bin/fennel-parity
25
27
  - bin/setup
26
28
  - examples/accumulator.kap
27
29
  - examples/ackermann.kap
@@ -56,6 +58,12 @@ files:
56
58
  - examples/kwargs.kap
57
59
  - examples/leap-year.kap
58
60
  - examples/length-of-last-word.kap
61
+ - examples/macros-dbg.kap
62
+ - examples/macros-multi.kap
63
+ - examples/macros-swap.kap
64
+ - examples/macros-thrice-if.kap
65
+ - examples/macros-unless.kap
66
+ - examples/macros-when-let.kap
59
67
  - examples/majority-element.kap
60
68
  - examples/manhattan-distance.kap
61
69
  - examples/match.kap
@@ -92,6 +100,7 @@ files:
92
100
  - examples/tset.kap
93
101
  - examples/two-sum-hash.kap
94
102
  - examples/two-sum.kap
103
+ - examples/ugly-number.kap
95
104
  - examples/underscore-patterns.kap
96
105
  - examples/use_bank_account.rb
97
106
  - examples/valid-parentheses-1.kap
@@ -113,17 +122,19 @@ files:
113
122
  - lib/kapusta/compiler/emitter/interop.rb
114
123
  - lib/kapusta/compiler/emitter/patterns.rb
115
124
  - lib/kapusta/compiler/emitter/support.rb
125
+ - lib/kapusta/compiler/macro_expander.rb
116
126
  - lib/kapusta/compiler/normalizer.rb
117
127
  - lib/kapusta/env.rb
118
128
  - lib/kapusta/error.rb
129
+ - lib/kapusta/errors.rb
119
130
  - lib/kapusta/formatter.rb
120
131
  - lib/kapusta/reader.rb
121
132
  - lib/kapusta/support.rb
122
133
  - lib/kapusta/version.rb
123
134
  - spec/cli_spec.rb
135
+ - spec/examples_errors_spec.rb
124
136
  - spec/examples_spec.rb
125
137
  - spec/formatter_spec.rb
126
- - spec/reader_spec.rb
127
138
  - spec/spec_helper.rb
128
139
  homepage: https://github.com/evmorov/kapusta
129
140
  licenses: