Skip to content

Commit 2aa912d

Browse files
committed
feat(analysis): add expansion and analysis of macros
Fixes #205
1 parent 40ce69d commit 2aa912d

9 files changed

+398
-102
lines changed

elsa-analyser.el

+19
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,13 @@ The registered object can be a `defun', `defmacro', or
656656
:return (elsa-type-mixed))
657657
:arglist (elsa-form-to-lisp args))))))
658658

659+
(defun elsa--analyse:elsa--form (form scope state)
660+
"Analyse special marker for macroexpanded forms."
661+
(let ((real-form (elsa-nth 2 form)))
662+
(elsa--analyse-form real-form scope state)
663+
(oset form type (oref real-form type))
664+
(oset form narrow-types (oref real-form narrow-types))))
665+
659666
(defun elsa--analyse:defmacro (form _scope state)
660667
"just skip for now, it's too complicated."
661668
(let ((name (elsa-get-name (elsa-cadr form)))
@@ -1142,6 +1149,18 @@ SCOPE and STATE are the scope and state objects."
11421149
(pcase name
11431150
((guard (functionp analyse-fn-name))
11441151
(funcall analyse-fn-name form scope state))
1152+
((guard (and (oref form expanded-form)
1153+
(oref form was-expanded)))
1154+
(let ((exp-form (oref form expanded-form)))
1155+
(elsa--analyse-form exp-form scope state)
1156+
(let ((form-alist nil))
1157+
(elsa-form-visit form
1158+
(lambda (fm)
1159+
(when-let ((expanded (oref fm expanded-form)))
1160+
(oset fm type (oref expanded type))
1161+
(oset fm narrow-types (oref expanded narrow-types))))))
1162+
(oset form type (oref exp-form type))
1163+
(oset form narrow-types (oref exp-form narrow-types))))
11451164
(`\` (elsa--analyse-backquote form scope state))
11461165
(`\, (elsa--analyse-unquote form scope state))
11471166
(`\,@ (elsa--analyse-splice form scope state))

elsa-error.el

+36-27
Original file line numberDiff line numberDiff line change
@@ -108,37 +108,46 @@ In general, we recognize three states: error, warning, notice
108108
(cl-defmethod elsa-message-to-lsp-severity ((_this elsa-notice))
109109
lsp/diagnostic-severity-information)
110110

111+
(defun elsa--message-resolve (expression)
112+
(or (when-let ((of (elsa-form-find-parent expression
113+
(lambda (x)
114+
(oref x original-form)))))
115+
(oref of original-form))
116+
expression))
117+
111118
(cl-defmethod elsa-message-format ((this elsa-message))
112119
"Format an `elsa-message'."
113-
(with-ansi
114-
(bright-green "%s" (oref this line))
115-
":"
116-
(green "%s" (or (oref this column) "?"))
117-
":"
118-
(elsa-message-type-ansi this)
119-
":"
120-
(format "%s" (replace-regexp-in-string "%" "%%" (oref this message)))))
120+
(let ((expr (elsa--message-resolve (oref this expression))))
121+
(with-ansi
122+
(bright-green "%s" (oref expr line))
123+
":"
124+
(green "%s" (or (oref expr column) "?"))
125+
":"
126+
(elsa-message-type-ansi this)
127+
":"
128+
(format "%s" (replace-regexp-in-string "%" "%%" (oref this message))))))
121129

122130
(cl-defmethod elsa-message-to-lsp ((this elsa-message))
123-
(lsp-make-diagnostic
124-
:code (oref this code)
125-
:range (lsp-make-range
126-
:start (lsp-make-position
127-
:line (1- (oref this line))
128-
:character (oref this column))
129-
:end (lsp-make-position
130-
:line (1- (oref this line))
131-
:character (let ((expr (oref this expression)))
132-
(if (and (elsa-form-sequence-p expr)
133-
(elsa-car expr))
134-
(oref (elsa-car expr) end-column)
135-
(+ (oref this column)
136-
(if (or (elsa-form-symbol-p expr)
137-
(elsa-get-name expr))
138-
(length (symbol-name (elsa-get-name expr)))
139-
1))))))
140-
:severity (elsa-message-to-lsp-severity this)
141-
:message (oref this message)))
131+
(let ((expression (elsa--message-resolve (oref this expression))))
132+
(lsp-make-diagnostic
133+
:code (oref this code)
134+
:range (lsp-make-range
135+
:start (lsp-make-position
136+
:line (1- (oref expression line))
137+
:character (oref expression column))
138+
:end (lsp-make-position
139+
:line (1- (oref expression line))
140+
:character (let ((expr expression))
141+
(if (and (elsa-form-sequence-p expr)
142+
(elsa-car expr))
143+
(oref (elsa-car expr) end-column)
144+
(+ (oref expression column)
145+
(if (or (elsa-form-symbol-p expr)
146+
(elsa-get-name expr))
147+
(length (symbol-name (elsa-get-name expr)))
148+
1))))))
149+
:severity (elsa-message-to-lsp-severity this)
150+
:message (oref this message))))
142151

143152
(defun elsa--make-message (constructor expression format args)
144153
(let (code)

elsa-form.el

+16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
(require 'trinary)
44

5+
(require 'elsa-methods)
56
(require 'elsa-types-simple)
67

78
(defclass elsa-form nil
@@ -23,6 +24,21 @@
2324
:type (or elsa-form null)
2425
:initarg :previous
2526
:documentation "Previous form in a sequence.")
27+
(was-expanded
28+
:type boolean
29+
:initform nil
30+
:documentation "Was this form a macro call form which was expanded.
31+
32+
This is only set on the macro call form which was expanded, not on the
33+
child forms.")
34+
(expanded-form
35+
:type (or elsa-form null)
36+
:initform nil
37+
:documentation "The form corresponding to this form in macroexpanded subtree.")
38+
(original-form
39+
:type (or elsa-form null)
40+
:initform nil
41+
:documentation "The form from which this form was macroexpanded.")
2642
(annotation :type list :initarg :annotation :initform nil))
2743
:abstract t)
2844

elsa-lsp-core.el

+11-5
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,17 @@ be re-analysed during textDocument/didOpen handler.")))
244244

245245
(defun elsa-lsp--analyze-textDocument/hover (form _state _method params)
246246
(-let* (((&HoverParams :position (&Position :line :character))
247-
params))
248-
(when (and (= (oref form line) (1+ line))
249-
(<= (oref form column) character)
250-
(or (< (1+ line) (oref form end-line))
251-
(<= character (oref form end-column))))
247+
params)
248+
(orig-form (oref form original-form)))
249+
(when (or (and orig-form
250+
(= (oref orig-form line) (1+ line))
251+
(<= (oref orig-form column) character)
252+
(or (< (1+ line) (oref orig-form end-line))
253+
(<= character (oref orig-form end-column))))
254+
(and (= (oref form line) (1+ line))
255+
(<= (oref form column) character)
256+
(or (< (1+ line) (oref form end-line))
257+
(<= character (oref form end-column)))))
252258
(throw 'lsp-response
253259
(lsp-make-hover
254260
:contents (lsp-make-markup-content

elsa-lsp.el

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
(defun elsa-lsp-stdin-loop ()
88
"Reads from standard input in a loop and process incoming requests."
99
(elsa-load-config)
10+
(require 'elsa-startup)
11+
1012
(-> (lgr-get-logger "elsa")
1113
(lgr-reset-appenders)
1214
(lgr-add-appender

0 commit comments

Comments
 (0)