Improved goto-definition sifting destructures
This commit is contained in:
parent
44e7158e7d
commit
c2cd1e50fe
@ -32,12 +32,13 @@
|
||||
(λ compile [file]
|
||||
"Compile the file, and record all the useful information from the compiler into the file object"
|
||||
|
||||
(local references [])
|
||||
(local definitions (doto {} (setmetatable has-tables-mt)))
|
||||
(local references {})
|
||||
(local definitions-by-scope (doto {} (setmetatable has-tables-mt)))
|
||||
(local definitions {})
|
||||
|
||||
(λ find-definition [name ?scope]
|
||||
(when ?scope
|
||||
(or (. definitions ?scope name)
|
||||
(or (. definitions-by-scope ?scope name)
|
||||
(find-definition name ?scope.parent))))
|
||||
|
||||
(λ reference [ast scope]
|
||||
@ -53,15 +54,21 @@
|
||||
;; recursively explore the binding (which, in the general case, is a destructuring assignment)
|
||||
;; right now I'm not keeping track of *how* the symbol was destructured: just finding all the symbols for now.
|
||||
;; also, there's no logic for (values)
|
||||
(λ recurse [binding]
|
||||
(λ recurse [binding keys]
|
||||
(if (fennel.sym? binding)
|
||||
(tset (. definitions scope)
|
||||
(tostring binding)
|
||||
{: binding :definition ?definition})
|
||||
(let [definition
|
||||
{: binding
|
||||
: ?definition
|
||||
:?keys (fcollect [i 1 (length keys)]
|
||||
(. keys i))}]
|
||||
(tset (. definitions-by-scope scope) (tostring binding) definition)
|
||||
(tset definitions binding definition))
|
||||
(= :table (type binding))
|
||||
(each [k v (iter binding)]
|
||||
(recurse v))))
|
||||
(recurse binding))
|
||||
(table.insert keys k)
|
||||
(recurse v keys)
|
||||
(table.remove keys))))
|
||||
(recurse binding []))
|
||||
|
||||
(λ define-function-name [ast scope]
|
||||
;; add a function definition to the definitions
|
||||
@ -70,10 +77,10 @@
|
||||
(and (fennel.sym? name)
|
||||
(not (multisym? name)) ;; not dealing with multisym for now
|
||||
(fennel.sequence? args)))
|
||||
(tset (. definitions scope.parent)
|
||||
(tset (. definitions-by-scope scope) ;; !!! parent or child?
|
||||
(tostring name)
|
||||
{:binding name
|
||||
:definition ast})))
|
||||
:?definition ast})))
|
||||
|
||||
(λ define-function-args [ast scope]
|
||||
;; add the definitions of function arguments to the definitions
|
||||
@ -82,7 +89,7 @@
|
||||
(where [_fn args] (fennel.sequence? args)) args
|
||||
(where [_fn _name args] (fennel.sequence? args)) args))
|
||||
(each [_ argument (ipairs args)]
|
||||
(define nil argument scope))) ;; we say function arguments are set to nil
|
||||
(define nil argument scope))) ;; we say function arguments are set to nil ;; !!! parent or child?
|
||||
|
||||
(λ define-function [ast scope]
|
||||
;; handle the definitions of a function
|
||||
@ -124,7 +131,8 @@
|
||||
|
||||
;; write things back to the file object
|
||||
(set file.references references)
|
||||
;; (set file.definitions definitions) ;; not needed yet
|
||||
(set file.definitions definitions)
|
||||
;; (set file.definitions-by-scope definitions-by-scope) ;; not needed yet
|
||||
(set file.ast ast))
|
||||
;; (set file.compiled? true))
|
||||
{: compile}
|
||||
|
||||
@ -63,7 +63,7 @@ Every time the client sends a message, it gets handled by a function in the corr
|
||||
(local byte (pos->byte file.text position.line position.character))
|
||||
(match (language.find-symbol file.ast byte)
|
||||
symbol
|
||||
(match (language.search-symbol self file symbol [])
|
||||
(match (language.search-main self file symbol [])
|
||||
(definition result-file) ;; curse you, magical match rules
|
||||
(message.range-and-uri definition result-file))))
|
||||
|
||||
|
||||
@ -15,21 +15,23 @@
|
||||
nil)
|
||||
|
||||
(set search-assignment
|
||||
(λ search-assignment [self file binding ?definition stack]
|
||||
(λ search-assignment [self file {: binding : ?definition : ?keys} stack]
|
||||
(if (= 0 (length stack))
|
||||
(values binding file) ;; BASE CASE!!
|
||||
|
||||
;; TODO sift down the binding
|
||||
(search self file ?definition stack))))
|
||||
(do
|
||||
(if ?keys
|
||||
(fcollect [i (length ?keys) 1 -1 &into stack]
|
||||
(. ?keys i)))
|
||||
(search self file ?definition stack)))))
|
||||
|
||||
(set search-symbol
|
||||
(λ search-symbol [self file symbol stack]
|
||||
(let [split (utils.multi-sym-split symbol)]
|
||||
(for [i (length split) 2 -1]
|
||||
(table.insert stack (. split i))))
|
||||
(fcollect [i (length split) 2 -1 &into stack]
|
||||
(. split i))) ;; TODO test coverage for this line
|
||||
(match (. file.references symbol)
|
||||
to (search-assignment self file to.binding to.definition stack)
|
||||
nil nil))) ;; BASE CASE: Give up
|
||||
to (search-assignment self file to stack))))
|
||||
|
||||
|
||||
(set search
|
||||
(λ search [self file item stack]
|
||||
@ -37,7 +39,9 @@
|
||||
(fennelutils.table? item)
|
||||
(if (. item (. stack (length stack)))
|
||||
(search self file (. item (table.remove stack)) stack)
|
||||
nil) ;; BASE CASE: Give up
|
||||
(= 0 (length stack))
|
||||
(values item file) ;; BASE CASE !!
|
||||
nil) ;; BASE CASE Give up
|
||||
(sym? item)
|
||||
(search-symbol self file item stack)
|
||||
;; TODO
|
||||
@ -49,6 +53,22 @@
|
||||
(search self newfile newitem stack))
|
||||
_ (error (.. "I don't know what to do with " (fennel.view item)))))))
|
||||
|
||||
(λ search-main [self file symbol]
|
||||
;; TODO partial byting, go to different defitition sites depending on which section of the symbol the trigger happens on
|
||||
|
||||
;; The stack is the multi-sym parts still to search
|
||||
;; for example, if I'm searching for "foo.bar.baz", my "item" or "symbol" is foo,
|
||||
;; and the stack has ["baz" "bar"], with "bar" at the "top"/"end" of the stack as the next key to search.
|
||||
(local stack
|
||||
(let [split (utils.multi-sym-split symbol)]
|
||||
(fcollect [i (length split) 2 -1]
|
||||
(. split i))))
|
||||
(match (values (. file.references symbol) (. file.definitions symbol))
|
||||
(ref _)
|
||||
(search-assignment self file ref stack)
|
||||
(_ def)
|
||||
(search self file def.?definition stack)))
|
||||
|
||||
(λ past? [?ast byte]
|
||||
;; check if a byte is past an ast object
|
||||
(and (= (type ?ast) :table)
|
||||
@ -101,4 +121,5 @@
|
||||
(find-symbol v byte true)))))
|
||||
|
||||
{: find-symbol
|
||||
: search-symbol}
|
||||
: search-symbol
|
||||
: search-main}
|
||||
|
||||
@ -49,19 +49,25 @@
|
||||
(it "can go to a function inside a table"
|
||||
(check "example.fnl" 28 6 "example.fnl" 4 4 4 7))
|
||||
|
||||
;; (it "can go to a field inside of a table")
|
||||
|
||||
(it "can go to a function in another file when accessed by multisym"
|
||||
(check "example.fnl" 7 7 "foo.fnl" 2 4 2 13)))
|
||||
(check "example.fnl" 7 7 "foo.fnl" 2 4 2 13))
|
||||
|
||||
;; (it "goes further if you go to definition on a binding")
|
||||
(it "goes further if you go to definition on a binding"
|
||||
(check "example.fnl" 31 12 "example.fnl" 23 4 23 5))
|
||||
|
||||
|
||||
;; (it "can go to a destructured function argument")
|
||||
|
||||
;; it can go up and down destructuring
|
||||
(it "can trace a variable that was introduced with destructuring assignment"
|
||||
(check "example.fnl" 38 15 "example.fnl" 33 7 33 13)))
|
||||
|
||||
;; (it "handles (local _ (require XXX))")
|
||||
;; (check "example.fnl" 0 10 "foo.fnl" 0 0 0 0)
|
||||
|
||||
;; (it "works directly on a require/include (require XXX))"
|
||||
;; (check "example.fnl" 1 5 "bar.fnl" 0 0 0 0))
|
||||
|
||||
;; (it "can go to a field inside of a table")
|
||||
;; (it "can go to a destructured function argument")
|
||||
;; (it "can go to a reference that occurs in a macro")
|
||||
;; (it "doesn't have ghost definitions from the same byte ranges as the macro files it's using")
|
||||
;; (it "can go to a function in another file imported via destructuring assignment")
|
||||
|
||||
@ -28,3 +28,19 @@
|
||||
|
||||
(obj.bar 2 3)
|
||||
(obj:a)
|
||||
|
||||
(local redefinition b)
|
||||
|
||||
(local findme 10)
|
||||
(local deep {:a {:b {:field findme}}})
|
||||
(local {:a {:b shallow}} deep)
|
||||
(local mixed [{:key [5 {:foo shallow}]}])
|
||||
(local [{:key [_ {:foo funny}]}] mixed)
|
||||
(print funny.field)
|
||||
|
||||
(local findme 10) ;; via field access instead of destructure
|
||||
(local deep {:a {:b {:field findme}}})
|
||||
(local shallow deep.a.b)
|
||||
(local mixed [{:key [5 {:foo shallow}]}])
|
||||
(local funny (. mixed 1 :key 2 foo))
|
||||
(print funny.field)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user