emacs-elsa / Elsa

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

Add EMake instructions to the README #148

Closed vermiculus closed 1 year ago

vermiculus commented 5 years ago

Partially address #135

This should work out-of-the-box (I gave it a good prodding in a new directory), but you should give it a whirl on the off-chance it only works in my environment.

Fuco1 commented 5 years ago

I'm getting

emake.mk:31: *** EMACS_VERSION is not set.  Stop.

which is easy to fix but maybe can catch someone off-guard. I suppose this is explained in EMake readme so you can link to there

Fuco1 commented 5 years ago

when I run it with the variable set I get

> env EMACS_VERSION=26.1 make lint-elsa       
Makefile:28: warning: overriding recipe for target 'compile'
emake.mk:94: warning: ignoring old recipe for target 'compile'
make: *** No rule to make target 'lint-elsa'.  Stop.

I'm not running this in a clean directory but in master of Elsa. Should it work or od I need to run the bootstrap?

vermiculus commented 5 years ago

One of the design decisions I made for EMake is to discourage any sort of auto-update. The version of EMake given by #146 was before lint-elsa existed. I wasn't going to add Elsa support to EMake until it actually worked when compiled – nice investigation/fix, by the way!

I've pushed a patch that updates the version of EMake used by this repository. After this, you should be able to run make clean test-buttercup lint-elsa.

vermiculus commented 5 years ago

EMACS_VERSION is not set

I've removed this requirement from EMake itself – it's more necessary for installation (which used to be part of emake.mk). Folks should no longer run into this.

Fuco1 commented 5 years ago

I've deleted emake.mk. After I run make clean and make test-buttercup I get

> make test-buttercup
Makefile:28: warning: overriding recipe for target 'compile'
emake.mk:122: warning: ignoring old recipe for target 'compile'
PACKAGE_FILE="elsa-pkg.el" PACKAGE_LISP="elsa-variable.el elsa-typed-cl.el elsa.el elsa-extension-cl.el elsa-extension-elsa.el elsa-analyser.el elsa-types.el elsa-scope.el elsa-english.el elsa-reader.el elsa-type-helpers.el elsa-extension-eieio.el elsa-typed-builtin.el elsa-ruleset.el elsa-typed-syntax.el elsa-extension-builtin.el elsa-extension-flycheck.el elsa-typed-subr.el elsa-typed-thingatpt.el elsa-error.el elsa-extension-seq.el elsa-typed-eieio.el elsa-font-lock.el elsa-rules-list.el elsa-state.el elsa-extension-dash.el elsa-check.el" PACKAGE_TESTS="tests/test-analyser.el tests/test-types.el tests/test-scope.el tests/test-analysis-expression-type.el tests/test-reader.el tests/elsa-test-helpers.el tests/test-type-helpers.el tests/test-elsa-ruleset-style.el tests/test-extension-builtin.el tests/test-elsa-ruleset-dead-code.el tests/test-elsa-extension-builtin.el tests/elsa-undercover.el tests/test-analysis-forms.el tests/test-variable.el" PACKAGE_ARCHIVES="gnu melpa" PACKAGE_TEST_DEPS="buttercup" PACKAGE_TEST_ARCHIVES="gnu melpa melpa" EMAKE_LOGLEVEL="INFO" EMAKE_WORKDIR=".emake" emacs --quick --batch --load '.emake/emake.el' --eval "(setq enable-dir-local-variables nil)"  --eval "(emake (pop argv))" install
emake:INFO: EMACS_VERSION not set, cannot verify; running "26.1"
emake:INFO: Installing in .emake/elpa...
emake:INFO: Installing in .emake/elpa...done
PACKAGE_FILE="elsa-pkg.el" PACKAGE_LISP="elsa-variable.el elsa-typed-cl.el elsa.el elsa-extension-cl.el elsa-extension-elsa.el elsa-analyser.el elsa-types.el elsa-scope.el elsa-english.el elsa-reader.el elsa-type-helpers.el elsa-extension-eieio.el elsa-typed-builtin.el elsa-ruleset.el elsa-typed-syntax.el elsa-extension-builtin.el elsa-extension-flycheck.el elsa-typed-subr.el elsa-typed-thingatpt.el elsa-error.el elsa-extension-seq.el elsa-typed-eieio.el elsa-font-lock.el elsa-rules-list.el elsa-state.el elsa-extension-dash.el elsa-check.el" PACKAGE_TESTS="tests/test-analyser.el tests/test-types.el tests/test-scope.el tests/test-analysis-expression-type.el tests/test-reader.el tests/elsa-test-helpers.el tests/test-type-helpers.el tests/test-elsa-ruleset-style.el tests/test-extension-builtin.el tests/test-elsa-ruleset-dead-code.el tests/test-elsa-extension-builtin.el tests/elsa-undercover.el tests/test-analysis-forms.el tests/test-variable.el" PACKAGE_ARCHIVES="gnu melpa" PACKAGE_TEST_DEPS="buttercup" PACKAGE_TEST_ARCHIVES="gnu melpa melpa" EMAKE_LOGLEVEL="INFO" EMAKE_WORKDIR=".emake" emacs --quick --batch --load '.emake/emake.el' --eval "(setq enable-dir-local-variables nil)"  --eval "(emake (pop argv))" test buttercup
emake:INFO: EMACS_VERSION not set, cannot verify; running "26.1"

