kapusta 0.4.1 → 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.
- checksums.yaml +4 -4
- data/bin/fennel-parity +36 -6
- data/examples/even-squares.kap +22 -7
- data/examples/roman-to-integer.kap +3 -3
- data/lib/kapusta/ast.rb +38 -4
- data/lib/kapusta/cli.rb +3 -0
- data/lib/kapusta/compiler/emitter/bindings.rb +52 -6
- data/lib/kapusta/compiler/emitter/collections.rb +64 -20
- data/lib/kapusta/compiler/emitter/control_flow.rb +7 -4
- data/lib/kapusta/compiler/emitter/expressions.rb +26 -15
- data/lib/kapusta/compiler/emitter/interop.rb +6 -4
- data/lib/kapusta/compiler/emitter/patterns.rb +22 -1
- data/lib/kapusta/compiler/emitter/support.rb +44 -22
- data/lib/kapusta/compiler/macro_expander.rb +55 -25
- data/lib/kapusta/compiler/normalizer.rb +35 -9
- data/lib/kapusta/compiler.rb +6 -2
- data/lib/kapusta/error.rb +25 -1
- data/lib/kapusta/errors.rb +69 -0
- data/lib/kapusta/formatter.rb +12 -5
- data/lib/kapusta/reader.rb +34 -12
- data/lib/kapusta/version.rb +1 -1
- data/lib/kapusta.rb +1 -0
- data/spec/examples_errors_spec.rb +229 -0
- data/spec/formatter_spec.rb +7 -6
- metadata +3 -2
- data/spec/reader_spec.rb +0 -26
data/lib/kapusta/reader.rb
CHANGED
|
@@ -72,7 +72,7 @@ module Kapusta
|
|
|
72
72
|
|
|
73
73
|
def read_next_item
|
|
74
74
|
skip_ws
|
|
75
|
-
raise
|
|
75
|
+
raise reader_error(:unexpected_eof, source_position) if eof?
|
|
76
76
|
|
|
77
77
|
return read_comment if @preserve_comments && peek == ';'
|
|
78
78
|
|
|
@@ -81,10 +81,11 @@ module Kapusta
|
|
|
81
81
|
|
|
82
82
|
def read_form
|
|
83
83
|
skip_ws
|
|
84
|
-
raise
|
|
84
|
+
raise reader_error(:unexpected_eof, source_position) if eof?
|
|
85
85
|
|
|
86
86
|
return read_comment if @preserve_comments && peek == ';'
|
|
87
87
|
|
|
88
|
+
position = source_position
|
|
88
89
|
form =
|
|
89
90
|
case peek
|
|
90
91
|
when '(' then read_list
|
|
@@ -99,9 +100,18 @@ module Kapusta
|
|
|
99
100
|
read_atom
|
|
100
101
|
end
|
|
101
102
|
|
|
103
|
+
attach_position(form, position)
|
|
102
104
|
read_postfix(form)
|
|
103
105
|
end
|
|
104
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
|
+
|
|
105
115
|
def read_quasiquote
|
|
106
116
|
advance
|
|
107
117
|
Quasiquote.new(read_form)
|
|
@@ -133,6 +143,8 @@ module Kapusta
|
|
|
133
143
|
advance
|
|
134
144
|
list = List.new(items)
|
|
135
145
|
list.multiline_source = closing_position[0] != opening_position[0]
|
|
146
|
+
list.line = opening_position[0]
|
|
147
|
+
list.column = opening_position[1]
|
|
136
148
|
list
|
|
137
149
|
end
|
|
138
150
|
|
|
@@ -152,6 +164,8 @@ module Kapusta
|
|
|
152
164
|
advance
|
|
153
165
|
vec = Vec.new(items)
|
|
154
166
|
vec.multiline_source = closing_position[0] != opening_position[0]
|
|
167
|
+
vec.line = opening_position[0]
|
|
168
|
+
vec.column = opening_position[1]
|
|
155
169
|
vec
|
|
156
170
|
end
|
|
157
171
|
|
|
@@ -180,14 +194,17 @@ module Kapusta
|
|
|
180
194
|
closing_position = source_position
|
|
181
195
|
advance
|
|
182
196
|
|
|
183
|
-
raise
|
|
197
|
+
raise reader_error(:odd_forms_in_hash, opening_position) unless pending.empty?
|
|
184
198
|
|
|
185
199
|
hash = HashLit.new(entries)
|
|
186
200
|
hash.multiline_source = closing_position[0] != opening_position[0]
|
|
201
|
+
hash.line = opening_position[0]
|
|
202
|
+
hash.column = opening_position[1]
|
|
187
203
|
hash
|
|
188
204
|
end
|
|
189
205
|
|
|
190
206
|
def read_string
|
|
207
|
+
opening_position = source_position
|
|
191
208
|
advance
|
|
192
209
|
buffer = +''
|
|
193
210
|
until eof? || peek == '"'
|
|
@@ -211,7 +228,7 @@ module Kapusta
|
|
|
211
228
|
buffer << advance
|
|
212
229
|
end
|
|
213
230
|
end
|
|
214
|
-
raise
|
|
231
|
+
raise reader_error(:unterminated_string, opening_position) if eof?
|
|
215
232
|
|
|
216
233
|
advance
|
|
217
234
|
buffer
|
|
@@ -249,22 +266,25 @@ module Kapusta
|
|
|
249
266
|
end
|
|
250
267
|
|
|
251
268
|
def read_atom
|
|
269
|
+
position = source_position
|
|
252
270
|
start = @pos
|
|
253
271
|
advance until delim?(peek)
|
|
254
272
|
token = @src[start...@pos]
|
|
255
|
-
raise
|
|
273
|
+
raise reader_error(:empty_token, position) if token.empty?
|
|
256
274
|
|
|
257
|
-
parse_atom(token)
|
|
275
|
+
parse_atom(token, position)
|
|
258
276
|
end
|
|
259
277
|
|
|
260
278
|
def unexpected_closing_delim(char)
|
|
261
|
-
|
|
262
|
-
Error.new("unexpected closing delimiter '#{char}' at line #{line}, column #{column}")
|
|
279
|
+
reader_error(:unexpected_closing_delimiter, source_position, char:)
|
|
263
280
|
end
|
|
264
281
|
|
|
265
282
|
def unclosed_opening_delim(char, position)
|
|
266
|
-
|
|
267
|
-
|
|
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])
|
|
268
288
|
end
|
|
269
289
|
|
|
270
290
|
def source_position
|
|
@@ -276,13 +296,15 @@ module Kapusta
|
|
|
276
296
|
[line, column]
|
|
277
297
|
end
|
|
278
298
|
|
|
279
|
-
def parse_atom(token)
|
|
299
|
+
def parse_atom(token, position)
|
|
280
300
|
return true if token == 'true'
|
|
281
301
|
return false if token == 'false'
|
|
282
302
|
return if token == 'nil'
|
|
283
303
|
return Integer(token, 10) if token.match?(/\A-?\d+\z/)
|
|
284
304
|
return Float(token) if token.match?(/\A-?\d+\.\d+\z/)
|
|
285
305
|
|
|
306
|
+
raise reader_error(:could_not_read_number, position, token:) if token.match?(/\A-?\d/)
|
|
307
|
+
|
|
286
308
|
if token.start_with?(':') && token.length > 1
|
|
287
309
|
Kapusta.kebab_to_snake(token[1..]).to_sym
|
|
288
310
|
elsif token.length > 1 && token.end_with?('#') && !token[0..-2].include?('#')
|
|
@@ -294,7 +316,7 @@ module Kapusta
|
|
|
294
316
|
|
|
295
317
|
def normalize_hash_pair(item, value)
|
|
296
318
|
if item.is_a?(Sym) && item.name == ':'
|
|
297
|
-
raise
|
|
319
|
+
raise reader_error(:bad_shorthand, source_position) unless value.is_a?(Sym)
|
|
298
320
|
|
|
299
321
|
key = Kapusta.kebab_to_snake(value.name).to_sym
|
|
300
322
|
[key, value]
|
data/lib/kapusta/version.rb
CHANGED
data/lib/kapusta.rb
CHANGED
|
@@ -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
|
data/spec/formatter_spec.rb
CHANGED
|
@@ -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
|
-
(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
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.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Evgenii Morozov
|
|
@@ -126,14 +126,15 @@ files:
|
|
|
126
126
|
- lib/kapusta/compiler/normalizer.rb
|
|
127
127
|
- lib/kapusta/env.rb
|
|
128
128
|
- lib/kapusta/error.rb
|
|
129
|
+
- lib/kapusta/errors.rb
|
|
129
130
|
- lib/kapusta/formatter.rb
|
|
130
131
|
- lib/kapusta/reader.rb
|
|
131
132
|
- lib/kapusta/support.rb
|
|
132
133
|
- lib/kapusta/version.rb
|
|
133
134
|
- spec/cli_spec.rb
|
|
135
|
+
- spec/examples_errors_spec.rb
|
|
134
136
|
- spec/examples_spec.rb
|
|
135
137
|
- spec/formatter_spec.rb
|
|
136
|
-
- spec/reader_spec.rb
|
|
137
138
|
- spec/spec_helper.rb
|
|
138
139
|
homepage: https://github.com/evmorov/kapusta
|
|
139
140
|
licenses:
|
data/spec/reader_spec.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
RSpec.describe Kapusta::Reader do
|
|
6
|
-
describe 'error messages' do
|
|
7
|
-
it 'reports unexpected closing delimiters with their source position' do
|
|
8
|
-
expect { Kapusta.eval('(print 1))') }
|
|
9
|
-
.to raise_error(Kapusta::Reader::Error,
|
|
10
|
-
/unexpected closing delimiter '\)' at line 1, column 10/)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it 'reports unclosed opening delimiters with their source position' do
|
|
14
|
-
cases = {
|
|
15
|
-
'(print 1' => /unclosed opening delimiter '\(' at line 1, column 1/,
|
|
16
|
-
'[1 2' => /unclosed opening delimiter '\[' at line 1, column 1/,
|
|
17
|
-
'{:name "A"' => /unclosed opening delimiter '\{' at line 1, column 1/
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
cases.each do |source, message|
|
|
21
|
-
expect { Kapusta.eval(source) }
|
|
22
|
-
.to raise_error(Kapusta::Reader::Error, message)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|