Skip to content

Commit 5f6c9c4

Browse files
authored
refactor: fix grammar/semantic issues and upgrade tree-sitter (#176)
1 parent f7a51cb commit 5f6c9c4

File tree

24 files changed

+249577
-243775
lines changed

24 files changed

+249577
-243775
lines changed

.github/workflows/tree_sitter_v.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ jobs:
3131
- name: Run tests
3232
run: npm run test
3333

34-
- name: Lint
35-
run: npm run lint
36-
3734
test-bindings:
3835
runs-on: ubuntu-latest
3936

.gitmodules

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
[submodule "tree_sitter_v/bindings/core"]
22
path = tree_sitter_v/bindings/core
33
url = https://github.com/tree-sitter/tree-sitter.git
4-
branch = master

src/analyzer/psi/GlobalVarDefinition.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ pub fn (_ &GlobalVarDefinition) is_public() bool {
1313
}
1414

1515
pub fn (n &GlobalVarDefinition) identifier() ?PsiElement {
16+
if node := n.find_child_by_name('name') {
17+
return node
18+
}
1619
return n.find_child_by_type(.identifier)
1720
}
1821

src/analyzer/psi/PsiFile.v

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,29 @@ pub fn (p &PsiFile) module_clause() ?&ModuleClause {
156156
}
157157

158158
pub fn (p &PsiFile) get_imports() []ImportSpec {
159-
import_list := p.root().find_child_by_type_or_stub(.import_list) or { return [] }
160-
declarations := import_list.find_children_by_type_or_stub(.import_declaration)
161-
mut import_specs := []ImportSpec{cap: declarations.len}
162-
for declaration in declarations {
163-
spec := declaration.find_child_by_type_or_stub(.import_spec) or { continue }
164-
if spec is ImportSpec {
165-
import_specs << spec
159+
mut specs := []ImportSpec{}
160+
161+
if p.is_stub_based() {
162+
for _, stub in p.stub_list.index_map {
163+
if stub.stub_type == .import_spec {
164+
if element := stub.get_psi() {
165+
if element is ImportSpec {
166+
specs << element
167+
}
168+
}
169+
}
170+
}
171+
} else {
172+
mut walker := new_psi_tree_walker(p.root())
173+
for {
174+
child := walker.next() or { break }
175+
if child is ImportSpec {
176+
specs << child
177+
}
166178
}
167179
}
168-
return import_specs
180+
181+
return specs
169182
}
170183

171184
pub fn (p &PsiFile) resolve_import_spec(name string) ?ImportSpec {

src/server/semantic/DumbAwareSemanticVisitor.v

Lines changed: 170 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -44,128 +44,204 @@ fn (_ DumbAwareSemanticVisitor) highlight_node(node psi.AstNode, root psi.PsiEle
4444
containing_file := root.containing_file() or { return }
4545
source_text := containing_file.source_text
4646

47-
if node.type_name == .enum_field_definition {
48-
if first_child := node.first_child() {
49-
result << element_to_semantic(first_child, .enum_member)
50-
}
51-
} else if node.type_name == .field_name {
52-
result << element_to_semantic(node, .property)
53-
} else if node.type_name == .range_clause {
54-
if first_child := node.first_child() {
55-
result << element_to_semantic(first_child, .property)
56-
}
57-
} else if node.type_name == .struct_field_declaration {
58-
if first_child := node.first_child() {
59-
if first_child.type_name != .embedded_definition {
47+
match node.type_name {
48+
.enum_field_definition {
49+
if first_child := node.first_child() {
50+
result << element_to_semantic(first_child, .enum_member)
51+
}
52+
}
53+
.field_name {
54+
result << element_to_semantic(node, .property)
55+
}
56+
.range_clause {
57+
if first_child := node.first_child() {
6058
result << element_to_semantic(first_child, .property)
6159
}
6260
}
63-
} else if node.type_name == .module_clause {
64-
if last_child := node.last_child() {
65-
result << element_to_semantic(last_child, .namespace)
61+
.struct_field_declaration {
62+
if first_child := node.first_child() {
63+
if first_child.type_name != .embedded_definition {
64+
result << element_to_semantic(first_child, .property)
65+
}
66+
}
67+
}
68+
.module_clause {
69+
if last_child := node.last_child() {
70+
result << element_to_semantic(last_child, .namespace)
71+
}
72+
}
73+
.attribute {
74+
// '['
75+
if first_child := node.first_child() {
76+
result << element_to_semantic(first_child, .decorator)
77+
}
78+
// ']'
79+
if last_child := node.last_child() {
80+
result << element_to_semantic(last_child, .decorator)
81+
}
82+
}
83+
.key_value_attribute {
84+
if value_child := node.child_by_field_name('value') {
85+
if value_child.type_name == .identifier {
86+
result << element_to_semantic(value_child, .string)
87+
}
88+
}
6689
}
67-
} else if node.type_name == .attribute {
68-
// '['
69-
if first_child := node.first_child() {
70-
result << element_to_semantic(first_child, .decorator)
90+
.qualified_type {
91+
if first_child := node.first_child() {
92+
result << element_to_semantic(first_child, .namespace)
93+
}
94+
if last_child := node.last_child() {
95+
result << element_to_semantic(last_child, .type_)
96+
}
7197
}
72-
// ']'
73-
if last_child := node.last_child() {
74-
result << element_to_semantic(last_child, .decorator)
98+
.unknown {
99+
text := node.text(source_text)
100+
if text == 'sql' {
101+
if parent := node.parent() {
102+
if parent.type_name == .sql_expression {
103+
result << element_to_semantic(node, .keyword)
104+
}
105+
}
106+
} else if text == 'chan' {
107+
if parent := node.parent() {
108+
if parent.type_name == .channel_type {
109+
result << element_to_semantic(node, .keyword)
110+
}
111+
}
112+
} else if text == 'thread' {
113+
if parent := node.parent() {
114+
if parent.type_name == .thread_type {
115+
result << element_to_semantic(node, .keyword)
116+
}
117+
}
118+
}
75119
}
76-
} else if node.type_name == .key_value_attribute {
77-
if value_child := node.child_by_field_name('value') {
78-
if value_child.type_name == .identifier {
79-
result << element_to_semantic(value_child, .string)
120+
.enum_declaration {
121+
if identifier := node.child_by_field_name('name') {
122+
result << element_to_semantic(identifier, .enum_)
80123
}
81124
}
82-
} else if node.type_name == .qualified_type {
83-
if first_child := node.first_child() {
84-
result << element_to_semantic(first_child, .namespace)
125+
.implements_clause {
126+
if !node.is_named() {
127+
result << element_to_semantic(node, .keyword)
128+
}
85129
}
86-
if last_child := node.last_child() {
87-
result << element_to_semantic(last_child, .type_)
130+
.interface_declaration {
131+
if identifier := node.child_by_field_name('name') {
132+
result << element_to_semantic(identifier, .interface_)
133+
}
88134
}
89-
} else if node.type_name == .unknown {
90-
text := node.text(source_text)
91-
92-
if text == 'sql' {
93-
if parent := node.parent() {
94-
if parent.type_name == .sql_expression {
95-
result << element_to_semantic(node, .keyword)
135+
.parameter_declaration, .receiver {
136+
if identifier := node.child_by_field_name('name') {
137+
if _ := node.child_by_field_name('mutability') {
138+
result << element_to_semantic(identifier, .parameter, 'mutable')
139+
} else {
140+
result << element_to_semantic(identifier, .parameter)
96141
}
97142
}
98143
}
99-
if text == 'chan' {
100-
if parent := node.parent() {
101-
if parent.type_name == .channel_type {
102-
result << element_to_semantic(node, .keyword)
144+
.reference_expression {
145+
def := psi.node_to_var_definition(node, containing_file, none)
146+
if !isnil(def) {
147+
if def.is_mutable() {
148+
result << element_to_semantic(node, .variable, 'mutable')
149+
} else {
150+
result << element_to_semantic(node, .variable)
103151
}
104152
}
153+
154+
first_char := node.first_char(source_text)
155+
if first_char == `@` || first_char == `$` {
156+
result << element_to_semantic(node, .property) // not a best variant...
157+
}
158+
}
159+
.const_definition {
160+
if name := node.child_by_field_name('name') {
161+
result << element_to_semantic(name, .property) // not a best variant...
162+
}
105163
}
106-
if text == 'thread' {
107-
if parent := node.parent() {
108-
if parent.type_name == .thread_type {
109-
result << element_to_semantic(node, .keyword)
164+
.import_path {
165+
count := node.child_count()
166+
for i in 0 .. count {
167+
if child := node.child(i) {
168+
if child.type_name == .import_name {
169+
result << element_to_semantic(child, .namespace)
170+
}
110171
}
111172
}
112173
}
113-
} else if node.type_name == .enum_declaration {
114-
if identifier := node.child_by_field_name('name') {
115-
result << element_to_semantic(identifier, .enum_)
174+
.import_alias {
175+
if last_child := node.last_child() {
176+
result << element_to_semantic(last_child, .namespace)
177+
}
116178
}
117-
} else if node.type_name == .parameter_declaration || node.type_name == .receiver {
118-
if identifier := node.child_by_field_name('name') {
119-
if _ := node.child_by_field_name('mutability') {
120-
result << element_to_semantic(identifier, .parameter, 'mutable')
121-
} else {
122-
result << element_to_semantic(identifier, .parameter)
179+
.compile_time_if_expression {
180+
if condition := node.child_by_field_name('condition') {
181+
highlight_compile_time_condition(condition, mut result)
123182
}
124183
}
125-
} else if node.type_name == .reference_expression {
126-
def := psi.node_to_var_definition(node, containing_file, none)
127-
if !isnil(def) {
128-
if def.is_mutable() {
129-
result << element_to_semantic(node, .variable, 'mutable')
130-
} else {
131-
result << element_to_semantic(node, .variable)
184+
.asm_statement {
185+
if first := node.first_child() {
186+
result << element_to_semantic(first, .keyword)
187+
}
188+
if modifier := node.child_by_field_name('modifiers') {
189+
result << element_to_semantic(modifier, .keyword)
190+
}
191+
if arch := node.child_by_field_name('arch') {
192+
result << element_to_semantic(arch, .variable, 'readonly', 'defaultLibrary')
132193
}
133194
}
134-
135-
first_char := node.first_char(source_text)
136-
if first_char == `@` || first_char == `$` {
137-
result << element_to_semantic(node, .property) // not a best variant...
138-
}
139-
} else if node.type_name == .const_definition {
140-
if name := node.child_by_field_name('name') {
141-
result << element_to_semantic(name, .property) // not a best variant...
142-
}
143-
} else if node.type_name == .import_path {
144-
if last_part := node.last_child() {
145-
result << element_to_semantic(last_part, .namespace)
146-
}
147-
} else if node.type_name in [.interpolation_opening, .interpolation_closing] {
148-
result << element_to_semantic(node, .keyword)
149-
} else if node.type_name == .generic_parameter {
150-
result << element_to_semantic(node, .type_parameter)
151-
} else if node.type_name == .global_var_definition {
152-
if identifier := node.child_by_field_name('name') {
153-
result << element_to_semantic(identifier, .variable, 'global')
154-
}
155-
} else if node.type_name == .function_declaration {
156-
if first_child := node.child_by_field_name('name') {
157-
first_char := first_child.first_char(source_text)
158-
if first_char in [`@`, `$`] {
159-
// tweak highlighting for @lock/@rlock
160-
result << element_to_semantic(first_child, .function)
195+
.interpolation_opening, .interpolation_closing {
196+
result << element_to_semantic(node, .keyword)
197+
}
198+
.generic_parameter {
199+
result << element_to_semantic(node, .type_parameter)
200+
}
201+
.variadic_parameter {
202+
result << element_to_semantic(node, .operator)
203+
}
204+
.global_var_definition {
205+
if identifier := node.child_by_field_name('name') {
206+
result << element_to_semantic(identifier, .variable, 'global')
207+
}
208+
if modifiers := node.child_by_field_name('modifiers') {
209+
result << element_to_semantic(modifiers, .keyword)
210+
}
211+
}
212+
.function_declaration {
213+
if first_child := node.child_by_field_name('name') {
214+
first_char := first_child.first_char(source_text)
215+
if first_char in [`@`, `$`] {
216+
// tweak highlighting for @lock/@rlock
217+
result << element_to_semantic(first_child, .function)
218+
}
219+
}
220+
}
221+
else {
222+
$if debug {
223+
// this useful for finding errors in parsing
224+
if node.type_name == .error {
225+
result << element_to_semantic(node, .namespace, 'mutable')
226+
}
161227
}
162228
}
163229
}
230+
}
164231

165-
$if debug {
166-
// this useful for finding errors in parsing
167-
if node.type_name == .error {
168-
result << element_to_semantic(node, .namespace, 'mutable')
232+
fn highlight_compile_time_condition(node psi.AstNode, mut result []SemanticToken) {
233+
if node.type_name == .reference_expression {
234+
result << element_to_semantic(node, .variable, 'readonly', 'defaultLibrary')
235+
} else if node.type_name == .binary_expression || node.type_name == .unary_expression {
236+
count := node.child_count()
237+
for i in 0 .. count {
238+
if child := node.child(i) {
239+
highlight_compile_time_condition(child, mut result)
240+
}
241+
}
242+
} else if node.type_name == .parenthesized_expression {
243+
if child := node.child(1) {
244+
highlight_compile_time_condition(child, mut result)
169245
}
170246
}
171247
}

src/tests/definitions.v

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,5 +371,22 @@ fn definitions() testing.Tester {
371371
t.assert_uri_from_stubs(first.target_uri, 'implicit.v')!
372372
})
373373

374+
t.test('global variable with volatile modifier', fn (mut t testing.Test, mut fixture testing.Fixture) ! {
375+
fixture.configure_by_text('1.v', '
376+
__global volatile base_revision = 0
377+
378+
fn main() {
379+
println(base/*caret*/_revision)
380+
}
381+
'.trim_indent())!
382+
383+
locations := fixture.definition_at_cursor()
384+
t.assert_has_definition(locations)!
385+
386+
first := locations.first()
387+
t.assert_uri(first.target_uri, fixture.current_file_uri())!
388+
t.assert_definition_name(first, 'base_revision')!
389+
})
390+
374391
return t
375392
}

0 commit comments

Comments
 (0)