Loading /home/matus/.emacs.d/projects/Elsa/tests/test-analyser.el (source)...
Cannot open load file: No such file or directory, elsa-test-helpers
emake.mk:143: recipe for target 'test-buttercup' failed
make: *** [test-buttercup] Error 255

Elsa loads this file which is inside tests directory and I think emake does not put it on the load path?

Fuco1 commented 5 years ago

When I run make lint-elsa it also tries to load the test files. What's the reason for that?

> make lint-elsa
Makefile:28: warning: overriding recipe for target 'compile'
emake.mk:122: warning: ignoring old recipe for target 'compile'
PACKAGE_FILE="elsa-pkg.el" PACKAGE_LISP="elsa-variable.el elsa-typed-cl.el elsa.el elsa-extension-cl.el elsa-extension-elsa.el elsa-analyser.el elsa-types.el elsa-scope.el elsa-english.el elsa-reader.el elsa-type-helpers.el elsa-extension-eieio.el elsa-typed-builtin.el elsa-ruleset.el elsa-typed-syntax.el elsa-extension-builtin.el elsa-extension-flycheck.el elsa-typed-subr.el elsa-typed-thingatpt.el elsa-error.el elsa-extension-seq.el elsa-typed-eieio.el elsa-font-lock.el elsa-rules-list.el elsa-state.el elsa-extension-dash.el elsa-check.el" PACKAGE_TESTS="tests/test-analyser.el tests/test-types.el tests/test-scope.el tests/test-analysis-expression-type.el tests/test-reader.el tests/elsa-test-helpers.el tests/test-type-helpers.el tests/test-elsa-ruleset-style.el tests/test-extension-builtin.el tests/test-elsa-ruleset-dead-code.el tests/test-elsa-extension-builtin.el tests/elsa-undercover.el tests/test-analysis-forms.el tests/test-variable.el" PACKAGE_ARCHIVES="gnu melpa" PACKAGE_TEST_DEPS="elsa dash trinary buttercup f" PACKAGE_TEST_ARCHIVES="gnu melpa melpa" EMAKE_LOGLEVEL="INFO" EMAKE_WORKDIR=".emake" emacs --quick --batch --load '.emake/emake.el' --eval "(setq enable-dir-local-variables nil)"  --eval "(emake (pop argv))" test elsa
emake:INFO: EMACS_VERSION not set, cannot verify; running "26.1"

Loading /home/matus/.emacs.d/projects/Elsa/tests/test-analyser.el (source)...
Cannot open load file: No such file or directory, elsa-test-helpers
emake.mk:133: recipe for target 'lint-elsa' failed
make: *** [lint-elsa] Error 255
vermiculus commented 5 years ago

Will there never be a reason to load test files when running an Elsa check? (This is effectively the difference between running a 'test' and running a generic target.)

vermiculus commented 5 years ago

