vinter 0.1.0 → 0.2.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/README.md +3 -3
- data/lib/vinter/parser.rb +165 -14
- data/lib/vinter.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 503bb79a2701783c22c7ef7f269bfc51dc93a72d68abc61286c4c0236aaa4d8f
|
4
|
+
data.tar.gz: f9f58293732eb9179228ec8e4c04bd87f279fc2e7edf65dc9969d1fe6f680b66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 577a51ca98e7bd940ab48a6482978c5f098fbba5c5e6921105950086f92cc327e44edf10259a3aafdf6fe8ff068690fb5d8b387aed85f5e07f2fc57b7ea8ce5d
|
7
|
+
data.tar.gz: 5f5e7316bd62168356532c07186e0a3ff03c2c4a49c8d43d7dff51d64f261bf9368598b80acc69ebcc802af64d5ef0906f8422a0c78e2401d87429668721e3f6
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Vinter
|
2
2
|
|
3
|
-
A Ruby gem that provides linting capabilities for Vim9 script files. This linter helps identify syntax errors and enforce best practices for
|
3
|
+
A Ruby gem that provides linting capabilities for Vim9 script files. This linter helps identify syntax errors and enforce best practices for for Vim9 script.
|
4
4
|
|
5
5
|
## Features
|
6
6
|
|
@@ -24,7 +24,7 @@ gem install vinter
|
|
24
24
|
Lint a Vim9 script file:
|
25
25
|
|
26
26
|
```bash
|
27
|
-
|
27
|
+
vinter path/to/your/script.vim
|
28
28
|
```
|
29
29
|
|
30
30
|
### Ruby API
|
@@ -33,7 +33,7 @@ vim9-lint path/to/your/script.vim
|
|
33
33
|
require 'vinter'
|
34
34
|
|
35
35
|
content = File.read('path/to/your/script.vim')
|
36
|
-
linter =
|
36
|
+
linter = Vinter::Linter.new
|
37
37
|
issues = linter.lint(content)
|
38
38
|
|
39
39
|
issues.each do |issue|
|
data/lib/vinter/parser.rb
CHANGED
@@ -180,6 +180,157 @@ module Vinter
|
|
180
180
|
}
|
181
181
|
end
|
182
182
|
|
183
|
+
def parse_while_statement
|
184
|
+
token = advance # Skip 'while'
|
185
|
+
line = token[:line]
|
186
|
+
column = token[:column]
|
187
|
+
condition = parse_expression
|
188
|
+
|
189
|
+
body = []
|
190
|
+
|
191
|
+
# Parse statements until we hit 'endwhile'
|
192
|
+
while @position < @tokens.length
|
193
|
+
if current_token[:type] == :keyword && current_token[:value] == 'endwhile'
|
194
|
+
break
|
195
|
+
end
|
196
|
+
|
197
|
+
stmt = parse_statement
|
198
|
+
body << stmt if stmt
|
199
|
+
end
|
200
|
+
|
201
|
+
# Expect endwhile
|
202
|
+
expect(:keyword) # This should be 'endwhile'
|
203
|
+
|
204
|
+
{
|
205
|
+
type: :while_statement,
|
206
|
+
condition: condition,
|
207
|
+
body: body,
|
208
|
+
line: line,
|
209
|
+
column: column
|
210
|
+
}
|
211
|
+
end
|
212
|
+
|
213
|
+
def parse_for_statement
|
214
|
+
token = advance # Skip 'for'
|
215
|
+
line = token[:line]
|
216
|
+
column = token[:column]
|
217
|
+
|
218
|
+
# Parse the loop variable(s)
|
219
|
+
if current_token && current_token[:type] == :paren_open
|
220
|
+
# Handle tuple assignment: for (key, val) in dict
|
221
|
+
advance # Skip '('
|
222
|
+
|
223
|
+
loop_vars = []
|
224
|
+
|
225
|
+
loop do
|
226
|
+
if current_token && current_token[:type] == :identifier
|
227
|
+
loop_vars << advance[:value]
|
228
|
+
else
|
229
|
+
@errors << {
|
230
|
+
message: "Expected identifier in for loop variables",
|
231
|
+
position: @position,
|
232
|
+
line: current_token ? current_token[:line] : 0,
|
233
|
+
column: current_token ? current_token[:column] : 0
|
234
|
+
}
|
235
|
+
break
|
236
|
+
end
|
237
|
+
|
238
|
+
if current_token && current_token[:type] == :comma
|
239
|
+
advance # Skip ','
|
240
|
+
else
|
241
|
+
break
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
expect(:paren_close) # Skip ')'
|
246
|
+
|
247
|
+
if !current_token || (current_token[:type] != :identifier || current_token[:value] != 'in')
|
248
|
+
@errors << {
|
249
|
+
message: "Expected 'in' after for loop variables",
|
250
|
+
position: @position,
|
251
|
+
line: current_token ? current_token[:line] : 0,
|
252
|
+
column: current_token ? current_token[:column] : 0
|
253
|
+
}
|
254
|
+
else
|
255
|
+
advance # Skip 'in'
|
256
|
+
end
|
257
|
+
|
258
|
+
iterable = parse_expression
|
259
|
+
|
260
|
+
# Parse the body until 'endfor'
|
261
|
+
body = []
|
262
|
+
while @position < @tokens.length
|
263
|
+
if current_token[:type] == :keyword && current_token[:value] == 'endfor'
|
264
|
+
break
|
265
|
+
end
|
266
|
+
|
267
|
+
stmt = parse_statement
|
268
|
+
body << stmt if stmt
|
269
|
+
end
|
270
|
+
|
271
|
+
# Expect endfor
|
272
|
+
expect(:keyword) # This should be 'endfor'
|
273
|
+
|
274
|
+
return {
|
275
|
+
type: :for_statement,
|
276
|
+
loop_vars: loop_vars,
|
277
|
+
iterable: iterable,
|
278
|
+
body: body,
|
279
|
+
line: line,
|
280
|
+
column: column
|
281
|
+
}
|
282
|
+
else
|
283
|
+
# Simple for var in list
|
284
|
+
if !current_token || current_token[:type] != :identifier
|
285
|
+
@errors << {
|
286
|
+
message: "Expected identifier as for loop variable",
|
287
|
+
position: @position,
|
288
|
+
line: current_token ? current_token[:line] : 0,
|
289
|
+
column: current_token ? current_token[:column] : 0
|
290
|
+
}
|
291
|
+
return nil
|
292
|
+
end
|
293
|
+
|
294
|
+
loop_var = advance[:value]
|
295
|
+
|
296
|
+
if !current_token || (current_token[:type] != :identifier || current_token[:value] != 'in')
|
297
|
+
@errors << {
|
298
|
+
message: "Expected 'in' after for loop variable",
|
299
|
+
position: @position,
|
300
|
+
line: current_token ? current_token[:line] : 0,
|
301
|
+
column: current_token ? current_token[:column] : 0
|
302
|
+
}
|
303
|
+
else
|
304
|
+
advance # Skip 'in'
|
305
|
+
end
|
306
|
+
|
307
|
+
iterable = parse_expression
|
308
|
+
|
309
|
+
# Parse the body until 'endfor'
|
310
|
+
body = []
|
311
|
+
while @position < @tokens.length
|
312
|
+
if current_token[:type] == :keyword && current_token[:value] == 'endfor'
|
313
|
+
break
|
314
|
+
end
|
315
|
+
|
316
|
+
stmt = parse_statement
|
317
|
+
body << stmt if stmt
|
318
|
+
end
|
319
|
+
|
320
|
+
# Expect endfor
|
321
|
+
expect(:keyword) # This should be 'endfor'
|
322
|
+
|
323
|
+
return {
|
324
|
+
type: :for_statement,
|
325
|
+
loop_var: loop_var,
|
326
|
+
iterable: iterable,
|
327
|
+
body: body,
|
328
|
+
line: line,
|
329
|
+
column: column
|
330
|
+
}
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
183
334
|
def parse_def_function
|
184
335
|
token = advance # Skip 'def'
|
185
336
|
line = token[:line]
|
@@ -541,23 +692,23 @@ module Vinter
|
|
541
692
|
token = advance # Skip 'import'
|
542
693
|
line = token[:line]
|
543
694
|
column = token[:column]
|
544
|
-
|
695
|
+
|
545
696
|
# Handle 'import autoload'
|
546
697
|
is_autoload = false
|
547
698
|
module_name = nil
|
548
699
|
path = nil
|
549
|
-
|
700
|
+
|
550
701
|
if current_token && current_token[:type] == :identifier && current_token[:value] == 'autoload'
|
551
702
|
is_autoload = true
|
552
703
|
module_name = advance[:value] # Store "autoload" as the module name
|
553
|
-
|
704
|
+
|
554
705
|
# After "autoload" keyword, expect a string path
|
555
706
|
if current_token && current_token[:type] == :string
|
556
707
|
path = current_token[:value]
|
557
708
|
advance
|
558
709
|
else
|
559
|
-
@errors << {
|
560
|
-
message: "Expected string path after 'autoload'",
|
710
|
+
@errors << {
|
711
|
+
message: "Expected string path after 'autoload'",
|
561
712
|
position: @position,
|
562
713
|
line: current_token ? current_token[:line] : 0,
|
563
714
|
column: current_token ? current_token[:column] : 0
|
@@ -567,11 +718,11 @@ module Vinter
|
|
567
718
|
# Regular import with a string path
|
568
719
|
if current_token && current_token[:type] == :string
|
569
720
|
path = current_token[:value]
|
570
|
-
|
721
|
+
|
571
722
|
# Extract module name from the path
|
572
723
|
# This is simplified logic - you might need more complex extraction
|
573
724
|
module_name = path.gsub(/['"]/, '').split('/').last.split('.').first
|
574
|
-
|
725
|
+
|
575
726
|
advance
|
576
727
|
else
|
577
728
|
# Handle other import formats
|
@@ -582,7 +733,7 @@ module Vinter
|
|
582
733
|
end
|
583
734
|
end
|
584
735
|
end
|
585
|
-
|
736
|
+
|
586
737
|
# Handle 'as name'
|
587
738
|
as_name = nil
|
588
739
|
if current_token && current_token[:type] == :identifier && current_token[:value] == 'as'
|
@@ -590,17 +741,17 @@ module Vinter
|
|
590
741
|
if current_token && current_token[:type] == :identifier
|
591
742
|
as_name = advance[:value]
|
592
743
|
else
|
593
|
-
@errors << {
|
594
|
-
message: "Expected identifier after 'as'",
|
744
|
+
@errors << {
|
745
|
+
message: "Expected identifier after 'as'",
|
595
746
|
position: @position,
|
596
747
|
line: current_token ? current_token[:line] : 0,
|
597
748
|
column: current_token ? current_token[:column] : 0
|
598
749
|
}
|
599
750
|
end
|
600
751
|
end
|
601
|
-
|
602
|
-
{
|
603
|
-
type: :import_statement,
|
752
|
+
|
753
|
+
{
|
754
|
+
type: :import_statement,
|
604
755
|
module: module_name,
|
605
756
|
path: path,
|
606
757
|
is_autoload: is_autoload,
|
@@ -608,7 +759,7 @@ module Vinter
|
|
608
759
|
line: line,
|
609
760
|
column: column
|
610
761
|
}
|
611
|
-
end
|
762
|
+
end
|
612
763
|
def parse_export_statement
|
613
764
|
token = advance # Skip 'export'
|
614
765
|
line = token[:line]
|
data/lib/vinter.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vinter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Bradbury
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A linter for the Vim9 script language, helping to identify issues and
|
14
14
|
enforce best practices
|