last working in middle of refactor
This commit is contained in:
parent
d3f6d95c09
commit
68bad4eaba
@ -61,9 +61,6 @@ are declared / referenced in which places."
|
|||||||
{:start position :end position}))
|
{:start position :end position}))
|
||||||
|
|
||||||
|
|
||||||
(λ is-values? [?ast]
|
|
||||||
(and (list? ?ast) (= (sym :values) (. ?ast 1))))
|
|
||||||
|
|
||||||
(λ compile [{:configuration {: macro-path} : root-uri &as self} file]
|
(λ compile [{:configuration {: macro-path} : root-uri &as self} file]
|
||||||
"Compile the file, and record all the useful information from the compiler into the file object"
|
"Compile the file, and record all the useful information from the compiler into the file object"
|
||||||
;; The useful information being recorded:
|
;; The useful information being recorded:
|
||||||
@ -144,7 +141,8 @@ are declared / referenced in which places."
|
|||||||
(fcollect [i 1 (length keys)]
|
(fcollect [i 1 (length keys)]
|
||||||
(. keys i)))
|
(. keys i)))
|
||||||
:multival ?multival
|
:multival ?multival
|
||||||
:var? (?. ?opts :isvar)}]
|
:var? (?. ?opts :isvar)
|
||||||
|
: file}]
|
||||||
(tset (. definitions-by-scope scope) (tostring symbol) definition)
|
(tset (. definitions-by-scope scope) (tostring symbol) definition)
|
||||||
(tset definitions symbol definition)))))
|
(tset definitions symbol definition)))))
|
||||||
|
|
||||||
@ -173,7 +171,8 @@ are declared / referenced in which places."
|
|||||||
(set target.fields (or target.fields {}))
|
(set target.fields (or target.fields {}))
|
||||||
(tset target.fields field
|
(tset target.fields field
|
||||||
{:binding multisym
|
{:binding multisym
|
||||||
:definition ast}))))
|
:definition ast
|
||||||
|
:file file}))))
|
||||||
;; ;; referenced-by inherits from all other symbols
|
;; ;; referenced-by inherits from all other symbols
|
||||||
;; :referenced-by (or (?. definitions multisym :referenced-by) [])}))))
|
;; :referenced-by (or (?. definitions multisym :referenced-by) [])}))))
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ Every time the client sends a message, it gets handled by a function in the corr
|
|||||||
(local capabilities
|
(local capabilities
|
||||||
{:textDocumentSync {:openClose true :change 2}
|
{:textDocumentSync {:openClose true :change 2}
|
||||||
;; :notebookDocumentSync nil
|
;; :notebookDocumentSync nil
|
||||||
:completionProvider {:workDoneProgress false} ;; TODO
|
:completionProvider {:workDoneProgress false}
|
||||||
:hoverProvider {:workDoneProgress false
|
:hoverProvider {:workDoneProgress false
|
||||||
:resolveProvider false
|
:resolveProvider false
|
||||||
:triggerCharacters ["(" "[" "{" "." ":" "\""]
|
:triggerCharacters ["(" "[" "{" "." ":" "\""]
|
||||||
@ -79,8 +79,8 @@ Every time the client sends a message, it gets handled by a function in the corr
|
|||||||
(language.search-ast self file parent [] {:stop-early? true})
|
(language.search-ast self file parent [] {:stop-early? true})
|
||||||
;; regular symbol
|
;; regular symbol
|
||||||
(language.search-main self file symbol {:stop-early? true} byte))
|
(language.search-main self file symbol {:stop-early? true} byte))
|
||||||
(result result-file)
|
result
|
||||||
(message.range-and-uri self result-file (or result.binding result.definition))
|
(message.range-and-uri self result.file (or result.binding result.definition))
|
||||||
(catch _ nil))))
|
(catch _ nil))))
|
||||||
|
|
||||||
(λ requests.textDocument/references [self send {: position
|
(λ requests.textDocument/references [self send {: position
|
||||||
@ -91,12 +91,12 @@ Every time the client sends a message, it gets handled by a function in the corr
|
|||||||
(case-try (language.find-symbol file.ast byte)
|
(case-try (language.find-symbol file.ast byte)
|
||||||
symbol
|
symbol
|
||||||
(language.find-nearest-definition self file symbol byte)
|
(language.find-nearest-definition self file symbol byte)
|
||||||
(where (definition def-file) (not= definition.referenced-by nil))
|
(where definition (not= definition.referenced-by nil))
|
||||||
(let [result (icollect [_ {: symbol} (ipairs definition.referenced-by)]
|
(let [result (icollect [_ {: symbol} (ipairs definition.referenced-by)]
|
||||||
(message.range-and-uri self def-file symbol))]
|
(message.range-and-uri self definition.file symbol))]
|
||||||
(if ?include-declaration?
|
(if ?include-declaration?
|
||||||
(table.insert result
|
(table.insert result
|
||||||
(message.range-and-uri self def-file definition.binding)))
|
(message.range-and-uri self definition.file definition.binding)))
|
||||||
|
|
||||||
;; TODO don't include duplicates
|
;; TODO don't include duplicates
|
||||||
result)
|
result)
|
||||||
@ -157,7 +157,7 @@ Every time the client sends a message, it gets handled by a function in the corr
|
|||||||
(let [stack (fcollect [i (- (length split) 1) 2 -1]
|
(let [stack (fcollect [i (- (length split) 1) 2 -1]
|
||||||
(. split i))]
|
(. split i))]
|
||||||
(case (language.search-assignment self file ref stack {})
|
(case (language.search-assignment self file ref stack {})
|
||||||
({: definition} file)
|
{: definition : file}
|
||||||
(case (values definition (type definition))
|
(case (values definition (type definition))
|
||||||
;; fields of a string are hardcoded to "string"
|
;; fields of a string are hardcoded to "string"
|
||||||
(_str :string) (icollect [label _ (pairs string)]
|
(_str :string) (icollect [label _ (pairs string)]
|
||||||
@ -203,20 +203,20 @@ Every time the client sends a message, it gets handled by a function in the corr
|
|||||||
symbol
|
symbol
|
||||||
(language.find-nearest-definition self file symbol symbol.bytestart)
|
(language.find-nearest-definition self file symbol symbol.bytestart)
|
||||||
;; TODO we are assuming that every reference is in the same file
|
;; TODO we are assuming that every reference is in the same file
|
||||||
(where (definition def-file) (not= definition.referenced-by nil))
|
(where definition (not= definition.referenced-by nil))
|
||||||
(let [usages (icollect [_ {: symbol} (ipairs definition.referenced-by)
|
(let [usages (icollect [_ {: symbol} (ipairs definition.referenced-by)
|
||||||
&into [{:range (message.multisym->range self def-file definition.binding 1)
|
&into [{:range (message.multisym->range self definition.file definition.binding 1)
|
||||||
:newText new-name}]]
|
:newText new-name}]]
|
||||||
(if (and (. file.lexical symbol)
|
(if (and (. file.lexical symbol)
|
||||||
(not (rawequal symbol definition.binding)))
|
(not (rawequal symbol definition.binding)))
|
||||||
{:newText new-name
|
{:newText new-name
|
||||||
:range (message.multisym->range self def-file symbol 1)}))]
|
:range (message.multisym->range self definition.file symbol 1)}))]
|
||||||
|
|
||||||
;; NOTE: I don't care about encoding here because we just need the relative positions
|
;; NOTE: I don't care about encoding here because we just need the relative positions
|
||||||
(table.sort usages
|
(table.sort usages
|
||||||
#(> (utils.position->byte def-file.text $1.range.start :utf-8)
|
#(> (utils.position->byte definition.file.text $1.range.start :utf-8)
|
||||||
(utils.position->byte def-file.text $2.range.start :utf-8)))
|
(utils.position->byte definition.file.text $2.range.start :utf-8)))
|
||||||
{:changes {def-file.uri usages}})
|
{:changes {definition.file.uri usages}})
|
||||||
(catch _ nil))))
|
(catch _ nil))))
|
||||||
|
|
||||||
(λ notifications.textDocument/didChange [self send {: contentChanges :textDocument {: uri}}]
|
(λ notifications.textDocument/didChange [self send {: contentChanges :textDocument {: uri}}]
|
||||||
|
|||||||
@ -18,22 +18,13 @@ definitions backward.
|
|||||||
As of now, there's no caching, but that could be a way to improve performance.
|
As of now, there's no caching, but that could be a way to improve performance.
|
||||||
"
|
"
|
||||||
|
|
||||||
(local {: sym? : list? : sequence? : varg? : sym : view} (require :fennel))
|
(local {: sym? : list? : sequence? : varg? : sym} (require :fennel))
|
||||||
(local utils (require :fennel-ls.utils))
|
(local utils (require :fennel-ls.utils))
|
||||||
(local state (require :fennel-ls.state))
|
(local state (require :fennel-ls.state))
|
||||||
|
|
||||||
(local get-ast-info utils.get-ast-info)
|
(local get-ast-info utils.get-ast-info)
|
||||||
|
|
||||||
(local -require- (sym :require))
|
(var search-multival nil) ;; all of the search functions are mutually recursive
|
||||||
(local -dot- (sym :.))
|
|
||||||
(local -do- (sym :do))
|
|
||||||
(local -let- (sym :let))
|
|
||||||
(local -fn- (sym :fn))
|
|
||||||
(local -nil- (sym :nil))
|
|
||||||
(local -values- (sym :nil))
|
|
||||||
(local -setmetatable- (sym :setmetatable))
|
|
||||||
|
|
||||||
(var search-ast nil) ;; all of the search functions are mutually recursive
|
|
||||||
|
|
||||||
(λ stack-add-keys! [stack ?keys]
|
(λ stack-add-keys! [stack ?keys]
|
||||||
"add the keys to the end of the stack in reverse order"
|
"add the keys to the end of the stack in reverse order"
|
||||||
@ -51,38 +42,9 @@ As of now, there's no caching, but that could be a way to improve performance.
|
|||||||
(λ stack-add-multisym! [stack symbol]
|
(λ stack-add-multisym! [stack symbol]
|
||||||
(stack-add-split! stack (utils.multi-sym-split symbol)))
|
(stack-add-split! stack (utils.multi-sym-split symbol)))
|
||||||
|
|
||||||
(λ search-multival [self file ast stack ?multival opts]
|
(λ search-val [self file ast stack opts]
|
||||||
(let [multival (or ?multival 1)]
|
"searches for the definition of the ast, adjusted to 1 value"
|
||||||
(if
|
(search-multival self file ast stack 1 opts))
|
||||||
;; we're looking at a (values), just solve it now
|
|
||||||
(list? ast)
|
|
||||||
(let [call (. ast 1)]
|
|
||||||
(if
|
|
||||||
(sym? call :do)
|
|
||||||
(search-multival self file (. ast (length ast)) stack multival opts)
|
|
||||||
(sym? call :values)
|
|
||||||
;; (values x y z)
|
|
||||||
;; len 3
|
|
||||||
;; multival 2
|
|
||||||
(let [len (- (length ast) 1)]
|
|
||||||
(if (< multival len)
|
|
||||||
(search-multival self file (. ast (+ 1 multival)) stack nil opts)
|
|
||||||
(search-multival self file (. ast (+ len 1)) stack (+ multival (- len) 1) opts)))
|
|
||||||
;; we're looking for value number 1 anyway
|
|
||||||
(= 1 multival)
|
|
||||||
(search-ast self file ast stack opts) ;; this goes to search-list but indirectly
|
|
||||||
|
|
||||||
(values nil file))) ;; GIVING UP !!
|
|
||||||
|
|
||||||
;; we're looking for value number 1 anyway
|
|
||||||
(= 1 multival)
|
|
||||||
(search-ast self file ast stack opts)
|
|
||||||
|
|
||||||
;; other cases
|
|
||||||
(sym? ast) (values nil file) ;; BASE CASE !!
|
|
||||||
;; (varg? ast) something
|
|
||||||
(= :table (type ast)) (values nil file) ;; BASE CASE !!
|
|
||||||
(values nil file)))) ;; supposed to be unreachable !!
|
|
||||||
|
|
||||||
(λ search-assignment [self file assignment stack opts]
|
(λ search-assignment [self file assignment stack opts]
|
||||||
(let [{:target {:binding _
|
(let [{:target {:binding _
|
||||||
@ -91,69 +53,71 @@ As of now, there's no caching, but that could be a way to improve performance.
|
|||||||
:multival ?multival
|
:multival ?multival
|
||||||
:fields ?fields}} assignment]
|
:fields ?fields}} assignment]
|
||||||
(if (and (= 0 (length stack)) opts.stop-early?)
|
(if (and (= 0 (length stack)) opts.stop-early?)
|
||||||
(values assignment.target file) ;; BASE CASE!!
|
assignment.target ;; BASE CASE!!
|
||||||
;; search a virtual field from :fields
|
;; search a virtual field from :fields
|
||||||
(and (not= 0 (length stack)) (?. ?fields (. stack (length stack))))
|
(and (not= 0 (length stack)) (?. ?fields (. stack (length stack))))
|
||||||
(search-assignment self file {:target (. ?fields (table.remove stack))} stack opts)
|
(search-assignment self file {:target (. ?fields (table.remove stack))} stack opts)
|
||||||
(search-multival self file ?definition (stack-add-keys! stack ?keys) ?multival opts))))
|
(search-multival self file ?definition (stack-add-keys! stack ?keys) (or ?multival 1) opts))))
|
||||||
|
|
||||||
(λ search-symbol [self file symbol stack opts]
|
(λ search-symbol [self file symbol stack opts]
|
||||||
(if (= symbol -nil-)
|
(if (= (tostring symbol) :nil)
|
||||||
(values {:definition symbol} file) ;; BASE CASE !!
|
{:definition symbol : file}
|
||||||
|
;; TODO globals
|
||||||
(case (. file.references symbol)
|
(case (. file.references symbol)
|
||||||
to (search-assignment self file to (stack-add-multisym! stack symbol) opts))))
|
to (search-assignment self file to (stack-add-multisym! stack symbol) opts))))
|
||||||
|
|
||||||
(λ search-table [self file tbl stack opts]
|
(λ search-table [self file tbl stack opts]
|
||||||
(if (. tbl (. stack (length stack)))
|
(if (. tbl (. stack (length stack)))
|
||||||
(search-ast self file (. tbl (table.remove stack)) stack opts)
|
(search-val self file (. tbl (table.remove stack)) stack opts)
|
||||||
(= 0 (length stack))
|
(= 0 (length stack))
|
||||||
(values {:definition tbl} file) ;; BASE CASE !!
|
{:definition tbl : file} ;; BASE CASE !!
|
||||||
nil)) ;; BASE CASE Give up
|
nil)) ;; BASE CASE Give up
|
||||||
|
|
||||||
(λ search-list [self file call stack opts]
|
(λ search-list [self file call stack multival opts]
|
||||||
(match call
|
(let [head (. call 1)]
|
||||||
[-require- mod]
|
(if (sym? head)
|
||||||
(when (= :string (type mod))
|
(case (tostring head)
|
||||||
(let [newfile (state.get-by-module self mod)]
|
(where (or :do :let))
|
||||||
(when newfile
|
(search-multival self file (. call (length call)) stack multival opts)
|
||||||
(let [newitem (. newfile.ast (length newfile.ast))]
|
:values
|
||||||
(search-ast self newfile newitem stack (doto opts (tset :searched-through-require true)))))))
|
(let [len (- (length call) 1)]
|
||||||
|
(if (< multival len)
|
||||||
|
(search-val self file (. call (+ 1 multival)) stack opts)
|
||||||
|
(search-multival self file (. call (+ len 1)) stack (+ multival (- len) 1) opts)))
|
||||||
|
:require
|
||||||
|
(let [mod (. call 2)]
|
||||||
|
(if (= multival 1)
|
||||||
|
(when (= :string (type mod))
|
||||||
|
(let [newfile (state.get-by-module self mod)]
|
||||||
|
(when newfile
|
||||||
|
(let [newitem (. newfile.ast (length newfile.ast))]
|
||||||
|
(search-val self newfile newitem stack (doto opts (tset :searched-through-require true)))))))))
|
||||||
|
"."
|
||||||
|
(if (= multival 1)
|
||||||
|
(let [[_ & rest] call]
|
||||||
|
(search-val self file (. call 2) (stack-add-split! stack rest) opts)))
|
||||||
|
;; TODO assume-function-name analyze-metatable
|
||||||
|
:setmetatable
|
||||||
|
(search-val self file (. call 2) stack opts)
|
||||||
|
|
||||||
;; A . form indexes into item 1 with the other items
|
(where (or :fn :lambda :λ))
|
||||||
(where [-dot- & split] (. split 1))
|
(if (= multival 1)
|
||||||
(search-ast self file (. split 1) (stack-add-split! stack split) opts)
|
{:definition call : file}) ;; BASE CASE !!
|
||||||
|
;; TODO expand-macros
|
||||||
|
|
||||||
;; A do block returns the last form
|
_
|
||||||
(where [-do- & body] (. body 1))
|
(if (and (= multival 1) (= 0 (length stack)))
|
||||||
(search-ast self file (. body (length body)) stack opts)
|
{:definition call : file}))))) ;; BASE CASE!!
|
||||||
|
|
||||||
(where [-let- _binding & body] (. body 1))
|
(set search-multival
|
||||||
(search-ast self file (. body (length body)) stack opts)
|
(λ [self file ast stack multival opts]
|
||||||
|
(if (list? ast) (search-list self file ast stack multival opts)
|
||||||
(where [-values- first])
|
(varg? ast) nil ;; TODO function-args
|
||||||
(search-ast self file first stack opts)
|
(= 1 multival)
|
||||||
|
(if (sym? ast) (search-symbol self file ast stack opts)
|
||||||
;; TODO care about the setmetatable call
|
(= :table (type ast)) (search-table self file ast stack opts)
|
||||||
(where [-setmetatable- tbl _mt])
|
(= 0 (length stack)) {:definition ast : file}) ;; BASE CASE !!
|
||||||
(search-ast self file tbl stack opts)
|
nil)))
|
||||||
|
|
||||||
;; fn marks a function literal
|
|
||||||
(where [fn*] (or (sym? fn* :fn) (sym? fn* :lambda) (sym? fn* :λ)))
|
|
||||||
(values {:definition call} file) ;; BASE CASE !!
|
|
||||||
|
|
||||||
;; if we don't know, give up
|
|
||||||
_
|
|
||||||
(if (= 0 (length stack))
|
|
||||||
(values {:definition call} file)))) ;; BASE CASE!!
|
|
||||||
|
|
||||||
(set search-ast
|
|
||||||
(λ [self file item stack opts]
|
|
||||||
(if
|
|
||||||
(sym? item) (search-symbol self file item stack opts)
|
|
||||||
(list? item) (search-list self file item stack opts)
|
|
||||||
(= :table (type item)) (search-table self file item stack opts)
|
|
||||||
(= 0 (length stack)) (values {:definition item} file)))) ;; BASE CASE !!
|
|
||||||
;; (error (.. "I don't know what to do with " (view item))))))
|
|
||||||
|
|
||||||
(local {:metadata METADATA
|
(local {:metadata METADATA
|
||||||
:scopes {:global {:specials SPECIALS
|
:scopes {:global {:specials SPECIALS
|
||||||
@ -181,12 +145,11 @@ If stop-early?, search-main will find the definition of `b` in (local b a).
|
|||||||
Otherwise, it would continue and find the value 1.
|
Otherwise, it would continue and find the value 1.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(values
|
|
||||||
{:binding <where the symbol is bound. this would be the name of the function or variable>
|
{:binding <where the symbol is bound. this would be the name of the function or variable>
|
||||||
:definition <the best known definition>
|
:definition <the best known definition>
|
||||||
:keys <which part of the definition to look into. this can only possibly be present if stop-early?>
|
:keys <which part of the definition to look into. this can only possibly be present if stop-early?>
|
||||||
:fields <other known fields which aren't part of the definition>}
|
:fields <other known fields which aren't lexically part of the definition>
|
||||||
file)
|
: file}
|
||||||
"
|
"
|
||||||
|
|
||||||
;; The stack is the multi-sym parts still to search
|
;; The stack is the multi-sym parts still to search
|
||||||
@ -200,7 +163,7 @@ Returns:
|
|||||||
_ (case (. file.references symbol)
|
_ (case (. file.references symbol)
|
||||||
ref (search-assignment self file ref stack opts)
|
ref (search-assignment self file ref stack opts)
|
||||||
_ (case (. file.definitions symbol)
|
_ (case (. file.definitions symbol)
|
||||||
def (search-multival self file def.definition (stack-add-keys! stack def.keys) def.multival opts)))))))
|
def (search-multival self file def.definition (stack-add-keys! stack def.keys) (or def.multival 1) opts)))))))
|
||||||
|
|
||||||
(λ find-local-definition [file name ?scope]
|
(λ find-local-definition [file name ?scope]
|
||||||
(when ?scope
|
(when ?scope
|
||||||
@ -221,7 +184,7 @@ Returns:
|
|||||||
_ (case (global-info self name)
|
_ (case (global-info self name)
|
||||||
global-item global-item
|
global-item global-item
|
||||||
_ (case (find-local-definition file name scope)
|
_ (case (find-local-definition file name scope)
|
||||||
def (search-ast self file def.definition (stack-add-keys! stack def.keys) (or ?opts {})))))))
|
def (search-val self file def.definition (stack-add-keys! stack def.keys) (or ?opts {})))))))
|
||||||
|
|
||||||
(λ _past? [?ast byte]
|
(λ _past? [?ast byte]
|
||||||
;; check if a byte is past an ast object
|
;; check if a byte is past an ast object
|
||||||
@ -281,7 +244,7 @@ Returns:
|
|||||||
|
|
||||||
(λ find-nearest-definition [self file symbol ?byte]
|
(λ find-nearest-definition [self file symbol ?byte]
|
||||||
(if (. file.definitions symbol)
|
(if (. file.definitions symbol)
|
||||||
(values (. file.definitions symbol) file)
|
(. file.definitions symbol)
|
||||||
(search-main self file symbol {:stop-early? true} ?byte)))
|
(search-main self file symbol {:stop-early? true} ?byte)))
|
||||||
|
|
||||||
{: find-symbol
|
{: find-symbol
|
||||||
@ -289,4 +252,4 @@ Returns:
|
|||||||
: search-main
|
: search-main
|
||||||
: search-assignment
|
: search-assignment
|
||||||
: search-name-and-scope
|
: search-name-and-scope
|
||||||
: search-ast}
|
:search-ast search-val}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user