branch: scratch/javaimp-parse commit e884e0297b4faaefabc6b4f8bc5969e79021604e Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
wip --- javaimp-parse.el | 162 ++++++++++++++++++++++++++++++++++++------------------- javaimp-tests.el | 21 ++++++++ 2 files changed, 127 insertions(+), 56 deletions(-) diff --git a/javaimp-parse.el b/javaimp-parse.el index b29b2e8..2b0c3e3 100644 --- a/javaimp-parse.el +++ b/javaimp-parse.el @@ -20,6 +20,7 @@ (require 'cl-lib) (require 'seq) +(require 'cc-mode) ;for java-mode-syntax-table (cl-defstruct javaimp-scope type ; one of anonymous-class, class, interface, enum, local-class, @@ -47,18 +48,80 @@ (defsubst javaimp--parse-is-class (scope) (member (symbol-name (javaimp-scope-type scope)) javaimp--parse-class-keywords)) +(defvar javaimp--arglist-syntax-table + "Enables parsing angle brackets as lists" + (let ((st (make-syntax-table java-mode-syntax-table))) + (modify-syntax-entry ?< "(>" st) + (modify-syntax-entry ?> ")<" st) + st)) -(defun javaimp--parse-get-package () + + +;;; Arglist + +(defun javaimp--parse-arglist (beg end) (save-excursion (save-restriction - (widen) - (goto-char (point-min)) - (catch 'found - (while (re-search-forward "^\\s *package\\s +\\([^;]+\\)\\s *;" nil t) - (let ((state (syntax-ppss))) - (unless (syntax-ppss-context state) - (throw 'found (match-string 1))))))))) + (narrow-to-region beg end) + (with-syntax-table javaimp--arglist-syntax-table ;skip generics like lists + (goto-char (point-max)) + (ignore-errors + (let (res) + (while (not (bobp)) + (push (javaimp--parse-arglist-one-arg) res) + ;; move back to the previous argument, if any + (javaimp--parse-arglist-until (lambda () + (= (char-before) ?,))) + (unless (bobp) + (backward-char))) + res)))))) + +(defun javaimp--parse-arglist-one-arg () + ;; Parse one argument backwards starting from point and return it in + ;; the form (TYPE . NAME). Leave point at where the job is done: + ;; skipping further backwards is done by the caller. + (let ((pos (progn + (skip-syntax-backward "-") + (point))) + name type) + (if (= 0 (skip-syntax-backward "w_")) + (error "Cannot parse argument name")) + (setq name (buffer-substring-no-properties (point) pos)) + (skip-syntax-backward "-") + (setq pos (point)) + ;; Parse type: allow anything, but stop at the word boundary which + ;; is not inside list (this is presumably the type start..) + (javaimp--parse-arglist-until (lambda () + (looking-at "\\<"))) + (if (bobp) + (error "Cannot parse argument type") + (setq type (replace-regexp-in-string + "[[:space:]]+" " " + (buffer-substring-no-properties (point) pos))) + (cons type name)))) +(defun javaimp--parse-arglist-until (stop-p) + ;; Goes backwards until position at which STOP-P returns non-nil. + ;; STOP-P is invoked without arguments and should not move point. + (catch 'done + (while t + (skip-syntax-backward "-") + (let ((state (syntax-ppss))) + (cond ((bobp) + (throw 'done nil)) + ((= (char-syntax (char-before)) ?\)) + (backward-list)) + ((syntax-ppss-context state) + ;; move out of comment/string if in one + (goto-char (nth 8 state))) + ((funcall stop-p) + (throw 'done nil)) + (t + (backward-char))))))) + + + +;;; Scopes (defvar javaimp--parse-scope-hook '(;; should be before method/stmt because looks similar, but with @@ -107,12 +170,12 @@ (defun javaimp--parse-scope-method-or-stmt (state) (save-excursion (when (and (ignore-errors - (goto-char ;skip over 1 list + (goto-char (scan-lists (nth 1 state) -1 0))) (eq (char-after) ?\()) - (let* ((arglist (buffer-substring-no-properties - (point) - (scan-lists (point) 1 0))) + (let* (;; leave open/close parens out + (arglist-region (cons (1+ (point)) + (1- (scan-lists (point) 1 0)))) (count (progn (skip-syntax-backward "-") (skip-syntax-backward "w_"))) @@ -123,50 +186,22 @@ (if (member name javaimp--parse-stmt-keywords) 'statement 'method)))) (when type - (make-javaimp-scope :type type - :name (if (eq type 'statement) - name - (concat name - ;; to distinguish overloaded methods - (javaimp--parse-arglist arglist))) - :start (point) - :open-brace (nth 1 state))))))) - -(defun javaimp--parse-arglist (arglist) - (with-temp-buffer - (with-syntax-table 'javaimp--arglist-syntax-table ;TODO <> - (condition-case nil - (let (name end res curr) - (insert arglist) - (backward-char) ; `)' - (while (not (bobp)) - (setq end (point)) - ;; name - (if (= 0 (skip-syntax-backward "w_")) - (error "No name") - (setq name (buffer-substring (point) end))) - (skip-syntax-backward "-") - (setq start nil - end (point)) - ;; type - allow anything but skip over angle brackets - (while (not start) - (cond ((bobp) - (error "Invalid type")) - ((= (char-before) ? ) - (setq start (point))) - ((= (char-before) ?>) - ;; skip over generics - (goto-char - (scan-lists (point) -1 0))) - (t - (backward-char)))) - (push (cons (buffer-substring start end) name) res) - (setq curr nil) - ;; TODO skip everything up to comma or open-paren - ) - res) - (t nil))))) - + (make-javaimp-scope + :type type + :name (if (eq type 'statement) + name + (concat name + "(" + (mapconcat (lambda (arg) + ;; omit name? + (concat (car arg) " " (cdr arg))) + (javaimp--parse-arglist + (car arglist-region) (cdr arglist-region)) + ", ") + ")" + )) + :start (point) + :open-brace (nth 1 state))))))) (defun javaimp--parse-scope-class (state) (save-excursion @@ -215,6 +250,21 @@ (setq tmp (cdr tmp)))) res)) + + +;; Main + +(defun javaimp--parse-get-package () + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (catch 'found + (while (re-search-forward "^\\s *package\\s +\\([^;]+\\)\\s *;" nil t) + (let ((state (syntax-ppss))) + (unless (syntax-ppss-context state) + (throw 'found (match-string 1))))))))) + (defun javaimp--parse-get-file-classes (file) (with-temp-buffer (insert-file-contents file) diff --git a/javaimp-tests.el b/javaimp-tests.el index 9951a81..055e21a 100644 --- a/javaimp-tests.el +++ b/javaimp-tests.el @@ -23,6 +23,27 @@ (should (eql (length projects) 2))))) +(ert-deftest javaimp-test--parse-arglist () + (dolist (data '(("") + (" ") + ("int i" + ("int" . "i")) + ("List<? extends Comparable<? super T>> list, T... elements" + ("List<? extends Comparable<? super T>>" . "list") + ("T..." . "elements")) + ("org.foo.Map <? extends K, ? extends V> m, String [] array, int i" + ;; TODO fix code to clear up extra ws here + ("org.foo.Map <? extends K, ? extends V>" . "m") + ("String []" . "array") + ("int" . "i")) + ("Bi_Function<? super K, ? super V, ? extends V> function" + ("Bi_Function<? super K, ? super V, ? extends V>" . "function")))) + (with-temp-buffer + (java-mode) + (insert (car data)) + (should (equal (javaimp--parse-arglist (point-min) (point-max)) + (cdr data)))))) + (ert-deftest javaimp-test--parse-get-package () (with-temp-buffer (insert "//package org.commented1;