branch: scratch/javaimp-parse commit fbe24265529a8c898a49b4f64bbf896a98a7d24e Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
wip --- javaimp-util.el | 127 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 31 deletions(-) diff --git a/javaimp-util.el b/javaimp-util.el index f2f4c00..70ccb0d 100644 --- a/javaimp-util.el +++ b/javaimp-util.el @@ -171,42 +171,107 @@ buffer and returns its result" (unless (syntax-ppss-context state) (throw 'found (match-string 1))))))))) +;; for imenu: named classes, then their members (skip over `{' then just jump by braces) +;; indentation: from the point up + +(defconst javaimp--class-re + (concat + (regexp-opt '("class" "interface" "enum") 'words) + (rx (and (+ (syntax whitespace)) + (group (+ (any alnum ?_))))))) + +(defstruct javaimp-scope + ;; one of anonymous, class, interface, enum, local-class, lambda, + ;; unknown + type + name + start + open-brace) + +(defun javaimp--parse-scope-class (state) + (if (and (re-search-backward javaimp--class-re nil t) + ;; if there's no paren in between - assume we're looking at + ;; class declaration + (not (save-match-data + (search-forward "(" (nth 1 state) t)))) + (make-javaimp-scope :type (intern (match-string 1)) + :name (match-string 2) + :start (point) + :open-brace (nth 1 state)))) + +(defun javaimp--parse-scope-anonymous (state) + ;; TODO + ;; anonymous: find "new"; scan-lists -1; no parens between + ;; generate name based on superclass + ) + +(defun javaimp--parse-scope-lambda (state) + ;; TODO + ;; "->" right before bracket; (scan-lists -1) if previous is `)', else (scan-sexps -1) + ) + + +(defmacro javaimp--parse-scope (state &rest parsers) + `(or ,@(mapcar (lambda (p) + `(save-excursion + (funcall ,p ,state))) + parsers))) + +(defun javaimp--collect-scopes (count) + (interactive "p") + (let ((state (syntax-ppss)) + curr res) + (unless (syntax-ppss-context state) + (save-excursion + (while (and (nth 1 state) + (or (not count) + (>= (setq count (1- count) 0)))) + ;; find innermost enclosing open-bracket + (goto-char (nth 1 state)) + (when (= (char-after) ?{) + (if (setq curr (javaimp--parse-scope + state + #'javaimp--parse-scope-anonymous + #'javaimp--parse-scope-class + #'javaimp--parse-scope-lambda)) + (progn + (push curr res) + (goto-char (javaimp-scope-start curr))) + (push (make-javaimp-scope :type 'unknown + :name "unknown" + :start nil + :open-brace (nth 1 state))))) + (setq state (syntax-ppss))))) + ;; if a class is enclosed in anyting other than a class, then it + ;; should be local + (let ((tmp res) + in-local) + (while tmp + (if (eq (javaimp-scope-type (car tmp)) 'class) + (if in-local (setf (javiamp-scope-type (car tmp)) 'local-class)) + (setq in-local t)) + (setq tmp (cdr tmp)))) + res)) + + (defun javaimp--get-file-classes (file) (with-temp-buffer (insert-file-contents file) (let ((parse-sexp-ignore-comments t) - (class-re (concat - (regexp-opt '("class" "interface" "enum") 'words) - (rx (and (+ (syntax whitespace)) - (group (+ (any alnum ?_))))))) res) - (while (re-search-forward class-re nil t) - (let ((state (syntax-ppss)) - curr) - (unless (syntax-ppss-context state) - (setq curr (list (match-string 2))) - ;; collect enclosing classes, if any - (save-excursion - (catch 'stop - (while (nth 1 state) - ;; find innermost enclosing open-bracket - (goto-char (nth 1 state)) - (if (and (= (char-after) ?{) - (re-search-backward class-re nil t) - ;; if there's no paren in between - assume - ;; it's a valid class (not a method - this - ;; way we exclude local classes) - (not (save-match-data - (search-forward "(" (nth 1 state) t)))) - (progn - (push (match-string 2) curr) - (setq state (syntax-ppss))) - (setq curr nil) - (throw 'stop nil))))) - (when curr - (let ((package (javaimp--get-package))) - (if package (push package curr))) - (push (mapconcat #'identity curr ".") res))))) + (while (re-search-forward javaimp--class-re nil t) + (let ((scopes (javaimp--collect-scopes nil)) + (curr (list (match-string 2)))) + (catch 'stop + (dolist (scope scopes) + (if (eq (javaimp-scope-type scope) 'class) + (push (javaimp-scope-name scope) curr) + (setq curr nil) + (throw 'stop nil)))) + (when curr + (let ((package (javaimp--get-package))) + (if package (push package curr))) + (push (mapconcat #'identity curr ".") res)))) (nreverse res)))) (provide 'javaimp-util)