Cst compat
Showing 11 of 17 files from the diff.
src/requests/textdocument.jl
changed.
src/utilities.jl
changed.
src/requests/misc.jl
changed.
src/requests/hover.jl
changed.
src/LanguageServer.jl
changed.
src/languageserverinstance.jl
changed.
src/requests/init.jl
changed.
src/staticlint.jl
changed.
src/requests/features.jl
changed.
src/requests/actions.jl
changed.
src/requests/completions.jl
changed.
Other files ignored by Codecov
test/requests/actions.jl
has changed.
test/test_communication.jl
has changed.
test/runtests.jl
has changed.
test/test_edit.jl
has changed.
Project.toml
has changed.
test/test_actions.jl
was deleted.
@@ -74,124 +74,10 @@
Loading
74 | 74 | end |
|
75 | 75 | doc._version = params.textDocument.version |
|
76 | 76 | ||
77 | - | if length(params.contentChanges) == 1 && !endswith(doc._uri, ".jmd") && !ismissing(first(params.contentChanges).range) |
|
78 | - | tdcce = first(params.contentChanges) |
|
79 | - | new_cst = _partial_update(doc, tdcce) |
|
80 | - | scopepass(getroot(doc), doc) |
|
81 | - | lint!(doc, server) |
|
82 | - | else |
|
83 | - | for tdcce in params.contentChanges |
|
84 | - | applytextdocumentchanges(doc, tdcce) |
|
85 | - | end |
|
86 | - | parse_all(doc, server) |
|
87 | - | end |
|
88 | - | end |
|
89 | - | ||
90 | - | function _partial_update(doc::Document, tdcce::TextDocumentContentChangeEvent) |
|
91 | - | cst = getcst(doc) |
|
92 | - | insert_range = get_offset(doc, tdcce.range) |
|
93 | - | ||
94 | - | applytextdocumentchanges(doc, tdcce) |
|
95 | - | ||
96 | - | updated_text = get_text(doc) |
|
97 | - | ||
98 | - | i1, i2, loc1, loc2 = get_update_area(cst, insert_range) |
|
99 | - | is = insert_size(tdcce.text, insert_range) |
|
100 | - | if isempty(updated_text) |
|
101 | - | empty!(cst.args) |
|
102 | - | StaticLint.clear_meta(cst) |
|
103 | - | cst.span = cst.fullspan = 0 |
|
104 | - | elseif 0 < i1 <= i2 |
|
105 | - | old_span = cst_len(cst, i1, i2) |
|
106 | - | ps = ParseState(updated_text, loc1) |
|
107 | - | args = EXPR[] |
|
108 | - | if i1 == 1 && (ps.nt.kind == CSTParser.Tokens.WHITESPACE || ps.nt.kind == CSTParser.Tokens.COMMENT) |
|
109 | - | CSTParser.next(ps) |
|
110 | - | push!(args, CSTParser.mLITERAL(ps.nt.startbyte, ps.nt.startbyte, "", Tokens.NOTHING)) |
|
111 | - | else |
|
112 | - | push!(args, CSTParser.parse(ps)[1]) |
|
113 | - | end |
|
114 | - | prev_pos = -1 |
|
115 | - | while ps.nt.startbyte < old_span + loc1 + is && !(ps.done || kindof(ps.nt) === CSTParser.Tokens.ENDMARKER) |
|
116 | - | if ps.nt.startbyte <= prev_pos |
|
117 | - | throw(LSInfiniteLoop("Loop not progressing as it should.")) |
|
118 | - | else |
|
119 | - | prev_pos = ps.nt.startbyte |
|
120 | - | end |
|
121 | - | push!(args, CSTParser.parse(ps)[1]) |
|
122 | - | end |
|
123 | - | new_span = 0 |
|
124 | - | for i = 1:length(args) |
|
125 | - | new_span += args[i].fullspan |
|
126 | - | end |
|
127 | - | # remove old blocks |
|
128 | - | while old_span + is < new_span && i2 < length(cst.args) |
|
129 | - | i2 += 1 |
|
130 | - | old_span += cst.args[i2].fullspan |
|
131 | - | end |
|
132 | - | for i = i1:i2 |
|
133 | - | StaticLint.clear_meta(cst.args[i]) |
|
134 | - | end |
|
135 | - | deleteat!(cst.args, i1:i2) |
|
136 | - | ||
137 | - | # insert new blocks |
|
138 | - | for a in args |
|
139 | - | insert!(cst.args, i1, a) |
|
140 | - | CSTParser.setparent!(cst.args[i1], cst) |
|
141 | - | i1 += 1 |
|
142 | - | end |
|
143 | - | else |
|
144 | - | StaticLint.clear_meta(cst) |
|
145 | - | cst = CSTParser.parse(updated_text, true) |
|
77 | + | for tdcce in params.contentChanges |
|
78 | + | applytextdocumentchanges(doc, tdcce) |
|
146 | 79 | end |
|
147 | - | CSTParser.update_span!(cst) |
|
148 | - | doc.cst = cst |
|
149 | - | if typof(doc.cst) === CSTParser.FileH |
|
150 | - | doc.cst.val = getpath(doc) |
|
151 | - | set_doc(doc.cst, doc) |
|
152 | - | end |
|
153 | - | end |
|
154 | - | ||
155 | - | insert_size(inserttext, insertrange) = sizeof(inserttext) - max(last(insertrange) - first(insertrange), 0) # OK, used to adjust EXPR spans |
|
156 | - | ||
157 | - | function cst_len(x, i1=1, i2=length(x.args)) |
|
158 | - | n = 0 |
|
159 | - | @inbounds for i = i1:i2 |
|
160 | - | n += x.args[i].fullspan |
|
161 | - | end |
|
162 | - | n |
|
163 | - | end |
|
164 | - | ||
165 | - | function get_update_area(cst, insert_range) |
|
166 | - | loc1 = loc2 = 0 |
|
167 | - | i1 = i2 = 0 |
|
168 | - | ||
169 | - | while i1 < length(cst.args) |
|
170 | - | i1 += 1 |
|
171 | - | a = cst.args[i1] |
|
172 | - | if loc1 <= first(insert_range) <= loc1 + a.fullspan |
|
173 | - | loc2 = loc1 |
|
174 | - | i2 = i1 |
|
175 | - | if !(loc1 <= last(insert_range) <= loc1 + a.fullspan) |
|
176 | - | while i2 < length(cst.args) |
|
177 | - | i2 += 1 |
|
178 | - | a = cst.args[i2] |
|
179 | - | if loc2 <= last(insert_range) <= loc2 + a.fullspan |
|
180 | - | if i2 < length(cst.args) && last(insert_range) <= loc2 + a.fullspan |
|
181 | - | i2 += 1 |
|
182 | - | end |
|
183 | - | break |
|
184 | - | end |
|
185 | - | loc2 += a.fullspan |
|
186 | - | end |
|
187 | - | elseif i2 < length(cst.args) && last(insert_range) == loc1 + a.fullspan |
|
188 | - | i2 += 1 |
|
189 | - | end |
|
190 | - | break |
|
191 | - | end |
|
192 | - | loc1 += a.fullspan |
|
193 | - | end |
|
194 | - | return i1, i2, loc1, loc2 |
|
80 | + | parse_all(doc, server) |
|
195 | 81 | end |
|
196 | 82 | ||
197 | 83 | function convert_lsrange_to_jlrange(doc::Document, range::Range) |
@@ -212,11 +98,8 @@
Loading
212 | 98 | set_text!(doc, tdcce.text) |
|
213 | 99 | else |
|
214 | 100 | editrange = convert_lsrange_to_jlrange(doc, tdcce.range) |
|
215 | - | ||
216 | 101 | text = get_text(doc) |
|
217 | - | ||
218 | 102 | new_text = string(text[1:prevind(text, editrange.start)], tdcce.text, text[nextind(text, editrange.stop):lastindex(text)]) |
|
219 | - | ||
220 | 103 | set_text!(doc, new_text) |
|
221 | 104 | end |
|
222 | 105 | end |
@@ -229,12 +112,12 @@
Loading
229 | 112 | else |
|
230 | 113 | doc.cst, ps = CSTParser.parse(ps, true) |
|
231 | 114 | end |
|
232 | - | if typof(doc.cst) === CSTParser.FileH |
|
115 | + | if headof(doc.cst) === :file |
|
233 | 116 | doc.cst.val = getpath(doc) |
|
234 | 117 | set_doc(doc.cst, doc) |
|
235 | 118 | end |
|
119 | + | semantic_pass(getroot(doc), doc) |
|
236 | 120 | ||
237 | - | scopepass(getroot(doc), doc) |
|
238 | 121 | lint!(doc, server) |
|
239 | 122 | end |
|
240 | 123 |
@@ -270,8 +153,7 @@
Loading
270 | 153 | r[2] = char |
|
271 | 154 | offset += errs[i][2].span |
|
272 | 155 | else |
|
273 | - | DiagnosticSeverities |
|
274 | - | if typof(errs[i][2]) === CSTParser.ErrorToken |
|
156 | + | if headof(errs[i][2]) === :errortoken |
|
275 | 157 | push!(out, Diagnostic(Range(r[1] - 1, r[2], line - 1, char), DiagnosticSeverities.Error, "Julia", "Julia", "Parsing error", missing, missing)) |
|
276 | 158 | elseif CSTParser.isidentifier(errs[i][2]) && !StaticLint.haserror(errs[i][2]) |
|
277 | 159 | push!(out, Diagnostic(Range(r[1] - 1, r[2], line - 1, char), DiagnosticSeverities.Warning, "Julia", "Julia", "Missing reference: $(errs[i][2].val)", missing, missing)) |
@@ -346,14 +228,15 @@
Loading
346 | 228 | push!(blocks, (ps.t.startbyte, CSTParser.INSTANCE(ps))) |
|
347 | 229 | end |
|
348 | 230 | end |
|
349 | - | top = EXPR(CSTParser.FileH, EXPR[]) |
|
231 | + | top = EXPR(:file, EXPR[], nothing) |
|
350 | 232 | if isempty(blocks) |
|
351 | 233 | return top, ps |
|
352 | 234 | end |
|
353 | 235 | ||
354 | 236 | for (startbyte, b) in blocks |
|
355 | - | if typof(b) === CSTParser.LITERAL && kindof(b) == CSTParser.Tokens.TRIPLE_CMD && (startswith(b.val, "julia") || startswith(b.val, "{julia")) |
|
356 | - | blockstr = b.val |
|
237 | + | if CSTParser.ismacrocall(b) && headof(b.args[1]) === :globalrefcmd && headof(b.args[3]) === :TRIPLESTRING && (startswith(b.args[3].val, "julia") || startswith(b.args[3].val, "{julia")) |
|
238 | + | ||
239 | + | blockstr = b.args[3].val |
|
357 | 240 | ps = CSTParser.ParseState(blockstr) |
|
358 | 241 | # skip first line |
|
359 | 242 | while ps.nt.startpos[1] == 1 |
@@ -361,18 +244,18 @@
Loading
361 | 244 | end |
|
362 | 245 | prec_str_size = currentbyte:startbyte + ps.nt.startbyte + 3 |
|
363 | 246 | ||
364 | - | push!(top.args, CSTParser.mLITERAL(length(prec_str_size), length(prec_str_size), "", CSTParser.Tokens.STRING)) |
|
247 | + | push!(top.args, EXPR(:STRING, length(prec_str_size), length(prec_str_size))) |
|
365 | 248 | ||
366 | 249 | args, ps = CSTParser.parse(ps, true) |
|
367 | 250 | append!(top.args, args.args) |
|
368 | 251 | CSTParser.update_span!(top) |
|
369 | 252 | currentbyte = top.fullspan + 1 |
|
370 | - | elseif typof(b) === CSTParser.LITERAL && kindof(b) == CSTParser.Tokens.CMD && startswith(b.val, "j ") |
|
371 | - | blockstr = b.val |
|
253 | + | elseif CSTParser.ismacrocall(b) && headof(b.args[1]) === :globalrefcmd && headof(b.args[3]) === :STRING && startswith(b.val, "j ") |
|
254 | + | blockstr = b.args[3].val |
|
372 | 255 | ps = CSTParser.ParseState(blockstr) |
|
373 | 256 | CSTParser.next(ps) |
|
374 | 257 | prec_str_size = currentbyte:startbyte + ps.nt.startbyte + 1 |
|
375 | - | push!(top.args, CSTParser.mLITERAL(length(prec_str_size), length(prec_str_size), "", CSTParser.Tokens.STRING)) |
|
258 | + | push!(top.args, EXPR(:STRING, length(prec_str_size), length(prec_str_size))) |
|
376 | 259 | ||
377 | 260 | args, ps = CSTParser.parse(ps, true) |
|
378 | 261 | append!(top.args, args.args) |
@@ -382,7 +265,7 @@
Loading
382 | 265 | end |
|
383 | 266 | ||
384 | 267 | prec_str_size = currentbyte:sizeof(str) # OK |
|
385 | - | push!(top.args, CSTParser.mLITERAL(length(prec_str_size), length(prec_str_size), "", CSTParser.Tokens.STRING)) |
|
268 | + | push!(top.args, EXPR(:STRING, length(prec_str_size), length(prec_str_size))) |
|
386 | 269 | ||
387 | 270 | return top, ps |
|
388 | 271 | end |
@@ -434,20 +317,20 @@
Loading
434 | 317 | pdoc = Document(puri, content, false, server) |
|
435 | 318 | setdocument!(server, URI2(puri), pdoc) |
|
436 | 319 | CSTParser.parse(get_text(pdoc), true) |
|
437 | - | if typof(pdoc.cst) === CSTParser.FileH |
|
320 | + | if headof(pdoc.cst) === :file |
|
438 | 321 | pdoc.cst.val = getpath(pdoc) |
|
439 | 322 | set_doc(pdoc.cst, pdoc) |
|
440 | 323 | end |
|
441 | 324 | else |
|
442 | 325 | pdoc = getdocument(server, URI2(puri)) |
|
443 | 326 | end |
|
444 | - | scopepass(getroot(pdoc), pdoc) |
|
327 | + | semantic_pass(getroot(pdoc), pdoc) |
|
445 | 328 | # check whether child has been included automatically |
|
446 | 329 | if any(getpath(d) == child_path for (k, d) in getdocuments_pair(server) if !(k in previous_server_docs)) |
|
447 | 330 | cdoc = getdocument(server, URI2(filepath2uri(child_path))) |
|
448 | 331 | parse_all(cdoc, server) |
|
449 | - | scopepass(getroot(cdoc)) |
|
450 | - | return true |
|
332 | + | semantic_pass(getroot(cdoc)) |
|
333 | + | return true, "", CSTParser.Tokens.STRING |
|
451 | 334 | else |
|
452 | 335 | # clean up |
|
453 | 336 | foreach(k -> !(k in previous_server_docs) && deletedocument!(server, k), getdocuments_key(server)) |
@@ -181,8 +181,8 @@
Loading
181 | 181 | if pos > offset |
|
182 | 182 | return nothing |
|
183 | 183 | end |
|
184 | - | if x.args !== nothing && typof(x) !== CSTParser.NONSTDIDENTIFIER |
|
185 | - | for a in x.args |
|
184 | + | if length(x) > 0 && headof(x) !== :NONSTDIDENTIFIER |
|
185 | + | for a in x |
|
186 | 186 | if pos < offset <= (pos + a.fullspan) |
|
187 | 187 | return get_expr(a, offset, pos, ignorewhitespace) |
|
188 | 188 | end |
@@ -200,8 +200,8 @@
Loading
200 | 200 | if all(pos .> offset) |
|
201 | 201 | return nothing |
|
202 | 202 | end |
|
203 | - | if x.args !== nothing && typof(x) !== CSTParser.NONSTDIDENTIFIER |
|
204 | - | for a in x.args |
|
203 | + | if length(x) > 0 && headof(x) !== :NONSTDIDENTIFIER |
|
204 | + | for a in x |
|
205 | 205 | if all(pos .< offset .<= (pos + a.fullspan)) |
|
206 | 206 | return get_expr(a, offset, pos, ignorewhitespace) |
|
207 | 207 | end |
@@ -221,35 +221,35 @@
Loading
221 | 221 | end |
|
222 | 222 | ||
223 | 223 | function get_expr1(x, offset, pos=0) |
|
224 | - | if x.args === nothing || isempty(x.args) || typof(x) === CSTParser.NONSTDIDENTIFIER |
|
224 | + | if length(x) == 0 || headof(x) === :NONSTDIDENTIFIER |
|
225 | 225 | if pos <= offset <= pos + x.span |
|
226 | 226 | return x |
|
227 | 227 | else |
|
228 | 228 | return nothing |
|
229 | 229 | end |
|
230 | 230 | else |
|
231 | - | for i = 1:length(x.args) |
|
232 | - | arg = x.args[i] |
|
231 | + | for i = 1:length(x) |
|
232 | + | arg = x[i] |
|
233 | 233 | if pos < offset < (pos + arg.span) # def within span |
|
234 | 234 | return get_expr1(arg, offset, pos) |
|
235 | 235 | elseif arg.span == arg.fullspan |
|
236 | 236 | if offset == pos |
|
237 | 237 | if i == 1 |
|
238 | 238 | return get_expr1(arg, offset, pos) |
|
239 | - | elseif CSTParser.typof(x.args[i - 1]) === CSTParser.IDENTIFIER |
|
240 | - | return get_expr1(x.args[i - 1], offset, pos) |
|
239 | + | elseif headof(x[i - 1]) === :IDENTIFIER |
|
240 | + | return get_expr1(x[i - 1], offset, pos) |
|
241 | 241 | else |
|
242 | 242 | return get_expr1(arg, offset, pos) |
|
243 | 243 | end |
|
244 | - | elseif i == length(x.args) # offset == pos + arg.fullspan |
|
244 | + | elseif i == length(x) # offset == pos + arg.fullspan |
|
245 | 245 | return get_expr1(arg, offset, pos) |
|
246 | 246 | end |
|
247 | 247 | else |
|
248 | 248 | if offset == pos |
|
249 | 249 | if i == 1 |
|
250 | 250 | return get_expr1(arg, offset, pos) |
|
251 | - | elseif CSTParser.typof(x.args[i - 1]) === CSTParser.IDENTIFIER |
|
252 | - | return get_expr1(x.args[i - 1], offset, pos) |
|
251 | + | elseif headof(x[i - 1]) === :IDENTIFIER |
|
252 | + | return get_expr1(x[i - 1], offset, pos) |
|
253 | 253 | else |
|
254 | 254 | return get_expr1(arg, offset, pos) |
|
255 | 255 | end |
@@ -271,18 +271,69 @@
Loading
271 | 271 | if pos > offset |
|
272 | 272 | return nothing |
|
273 | 273 | end |
|
274 | - | if x.args !== nothing |
|
275 | - | for a in x.args |
|
274 | + | if length(x) > 0 |
|
275 | + | for a in x |
|
276 | 276 | if pos <= offset <= (pos + a.span) |
|
277 | 277 | return get_identifier(a, offset, pos) |
|
278 | 278 | end |
|
279 | 279 | pos += a.fullspan |
|
280 | 280 | end |
|
281 | - | elseif typof(x) === CSTParser.IDENTIFIER && (pos <= offset <= (pos + x.span)) || pos == 0 |
|
281 | + | elseif headof(x) === :IDENTIFIER && (pos <= offset <= (pos + x.span)) || pos == 0 |
|
282 | 282 | return x |
|
283 | 283 | end |
|
284 | 284 | end |
|
285 | 285 | ||
286 | + | ||
287 | + | if VERSION < v"1.1" || Sys.iswindows() && VERSION < v"1.3" |
|
288 | + | _splitdir_nodrive(path::String) = _splitdir_nodrive("", path) |
|
289 | + | function _splitdir_nodrive(a::String, b::String) |
|
290 | + | m = match(Base.Filesystem.path_dir_splitter, b) |
|
291 | + | m === nothing && return (a, b) |
|
292 | + | a = string(a, isempty(m.captures[1]) ? m.captures[2][1] : m.captures[1]) |
|
293 | + | a, String(m.captures[3]) |
|
294 | + | end |
|
295 | + | splitpath(p::AbstractString) = splitpath(String(p)) |
|
296 | + | ||
297 | + | function splitpath(p::String) |
|
298 | + | drive, p = _splitdrive(p) |
|
299 | + | out = String[] |
|
300 | + | isempty(p) && (pushfirst!(out, p)) # "" means the current directory. |
|
301 | + | while !isempty(p) |
|
302 | + | dir, base = _splitdir_nodrive(p) |
|
303 | + | dir == p && (pushfirst!(out, dir); break) # Reached root node. |
|
304 | + | if !isempty(base) # Skip trailing '/' in basename |
|
305 | + | pushfirst!(out, base) |
|
306 | + | end |
|
307 | + | p = dir |
|
308 | + | end |
|
309 | + | if !isempty(drive) # Tack the drive back on to the first element. |
|
310 | + | out[1] = drive * out[1] # Note that length(out) is always >= 1. |
|
311 | + | end |
|
312 | + | return out |
|
313 | + | end |
|
314 | + | _path_separator = "\\" |
|
315 | + | _path_separator_re = r"[/\\]+" |
|
316 | + | function _pathsep(paths::AbstractString...) |
|
317 | + | for path in paths |
|
318 | + | m = match(_path_separator_re, String(path)) |
|
319 | + | m !== nothing && return m.match[1:1] |
|
320 | + | end |
|
321 | + | return _path_separator |
|
322 | + | end |
|
323 | + | function joinpath(a::String, b::String) |
|
324 | + | isabspath(b) && return b |
|
325 | + | A, a = _splitdrive(a) |
|
326 | + | B, b = _splitdrive(b) |
|
327 | + | !isempty(B) && A != B && return string(B,b) |
|
328 | + | C = isempty(B) ? A : B |
|
329 | + | isempty(a) ? string(C,b) : |
|
330 | + | occursin(_path_separator_re, a[end:end]) ? string(C,a,b) : |
|
331 | + | string(C,a,_pathsep(a,b),b) |
|
332 | + | end |
|
333 | + | joinpath(a::AbstractString, b::AbstractString) = joinpath(String(a), String(b)) |
|
334 | + | joinpath(a, b, c, paths...) = joinpath(joinpath(a, b), c, paths...) |
|
335 | + | end |
|
336 | + | ||
286 | 337 | @static if Sys.iswindows() && VERSION < v"1.3" |
|
287 | 338 | function _splitdir_nodrive(a::String, b::String) |
|
288 | 339 | m = match(r"^(.*?)([/\\]+)([^/\\]*)$", b) |
@@ -292,11 +343,13 @@
Loading
292 | 343 | end |
|
293 | 344 | function _dirname(path::String) |
|
294 | 345 | m = match(r"^([^\\]+:|\\\\[^\\]+\\[^\\]+|\\\\\?\\UNC\\[^\\]+\\[^\\]+|\\\\\?\\[^\\]+:|)(.*)$"s, path) |
|
346 | + | m === nothing && return "" |
|
295 | 347 | a, b = String(m.captures[1]), String(m.captures[2]) |
|
296 | 348 | _splitdir_nodrive(a, b)[1] |
|
297 | 349 | end |
|
298 | 350 | function _splitdrive(path::String) |
|
299 | 351 | m = match(r"^([^\\]+:|\\\\[^\\]+\\[^\\]+|\\\\\?\\UNC\\[^\\]+\\[^\\]+|\\\\\?\\[^\\]+:|)(.*)$"s, path) |
|
352 | + | m === nothing && return "", path |
|
300 | 353 | String(m.captures[1]), String(m.captures[2]) |
|
301 | 354 | end |
|
302 | 355 | function _splitdir(path::String) |
@@ -306,6 +359,7 @@
Loading
306 | 359 | else |
|
307 | 360 | _dirname = dirname |
|
308 | 361 | _splitdir = splitdir |
|
362 | + | _splitdrive = splitdrive |
|
309 | 363 | end |
|
310 | 364 | ||
311 | 365 | function valid_id(s::String) |
@@ -330,7 +384,7 @@
Loading
330 | 384 | ||
331 | 385 | function resolve_op_ref(x::EXPR, server) |
|
332 | 386 | StaticLint.hasref(x) && return true |
|
333 | - | typof(x) !== CSTParser.OPERATOR && return false |
|
387 | + | !CSTParser.isoperator(x) && return false |
|
334 | 388 | pf = parent_file(x) |
|
335 | 389 | pf === nothing && return false |
|
336 | 390 | scope = StaticLint.retrieve_scope(x) |
@@ -367,36 +421,8 @@
Loading
367 | 421 | return true |
|
368 | 422 | end |
|
369 | 423 | return false |
|
370 | - | catch |
|
424 | + | catch err |
|
371 | 425 | return false |
|
372 | 426 | end |
|
373 | 427 | end |
|
374 | 428 | ||
375 | - | if VERSION < v"1.1" |
|
376 | - | _splitdir_nodrive(path::String) = _splitdir_nodrive("", path) |
|
377 | - | function _splitdir_nodrive(a::String, b::String) |
|
378 | - | m = match(Base.Filesystem.path_dir_splitter, b) |
|
379 | - | m === nothing && return (a, b) |
|
380 | - | a = string(a, isempty(m.captures[1]) ? m.captures[2][1] : m.captures[1]) |
|
381 | - | a, String(m.captures[3]) |
|
382 | - | end |
|
383 | - | splitpath(p::AbstractString) = splitpath(String(p)) |
|
384 | - | ||
385 | - | function splitpath(p::String) |
|
386 | - | drive, p = splitdrive(p) |
|
387 | - | out = String[] |
|
388 | - | isempty(p) && (pushfirst!(out, p)) # "" means the current directory. |
|
389 | - | while !isempty(p) |
|
390 | - | dir, base = _splitdir_nodrive(p) |
|
391 | - | dir == p && (pushfirst!(out, dir); break) # Reached root node. |
|
392 | - | if !isempty(base) # Skip trailing '/' in basename |
|
393 | - | pushfirst!(out, base) |
|
394 | - | end |
|
395 | - | p = dir |
|
396 | - | end |
|
397 | - | if !isempty(drive) # Tack the drive back on to the first element. |
|
398 | - | out[1] = drive * out[1] # Note that length(out) is always >= 1. |
|
399 | - | end |
|
400 | - | return out |
|
401 | - | end |
|
402 | - | end |
@@ -21,29 +21,29 @@
Loading
21 | 21 | x = getcst(doc) |
|
22 | 22 | loc = 0 |
|
23 | 23 | ||
24 | - | if typof(x) === CSTParser.FileH |
|
25 | - | for a in x.args |
|
24 | + | if headof(x) === :file |
|
25 | + | for a in x |
|
26 | 26 | if loc <= offset <= loc + a.span |
|
27 | 27 | if CSTParser.defines_module(a) # Within module at the top-level, lets see if we can select on of the block arguments |
|
28 | - | if loc <= offset <= loc + a.args[1].span # Within `module` keyword, so return entire expression |
|
28 | + | if loc <= offset <= loc + a.trivia[1].span # Within `module` keyword, so return entire expression |
|
29 | 29 | return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + a.span)...), Position(get_position_at(doc, loc + a.fullspan)...) |
|
30 | 30 | end |
|
31 | - | if loc + a.args[1].fullspan <= offset <= loc + a.args[1].fullspan + a.args[2].span # Within name of the module, so return entire expression |
|
31 | + | if loc + a.trivia[1].fullspan <= offset <= loc + a.trivia[1].fullspan + a.args[2].span # Within name of the module, so return entire expression |
|
32 | 32 | return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + a.span)...), Position(get_position_at(doc, loc + a.fullspan)...) |
|
33 | 33 | end |
|
34 | 34 | ||
35 | - | if loc + a.args[1].fullspan + a.args[2].fullspan <= offset <= loc + a.args[1].fullspan + a.args[2].fullspan + a.args[3].span # Within the body of a module |
|
36 | - | loc += a.args[1].fullspan + a.args[2].fullspan |
|
35 | + | if loc + a.trivia[1].fullspan + a.args[2].fullspan <= offset <= loc + a.trivia[1].fullspan + a.args[2].fullspan + a.args[3].span # Within the body of a module |
|
36 | + | loc += a.trivia[1].fullspan + a.args[2].fullspan |
|
37 | 37 | for b in a.args[3].args |
|
38 | 38 | if loc <= offset <= loc + b.span |
|
39 | 39 | return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + b.span)...), Position(get_position_at(doc, loc + b.fullspan)...) |
|
40 | 40 | end |
|
41 | 41 | loc += b.fullspan |
|
42 | 42 | end |
|
43 | - | elseif loc + a.args[1].fullspan + a.args[2].fullspan + a.args[3].fullspan < offset < loc + a.args[1].fullspan + a.args[2].fullspan + a.args[3].fullspan + a.args[4].span # Within `end` of the module, so return entire expression |
|
43 | + | elseif loc + a.trivia[1].fullspan + a.args[2].fullspan + a.args[3].fullspan < offset < loc + a.trivia[1].fullspan + a.args[2].fullspan + a.args[3].fullspan + a.trivia[2].span # Within `end` of the module, so return entire expression |
|
44 | 44 | return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + a.span)...), Position(get_position_at(doc, loc + a.fullspan)...) |
|
45 | 45 | end |
|
46 | - | elseif typof(a) === CSTParser.TopLevel |
|
46 | + | elseif headof(a) === :toplevel |
|
47 | 47 | for b in a.args |
|
48 | 48 | if loc <= offset <= loc + b.span |
|
49 | 49 | return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + b.span)...), Position(get_position_at(doc, loc + b.fullspan)...) |
@@ -1,7 +1,7 @@
Loading
1 | 1 | function textDocument_hover_request(params::TextDocumentPositionParams, server::LanguageServerInstance, conn) |
|
2 | 2 | doc = getdocument(server, URI2(params.textDocument.uri)) |
|
3 | 3 | x = get_expr1(getcst(doc), get_offset(doc, params.position)) |
|
4 | - | x isa EXPR && typof(x) === CSTParser.OPERATOR && resolve_op_ref(x, server) |
|
4 | + | x isa EXPR && CSTParser.isoperator(x) && resolve_op_ref(x, server) |
|
5 | 5 | documentation = get_hover(x, "", server) |
|
6 | 6 | documentation = get_closer_hover(x, documentation) |
|
7 | 7 | documentation = get_fcall_position(x, documentation) |
@@ -33,9 +33,9 @@
Loading
33 | 33 | else |
|
34 | 34 | try |
|
35 | 35 | documentation = if binding_has_preceding_docs(b) |
|
36 | - | string(documentation, Expr(parentof(b.val).args[2])) |
|
36 | + | string(documentation, Expr(parentof(b.val).args[3])) |
|
37 | 37 | elseif const_binding_has_preceding_docs(b) |
|
38 | - | string(documentation, Expr(parentof(parentof(b.val)).args[2])) |
|
38 | + | string(documentation, Expr(parentof(parentof(b.val)).args[3])) |
|
39 | 39 | else |
|
40 | 40 | documentation |
|
41 | 41 | end |
@@ -107,16 +107,16 @@
Loading
107 | 107 | if b.val isa EXPR |
|
108 | 108 | documentation = if binding_has_preceding_docs(b) |
|
109 | 109 | # Binding has preceding docs so use them.. |
|
110 | - | string(documentation, Expr(parentof(b.val).args[2])) |
|
110 | + | string(documentation, Expr(parentof(b.val).args[3])) |
|
111 | 111 | elseif const_binding_has_preceding_docs(b) |
|
112 | - | string(documentation, Expr(parentof(parentof(b.val)).args[2])) |
|
112 | + | string(documentation, Expr(parentof(parentof(b.val)).args[3])) |
|
113 | 113 | else |
|
114 | 114 | documentation |
|
115 | 115 | end |
|
116 | 116 | if CSTParser.defines_function(b.val) |
|
117 | - | documentation = string(documentation, "```julia\n", Expr(CSTParser.get_sig(b.val)), "\n```\n") |
|
117 | + | documentation = string(ensure_ends_with(documentation), "```julia\n", Expr(CSTParser.get_sig(b.val)), "\n```\n") |
|
118 | 118 | elseif CSTParser.defines_datatype(b.val) |
|
119 | - | documentation = string(documentation, "```julia\n", Expr(b.val), "\n```\n") |
|
119 | + | documentation = string(ensure_ends_with(documentation), "```julia\n", Expr(b.val), "\n```\n") |
|
120 | 120 | end |
|
121 | 121 | elseif b.val isa SymbolServer.SymStore |
|
122 | 122 | return get_hover(b.val, documentation, server) |
@@ -127,6 +127,8 @@
Loading
127 | 127 | return documentation |
|
128 | 128 | end |
|
129 | 129 | ||
130 | + | ensure_ends_with(s, c = "\n") = endswith(s, c) ? s : string(s, c) |
|
131 | + | ||
130 | 132 | binding_has_preceding_docs(b::StaticLint.Binding) = expr_has_preceding_docs(b.val) |
|
131 | 133 | ||
132 | 134 | function const_binding_has_preceding_docs(b::StaticLint.Binding) |
@@ -138,14 +140,14 @@
Loading
138 | 140 | expr_has_preceding_docs(x::EXPR) = is_doc_expr(parentof(x)) |
|
139 | 141 | ||
140 | 142 | is_const_expr(x) = false |
|
141 | - | is_const_expr(x::EXPR) = length(x.args) == 2 && kindof(x.args[1]) === CSTParser.Tokens.CONST |
|
143 | + | is_const_expr(x::EXPR) = headof(x) === :const |
|
142 | 144 | ||
143 | 145 | is_doc_expr(x) = false |
|
144 | 146 | function is_doc_expr(x::EXPR) |
|
145 | - | return typof(x) === CSTParser.MacroCall && |
|
146 | - | length(x.args) == 3 && |
|
147 | - | typof(x.args[1]) === CSTParser.GlobalRefDoc && |
|
148 | - | CSTParser.isstring(x.args[2]) |
|
147 | + | return CSTParser.ismacrocall(x) && |
|
148 | + | length(x.args) == 4 && |
|
149 | + | headof(x.args[1]) === :globalrefdoc && |
|
150 | + | CSTParser.isstring(x.args[3]) |
|
149 | 151 | end |
|
150 | 152 | ||
151 | 153 | get_fcall_position(x, documentation, visited=nothing) = documentation |
@@ -157,14 +159,14 @@
Loading
157 | 159 | push!(visited, x) # TODO: remove |
|
158 | 160 | end # TODO: remove |
|
159 | 161 | if parentof(x) isa EXPR |
|
160 | - | if typof(parentof(x)) === CSTParser.Call |
|
162 | + | if CSTParser.iscall(parentof(x)) |
|
161 | 163 | call_counts = StaticLint.call_nargs(parentof(x)) |
|
162 | 164 | call_counts[1] < 5 && return documentation |
|
163 | 165 | arg_i = 0 |
|
164 | - | for i = 1:length(parentof(x).args) |
|
165 | - | arg = parentof(x).args[i] |
|
166 | + | for (i, arg) = enumerate(parentof(x)) |
|
166 | 167 | if arg == x |
|
167 | 168 | arg_i = div(i - 1, 2) |
|
169 | + | break |
|
168 | 170 | end |
|
169 | 171 | end |
|
170 | 172 | arg_i == 0 && return documentation |
@@ -172,7 +174,7 @@
Loading
172 | 174 | if StaticLint.hasref(fname) && |
|
173 | 175 | (refof(fname) isa StaticLint.Binding && refof(fname).val isa EXPR && CSTParser.defines_struct(refof(fname).val) && StaticLint.struct_nargs(refof(fname).val)[1] == call_counts[1]) |
|
174 | 176 | dt_ex = refof(fname).val |
|
175 | - | args = CSTParser.defines_mutable(dt_ex) ? dt_ex.args[4] : dt_ex.args[3] |
|
177 | + | args = dt_ex.args[3] |
|
176 | 178 | args.args === nothing || arg_i > length(args.args) && return documentation |
|
177 | 179 | _fieldname = CSTParser.str_value(CSTParser.get_arg_name(args.args[arg_i])) |
|
178 | 180 | documentation = string("Datatype field `$_fieldname` of $(CSTParser.str_value(CSTParser.get_name(dt_ex)))", "\n", documentation) |
@@ -196,27 +198,24 @@
Loading
196 | 198 | get_closer_hover(x, documentation) = documentation |
|
197 | 199 | function get_closer_hover(x::EXPR, documentation) |
|
198 | 200 | if parentof(x) isa EXPR |
|
199 | - | if kindof(x) === CSTParser.Tokens.END |
|
200 | - | if typof(parentof(x)) === CSTParser.FunctionDef |
|
201 | + | if headof(x) === :END |
|
202 | + | if headof(parentof(x)) === :function |
|
201 | 203 | documentation = string(documentation, "Closes function definition for `", Expr(CSTParser.get_sig(parentof(x))), "`\n") |
|
202 | - | elseif (typof(parentof(x)) === CSTParser.ModuleH || typof(parentof(x)) === CSTParser.ModuleH) && length(parentof(x).args) > 1 |
|
204 | + | elseif CSTParser.defines_module(parentof(x)) && length(parentof(x).args) > 1 |
|
203 | 205 | documentation = string(documentation, "Closes module definition for `", Expr(parentof(x).args[2]), "`\n") |
|
204 | - | elseif typof(parentof(x)) === CSTParser.Struct |
|
206 | + | elseif CSTParser.defines_struct(parentof(x)) |
|
205 | 207 | documentation = string(documentation, "Closes struct definition for `", Expr(CSTParser.get_sig(parentof(x))), "`\n") |
|
206 | - | elseif typof(parentof(x)) === CSTParser.Mutable |
|
207 | - | documentation = string(documentation, "Closes mutable struct definition for `", Expr(CSTParser.get_sig(parentof(x))), "`\n") |
|
208 | - | elseif typof(parentof(x)) === CSTParser.For && length(parentof(x).args) > 2 |
|
208 | + | elseif headof(parentof(x)) === :for && length(parentof(x).args) > 2 |
|
209 | 209 | documentation = string(documentation, "Closes for-loop expression over `", Expr(parentof(x).args[2]), "`\n") |
|
210 | - | elseif typof(parentof(x)) === CSTParser.While && length(parentof(x).args) > 2 |
|
210 | + | elseif headof(parentof(x)) === :while && length(parentof(x).args) > 2 |
|
211 | 211 | documentation = string(documentation, "Closes while-loop expression over `", Expr(parentof(x).args[2]), "`\n") |
|
212 | 212 | else |
|
213 | - | documentation = "Closes `$(typof(parentof(x)))` expression." |
|
213 | + | documentation = "Closes `$(headof(parentof(x)))` expression." |
|
214 | 214 | end |
|
215 | - | elseif kindof(x) === CSTParser.Tokens.RPAREN |
|
216 | - | if typof(parentof(x)) === CSTParser.Call && length(parentof(x).args) > 0 |
|
215 | + | elseif headof(x) === :RPAREN |
|
216 | + | if CSTParser.iscall(parentof(x)) && length(parentof(x).args) > 0 |
|
217 | 217 | documentation = string(documentation, "Closes call of ", Expr(parentof(x).args[1]), "\n") |
|
218 | 218 | end |
|
219 | - | elseif kindof(x) === CSTParser.Tokens.RBRACE || kindof(x) === CSTParser.Tokens.RSQUARE |
|
220 | 219 | end |
|
221 | 220 | end |
|
222 | 221 | return documentation |
@@ -1,7 +1,7 @@
Loading
1 | 1 | module LanguageServer |
|
2 | 2 | import URIParser |
|
3 | 3 | using JSON, REPL, CSTParser, DocumentFormat, SymbolServer, StaticLint |
|
4 | - | using CSTParser: EXPR, Tokenize.Tokens, typof, kindof, parentof, valof |
|
4 | + | using CSTParser: EXPR, Tokenize.Tokens, Tokenize.Tokens.kind, headof, parentof, valof |
|
5 | 5 | using StaticLint: refof, scopeof, bindingof |
|
6 | 6 | using UUIDs |
|
7 | 7 | using Base.Docs, Markdown |
@@ -130,7 +130,7 @@
Loading
130 | 130 | for d in getdocuments_value(server) |
|
131 | 131 | if d.root === doc |
|
132 | 132 | d.root = d |
|
133 | - | scopepass(getroot(d), d) |
|
133 | + | semantic_pass(getroot(d), d) |
|
134 | 134 | end |
|
135 | 135 | end |
|
136 | 136 | end |
@@ -320,7 +320,7 @@
Loading
320 | 320 | root = getroot(doc) |
|
321 | 321 | if !(root in roots) |
|
322 | 322 | push!(roots, root) |
|
323 | - | scopepass(root, doc) |
|
323 | + | semantic_pass(root, doc) |
|
324 | 324 | end |
|
325 | 325 | ||
326 | 326 | lint!(doc, server) |
@@ -1,5 +1,5 @@
Loading
1 | 1 | import StaticLint: hasfile, canloadfile, loadfile, setfile, getfile, getsymbolserver, getsymbolextendeds |
|
2 | - | import StaticLint: getpath, getroot, setroot, getcst, setcst, scopepass, getserver, setserver |
|
2 | + | import StaticLint: getpath, getroot, setroot, getcst, setcst, semantic_pass, getserver, setserver |
|
3 | 3 | hasfile(server::LanguageServerInstance, path::String) = !isempty(path) && hasdocument(server, URI2(filepath2uri(path))) |
|
4 | 4 | function canloadfile(server::LanguageServerInstance, path::String) |
|
5 | 5 | try |
@@ -6,15 +6,14 @@
Loading
6 | 6 | else # TODO: remove |
|
7 | 7 | push!(visited, b) # TODO: remove |
|
8 | 8 | end # TODO: remove |
|
9 | - | ||
10 | 9 | if b.type == StaticLint.CoreTypes.Function && b.val isa EXPR && CSTParser.defines_function(b.val) |
|
11 | 10 | get_siginfo_from_call(b.val, sigs) |
|
12 | 11 | elseif b.val isa EXPR && CSTParser.defines_struct(b.val) |
|
13 | - | args = CSTParser.defines_mutable(b.val) ? b.val[4] : b.val[3] |
|
12 | + | args = b.val.args[3] |
|
14 | 13 | if length(args) > 0 |
|
15 | 14 | inner_constructor_i = findfirst(a -> CSTParser.defines_function(a), args.args) |
|
16 | 15 | if inner_constructor_i !== nothing |
|
17 | - | get_siginfo_from_call(args[inner_constructor_i], sigs) |
|
16 | + | get_siginfo_from_call(args.args[inner_constructor_i], sigs) |
|
18 | 17 | else |
|
19 | 18 | params = ParameterInformation[] |
|
20 | 19 | for field in args.args |
@@ -64,14 +63,13 @@
Loading
64 | 63 | rng = Range(doc, offset:offset) |
|
65 | 64 | x = get_expr(getcst(doc), offset) |
|
66 | 65 | arg = 0 |
|
67 | - | ||
68 | - | if x isa EXPR && parentof(x) isa EXPR && StaticLint.is_call(parentof(x)) |
|
66 | + | if x isa EXPR && parentof(x) isa EXPR && CSTParser.iscall(parentof(x)) |
|
69 | 67 | if CSTParser.isidentifier(parentof(x).args[1]) |
|
70 | 68 | call_name = parentof(x).args[1] |
|
71 | - | elseif StaticLint.is_curly(parentof(x).args[1]) && CSTParser.isidentifier(parentof(x).args[1].args[1]) |
|
69 | + | elseif CSTParser.iscurly(parentof(x).args[1]) && CSTParser.isidentifier(parentof(x).args[1].args[1]) |
|
72 | 70 | call_name = parentof(x).args[1].args[1] |
|
73 | - | elseif StaticLint.is_getfield_w_quotenode(parentof(x).args[1]) |
|
74 | - | call_name = parentof(x).args[1].args[3].args[1] |
|
71 | + | elseif CSTParser.is_getfield_w_quotenode(parentof(x).args[1]) |
|
72 | + | call_name = parentof(x).args[1].args[2].args[1] |
|
75 | 73 | else |
|
76 | 74 | call_name = nothing |
|
77 | 75 | end |
@@ -79,14 +77,14 @@
Loading
79 | 77 | get_signatures(f_binding, tls, sigs, server) |
|
80 | 78 | end |
|
81 | 79 | end |
|
82 | - | if (isempty(sigs) || (typof(x) === CSTParser.PUNCTUATION && kindof(x) === CSTParser.Tokens.RPAREN)) |
|
80 | + | if (isempty(sigs) || (headof(x) === :RPAREN)) |
|
83 | 81 | return SignatureHelp(SignatureInformation[], 0, 0) |
|
84 | 82 | end |
|
85 | 83 | ||
86 | - | if typof(x) === CSTParser.Tokens.LPAREN |
|
84 | + | if headof(x) === :LPAREN |
|
87 | 85 | arg = 0 |
|
88 | 86 | else |
|
89 | - | arg = sum(CSTParser.is_comma(a) for a in parentof(x).args) |
|
87 | + | arg = sum(headof(a) === :COMMA for a in parentof(x).trivia) |
|
90 | 88 | end |
|
91 | 89 | return SignatureHelp(filter(s -> length(s.parameters) > arg, sigs), 0, arg) |
|
92 | 90 | end |
@@ -108,6 +106,12 @@
Loading
108 | 106 | ||
109 | 107 | function get_definitions(x, tls, server, locations, visited=nothing) end # Fallback |
|
110 | 108 | ||
109 | + | function get_definitions(x::SymbolServer.ModuleStore, tls, server, locations, visited=nothing) |
|
110 | + | if haskey(x.vals, :eval) && x[:eval] isa SymbolServer.FunctionStore |
|
111 | + | get_definitions(x[:eval], tls, server, locations, visited) |
|
112 | + | end |
|
113 | + | end |
|
114 | + | ||
111 | 115 | function get_definitions(x::T, tls, server, locations, visited=nothing) where T <: Union{SymbolServer.FunctionStore,SymbolServer.DataTypeStore} |
|
112 | 116 | StaticLint.iterate_over_ss_methods(x, tls, server, function (m) |
|
113 | 117 | try |
@@ -152,11 +156,11 @@
Loading
152 | 156 | b = resolve_shadow_binding(b) |
|
153 | 157 | (tls = StaticLint.retrieve_toplevel_scope(x)) === nothing && return locations |
|
154 | 158 | get_definitions(b, tls, server, locations) |
|
155 | - | elseif x isa EXPR && typof(x) === CSTParser.LITERAL && (kindof(x) === Tokens.STRING || kindof(x) === Tokens.TRIPLE_STRING) |
|
159 | + | elseif x isa EXPR && CSTParser.isstringliteral(x) |
|
156 | 160 | # TODO: move to its own function |
|
157 | 161 | if sizeof(valof(x)) < 256 # AUDIT: OK |
|
158 | 162 | try |
|
159 | - | if isfile(valof(x)) |
|
163 | + | if isabspath(valof(x)) && isfile(valof(x)) |
|
160 | 164 | push!(locations, Location(filepath2uri(valof(x)), Range(0, 0, 0, 0))) |
|
161 | 165 | elseif !isempty(getpath(doc)) && isfile(joinpath(_dirname(getpath(doc)), valof(x))) |
|
162 | 166 | push!(locations, Location(filepath2uri(joinpath(_dirname(getpath(doc)), valof(x))), Range(0, 0, 0, 0))) |
@@ -175,14 +179,14 @@
Loading
175 | 179 | ||
176 | 180 | function get_file_loc(x::EXPR, offset=0, c=nothing) |
|
177 | 181 | if c !== nothing |
|
178 | - | for a in x.args |
|
182 | + | for a in x |
|
179 | 183 | a == c && break |
|
180 | 184 | offset += a.fullspan |
|
181 | 185 | end |
|
182 | 186 | end |
|
183 | 187 | if parentof(x) !== nothing |
|
184 | 188 | return get_file_loc(parentof(x), offset, x) |
|
185 | - | elseif typof(x) === CSTParser.FileH && StaticLint.hasmeta(x) |
|
189 | + | elseif headof(x) === :file && StaticLint.hasmeta(x) |
|
186 | 190 | return x.meta.error, offset |
|
187 | 191 | else |
|
188 | 192 | return nothing, offset |
@@ -215,7 +219,6 @@
Loading
215 | 219 | return locations |
|
216 | 220 | end |
|
217 | 221 | ||
218 | - | # If |
|
219 | 222 | function find_references(b::StaticLint.Binding, refs=EXPR[], from_end=false) |
|
220 | 223 | if !from_end && (b.type === StaticLint.CoreTypes.Function || b.type === StaticLint.CoreTypes.DataType) |
|
221 | 224 | b = StaticLint.last_method(b) |
@@ -253,17 +256,17 @@
Loading
253 | 256 | ||
254 | 257 | is_valid_binding_name(name) = false |
|
255 | 258 | function is_valid_binding_name(name::EXPR) |
|
256 | - | (typof(name) === CSTParser.IDENTIFIER && valof(name) isa String && !isempty(valof(name))) || |
|
257 | - | (typof(name) === CSTParser.OPERATOR) || |
|
258 | - | (typof(name) === CSTParser.NONSTDIDENTIFIER && length(name) == 2 && valof(name[2]) isa String && !isempty(valof(name[2]))) |
|
259 | + | (headof(name) === :IDENTIFIER && valof(name) isa String && !isempty(valof(name))) || |
|
260 | + | CSTParser.isoperator(name) || |
|
261 | + | (headof(name) === :NONSTDIDENTIFIER && length(name.args) == 2 && valof(name.args[2]) isa String && !isempty(valof(name.args[2]))) |
|
259 | 262 | end |
|
260 | 263 | function get_name_of_binding(name::EXPR) |
|
261 | - | if typof(name) === CSTParser.IDENTIFIER |
|
264 | + | if headof(name) === :IDENTIFIER |
|
262 | 265 | valof(name) |
|
263 | - | elseif typof(name) === CSTParser.OPERATOR |
|
266 | + | elseif CSTParser.isoperator(name) |
|
264 | 267 | string(Expr(name)) |
|
265 | - | elseif typof(name) === CSTParser.NONSTDIDENTIFIER |
|
266 | - | valof(name[2]) |
|
268 | + | elseif headof(name) === :NONSTDIDENTIFIER |
|
269 | + | valof(name.args[2]) |
|
267 | 270 | else |
|
268 | 271 | "" |
|
269 | 272 | end |
@@ -288,8 +291,8 @@
Loading
288 | 291 | if bindingof(x) !== nothing |
|
289 | 292 | push!(bindings, (pos .+ (0:x.span), bindingof(x))) |
|
290 | 293 | end |
|
291 | - | if x.args !== nothing |
|
292 | - | for a in x.args |
|
294 | + | if length(x) > 0 |
|
295 | + | for a in x |
|
293 | 296 | collect_bindings_w_loc(a, pos, bindings) |
|
294 | 297 | pos += a.fullspan |
|
295 | 298 | end |
@@ -301,11 +304,11 @@
Loading
301 | 304 | if bindingof(x) isa StaticLint.Binding && valof(bindingof(x).name) isa String && bindingof(x).val isa EXPR && startswith(valof(bindingof(x).name), query) |
|
302 | 305 | push!(bindings, (pos .+ (0:x.span), bindingof(x))) |
|
303 | 306 | end |
|
304 | - | if scopeof(x) !== nothing && !(typof(x) === CSTParser.FileH || typof(x) === CSTParser.ModuleH || typof(x) === CSTParser.BareModule) |
|
307 | + | if scopeof(x) !== nothing && !(headof(x) === :file || CSTParser.defines_module(x)) |
|
305 | 308 | return bindings |
|
306 | 309 | end |
|
307 | - | if x.args !== nothing |
|
308 | - | for a in x.args |
|
310 | + | if length(x) > 0 |
|
311 | + | for a in x |
|
309 | 312 | collect_toplevel_bindings_w_loc(a, pos, bindings, query=query) |
|
310 | 313 | pos += a.fullspan |
|
311 | 314 | end |
@@ -315,7 +318,7 @@
Loading
315 | 318 | ||
316 | 319 | function _binding_kind(b, server) |
|
317 | 320 | if b isa StaticLint.Binding |
|
318 | - | if b.type == nothing |
|
321 | + | if b.type === nothing |
|
319 | 322 | return 13 |
|
320 | 323 | elseif b.type == StaticLint.CoreTypes.Module |
|
321 | 324 | return 2 |
@@ -367,8 +370,8 @@
Loading
367 | 370 | end |
|
368 | 371 | ||
369 | 372 | function get_module_of(s::StaticLint.Scope, ms=[]) |
|
370 | - | if CSTParser.defines_module(s.expr) && CSTParser.isidentifier(s.expr[2]) |
|
371 | - | pushfirst!(ms, StaticLint.valofid(s.expr[2])) |
|
373 | + | if CSTParser.defines_module(s.expr) && CSTParser.isidentifier(s.expr.args[2]) |
|
374 | + | pushfirst!(ms, StaticLint.valofid(s.expr.args[2])) |
|
372 | 375 | end |
|
373 | 376 | if parentof(s) isa StaticLint.Scope |
|
374 | 377 | return get_module_of(parentof(s), ms) |
@@ -387,7 +390,7 @@
Loading
387 | 390 | end |
|
388 | 391 | ||
389 | 392 | x = get_expr1(getcst(doc), get_offset(doc, params.position)) |
|
390 | - | x isa EXPR && typof(x) === CSTParser.OPERATOR && resolve_op_ref(x, server) |
|
393 | + | x isa EXPR && CSTParser.isoperator(x) && resolve_op_ref(x, server) |
|
391 | 394 | documentation = get_hover(x, "", server) |
|
392 | 395 | ||
393 | 396 | return documentation |
@@ -34,7 +34,7 @@
Loading
34 | 34 | ||
35 | 35 | function find_using_statement(x::EXPR) |
|
36 | 36 | for ref in refof(x).refs |
|
37 | - | if parentof(ref) isa EXPR && typof(parentof(ref)) === CSTParser.Using |
|
37 | + | if StaticLint.is_in_fexpr(ref, x -> headof(x) === :using || headof(x) === :import) |
|
38 | 38 | return parentof(ref) |
|
39 | 39 | end |
|
40 | 40 | end |
@@ -50,9 +50,8 @@
Loading
50 | 50 | vars = Set{String}() # names that need to be imported |
|
51 | 51 | # Find uses of `x` and mark edits |
|
52 | 52 | for ref in refof(x).refs |
|
53 | - | if parentof(ref) isa EXPR && typof(parentof(ref)) == CSTParser.BinaryOpCall && length(parentof(ref).args) == 3 && kindof(parentof(ref).args[2]) === CSTParser.Tokens.DOT && parentof(ref).args[1] == ref |
|
54 | - | typof(parentof(ref).args[3]) !== CSTParser.Quotenode && continue # some malformed EXPR, skip |
|
55 | - | childname = parentof(ref).args[3].args[1] |
|
53 | + | if parentof(ref) isa EXPR && CSTParser.is_getfield_w_quotenode(parentof(ref)) && parentof(ref).args[1] == ref |
|
54 | + | childname = parentof(ref).args[2].args[1] |
|
56 | 55 | StaticLint.hasref(childname) && refof(childname) isa StaticLint.Binding && continue # check this isn't the name of something being explictly overwritten |
|
57 | 56 | !haskey(refof(x).val.vals, Symbol(valof(childname))) && continue # skip, perhaps mark as missing ref ? |
|
58 | 57 |
@@ -67,7 +66,7 @@
Loading
67 | 66 | isempty(tdes) && return |
|
68 | 67 | ||
69 | 68 | # Add `using x: vars...` statement |
|
70 | - | if parentof(using_stmt) isa EXPR && (typof(parentof(using_stmt)) === CSTParser.Block || typof(parentof(using_stmt)) === CSTParser.FileH) |
|
69 | + | if parentof(using_stmt) isa EXPR && (headof(parentof(using_stmt)) === :block || headof(parentof(using_stmt)) === :file) |
|
71 | 70 | # this should cover all cases |
|
72 | 71 | i1 = 0 |
|
73 | 72 | for i = 1:length(parentof(using_stmt).args) |
@@ -93,28 +92,28 @@
Loading
93 | 92 | JSONRPC.send(conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams(missing, WorkspaceEdit(missing, collect(values(tdes))))) |
|
94 | 93 | end |
|
95 | 94 | ||
96 | - | is_single_line_func(x) = CSTParser.defines_function(x) && typof(x) !== CSTParser.FunctionDef |
|
95 | + | is_single_line_func(x) = CSTParser.defines_function(x) && headof(x) !== :function |
|
97 | 96 | ||
98 | 97 | function expand_inline_func(x, server, conn) |
|
99 | 98 | func = _get_parent_fexpr(x, is_single_line_func) |
|
100 | 99 | length(func) < 3 && return |
|
101 | - | sig = func[1] |
|
102 | - | op = func[2] |
|
103 | - | body = func[3] |
|
104 | - | if typof(body) == CSTParser.Block && length(body) == 1 |
|
100 | + | sig = func.args[1] |
|
101 | + | op = func.head |
|
102 | + | body = func.args[2] |
|
103 | + | if headof(body) == :block && length(body) == 1 |
|
105 | 104 | file, offset = get_file_loc(func) |
|
106 | 105 | tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[ |
|
107 | 106 | TextEdit(Range(file, offset .+ (0:func.fullspan)), string("function ", get_text(file)[offset .+ (1:sig.span)], "\n ", get_text(file)[offset + sig.fullspan + op.fullspan .+ (1:body.span)], "\nend\n")) |
|
108 | 107 | ]) |
|
109 | 108 | JSONRPC.send(conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams(missing, WorkspaceEdit(missing, TextDocumentEdit[tde]))) |
|
110 | - | elseif (typof(body) === CSTParser.Begin || typof(body) === CSTParser.InvisBrackets) && length(body) == 3 && |
|
111 | - | typof(body[2]) === CSTParser.Block && length(body[2]) > 0 |
|
109 | + | elseif (headof(body) === :begin || CSTParser.isbracketed(body)) && |
|
110 | + | headof(body.args[1]) === :block && length(body.args[1]) > 0 |
|
112 | 111 | file, offset = get_file_loc(func) |
|
113 | 112 | newtext = string("function ", get_text(file)[offset .+ (1:sig.span)]) |
|
114 | - | blockoffset = offset + sig.fullspan + op.fullspan + body[1].fullspan |
|
115 | - | for i = 1:length(body[2]) |
|
116 | - | newtext = string(newtext, "\n ", get_text(file)[blockoffset .+ (1:body[2][i].span)]) |
|
117 | - | blockoffset += body[2][i].fullspan |
|
113 | + | blockoffset = offset + sig.fullspan + op.fullspan + body.trivia[1].fullspan |
|
114 | + | for i = 1:length(body.args[1].args) |
|
115 | + | newtext = string(newtext, "\n ", get_text(file)[blockoffset .+ (1:body.args[1].args[i].span)]) |
|
116 | + | blockoffset += body.args[1].args[i].fullspan |
|
118 | 117 | end |
|
119 | 118 | newtext = string(newtext, "\nend\n") |
|
120 | 119 | tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[TextEdit(Range(file, offset .+ (0:func.fullspan)), newtext)]) |
@@ -153,8 +152,8 @@
Loading
153 | 152 | end |
|
154 | 153 | ||
155 | 154 | function reexport_package(x::EXPR, server, conn) |
|
156 | - | (refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module)) || (refof(x).val isa SymbolServer.ModuleStore) || return |
|
157 | - | mod::SymbolServer.ModuleStore = refof(x).val |
|
155 | + | (refof(x) isa SymbolServer.ModuleStore || refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module)) || (refof(x).val isa SymbolServer.ModuleStore) || return |
|
156 | + | mod::SymbolServer.ModuleStore = refof(x) isa SymbolServer.ModuleStore ? refof(x) : refof(x).val |
|
158 | 157 | using_stmt = parentof(x) |
|
159 | 158 | file, offset = get_file_loc(x) |
|
160 | 159 | insertpos = get_next_line_offset(using_stmt) |
@@ -167,13 +166,13 @@
Loading
167 | 166 | JSONRPC.send(conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams(missing, WorkspaceEdit(missing, TextDocumentEdit[tde]))) |
|
168 | 167 | end |
|
169 | 168 | ||
170 | - | # TODO move to StaticLint |
|
169 | + | # TODO move to StaticL int |
|
171 | 170 | # to be called where typof(x) === CSTParser.ModuleH/BareModule |
|
172 | 171 | function find_exported_names(x::EXPR) |
|
173 | 172 | exported_vars = EXPR[] |
|
174 | 173 | for i in 1:length(x.args[3].args) |
|
175 | 174 | expr = x.args[3].args[i] |
|
176 | - | if typof(expr) == CSTParser.Export && |
|
175 | + | if headof(expr) === :export |
|
177 | 176 | for j = 2:length(expr) |
|
178 | 177 | if CSTParser.isidentifier(expr.args[j]) && StaticLint.hasref(expr.args[j]) |
|
179 | 178 | push!(exported_vars, expr.args[j]) |
@@ -187,7 +186,7 @@
Loading
187 | 186 | function reexport_module(x::EXPR, server, conn) |
|
188 | 187 | using_stmt = parentof(x) |
|
189 | 188 | mod_expr = refof(x).val isa StaticLint.Binding ? refof(x).val.val : refof(x).val |
|
190 | - | (mod_expr.args isa Nothing || length(mod_expr.args) < 3 || typof(mod_expr.args[3]) != CSTParser.Block || mod_expr.args[3].args isa Nothing) && return # module expr without block |
|
189 | + | (mod_expr.args isa Nothing || length(mod_expr.args) < 3 || headof(mod_expr.args[3]) !== :block || mod_expr.args[3].args isa Nothing) && return # module expr without block |
|
191 | 190 | # find export EXPR |
|
192 | 191 | exported_names = find_exported_names(mod_expr) |
|
193 | 192 |
@@ -266,6 +265,6 @@
Loading
266 | 265 | (x, params) -> is_fixable_missing_ref(x, params.context), |
|
267 | 266 | applymissingreffix), |
|
268 | 267 | "ReexportModule" => ServerAction(Command("Re-export package variables.", "ReexportModule", missing), |
|
269 | - | (x, params) -> parentof(x) isa EXPR && typof(parentof(x)) === CSTParser.Using && refof(x) isa StaticLint.Binding && (refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module) || refof(x).val isa SymbolServer.ModuleStore), |
|
268 | + | (x, params) -> StaticLint.is_in_fexpr(x, x -> headof(x) === :using || headof(x) === :import) && (refof(x) isa StaticLint.Binding && (refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module) || refof(x).val isa SymbolServer.ModuleStore) || refof(x) isa SymbolServer.ModuleStore), |
|
270 | 269 | reexport_package) |
|
271 | 270 | ) |
@@ -19,9 +19,12 @@
Loading
19 | 19 | elseif t isa CSTParser.Tokens.Token && t.kind == CSTParser.Tokenize.Tokens.COMMENT |
|
20 | 20 | partial = is_latex_comp(t.val, offset - t.startbyte) |
|
21 | 21 | !isempty(partial) && latex_completions(doc, offset, partial, CIs) |
|
22 | - | elseif t isa CSTParser.Tokens.Token && (t.kind == CSTParser.Tokenize.Tokens.STRING || t.kind == CSTParser.Tokenize.Tokens.TRIPLE_STRING) |
|
22 | + | elseif t isa CSTParser.Tokens.Token && (t.kind in (CSTParser.Tokenize.Tokens.STRING, |
|
23 | + | CSTParser.Tokenize.Tokens.TRIPLE_STRING, |
|
24 | + | CSTParser.Tokenize.Tokens.CMD, |
|
25 | + | CSTParser.Tokenize.Tokens.TRIPLE_CMD)) |
|
23 | 26 | string_completion(doc, offset, rng, t, CIs) |
|
24 | - | elseif x isa EXPR && parentof(x) !== nothing && (typof(parentof(x)) === CSTParser.Using || typof(parentof(x)) === CSTParser.Import) |
|
27 | + | elseif x isa EXPR && is_in_import_statement(x) |
|
25 | 28 | import_completions(doc, offset, rng, ppt, pt, t, is_at_end, x, CIs, server) |
|
26 | 29 | elseif t isa CSTParser.Tokens.Token && t.kind == CSTParser.Tokens.DOT && pt isa CSTParser.Tokens.Token && pt.kind == CSTParser.Tokens.IDENTIFIER |
|
27 | 30 | # getfield completion, no partial |
@@ -143,7 +146,7 @@
Loading
143 | 146 | end |
|
144 | 147 | end |
|
145 | 148 | end |
|
146 | - | if parentof(x) !== nothing && typof(x) !== CSTParser.ModuleH && typof(x) !== CSTParser.BareModule |
|
149 | + | if parentof(x) !== nothing && !CSTParser.defines_module(x) |
|
147 | 150 | return collect_completions(parentof(x), spartial, rng, CIs, server, inclexported, dotcomps) |
|
148 | 151 | else |
|
149 | 152 | return |
@@ -168,9 +171,9 @@
Loading
168 | 171 | ||
169 | 172 | function is_rebinding_of_module(x) |
|
170 | 173 | x isa EXPR && refof(x).type === StaticLint.CoreTypes.Module && # binding is a Module |
|
171 | - | refof(x).val isa EXPR && typof(refof(x).val) === CSTParser.BinaryOpCall && kindof(refof(x).val.args[2]) === CSTParser.Tokens.EQ && # binding expr is an assignment |
|
172 | - | StaticLint.hasref(refof(x).val.args[3]) && refof(refof(x).val.args[3]).type === StaticLint.CoreTypes.Module && |
|
173 | - | refof(refof(x).val.args[3]).val isa EXPR && typof(refof(refof(x).val.args[3]).val) === CSTParser.ModuleH# double check the rhs points to a module |
|
174 | + | refof(x).val isa EXPR && CSTParser.isassignment(refof(x).val) && # binding expr is an assignment |
|
175 | + | StaticLint.hasref(refof(x).val.args[2]) && refof(refof(x).val.args[2]).type === StaticLint.CoreTypes.Module && |
|
176 | + | refof(refof(x).val.args[2]).val isa EXPR && CSTParser.defines_module(refof(refof(x).val.args[2]).val)# double check the rhs points to a module |
|
174 | 177 | end |
|
175 | 178 | ||
176 | 179 | function _get_dot_completion(px, spartial, rng, CIs, server) end |
@@ -179,10 +182,10 @@
Loading
179 | 182 | if refof(px) isa StaticLint.Binding |
|
180 | 183 | if refof(px).val isa StaticLint.SymbolServer.ModuleStore |
|
181 | 184 | collect_completions(refof(px).val, spartial, rng, CIs, server, true) |
|
182 | - | elseif refof(px).val isa EXPR && typof(refof(px).val) === CSTParser.ModuleH && scopeof(refof(px).val) isa StaticLint.Scope |
|
185 | + | elseif refof(px).val isa EXPR && CSTParser.defines_module(refof(px).val) && scopeof(refof(px).val) isa StaticLint.Scope |
|
183 | 186 | collect_completions(scopeof(refof(px).val), spartial, rng, CIs, server, true) |
|
184 | 187 | elseif is_rebinding_of_module(px) |
|
185 | - | collect_completions(scopeof(refof(refof(px).val.args[3]).val), spartial, rng, CIs, server, true) |
|
188 | + | collect_completions(scopeof(refof(refof(px).val.args[2]).val), spartial, rng, CIs, server, true) |
|
186 | 189 | elseif refof(px).type isa SymbolServer.DataTypeStore |
|
187 | 190 | for a in refof(px).type.fieldnames |
|
188 | 191 | a = String(a) |
@@ -235,10 +238,8 @@
Loading
235 | 238 | end |
|
236 | 239 | ||
237 | 240 | function get_import_root(x::EXPR) |
|
238 | - | for i = 1:length(x.args) |
|
239 | - | if typof(x.args[i]) === CSTParser.OPERATOR && kindof(x.args[i]) === CSTParser.Tokens.COLON && i > 2 |
|
240 | - | return x.args[i - 1] |
|
241 | - | end |
|
241 | + | if CSTParser.isoperator(headof(x.args[1])) && valof(headof(x.args[1])) == ":" |
|
242 | + | return last(x.args[1].args[1].args) |
|
242 | 243 | end |
|
243 | 244 | return nothing |
|
244 | 245 | end |
@@ -246,7 +247,7 @@
Loading
246 | 247 | function string_completion(doc, offset, rng, t, CIs) |
|
247 | 248 | path_completion(doc, offset, rng, t, CIs) |
|
248 | 249 | # Need to adjust things for quotation marks |
|
249 | - | if t.kind == CSTParser.Tokenize.Tokens.STRING |
|
250 | + | if t.kind in (CSTParser.Tokenize.Tokens.STRING,CSTParser.Tokenize.Tokens.CMD) |
|
250 | 251 | t.startbyte < offset <= t.endbyte || return |
|
251 | 252 | relative_offset = offset - t.startbyte - 1 |
|
252 | 253 | content = t.val[2:prevind(t.val, lastindex(t.val))] |
@@ -321,9 +322,13 @@
Loading
321 | 322 | end |
|
322 | 323 | end |
|
323 | 324 | ||
325 | + | is_in_import_statement(x::EXPR) = is_in_fexpr(x, x -> headof(x) in (:using, :import)) |
|
326 | + | ||
324 | 327 | function import_completions(doc, offset, rng, ppt, pt, t, is_at_end, x, CIs, server) |
|
325 | - | import_statement = parentof(x) |
|
328 | + | import_statement = StaticLint.get_parent_fexpr(x, x -> headof(x) === :using || headof(x) === :import) |
|
329 | + | ||
326 | 330 | import_root = get_import_root(import_statement) |
|
331 | + | ||
327 | 332 | if (t.kind == CSTParser.Tokens.WHITESPACE && pt.kind ∈ (CSTParser.Tokens.USING, CSTParser.Tokens.IMPORT, CSTParser.Tokens.IMPORTALL, CSTParser.Tokens.COMMA, CSTParser.Tokens.COLON)) || |
|
328 | 333 | (t.kind in (CSTParser.Tokens.COMMA, CSTParser.Tokens.COLON)) |
|
329 | 334 | # no partial, no dot |
Files | Coverage |
---|---|
src | 67.98% |
Project Totals (29 files) | 67.98% |
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file.
The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files.
The size and color of each slice is representing the number of statements and the coverage, respectively.