diff --git a/src/fennel-ls/compiler.fnl b/src/fennel-ls/compiler.fnl index 462c296..e207095 100644 --- a/src/fennel-ls/compiler.fnl +++ b/src/fennel-ls/compiler.fnl @@ -11,6 +11,8 @@ identifiers are declared / referenced in which places." (local searcher (require :fennel-ls.searcher)) (local utils (require :fennel-ls.utils)) +(local nil* (sym :nil)) + (fn scope? [candidate] ;; just checking a couple of the fields (and @@ -67,6 +69,8 @@ identifiers are declared / referenced in which places." lexical {} ; all lists, tables, and symbols in the original source require-calls {}] ; the keys are all the calls that start with `require + (local defer []) + (λ find-definition [name ?scope] (if ?scope (or (. definitions-by-scope ?scope name) @@ -185,18 +189,18 @@ identifiers are declared / referenced in which places." _ [])) (each [_ argument (ipairs args)] (if (not (sym? argument :&)) - (define (sym :nil) argument scope)))) ;; TODO for now, function arguments are set to nil + (define nil* argument scope)))) ;; TODO for now, function arguments are set to nil (λ define-function [ast scope] ;; handle the definitions of a function (define-function-name ast scope)) (λ compile-for [ast scope binding] - (define (sym :nil) binding scope)) + (define nil* binding scope)) (λ compile-each [ast scope bindings] (each [_ binding (ipairs bindings)] - (define (sym :nil) binding scope))) + (define nil* binding scope))) (λ compile-fn [ast scope] (tset scopes ast scope) @@ -205,8 +209,6 @@ identifiers are declared / referenced in which places." (λ compile-do [ast scope] (tset scopes ast scope)) - (local defer []) - (λ call [ast scope] "every list that is a call to a special or macro or function" (tset calls ast true) @@ -216,7 +218,7 @@ identifiers are declared / referenced in which places." (case (and (sym? head) (tostring head)) ;; This cannot be done through the :fn feature of the compiler plugin system ;; because it needs to be called *before* the body of the function is processed. - (where (or :fn :lambda :λ)) + (where :fn) (define-function ast scope) (where (or :require :include)) (tset require-calls ast true) @@ -248,7 +250,7 @@ identifiers are declared / referenced in which places." (when (and (= 1 (msg:find "expected even number of name/value bindings")) (sequence? ?ast) (= 1 (% (length ?ast) 2))) - (table.insert ?ast (sym :nil)) + (table.insert ?ast nil*) (table.insert defer #(table.remove ?ast)) true) (when (and (= 1 (msg:find "expected a function, macro, or special to call")) @@ -356,7 +358,13 @@ identifiers are declared / referenced in which places." (when (or (table? ast) (list? ast)) (each [k v (iter ast)] (parsed k) - (parsed v)))) + (parsed v))) + (when (and (list? ast) + (or (sym? (. ast 1) :λ) + (sym? (. ast 1) :lambda))) + (let [old-sym (. ast 1)] + (tset ast 1 (sym :fn)) + (table.insert defer #(tset ast 1 old-sym))))) (parsed ast lexical) diff --git a/src/fennel-ls/formatter.fnl b/src/fennel-ls/formatter.fnl index efbfddb..4c9148f 100644 --- a/src/fennel-ls/formatter.fnl +++ b/src/fennel-ls/formatter.fnl @@ -53,14 +53,16 @@ user code. Fennel-ls doesn't support user-code formatting as of now." fntype is one of fn or λ or lambda" (case ?ast ;; name + docstring - (where [fntype name arglist docstring _body] + (where [fntype name arglist docstring body] + body (fn? fntype) (sym? name) (type= arglist :table) (type= docstring :string)) {: fntype : name : arglist : docstring} ;; docstring - (where [fntype arglist docstring _body] + (where [fntype arglist docstring body] + body (fn? fntype) (type= arglist :table) (type= docstring :string)) diff --git a/test/hover.fnl b/test/hover.fnl index eed7f8c..d9e628c 100644 --- a/test/hover.fnl +++ b/test/hover.fnl @@ -96,15 +96,18 @@ except that it sets a new message handler `msgh`.") \"this is a doc string\" (print arg1 arg2 arg3)) (my-function)|" nil) - (check "(λ foo| [x ...] + (check "(fn foo| [x ...] \"not a docstring, this gets returned\")" "```fnl\n(fn foo [x ...] ...)\n```") + (check "(λ foo| [x ...] + \"not a docstring, this gets returned\")" + "```fnl\n(λ foo [x ...] ...)\n```") (check "(λ foo| [{: start : end}] :body)" - "```fnl\n(fn foo [{: end : start}] ...)\n```") + "```fnl\n(λ foo [{: end : start}] ...)\n```") (check "(λ foo| [{:list [a b c] :table {: d : e : f}}] :body)" - "```fnl\n(fn foo [{:list [a b c] :table {: d : e : f}}] ...)\n```") + "```fnl\n(λ foo [{:list [a b c] :table {: d : e : f}}] ...)\n```") nil) (fn test-multisym [] diff --git a/test/lint.fnl b/test/lint.fnl index 8899160..a99d618 100644 --- a/test/lint.fnl +++ b/test/lint.fnl @@ -59,6 +59,11 @@ ;; setting a field without reading is okay (check "(fn [a b] (set a.x 10) (fn b.f []))" [] [{}]) (check "(case {:b 1} (where (or {:a x} {:b x})) x)" [] [{}]) + + (check "(fn foo [a] nil) (foo)" [{:message "unused definition: a"}] []) + (check "(λ foo [a] nil) (foo)" [{:message "unused definition: a"}] []) + (check "(lambda foo [a] nil) (foo)" [{:message "unused definition: a"}] []) + nil) (fn test-ampersand []