From 68bad4eaba292223999dece20912b03f02b4dd4e Mon Sep 17 00:00:00 2001 From: XeroOl Date: Mon, 12 Feb 2024 15:52:22 -0600 Subject: [PATCH] last working in middle of refactor --- src/fennel-ls/compiler.fnl | 9 +-- src/fennel-ls/handlers.fnl | 26 +++--- src/fennel-ls/language.fnl | 157 ++++++++++++++----------------------- 3 files changed, 77 insertions(+), 115 deletions(-) diff --git a/src/fennel-ls/compiler.fnl b/src/fennel-ls/compiler.fnl index 0bf2550..1a9c92a 100644 --- a/src/fennel-ls/compiler.fnl +++ b/src/fennel-ls/compiler.fnl @@ -61,9 +61,6 @@ are declared / referenced in which places." {:start position :end position})) -(λ is-values? [?ast] - (and (list? ?ast) (= (sym :values) (. ?ast 1)))) - (λ 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" ;; The useful information being recorded: @@ -144,7 +141,8 @@ are declared / referenced in which places." (fcollect [i 1 (length keys)] (. keys i))) :multival ?multival - :var? (?. ?opts :isvar)}] + :var? (?. ?opts :isvar) + : file}] (tset (. definitions-by-scope scope) (tostring symbol) definition) (tset definitions symbol definition))))) @@ -173,7 +171,8 @@ are declared / referenced in which places." (set target.fields (or target.fields {})) (tset target.fields field {:binding multisym - :definition ast})))) + :definition ast + :file file})))) ;; ;; referenced-by inherits from all other symbols ;; :referenced-by (or (?. definitions multisym :referenced-by) [])})))) diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index fe2ce49..af5b7c3 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -20,7 +20,7 @@ Every time the client sends a message, it gets handled by a function in the corr (local capabilities {:textDocumentSync {:openClose true :change 2} ;; :notebookDocumentSync nil - :completionProvider {:workDoneProgress false} ;; TODO + :completionProvider {:workDoneProgress false} :hoverProvider {:workDoneProgress false :resolveProvider false :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}) ;; regular symbol (language.search-main self file symbol {:stop-early? true} byte)) - (result result-file) - (message.range-and-uri self result-file (or result.binding result.definition)) + result + (message.range-and-uri self result.file (or result.binding result.definition)) (catch _ nil)))) (λ 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) symbol (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)] - (message.range-and-uri self def-file symbol))] + (message.range-and-uri self definition.file symbol))] (if ?include-declaration? (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 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] (. split i))] (case (language.search-assignment self file ref stack {}) - ({: definition} file) + {: definition : file} (case (values definition (type definition)) ;; fields of a string are hardcoded to "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 (language.find-nearest-definition self file symbol symbol.bytestart) ;; 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) - &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}]] (if (and (. file.lexical symbol) (not (rawequal symbol definition.binding))) {: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 (table.sort usages - #(> (utils.position->byte def-file.text $1.range.start :utf-8) - (utils.position->byte def-file.text $2.range.start :utf-8))) - {:changes {def-file.uri usages}}) + #(> (utils.position->byte definition.file.text $1.range.start :utf-8) + (utils.position->byte definition.file.text $2.range.start :utf-8))) + {:changes {definition.file.uri usages}}) (catch _ nil)))) (λ notifications.textDocument/didChange [self send {: contentChanges :textDocument {: uri}}] diff --git a/src/fennel-ls/language.fnl b/src/fennel-ls/language.fnl index f5218af..10eadc2 100644 --- a/src/fennel-ls/language.fnl +++ b/src/fennel-ls/language.fnl @@ -18,22 +18,13 @@ definitions backward. 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 state (require :fennel-ls.state)) (local get-ast-info utils.get-ast-info) -(local -require- (sym :require)) -(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 +(var search-multival nil) ;; all of the search functions are mutually recursive (λ stack-add-keys! [stack ?keys] "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-split! stack (utils.multi-sym-split symbol))) -(λ search-multival [self file ast stack ?multival opts] - (let [multival (or ?multival 1)] - (if - ;; 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-val [self file ast stack opts] + "searches for the definition of the ast, adjusted to 1 value" + (search-multival self file ast stack 1 opts)) (λ search-assignment [self file assignment stack opts] (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 :fields ?fields}} assignment] (if (and (= 0 (length stack)) opts.stop-early?) - (values assignment.target file) ;; BASE CASE!! + assignment.target ;; BASE CASE!! ;; search a virtual field from :fields (and (not= 0 (length stack)) (?. ?fields (. stack (length stack)))) (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] - (if (= symbol -nil-) - (values {:definition symbol} file) ;; BASE CASE !! + (if (= (tostring symbol) :nil) + {:definition symbol : file} + ;; TODO globals (case (. file.references symbol) to (search-assignment self file to (stack-add-multisym! stack symbol) opts)))) (λ search-table [self file tbl stack opts] (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)) - (values {:definition tbl} file) ;; BASE CASE !! + {:definition tbl : file} ;; BASE CASE !! nil)) ;; BASE CASE Give up -(λ search-list [self file call stack opts] - (match call - [-require- mod] - (when (= :string (type mod)) - (let [newfile (state.get-by-module self mod)] - (when newfile - (let [newitem (. newfile.ast (length newfile.ast))] - (search-ast self newfile newitem stack (doto opts (tset :searched-through-require true))))))) +(λ search-list [self file call stack multival opts] + (let [head (. call 1)] + (if (sym? head) + (case (tostring head) + (where (or :do :let)) + (search-multival self file (. call (length call)) stack multival opts) + :values + (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 [-dot- & split] (. split 1)) - (search-ast self file (. split 1) (stack-add-split! stack split) opts) + (where (or :fn :lambda :λ)) + (if (= multival 1) + {:definition call : file}) ;; BASE CASE !! + ;; TODO expand-macros - ;; A do block returns the last form - (where [-do- & body] (. body 1)) - (search-ast self file (. body (length body)) stack opts) + _ + (if (and (= multival 1) (= 0 (length stack))) + {:definition call : file}))))) ;; BASE CASE!! - (where [-let- _binding & body] (. body 1)) - (search-ast self file (. body (length body)) stack opts) - - (where [-values- first]) - (search-ast self file first stack opts) - - ;; TODO care about the setmetatable call - (where [-setmetatable- tbl _mt]) - (search-ast self file tbl stack opts) - - ;; 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)))))) +(set search-multival + (λ [self file ast stack multival opts] + (if (list? ast) (search-list self file ast stack multival opts) + (varg? ast) nil ;; TODO function-args + (= 1 multival) + (if (sym? ast) (search-symbol self file ast stack opts) + (= :table (type ast)) (search-table self file ast stack opts) + (= 0 (length stack)) {:definition ast : file}) ;; BASE CASE !! + nil))) (local {:metadata METADATA :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. Returns: -(values {:binding :definition :keys - :fields } - file) + :fields + : file} " ;; The stack is the multi-sym parts still to search @@ -200,7 +163,7 @@ Returns: _ (case (. file.references symbol) ref (search-assignment self file ref stack opts) _ (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] (when ?scope @@ -221,7 +184,7 @@ Returns: _ (case (global-info self name) global-item global-item _ (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] ;; check if a byte is past an ast object @@ -281,7 +244,7 @@ Returns: (λ find-nearest-definition [self file symbol ?byte] (if (. file.definitions symbol) - (values (. file.definitions symbol) file) + (. file.definitions symbol) (search-main self file symbol {:stop-early? true} ?byte))) {: find-symbol @@ -289,4 +252,4 @@ Returns: : search-main : search-assignment : search-name-and-scope - : search-ast} + :search-ast search-val}