branch: externals/javaimp commit a3bfdc2352197065bfc396ae85b2515980410da4 Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
Clean up syntax / parsing settings --- javaimp-parse.el | 171 ++++++++++++++++++++++++++----------------------------- javaimp-tests.el | 11 ++++ javaimp.el | 10 ++++ tests/imenu.el | 8 +-- tests/parse.el | 22 +++---- tests/tests.el | 5 +- 6 files changed, 115 insertions(+), 112 deletions(-) diff --git a/javaimp-parse.el b/javaimp-parse.el index 984dfa5579..0e1cb1350e 100644 --- a/javaimp-parse.el +++ b/javaimp-parse.el @@ -70,21 +70,19 @@ regexp. First group is directive, second group is identifier." (javaimp-parse--directive-regexp "import\\(?:[[:space:]]+static\\)?")) -(defvar javaimp-syntax-table - (make-syntax-table java-mode-syntax-table) ;TODO don't depend on cc-mode - "Javaimp syntax table") - -(defvar javaimp--arglist-syntax-table - (let ((st (make-syntax-table javaimp-syntax-table))) +(defvar javaimp--parse-syntax-table + ;; TODO don't depend on cc-mode + (let ((st (make-syntax-table java-mode-syntax-table))) + ;; To be able to skip over generic types as over lists (modify-syntax-entry ?< "(>" st) (modify-syntax-entry ?> ")<" st) - (modify-syntax-entry ?. "_" st) ; separates parts of fully-qualified type - ;; Override prefix syntax so that scan-sexps right after @ in - ;; annotation doesn't ignore it. + ;; Dot separates parts of fully-qualified type + (modify-syntax-entry ?. "_" st) ; + ;; Override prefix syntax so that scan-sexps backwards right after + ;; @ in annotation doesn't ignore it. (modify-syntax-entry ?@ "_" st) st) - "Enables parsing angle brackets as lists") - + "Syntax table used in parsing.") (defvar-local javaimp-parse--dirty-pos nil "Marker which points to a buffer position after which all parsed @@ -123,7 +121,7 @@ non-nil, then name parsing is skipped." (let ((substr (buffer-substring-no-properties beg end))) (with-temp-buffer (insert substr) - (with-syntax-table javaimp--arglist-syntax-table + (with-syntax-table javaimp--parse-syntax-table (ignore-errors (let (res) (while (progn @@ -237,7 +235,7 @@ is unchanged." (catch 'found (while (javaimp-parse--rsb-keyword regexp bound t) (let ((scan-pos (match-end 0))) - (with-syntax-table javaimp--arglist-syntax-table + (with-syntax-table javaimp--parse-syntax-table ;; Skip over any number of lists, which may be exceptions ;; in "throws", or something like that (while (and scan-pos (<= scan-pos brace-pos)) @@ -259,38 +257,37 @@ point (but not farther than BOUND). Matches inside comments / strings are skipped. Return the beginning of the match (then the point is also at that position) or nil (then the point is left unchanged)." - (with-syntax-table javaimp-syntax-table - (let ((state (syntax-ppss)) - prev-semi pos res) - ;; Move out of any comment/string - (when (nth 8 state) - (goto-char (nth 8 state)) - (setq state (syntax-ppss))) - ;; If we skip a previous scope (including unnamed initializers), - ;; or reach enclosing scope start, we'll fail the check in the - ;; below loop. But a semicolon, which delimits statements, will - ;; just be skipped by scan-sexps, so find it and use as bound. - ;; If it is in another scope, that's not a problem, for the same - ;; reasons as described above. - (setq prev-semi (save-excursion - (javaimp-parse--rsb-keyword ";" bound t)) - bound (when (or bound prev-semi) - (apply #'max - (delq nil - (list bound - (and prev-semi (1+ prev-semi))))))) - ;; Go back by sexps - (with-syntax-table javaimp--arglist-syntax-table - (while (and (ignore-errors - (setq pos (scan-sexps (point) -1))) - (or (not bound) (>= pos bound)) - (or (member (char-after pos) - '(?@ ?\( ;annotation type / args - ?<)) ;generic type - ;; keyword / identifier first char - (= (syntax-class (syntax-after pos)) 2))) ;word - (goto-char (setq res pos)))) - res))) + (let ((state (syntax-ppss)) + prev-semi pos res) + ;; Move out of any comment/string + (when (nth 8 state) + (goto-char (nth 8 state)) + (setq state (syntax-ppss))) + ;; If we skip a previous scope (including unnamed initializers), + ;; or reach enclosing scope start, we'll fail the check in the + ;; below loop. But a semicolon, which delimits statements, will + ;; just be skipped by scan-sexps, so find it and use as bound. + ;; If it is in another scope, that's not a problem, for the same + ;; reasons as described above. + (setq prev-semi (save-excursion + (javaimp-parse--rsb-keyword ";" bound t)) + bound (when (or bound prev-semi) + (apply #'max + (delq nil + (list bound + (and prev-semi (1+ prev-semi))))))) + ;; Go back by sexps + (with-syntax-table javaimp--parse-syntax-table + (while (and (ignore-errors + (setq pos (scan-sexps (point) -1))) + (or (not bound) (>= pos bound)) + (or (memql (char-after pos) + '(?@ ?\( ;annotation type / args + ?<)) ;generic type + ;; keyword / identifier first char + (= (syntax-class (syntax-after pos)) 2))) ;word + (goto-char (setq res pos)))) + res)) ;;; Scopes @@ -490,7 +487,6 @@ lambdas are also recognized as such." :start nil))) - (defun javaimp-parse--scopes (count) "Attempts to parse COUNT enclosing scopes at point. Returns most nested one, with its parents sets accordingly. If @@ -545,57 +541,57 @@ nothing." (setq res (cdr res))) parent))) + (defun javaimp-parse--all-scopes () - "Parses all scopes in this buffer which are after + "Parse all scopes in this buffer which are after `javaimp-parse--dirty-pos', if it points anywhere. Makes it -point nowhere when done." - (unless javaimp-parse--dirty-pos ;init on first use - (setq javaimp-parse--dirty-pos (point-min-marker)) - (javaimp-parse--setup-buffer)) +point nowhere when done. All entry-point functions will usually +call this function first." + (unless javaimp-parse--dirty-pos + (setq javaimp-parse--dirty-pos (point-min-marker))) (when (marker-position javaimp-parse--dirty-pos) (with-silent-modifications ;we update only private props (remove-text-properties javaimp-parse--dirty-pos (point-max) '(javaimp-parse-scope nil)) (goto-char (point-max)) - (let ((parse-sexp-ignore-comments t) - ;; Can be removed when we no longer rely on cc-mode + (let (;; Can be removed when we no longer rely on cc-mode (parse-sexp-lookup-properties nil)) - (with-syntax-table javaimp-syntax-table - (while (javaimp-parse--rsb-keyword "{" javaimp-parse--dirty-pos t) - (save-excursion - (forward-char) - ;; Set props at this brace and all the way up - (javaimp-parse--scopes nil)))))) + (while (javaimp-parse--rsb-keyword "{" javaimp-parse--dirty-pos t) + (save-excursion + (forward-char) + ;; Set props at this brace and all the way up + (javaimp-parse--scopes nil))))) (set-marker javaimp-parse--dirty-pos nil))) -(defun javaimp-parse--setup-buffer () - ;; FIXME This may be done in major/minor mode setup - (setq syntax-ppss-table javaimp-syntax-table) - (setq-local multibyte-syntax-as-symbol t) - (add-hook 'after-change-functions #'javaimp-parse--update-dirty-pos)) +(defun javaimp-parse--update-dirty-pos (beg _end _old-len) + "Function to add to `after-change-functions' hook." + (when (and javaimp-parse--dirty-pos + (or (not (marker-position javaimp-parse--dirty-pos)) + (< beg javaimp-parse--dirty-pos))) + (set-marker javaimp-parse--dirty-pos beg))) + (defun javaimp-parse--enclosing-scope (&optional pred) "Return innermost enclosing scope matching PRED." - (with-syntax-table javaimp-syntax-table - (let ((state (syntax-ppss))) - ;; Move out of any comment/string - (when (nth 8 state) - (goto-char (nth 8 state)) - (setq state (syntax-ppss))) - (catch 'found - (while t - (let ((res (save-excursion - (javaimp-parse--scopes nil)))) - (when (and (javaimp-scope-p res) - (or (null pred) - (funcall pred res))) - (throw 'found res)) - ;; Go up until we get something - (if (nth 1 state) - (progn - (goto-char (nth 1 state)) - (setq state (syntax-ppss))) - (throw 'found nil)))))))) + (let ((state (syntax-ppss))) + ;; Move out of any comment/string + (when (nth 8 state) + (goto-char (nth 8 state)) + (setq state (syntax-ppss))) + (catch 'found + (while t + (let ((res (save-excursion + (javaimp-parse--scopes nil)))) + (when (and (javaimp-scope-p res) + (or (null pred) + (funcall pred res))) + (throw 'found res)) + ;; Go up until we get something + (if (nth 1 state) + (progn + (goto-char (nth 1 state)) + (setq state (syntax-ppss))) + (throw 'found nil))))))) (defun javaimp-parse--class-abstract-methods () (goto-char (point-max)) @@ -637,13 +633,6 @@ point nowhere when done." (goto-char (nth 1 (syntax-ppss)))))) res)) -(defun javaimp-parse--update-dirty-pos (beg _end _old-len) - "Function to add to `after-change-functions' hook." - (when (and javaimp-parse--dirty-pos - (or (not (marker-position javaimp-parse--dirty-pos)) - (< beg javaimp-parse--dirty-pos))) - (set-marker javaimp-parse--dirty-pos beg))) - ;; Functions intended to be called from other parts of javaimp. They ;; do not preserve excursion / restriction - it's the caller's diff --git a/javaimp-tests.el b/javaimp-tests.el index 9542ae2774..4ca01ad20f 100644 --- a/javaimp-tests.el +++ b/javaimp-tests.el @@ -21,4 +21,15 @@ supplying that directory name as the only arg." (funcall handler tmpdir) (error "Cannot untar test data file %s: %d" filename rc))))) +(defmacro javaimp-with-temp-buffer (file &rest body) + "Execute BODY in temporary buffer with `javaimp-minor-mode' +turned on. If FILE is non-nil then its contents are inserted." + (declare (debug t) (indent 1)) + `(with-temp-buffer + (when ,file + (insert-file-contents (ert-resource-file ,file))) + (java-mode) + (javaimp-minor-mode) + ,@body)) + (provide 'javaimp-tests) diff --git a/javaimp.el b/javaimp.el index b281c3b430..5e9b2fb7f5 100644 --- a/javaimp.el +++ b/javaimp.el @@ -129,6 +129,7 @@ ;; presented in a nested fashion, instead of a flat list (default is ;; flat list). + ;;; Code: (require 'javaimp-util) @@ -1224,6 +1225,7 @@ PREV-INDEX gives the index of the method itself." "C-M-a" #'beginning-of-defun "C-M-e" #'end-of-defun) + ;;;###autoload (define-minor-mode javaimp-minor-mode "Javaimp minor mode. @@ -1247,7 +1249,12 @@ defun javadoc to be included in the narrowed region when using #'javaimp-end-of-defun) (add-function :override (local 'add-log-current-defun-function) #'javaimp-add-log-current-defun) + (add-hook 'after-change-functions #'javaimp-parse--update-dirty-pos nil t) (add-hook 'xref-backend-functions #'javaimp-xref--backend nil t) + (setq-local parse-sexp-ignore-comments t) + (setq-local multibyte-syntax-as-symbol t) + ;; Discard parse state, if any + (setq javaimp-parse--dirty-pos nil) ;; There're spaces within generic types, just show them (setq-local imenu-space-replacement nil)) (remove-function (local 'imenu-create-index-function) @@ -1258,7 +1265,10 @@ defun javadoc to be included in the narrowed region when using #'javaimp-end-of-defun) (remove-function (local 'add-log-current-defun-function) #'javaimp-add-log-current-defun) + (remove-hook 'after-change-functions #'javaimp-parse--update-dirty-pos t) (remove-hook 'xref-backend-functions #'javaimp-xref--backend t) + (kill-local-variable 'parse-sexp-ignore-comments) + (kill-local-variable 'multibyte-syntax-as-symbol) (kill-local-variable 'imenu-space-replacement))) diff --git a/tests/imenu.el b/tests/imenu.el index f1d5d9ed83..cbf7fb3639 100644 --- a/tests/imenu.el +++ b/tests/imenu.el @@ -6,8 +6,8 @@ ;; Maintainer: Filipp Gunbin <fgun...@fastmail.fm> (require 'ert) -(require 'ert-x) (require 'javaimp) +(require 'javaimp-tests) (defun javaimp-test-imenu--simplify-entries (alist) (dolist (elt alist) @@ -18,8 +18,7 @@ (ert-deftest javaimp-imenu-create-index () - (let ((actual (with-temp-buffer - (insert-file-contents (ert-resource-file "test1.java")) + (let ((actual (javaimp-with-temp-buffer "test1.java" (let ((imenu-use-markers nil)) (javaimp-imenu-create-index)))) (expected-names @@ -45,8 +44,7 @@ (should (equal (nth i expected-names) (car (nth i actual))))))) (ert-deftest javaimp-imenu-create-index-use-sub-alists () - (let ((actual (with-temp-buffer - (insert-file-contents (ert-resource-file "test1.java")) + (let ((actual (javaimp-with-temp-buffer "test1.java" (let ((imenu-use-markers nil) (javaimp-imenu-use-sub-alists t)) (javaimp-imenu-create-index)))) diff --git a/tests/parse.el b/tests/parse.el index 62f6abd180..b4c0b99121 100644 --- a/tests/parse.el +++ b/tests/parse.el @@ -6,9 +6,8 @@ ;; Maintainer: Filipp Gunbin <fgun...@fastmail.fm> (require 'ert) -(require 'ert-x) -(require 'javaimp-parse) -(require 'javaimp-util) +(require 'javaimp) +(require 'javaimp-tests) ;; Tests for parse helpers @@ -35,7 +34,7 @@ ("int" . "i") ("String[][]" . "arr")) )) - (with-temp-buffer + (javaimp-with-temp-buffer nil (insert (car data)) (should (equal (javaimp-parse--arglist (point-min) (point-max)) (cdr data)))))) @@ -57,19 +56,18 @@ Exception4<? super Exception5>>") ("Exception6") ("Exception7<Exception8>")))) - (with-temp-buffer + (javaimp-with-temp-buffer nil (insert (car data)) (should (equal (javaimp-parse--arglist (point-min) (point-max) t) (cdr data)))))) - ;; Tests for scope parsers (defun javaimp-test-parse--scope (parser &rest test-items) (declare (indent 1)) (dolist (item test-items) - (with-temp-buffer + (javaimp-with-temp-buffer nil (insert (nth 0 item)) (let* ((javaimp-parse--scope-hook (lambda (arg) @@ -281,7 +279,7 @@ throws E1 {" (nreverse res))) (ert-deftest javaimp-parse-get-package () - (with-temp-buffer + (javaimp-with-temp-buffer nil (insert " package foo.bar.baz ; //package commented.line; @@ -292,7 +290,7 @@ package commented.block; (should (equal (javaimp-parse-get-package) "foo.bar.baz")))) (ert-deftest javaimp-parse-get-imports () - (with-temp-buffer + (javaimp-with-temp-buffer nil (insert " import some.class1 ; import static some.class.fun1; @@ -316,8 +314,7 @@ import static some_class.fun_2; // comment ("some_class.fun_2" . static)))))) (ert-deftest javaimp-parse-get-all-scopes () - (with-temp-buffer - (insert-file-contents (ert-resource-file "test1.java")) + (javaimp-with-temp-buffer "test1.java" (should-not javaimp-parse--dirty-pos) ;; ;; parse full buffer @@ -363,8 +360,7 @@ import static some_class.fun_2; // comment ;; eob ((goto-char (point-max)))))) (dolist (testcase testcases) - (with-temp-buffer - (insert-file-contents (ert-resource-file "test1.java")) + (javaimp-with-temp-buffer "test1.java" (eval (car testcase)) ;move (should (equal (cdr testcase) diff --git a/tests/tests.el b/tests/tests.el index 02ee0ccffc..f25b114049 100644 --- a/tests/tests.el +++ b/tests/tests.el @@ -6,12 +6,11 @@ ;; Maintainer: Filipp Gunbin <fgun...@fastmail.fm> (require 'ert) -(require 'ert-x) (require 'javaimp) +(require 'javaimp-tests) (ert-deftest javaimp-collect-idents () - (with-temp-buffer - (insert-file-contents (ert-resource-file "test1.java")) + (javaimp-with-temp-buffer "test1.java" (should (equal (mapcar #'javaimp--ident-to-fqcn (javaimp--collect-idents (javaimp-scope-defun-p) (current-buffer) t))