last working in middle of refactor

This commit is contained in:
XeroOl 2024-02-12 15:52:22 -06:00
parent d3f6d95c09
commit 68bad4eaba
3 changed files with 77 additions and 115 deletions

View File

@ -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) [])}))))

View File

@ -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}}]

View File

@ -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}