Skip to content

Commit

Permalink
feat(analysis): add expansion and analysis of macros
Browse files Browse the repository at this point in the history
Fixes #205
  • Loading branch information
Fuco1 committed Mar 18, 2023
1 parent 40ce69d commit 2aa912d
Show file tree
Hide file tree
Showing 9 changed files with 398 additions and 102 deletions.
19 changes: 19 additions & 0 deletions elsa-analyser.el
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,13 @@ The registered object can be a `defun', `defmacro', or
:return (elsa-type-mixed))
:arglist (elsa-form-to-lisp args))))))

(defun elsa--analyse:elsa--form (form scope state)
"Analyse special marker for macroexpanded forms."
(let ((real-form (elsa-nth 2 form)))
(elsa--analyse-form real-form scope state)
(oset form type (oref real-form type))
(oset form narrow-types (oref real-form narrow-types))))

(defun elsa--analyse:defmacro (form _scope state)
"just skip for now, it's too complicated."
(let ((name (elsa-get-name (elsa-cadr form)))
Expand Down Expand Up @@ -1142,6 +1149,18 @@ SCOPE and STATE are the scope and state objects."
(pcase name
((guard (functionp analyse-fn-name))
(funcall analyse-fn-name form scope state))
((guard (and (oref form expanded-form)
(oref form was-expanded)))
(let ((exp-form (oref form expanded-form)))
(elsa--analyse-form exp-form scope state)
(let ((form-alist nil))
(elsa-form-visit form
(lambda (fm)
(when-let ((expanded (oref fm expanded-form)))
(oset fm type (oref expanded type))
(oset fm narrow-types (oref expanded narrow-types))))))
(oset form type (oref exp-form type))
(oset form narrow-types (oref exp-form narrow-types))))
(`\` (elsa--analyse-backquote form scope state))
(`\, (elsa--analyse-unquote form scope state))
(`\,@ (elsa--analyse-splice form scope state))
Expand Down
63 changes: 36 additions & 27 deletions elsa-error.el
Original file line number Diff line number Diff line change
Expand Up @@ -108,37 +108,46 @@ In general, we recognize three states: error, warning, notice
(cl-defmethod elsa-message-to-lsp-severity ((_this elsa-notice))
lsp/diagnostic-severity-information)

(defun elsa--message-resolve (expression)
(or (when-let ((of (elsa-form-find-parent expression
(lambda (x)
(oref x original-form)))))
(oref of original-form))
expression))

(cl-defmethod elsa-message-format ((this elsa-message))
"Format an `elsa-message'."
(with-ansi
(bright-green "%s" (oref this line))
":"
(green "%s" (or (oref this column) "?"))
":"
(elsa-message-type-ansi this)
":"
(format "%s" (replace-regexp-in-string "%" "%%" (oref this message)))))
(let ((expr (elsa--message-resolve (oref this expression))))
(with-ansi
(bright-green "%s" (oref expr line))
":"
(green "%s" (or (oref expr column) "?"))
":"
(elsa-message-type-ansi this)
":"
(format "%s" (replace-regexp-in-string "%" "%%" (oref this message))))))

(cl-defmethod elsa-message-to-lsp ((this elsa-message))
(lsp-make-diagnostic
:code (oref this code)
:range (lsp-make-range
:start (lsp-make-position
:line (1- (oref this line))
:character (oref this column))
:end (lsp-make-position
:line (1- (oref this line))
:character (let ((expr (oref this expression)))
(if (and (elsa-form-sequence-p expr)
(elsa-car expr))
(oref (elsa-car expr) end-column)
(+ (oref this column)
(if (or (elsa-form-symbol-p expr)
(elsa-get-name expr))
(length (symbol-name (elsa-get-name expr)))
1))))))
:severity (elsa-message-to-lsp-severity this)
:message (oref this message)))
(let ((expression (elsa--message-resolve (oref this expression))))
(lsp-make-diagnostic
:code (oref this code)
:range (lsp-make-range
:start (lsp-make-position
:line (1- (oref expression line))
:character (oref expression column))
:end (lsp-make-position
:line (1- (oref expression line))
:character (let ((expr expression))
(if (and (elsa-form-sequence-p expr)
(elsa-car expr))
(oref (elsa-car expr) end-column)
(+ (oref expression column)
(if (or (elsa-form-symbol-p expr)
(elsa-get-name expr))
(length (symbol-name (elsa-get-name expr)))
1))))))
:severity (elsa-message-to-lsp-severity this)
:message (oref this message))))

(defun elsa--make-message (constructor expression format args)
(let (code)
Expand Down
16 changes: 16 additions & 0 deletions elsa-form.el
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

(require 'trinary)

(require 'elsa-methods)
(require 'elsa-types-simple)

(defclass elsa-form nil
Expand All @@ -23,6 +24,21 @@
:type (or elsa-form null)
:initarg :previous
:documentation "Previous form in a sequence.")
(was-expanded
:type boolean
:initform nil
:documentation "Was this form a macro call form which was expanded.
This is only set on the macro call form which was expanded, not on the
child forms.")
(expanded-form
:type (or elsa-form null)
:initform nil
:documentation "The form corresponding to this form in macroexpanded subtree.")
(original-form
:type (or elsa-form null)
:initform nil
:documentation "The form from which this form was macroexpanded.")
(annotation :type list :initarg :annotation :initform nil))
:abstract t)

Expand Down
16 changes: 11 additions & 5 deletions elsa-lsp-core.el
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,17 @@ be re-analysed during textDocument/didOpen handler.")))

(defun elsa-lsp--analyze-textDocument/hover (form _state _method params)
(-let* (((&HoverParams :position (&Position :line :character))
params))
(when (and (= (oref form line) (1+ line))
(<= (oref form column) character)
(or (< (1+ line) (oref form end-line))
(<= character (oref form end-column))))
params)
(orig-form (oref form original-form)))
(when (or (and orig-form
(= (oref orig-form line) (1+ line))
(<= (oref orig-form column) character)
(or (< (1+ line) (oref orig-form end-line))
(<= character (oref orig-form end-column))))
(and (= (oref form line) (1+ line))
(<= (oref form column) character)
(or (< (1+ line) (oref form end-line))
(<= character (oref form end-column)))))
(throw 'lsp-response
(lsp-make-hover
:contents (lsp-make-markup-content
Expand Down
2 changes: 2 additions & 0 deletions elsa-lsp.el
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
(defun elsa-lsp-stdin-loop ()
"Reads from standard input in a loop and process incoming requests."
(elsa-load-config)
(require 'elsa-startup)

(-> (lgr-get-logger "elsa")
(lgr-reset-appenders)
(lgr-add-appender
Expand Down
Loading

0 comments on commit 2aa912d

Please sign in to comment.