I've made some updates to avoid loading test files for any lint tool.

I am however hitting a bug:

emake:DEBUG: Simulating command-line arguments: ("emake.el")

analyzer: updating variable emake-environment-variables, old type nil
analyzer: updating variable emake--env-cache, old type nil
analyzer: updating variable emake--debug-flags, old type nil
analyzer: updating variable emake-package-dev-locations-functions, old type nil
analyzer: updating variable emake-package-file-subdirectories, old type nil
analyzer: updating variable emake-project-root, old type nil
analyzer: updating variable emake-package-archive-master-alist, old type nil
Debugger entered--Lisp error: (error "Other must be ‘elsa-type-child-p’")
  signal(error ("Other must be ‘elsa-type-child-p’"))
  error("Other must be `elsa-type-child-p'")
  #f(compiled-function (this other) #<bytecode 0x416fdfcd>)(#<elsa-type-mixed elsa-type-mixed> #<elsa-form-symbol elsa-form-symbol>)
  apply(#f(compiled-function (this other) #<bytecode 0x416fdfcd>) #<elsa-type-mixed elsa-type-mixed> #<elsa-form-symbol elsa-form-symbol>)
  #f(compiled-function (arg &rest args) #<bytecode 0x416bcf39>)(#<elsa-type-mixed elsa-type-mixed> #<elsa-form-symbol elsa-form-symbol>)
  apply(#f(compiled-function (arg &rest args) #<bytecode 0x416bcf39>) #<elsa-type-mixed elsa-type-mixed> #<elsa-form-symbol elsa-form-symbol> nil)
  elsa-type-accept(#<elsa-type-mixed elsa-type-mixed> #<elsa-form-symbol elsa-form-symbol>)
  #f(compiled-function (assignment) #<bytecode 0x416a830d>)((#<elsa-form-symbol elsa-form-symbol> #<elsa-form-symbol elsa-form-symbol>))
  -each(((#<elsa-form-symbol elsa-form-symbol> #<elsa-form-symbol elsa-form-symbol>)) #f(compiled-function (assignment) #<bytecode 0x416a830d>))
  elsa--analyse:setq(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-list(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-form(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-body((#<elsa-form-list elsa-form-list>) #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  #f(compiled-function (branch) #<bytecode 0x416a2775>)(#<elsa-form-list elsa-form-list>)
  -each((#<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list>) #f(compiled-function (branch) #<bytecode 0x416a2775>))
  elsa--analyse:cond(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-list(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-form(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-body((#<elsa-form-list elsa-form-list>) #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse:let*(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-list(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-form(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-body((#<elsa-form-string elsa-form-string> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list>) #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-defun-like-form(emake-test (#<elsa-form-symbol elsa-form-symbol> #<elsa-form-symbol elsa-form-symbol> #<elsa-form-symbol elsa-form-symbol>) (#<elsa-form-string elsa-form-string> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list> #<elsa-form-list elsa-form-list>) #<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse:defun(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-list(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa--analyse-form(#<elsa-form-list elsa-form-list> #<elsa-scope elsa-scope> #<elsa-state elsa-state>)
  elsa-analyse-form(#<elsa-state elsa-state> #<elsa-form-list elsa-form-list>)
  elsa-process-file("emake.el")
  elsa-run()
  (let ((standard-output standard-output)) (elsa-run))
  (progn (let ((standard-output standard-output)) (elsa-run)) (save-current-buffer (set-buffer standard-output) (buffer-string)))
  (unwind-protect (progn (let ((standard-output standard-output)) (elsa-run)) (save-current-buffer (set-buffer standard-output) (buffer-string))) (kill-buffer standard-output))
  (let ((standard-output (get-buffer-create (generate-new-buffer-name " *string-output*")))) (unwind-protect (progn (let ((standard-output standard-output)) (elsa-run)) (save-current-buffer (set-buffer standard-output) (buffer-string))) (kill-buffer standard-output)))
  (let ((output (let ((standard-output (get-buffer-create (generate-new-buffer-name " *string-output*")))) (unwind-protect (progn (let ((standard-output standard-output)) (elsa-run)) (save-current-buffer (set-buffer standard-output) (buffer-string))) (kill-buffer standard-output))))) (if (string-empty-p output) nil (princ output) (error "Elsa issues detected")))
  (closure (t) nil (let ((output (let ((standard-output (get-buffer-create (generate-new-buffer-name " *string-output*")))) (unwind-protect (progn (let ((standard-output standard-output)) (elsa-run)) (save-current-buffer (set-buffer standard-output) (buffer-string))) (kill-buffer standard-output))))) (if (string-empty-p output) nil (princ output) (error "Elsa issues detected"))))()
  funcall((closure (t) nil (let ((output (let ((standard-output (get-buffer-create (generate-new-buffer-name " *string-output*")))) (unwind-protect (progn (let ((standard-output standard-output)) (elsa-run)) (save-current-buffer (set-buffer standard-output) (buffer-string))) (kill-buffer standard-output))))) (if (string-empty-p output) nil (princ output) (error "Elsa issues detected")))))
  (let ((command-line-args-left (emake--clean-list list-env))) (emake-message-debug "Simulating command-line arguments: %S" command-line-args-left) (funcall fn))
  emake--with-args-from-env("PACKAGE_LISP" (closure (t) nil (let ((output (let ((standard-output (get-buffer-create (generate-new-buffer-name " *string-output*")))) (unwind-protect (progn (let ((standard-output standard-output)) (elsa-run)) (save-current-buffer (set-buffer standard-output) (buffer-string))) (kill-buffer standard-output))))) (if (string-empty-p output) nil (princ output) (error "Elsa issues detected")))))
  emake--test-helper-elsa()
  funcall(emake--test-helper-elsa)
  (let ((command-line-args-left args)) (funcall test-runner))
  (progn (let ((command-line-args-left args)) (funcall test-runner)))
  (unwind-protect (progn (let ((command-line-args-left args)) (funcall test-runner))) (emake-message-debug (concat G26 "done")))
  (let ((G26 (concat (format "Running test `%S'" test-runner) "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-debug (concat G26 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-debug G26) (unwind-protect (progn (let ((command-line-args-left args)) (funcall test-runner))) (emake-message-debug (concat G26 "done"))))
  (let* ((G23 (emake--clean-list "PACKAGE_ARCHIVES")) (package-user-dir (expand-file-name (concat (file-name-as-directory (emake--getenv "EMAKE_WORKDIR")) "elpa") emake-project-root)) (package-archives (seq-filter (function (lambda (pair) (member (car pair) G23))) emake-package-archive-master-alist))) (let ((G24 (concat "Initializing package.el" "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-debug (concat G24 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-debug G24) (unwind-protect (progn (package-initialize)) (emake-message-debug (concat G24 "done")))) (let ((--dolist-tail-- (cdr (emake-package-reqs)))) (while --dolist-tail-- (let ((pair (car --dolist-tail--))) (emake-message-debug "Using dependency `%S' at %s" (car pair) (cdr pair)) (add-to-list 'load-path (cdr pair)) (setq --dolist-tail-- (cdr --dolist-tail--))))) (if (function-get test-runner 'emake-lintp) nil (let* ((test-files (and t (emake--clean-list "PACKAGE_TESTS")))) (if test-files (progn (add-to-list 'load-path emake-project-root) (let ((--dolist-tail-- test-files)) (while --dolist-tail-- (let ((test-file (car --dolist-tail--))) (let ((G25 (concat (format "Loading test definitions in %s" test-file) "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-debug (concat G25 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-debug G25) (unwind-protect (progn (if (file-readable-p test-file) nil (error "Cannot read file: %S" test-file)) (load test-file)) (emake-message-debug (concat G25 "done")))) (setq --dolist-tail-- (cdr --dolist-tail--)))))) nil))) (let ((G26 (concat (format "Running test `%S'" test-runner) "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-debug (concat G26 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-debug G26) (unwind-protect (progn (let ((command-line-args-left args)) (funcall test-runner))) (emake-message-debug (concat G26 "done")))))
  emake-test("elsa")
  apply(emake-test "elsa")
  (progn (let* ((behavior (and t (cond ((member "show-environment" emake--debug-flags) t) ((member "show-environment:non-nil" emake--debug-flags) 'only))))) (if behavior (let ((G5 (concat "Showing relevant environment information" "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-info (concat G5 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-info G5) (unwind-protect (progn (emake--env-help fun behavior)) (emake-message-info (concat G5 "done")))) nil)) (apply fun (prog1 command-line-args-left (setq command-line-args-left nil))))
  (unwind-protect (progn (let* ((behavior (and t (cond ((member "show-environment" emake--debug-flags) t) ((member "show-environment:non-nil" emake--debug-flags) 'only))))) (if behavior (let ((G5 (concat "Showing relevant environment information" "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-info (concat G5 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-info G5) (unwind-protect (progn (emake--env-help fun behavior)) (emake-message-info (concat G5 "done")))) nil)) (apply fun (prog1 command-line-args-left (setq command-line-args-left nil)))) (emake-message-debug (concat G4 "done")))
  (let ((G4 (concat (format (if command-line-args-left "Running target %S with function `%S' with arguments %S" "Running target %S with function `%S'") target fun command-line-args-left) "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-debug (concat G4 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-debug G4) (unwind-protect (progn (let* ((behavior (and t (cond ((member "show-environment" emake--debug-flags) t) ((member "show-environment:non-nil" emake--debug-flags) 'only))))) (if behavior (let ((G5 (concat "Showing relevant environment information" "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-info (concat G5 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-info G5) (unwind-protect (progn (emake--env-help fun behavior)) (emake-message-info (concat G5 "done")))) nil)) (apply fun (prog1 command-line-args-left (setq command-line-args-left nil)))) (emake-message-debug (concat G4 "done"))))
  (let ((fun (emake--resolve-target target))) (progn (or (emake-verify-version) (cl--assertion-failed '(emake-verify-version))) nil) (let ((G4 (concat (format (if command-line-args-left "Running target %S with function `%S' with arguments %S" "Running target %S with function `%S'") target fun command-line-args-left) "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-debug (concat G4 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-debug G4) (unwind-protect (progn (let* ((behavior (and t (cond ((member "show-environment" emake--debug-flags) t) ((member "show-environment:non-nil" emake--debug-flags) 'only))))) (if behavior (let ((G5 (concat "Showing relevant environment information" "...")) (kill-emacs-hook kill-emacs-hook)) (setq kill-emacs-hook (cons (function (lambda nil (emake-message-info (concat G5 "done (emacs killed)")))) kill-emacs-hook)) (emake-message-info G5) (unwind-protect (progn (emake--env-help fun behavior)) (emake-message-info (concat G5 "done")))) nil)) (apply fun (prog1 command-line-args-left (setq command-line-args-left nil)))) (emake-message-debug (concat G4 "done")))))
  emake("test")
  eval((emake (pop argv)))
  command-line-1(("--load" ".emake/emake.el" "--eval" "(setq enable-dir-local-variables nil)" "--eval" "(emake (pop argv))" "test" "elsa"))
  command-line()
  normal-top-level()

I seem to be tripping this assertion:

(cl-defmethod elsa-type-accept ((_this elsa-type-mixed) other)
  (unless (elsa-type-child-p other) (error "Other must be `elsa-type-child-p'"))
  (not (eq (eieio-object-class other) 'elsa-type-unbound)))

though I don't know exactly how I should see what the problem is. The printed value of other is massive – is there a way I can retrieve the raw form being analyzed from it?

Fuco1 commented 5 years ago

The new print syntax for structures is so f-kng bad, plus it can't even be read back. I have no idea who smoked what but it's pretty :/

This must be from the change I've made yesterday as it shows setq in the log.

I don't think there is any reason ever to load anything with elsa. It only reads files as streams of text but never actually interprets the code.

vermiculus commented 5 years ago

I've got an #s(...) form if you're able to use it. It's massive, though – about 2.5MB – and I can't manage to format it prettily.

Fuco1 commented 1 year ago

I added emake to the readme. We don't use travis anymore because it's no longer viable for open source, so those changes won't be merged.