Use metadata tree instead of hash table for token lookup

WIP-cache
Hugo Thunnissen 10 months ago
parent b68baaec83
commit 9a25959aad

@ -25,6 +25,8 @@
(require 'phpinspect-splayt)
(require 'phpinspect-meta)
(require 'phpinspect-util)
(require 'compat)
(cl-defstruct (phpinspect-bmap (:constructor phpinspect-make-bmap))
(starts (make-hash-table :test #'eql
@ -40,8 +42,17 @@
:type list)
(overlays (phpinspect-make-splayt)
:type phpinspect-splayt)
(-root-meta nil
:type phpinspect-meta)
(last-token-start nil
:type integer))
:type integer))
(define-inline phpinspect-bmap-root-meta (bmap)
(inline-letevals (bmap)
(inline-quote
(with-memoization (phpinspect-bmap--root-meta ,bmap)
(phpinspect-bmap-token-starting-at
,bmap (phpinspect-bmap-last-token-start ,bmap))))))
(defsubst phpinspect-make-region (start end)
(list start end))
@ -84,9 +95,6 @@
(define-inline phpinspect-overlay-end (overlay)
(inline-quote (caddr ,overlay)))
(define-inline phpinspect-overlay-token-meta (overlay)
(inline-quote (car (nthcdr 5 ,overlay))))
(define-inline phpinspect-overlay-overlaps-point (overlay point)
(inline-letevals (overlay point)
(inline-quote
@ -134,7 +142,10 @@
(meta (phpinspect-bmap-meta bmap))
(last-token-start (phpinspect-bmap-last-token-start bmap))
(existing-end (gethash end ends))
(token-meta (or overlay (phpinspect-make-meta nil start end whitespace-before token overlay))))
(token-meta (or overlay (phpinspect-make-meta nil start end whitespace-before token))))
(when (< end start)
(error "Token %s ends before it starts. Start: %s, end: %s" token start end))
(unless whitespace-before
(setq whitespace-before ""))
@ -149,11 +160,8 @@
(when (and last-token-start
(<= start last-token-start))
(let ((child)
(stack (phpinspect-bmap-token-stack bmap))
(right-siblings))
(while (and (car stack) (>= (phpinspect-meta-start (car stack))
start))
(stack (phpinspect-bmap-token-stack bmap)))
(while (and (car stack) (>= (phpinspect-meta-start (car stack)) start))
(setq child (pop stack))
(phpinspect-meta-set-parent child token-meta))
@ -224,29 +232,9 @@
(and (listp token)
(keywordp (car token))))
(cl-defmethod phpinspect-bmap-last-token-before-point ((bmap phpinspect-bmap) point &optional limit)
"Search backward in BMAP for last token ending before POINT.
LIMIT is the maximum number of positions to check backward before
giving up. If not provided, this is 100."
(unless limit (setq limit 100))
(let* ((ending)
(point-limit (- point limit)))
(unless (hash-table-empty-p (phpinspect-bmap-ends bmap))
(while (not (or (<= point 0) (<= point point-limit)
(setq ending (phpinspect-bmap-tokens-ending-at bmap point))))
(setq point (- point 1)))
(car (last ending)))))
(cl-defmethod phpinspect-bmap-last-token-starting-before-point ((bmap phpinspect-bmap) point &optional limit)
(unless limit (setq limit 100))
(let* ((starting)
(point-limit (- point limit)))
(unless (hash-table-empty-p (phpinspect-bmap-starts bmap))
(while (not (or (<= point 0) (<= point point-limit)
(setq starting (phpinspect-bmap-token-starting-at bmap point))))
(setq point (- point 1)))
starting)))
(cl-defmethod phpinspect-bmap-last-token-before-point ((bmap phpinspect-bmap) point)
"Search backward in BMAP for last token ending before POINT."
(phpinspect-meta-find-child-before-recursively (phpinspect-bmap-root-meta bmap) point))
(defsubst phpinspect-bmap-overlay (bmap bmap-overlay token-meta pos-delta &optional whitespace-before)
(let* ((overlays (phpinspect-bmap-overlays bmap))

@ -124,7 +124,7 @@ and CONTEXT. All strategies must implement this method.")
(phpinspect-completion-query-point q))
(phpinspect-variable-p
(phpinspect-meta-token
(phpinspect-bmap-last-token-starting-before-point
(phpinspect-bmap-last-token-before-point
(phpinspect-buffer-parse-map (phpinspect-completion-query-buffer q))
(phpinspect-completion-query-point q))))))

@ -22,6 +22,9 @@
;;; Commentary:
;;; Code:
(require 'phpinspect-util)
(require 'phpinspect-meta)
(require 'phpinspect-parser)
(defvar phpinspect-eldoc-word-width 14
"The maximum width of words in eldoc strings.")
@ -120,43 +123,65 @@ be implemented for return values of `phpinspect-eld-strategy-execute'")
((strat phpinspect-eld-function-args) (q phpinspect-eldoc-query) (rctx phpinspect--resolvecontext))
(phpinspect--log "Executing `phpinspect-eld-function-args' strategy")
(let* ((token-map (phpinspect-buffer-parse-map (phpinspect-eldoc-query-buffer q)))
(enclosing-token (cadr (phpinspect--resolvecontext-enclosing-tokens
(enclosing-token (car (phpinspect--resolvecontext-enclosing-metadata
rctx)))
(statement (phpinspect-find-statement-before-point
token-map (phpinspect-bmap-token-meta token-map enclosing-token)
(phpinspect-eldoc-query-point q)))
(left-sibling )
(statement )
match-result static arg-list arg-pos)
(phpinspect--log "Eldoc statement is: %s" statement)
(phpinspect--log "Enclosing token was: %s" enclosing-token)
(cond
;; Subject is a statement
((and (phpinspect-list-p (car (last (phpinspect--resolvecontext-subject rctx))))
enclosing-token)
(setq left-sibling (phpinspect-meta-find-child-before-recursively
enclosing-token (phpinspect-eldoc-query-point q)))
(phpinspect-meta-overlaps-point left-sibling (phpinspect-eldoc-query-point q)))
;; Subject is inside an argument list
((and enclosing-token
(phpinspect-list-p (phpinspect-meta-token enclosing-token)))
(setq left-sibling (phpinspect-meta-find-left-sibling enclosing-token)
statement (list enclosing-token))))
(phpinspect--log "Left sibling: %s" (phpinspect-meta-string left-sibling))
(phpinspect--log "Enclosing parent: %s" (phpinspect-meta-string (phpinspect-meta-parent enclosing-token)))
(while (and left-sibling
(not (or (phpinspect-return-p (phpinspect-meta-token left-sibling))
(phpinspect-end-of-statement-p (phpinspect-meta-token left-sibling)))))
(push left-sibling statement)
(setq left-sibling (phpinspect-meta-find-left-sibling left-sibling)))
(phpinspect--log "Eldoc statement is: %s" (mapcar #'phpinspect-meta-token statement))
(phpinspect--log "Enclosing token was: %s" (phpinspect-meta-token enclosing-token))
(when enclosing-token
(cond
;; Method call
((setq match-result (phpinspect--match-sequence (last statement 2)
:f #'phpinspect-attrib-p
:f #'phpinspect-list-p))
:f (phpinspect-meta-wrap-token-pred #'phpinspect-attrib-p)
:f (phpinspect-meta-wrap-token-pred #'phpinspect-list-p)))
(phpinspect--log "Eldoc context is a method call")
(setq arg-list (car (last match-result))
static (phpinspect-static-attrib-p (car match-result))
static (phpinspect-static-attrib-p (phpinspect-meta-token (car match-result)))
arg-pos (seq-reduce
(lambda (count token)
(if (and (phpinspect-comma-p token)
(>= (phpinspect-eldoc-query-point q)
(phpinspect-meta-end
(phpinspect-bmap-token-meta token-map token))))
(lambda (count meta)
(if (phpinspect-comma-p (phpinspect-meta-token meta))
(+ count 1)
count))
arg-list 0))
(phpinspect-meta-find-children-before arg-list (phpinspect-eldoc-query-point q)) 0))
;; Set resolvecontext subject to the statement minus the method
;; name. Point is likely to be at a location inside a method call like
;; "$a->b->doSomething(". The resulting subject should be "$a->b".
(setf (phpinspect--resolvecontext-subject rctx) (butlast statement 2))
(setf (phpinspect--resolvecontext-subject rctx)
(mapcar #'phpinspect-meta-token (butlast statement 2)))
(let* ((type-of-previous-statement
(phpinspect-resolve-type-from-context rctx))
(method-name-sym (phpinspect-intern-name (car (cdadar match-result))))
(method-name-sym (phpinspect-intern-name (cadadr (phpinspect-meta-token (car match-result)))))
(class (phpinspect-project-get-class-create
(phpinspect--resolvecontext-project rctx)
type-of-previous-statement))

@ -27,6 +27,8 @@
(require 'phpinspect-project)
(require 'phpinspect-parser)
(require 'phpinspect-type)
(require 'phpinspect-meta)
(require 'phpinspect-util)
(cl-defstruct (phpinspect--resolvecontext
(:constructor phpinspect--make-resolvecontext))
@ -38,6 +40,10 @@
:type string
:documentation
"The root directory of the project we're resolving types for.")
(enclosing-metadata nil
:type list
:documentation
"Metadata of tokens that enclose the subject.")
(enclosing-tokens nil
:type list
:documentation
@ -60,24 +66,21 @@
(string= "return" (cadr token))))
(defun phpinspect-find-statement-before-point (bmap meta point)
(let ((children (reverse (cdr (phpinspect-meta-token meta))))
child-meta
previous-siblings)
(let ((children (reverse (phpinspect-meta-find-children-before meta point)))
token previous-siblings)
(catch 'return
(dolist (child children)
(when (phpinspect-probably-token-p child)
(setq child-meta (phpinspect-bmap-token-meta bmap child))
(unless child-meta
(phpinspect--log "[ERROR] No metadata object found for token %s" child))
(when (< (phpinspect-meta-start child-meta) point)
(if (and (not previous-siblings) (phpinspect-blocklike-p child))
(progn
(throw 'return (phpinspect-find-statement-before-point bmap child-meta point)))
(when (or (phpinspect-return-p child)
(phpinspect-end-of-statement-p child))
(throw 'return previous-siblings))
(push child previous-siblings)))))
previous-siblings)))
(setq token (phpinspect-meta-token child))
(when (< (phpinspect-meta-start child) point)
(if (and (not previous-siblings) (phpinspect-blocklike-p token))
(progn
(throw 'return (phpinspect-find-statement-before-point bmap child point)))
(when (or (phpinspect-return-p token)
(phpinspect-end-of-statement-p token))
(throw 'return previous-siblings))
(push child previous-siblings)))))
previous-siblings))
(defun phpinspect--get-last-statement-in-token (token)
(setq token (cond ((phpinspect-function-p token)
@ -107,25 +110,23 @@
(siblings))
(phpinspect--log "Last token before point: %s, right siblings: %s, parent: %s"
(phpinspect-meta-string subject)
(phpinspect-meta-right-siblings subject)
(mapcar #'phpinspect-meta-token (phpinspect-meta-right-siblings subject))
(phpinspect-meta-string (phpinspect-meta-parent subject)))
(let ((next-sibling (car (phpinspect-meta-right-siblings subject))))
;; When the right sibling of the last ending token overlaps point, this is
;; our actual subject.
(when (and next-sibling
(setq next-sibling (phpinspect-bmap-token-meta bmap next-sibling))
(phpinspect-meta-overlaps-point next-sibling point))
(setq subject next-sibling)))
;; Dig down through tokens that can contain statements
(catch 'break
(while (and subject
(phpinspect-enclosing-token-p (phpinspect-meta-token subject))
(cdr (phpinspect-meta-token subject)) 0)
(let ((new-subject
(phpinspect-bmap-token-meta
bmap (car (last (cdr (phpinspect-meta-token subject)))))))
(let (new-subject)
(catch 'break
(while (and subject
(phpinspect-enclosing-token-p (phpinspect-meta-token subject))
(cdr (phpinspect-meta-token subject)))
(setq new-subject (phpinspect-meta-find-child-before subject point))
(if new-subject
(setq subject new-subject)
(throw 'break nil)))))
@ -134,10 +135,9 @@
(phpinspect-meta-token subject))
(when subject
(setq subject-token
(phpinspect-find-statement-before-point
bmap
(phpinspect-meta-parent subject)
point))
(mapcar #'phpinspect-meta-token
(phpinspect-find-statement-before-point
bmap (phpinspect-meta-parent subject) point)))
(phpinspect--log "Ultimate resolvecontext subject token: %s. Parent: %s"
subject-token (phpinspect-meta-token
@ -151,12 +151,13 @@
(or (not granny)
(phpinspect-function-p (phpinspect-meta-token granny))
(phpinspect-class-p (phpinspect-meta-token granny))))
(push (phpinspect-meta-token parent) enclosing-tokens))
(push parent enclosing-tokens))
(setq parent (phpinspect-meta-parent parent))))))
(phpinspect--make-resolvecontext
:subject (phpinspect--get-last-statement-in-token subject-token)
:enclosing-tokens (nreverse enclosing-tokens)
:enclosing-tokens (nreverse (mapcar #'phpinspect-meta-token enclosing-tokens))
:enclosing-metadata (nreverse enclosing-tokens)
:project-root (phpinspect-current-project-root))))
(defun phpinspect--resolvecontext-project (rctx)
@ -212,5 +213,11 @@ accompanied by all of its enclosing tokens."
resolvecontext))
namespace-name)))
(cl-defmethod phpinspect--resolvecontext-pop-meta ((rctx phpinspect--resolvecontext))
"Remove the first element of enclosing token metadata and
return it. Pops enclosing tokens to keep both in sync."
(pop (phpinspect--resolvecontext-enclosing-tokens rctx))
(pop (phpinspect--resolvecontext-enclosing-metadata rctx)))
(provide 'phpinspect-resolvecontext)
;;; phpinspect-resolvecontext.el ends here

@ -22,7 +22,7 @@ class Thing
(phpinspect-project-root-function (lambda () "phpinspect-test"))
(phpinspect-eldoc-word-width 100)
(buffer (phpinspect-make-buffer :buffer (current-buffer)))
second-arg-pos first-arg-pos)
second-arg-pos inside-nested-list-pos first-arg-pos)
(phpinspect-ensure-worker)
(phpinspect-purge-cache)
(phpinspect-cache-project-class
@ -33,6 +33,8 @@ class Thing
(backward-char)
(setq second-arg-pos (point))
(backward-char 6)
(setq inside-nested-list-pos (point))
(backward-char 8)
(setq first-arg-pos (point))
(let ((result (phpinspect-eldoc-query-execute
@ -41,6 +43,10 @@ class Thing
(should (= 1 (phpinspect-function-doc-arg-pos result)))
(should (string= "getThis" (phpinspect--function-name (phpinspect-function-doc-fn result))))
(setq result (phpinspect-eldoc-query-execute
(phpinspect-make-eldoc-query :point inside-nested-list-pos :buffer buffer)))
(should-not result)
(setq result (phpinspect-eldoc-query-execute
(phpinspect-make-eldoc-query :point first-arg-pos :buffer buffer)))
(should (phpinspect-function-doc-p result))

Loading…
Cancel
Save