emacs-elsa / Elsa

Emacs Lisp Static Analyzer and gradual type system.
GNU General Public License v3.0
643 stars 27 forks source link

Bool-vector type not supported by elsa-reader #228

Open wtianyi opened 4 months ago

wtianyi commented 4 months ago

When processing ansi-color.el, e.g.

(elsa-process-file "/opt/homebrew/Cellar/emacs-mac/emacs-29.1-mac-10.0/share/emacs/29.1/lisp/ansi-color.el.gz")

A bool vector #&8"\0" at line 975 is not recognized, leading to an error "Invalid form" is thrown https://github.com/emacs-elsa/Elsa/blob/f719e2404ab6f3323df9341751469cb2e413e013/elsa-reader.el#L865

It seems that bool-vector-p can be used to check whether it's a bool vector, and the corresponding type does exist in Elsa: https://github.com/emacs-elsa/Elsa/blob/f719e2404ab6f3323df9341751469cb2e413e013/elsa-types.el#L929

However, I lack the knowledge to add the elsa-form- class and the reader for it.

wtianyi commented 4 months ago

It seems easier than I initially expected, so I took a stab. #229

Being new to ELisp, I have a remotely related and probably dumb question: How come the elsa-form-*-p predicates work without being explicitly defined? What keyword should I search if I would like to learn more on this?

Fuco1 commented 4 months ago

The predicates come from the defclass. For example

(defclass elsa-form-number (elsa-form-atom)
  ((value :type number :initarg :value)))

expands to

(progn
  (defalias 'elsa-form-number-p
    (eieio-make-class-predicate 'elsa-form-number))
  (defalias 'elsa-form-number--eieio-childp
    (eieio-make-child-predicate 'elsa-form-number))
  (define-symbol-prop 'elsa-form-number 'cl-deftype-satisfies
    (function elsa-form-number--eieio-childp))
  (eieio-defclass-internal 'elsa-form-number
                           '(elsa-form-atom)
                           '((value :type number :initarg :value))
                           'nil)
  (defun elsa-form-number
      (&rest slots)
    "Create a new object of class type `elsa-form-number'."
    (declare
     (compiler-macro
      (lambda
        (whole)
        (if
            (not
             (stringp
              (car slots)))
            whole
          (macroexp-warn-and-return
           (format "Obsolete name arg %S to constructor %S"
                   (car slots)
                   (car whole))
           `(,(car whole)
             (identity ,(car slots))
             ,@(cdr slots)))))))
    (apply
     (function make-instance)
     'elsa-form-number slots)))

There's a package called macrostep which you can use to expand macros.

wtianyi commented 4 months ago

Thank you! This is very helpful!