analyzer can search into macro expansions and functions

shoutouts to rudy for working with me on these changes.
This commit is contained in:
XeroOl 2025-01-19 19:56:37 -06:00
parent bfc6d64237
commit ae66e6d002
3 changed files with 45 additions and 9 deletions

View File

@ -42,6 +42,7 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find
(local utils (require :fennel-ls.utils))
(local files (require :fennel-ls.files))
(local docs (require :fennel-ls.docs))
(local {: view} (require :fennel))
(local get-ast-info utils.get-ast-info)
@ -146,11 +147,19 @@ find the definition `10`, but if `opts.stop-early?` is set, it would find
(where (or :fn :lambda :λ))
(if (and (= multival 1) (= 0 (length stack)))
{:definition call : file}) ;; BASE CASE !!
;; TODO expand-macros
_
(if (and (= multival 1) (= 0 (length stack)))
{:definition call : file}))))) ;; BASE CASE!!
(case (. file.macro-calls call)
macroexpanded (search-multival server file macroexpanded stack multival opts)
_ (case (search-val server file (. call 1) [] {})
(where {: definition : file}
(list? definition)
(let [head (. definition 1)]
(or (sym? head :fn)
(sym? head :lambda)
(sym? head :λ))))
(search-multival server file (. definition (length definition)) stack multival opts)))))))
(set search-multival
(λ [server file ?ast stack multival opts]

View File

@ -67,7 +67,8 @@ identifiers are declared / referenced in which places."
scopes {} ; ast -> scope
calls {} ; all calls in the macro-expanded code -> true
lexical {} ; all lists, tables, and symbols in the original source
require-calls {}] ; the keys are all the calls that start with `require
require-calls {} ; the keys are all the calls that start with `require
macro-calls {}]; ast -> expanded
(local defer [])
@ -235,8 +236,9 @@ identifiers are declared / referenced in which places."
(let [len (length ast)]
(table.insert defer #(tset ast (+ len 1) nil))))))
(fn macroexpand [ast _transformed scope]
(fn macroexpand [ast transformed scope]
"every list that is a call to a macro"
(tset macro-calls ast transformed)
(let [macro-id (. ast 1)
macro-fn (accumulate [t scope.macros
_ part (ipairs (utils.multi-sym-split macro-id))]
@ -423,6 +425,7 @@ identifiers are declared / referenced in which places."
(set file.references references)
(set file.require-calls require-calls)
(set file.allowed-globals allowed-globals)
(set file.macro-refs macro-refs))))
(set file.macro-refs macro-refs)
(set file.macro-calls macro-calls))))
{: compile}

View File

@ -205,22 +205,46 @@
(check "|#$...")
nil)
(fn test-thru-function-return []
(check {:button.fnl "(fn new []
{:options =={}==})
{: new}"
:main.fnl "(let [button (require :button)
b (button.new)]
b.options|"})
(check "(fn foo [] (values {} =={}== {}))
(local (x y| z) (foo))")
(check "(fn foo [] [{} =={}== {}])
(local [x y| z] (foo))")
nil)
(fn test-macro []
"Macros are mostly unsupported for now.
Fennel-ls can understand the expansion of macros, because it mostly operates
on the post-expansion version of the AST."
;; Can see the expansion of a macro
(check "(macro hello [x y z] y)
(local x| (hello {} =={}== {}))")
;; ;; Can see the macro itself
;; (check "==(macro hello [x y z] y)==
;; (local x (hello| {} {} {})")
nil)
; ;; (it "can go to a destructured function argument")
; ;; (it "can go through more than one file")
; ;; (it "will give up instead of freezing on recursive requires")
; ;; (it "will give up instead of freezing on recursive tables constructed with (set)")
; ;; (it "finds the definition of in-file macros")
; ;; (it "can follow import-macros (destructuring)")
; ;; (it "can follow import-macros (namespaced)")
; ;; (it "can go to the definition in a lua file")
; ;; (it "finds (set a.b) definitions")
; ;; (it "finds (tset a :b) definitions")
; ;; (it "finds (setmetatable a {:__index {:b def}) definitions")
; ;; (it "finds definitions into a function (fn foo [] (local x 10) {: x}) (let [result (foo)] (print result.x)) finds result.x")
; ;; (it "finds definitions through a function (fn foo [{: y}] {:x y}) (let [result (foo {:y {}})] (print result.x)) finds result.x")
; ;; (it "finds through setmetatable with an :__index function")
{: test-local
: test-fields
: test-thru-require
: test-thru-function-return
: test-macro
: test-no-crash}