bugs, everywhere
ci/woodpecker/push/woodpecker Pipeline failed Details

WIP-incremental-parsing
Hugo Thunnissen 10 months ago
parent 4abc3f405a
commit fc46349bfe

@ -1,5 +1,11 @@
(require 'phpinspect)
(require 'phpinspect-parser)
(defun phpinspect-parse-current-buffer ()
(phpinspect-parse-buffer-until-point
(current-buffer)
(point-max)))
(let ((here (file-name-directory (or load-file-name buffer-file-name))))

@ -40,53 +40,159 @@
(current-row-start nil
:type integer)
(current-row-end nil
:type integer)
(whitespace-before ""
:type string))
:type integer))
(defsubst phpinspect--make-meta (parent start end whitespace-before token &optional overlayed)
(list parent start end whitespace-before token overlayed))
(defsubst phpinspect-make-region (start end)
(list start end))
(defsubst phpinspect--meta-parent (meta)
(car meta))
(defalias 'phpinspect-region-start #'car)
(defalias 'phpinspect-region-end #'cadr)
(gv-define-setter phpinspect--meta-end (end meta) `(setcar (cddr ,meta) ,end))
(gv-define-setter phpinspect--meta-start (start meta) `(setcar (cdr ,meta) ,start))
(gv-define-setter phpinspect--meta-overlayed (overlayed meta) `(setcar (nthcdr 5 ,meta) ,overlayed))
(defsubst phpinspect-region-size (region)
(- (phpinspect-region-end region) (phpinspect-region-start region)))
(defsubst phpinspect--meta-overlayed-p (meta overlay)
(eq (phpinspect--meta-overlayed meta) overlay))
(defsubst phpinspect-region> (reg1 reg2)
(> (phpinspect-region-size reg1) (phpinspect-region-size reg2)))
(defsubst phpinspect--meta-overlayed (meta)
(defsubst phpinspect-region< (reg1 reg2)
(< (phpinspect-region-size reg1) (phpinspect-region-size reg2)))
(defsubst phpinspect-region-overlaps-point (reg point)
(and (> (phpinspect-region-end reg) point)
(<= (phpinspect-region-start reg) point)))
(defsubst phpinspect-region-overlaps (reg1 reg2)
(or (phpinspect-region-reg2s-point reg1 (phpinspect-region-start reg2))
(phpinspect-region-reg2s-point reg1 (- (phpinspect-region-end reg2) 1))
(phpinspect-region-reg2s-point reg2 (phpinspect-region-start reg1))
(phpinspect-region-reg2s-point reg2 (- (phpinspect-region-end reg1) 1))))
(defsubst phpinspect-region-encloses (reg1 reg2)
(and (<= (phpinspect-region-start reg1) (phpinspect-region-start reg2))
(>= (phpinspect-region-end reg1) (phpinspect-region-end reg2))))
(defsubst phpinspect-make-meta (parent start end whitespace-before token &optional overlay)
(list 'meta parent start end whitespace-before token overlay))
(defsubst phpinspect-meta-parent (meta)
(cadr meta))
(gv-define-setter phpinspect-meta-end (end meta) `(setcar (cdddr ,meta) ,end))
(gv-define-setter phpinspect-meta-start (start meta) `(setcar (cddr ,meta) ,start))
(gv-define-setter phpinspect-meta-overlay (overlay meta) `(setcar (nthcdr 6 ,meta) ,overlay))
(gv-define-setter phpinspect-meta-parent (parent meta) `(setcar (cdr ,meta) ,parent))
(defsubst phpinspect-meta-overlay (meta)
(car (nthcdr 6 meta)))
(defsubst phpinspect-meta-token (meta)
(car (nthcdr 5 meta)))
(defsubst phpinspect--meta-token (meta)
(car (cddddr meta)))
(defsubst phpinspect-meta-end (meta)
(cadddr meta))
(defsubst phpinspect-meta-width (meta)
(- (phpinspect-meta-end meta) (phpinspect-meta-start meta)))
(defun phpinspect-meta-sort-width (meta1 meta2)
(< (phpinspect-meta-width meta1) (phpinspect-meta-width meta2)))
(defsubst phpinspect--meta-end (meta)
(defsubst phpinspect-meta-start (meta)
(caddr meta))
(defsubst phpinspect--meta-start (meta)
(cadr meta))
(defsubst phpinspect-meta-overlaps-point (meta point)
(and (> (phpinspect-meta-end meta) point)
(<= (phpinspect-meta-start meta) point)))
(defsubst phpinspect-meta-find-parent-matching-token (meta predicate)
(if (funcall predicate (phpinspect-meta-token meta))
meta
(catch 'found
(while (phpinspect-meta-parent meta)
(setq meta (phpinspect-meta-parent meta))
(when (funcall predicate (phpinspect-meta-token meta))
(throw 'found meta))))))
(gv-define-setter phpinspect-overlay-end (end overlay) `(setcar (cddr ,overlay) ,end))
(gv-define-setter phpinspect-overlay-start (start overlay) `(setcar (cdr ,overlay) ,start))
(gv-define-setter phpinspect-overlay-delta (delta overlay) `(setcar (cdddr ,overlay) ,delta))
(defsubst phpinspect-overlay-bmap (overlay)
(car (nthcdr 4 overlay)))
(defsubst phpinspect-overlay-delta (overlay)
(cadddr overlay))
(defsubst phpinspect-overlay-start (overlay)
(cadr overlay))
(defsubst phpinspect--meta-overlaps-point (meta point)
(and (> (phpinspect--meta-end meta) point)
(<= (phpinspect--meta-start meta) point)))
(defsubst phpinspect-overlay-end (overlay)
(caddr overlay))
(defsubst phpinspect-bmap-register-whitespace (bmap whitespace)
(setf (phpinspect-bmap-whitespace-before bmap) whitespace))
(defsubst phpinspect-overlay-overlaps-point (overlay point)
(and (> (phpinspect-overlay-end overlay) point)
(<= (phpinspect-overlay-start overlay) point)))
(defsubst phpinspect-bmap-register (bmap start end token)
(defmacro phpinspect-bmap-iterate-region (region place-and-bmap &rest body)
(declare (indent defun))
(let ((place (car place-and-bmap))
(bmap (gensym))
(bmap-stack (gensym))
(region-start (gensym))
(region-end (gensym)))
`(let ((,bmap)
(,bmap-stack (list ,(cadr place-and-bmap)))
(,region-start (car ,region))
(,region-end (cadr ,region)))
(while (setq ,bmap (pop ,bmap-stack))
(phpinspect-bmap-iterate (,place ,bmap)
(when (and (<= ,region-start
(phpinspect-meta-start ,place))
(>= ,region-end
(phpinspect-meta-end ,place)))
,@body))))))
(defmacro phpinspect-bmap-iterate (place-and-bmap &rest body)
(declare (indent defun))
(let ((place (car place-and-bmap))
(bmap (gensym))
(bmap-stack (gensym))
(_ignored (gensym))
(overlay-start (gensym))
(overlay-end (gensym)))
`(let ((,bmap-stack (list ,(cadr place-and-bmap)))
(,bmap))
(while (setq ,bmap (pop ,bmap-stack))
(if (phpinspect-overlay-p ,bmap)
(let ((,overlay-start (phpinspect-overlay-start ,bmap))
(,overlay-end (phpinspect-overlay-end ,bmap)))
(maphash (lambda (,_ignored ,place)
(setq ,place (phpinspect-overlay-wrap-meta ,bmap ,place))
(when (and (<= ,overlay-start
(phpinspect-meta-start ,place))
(>= ,overlay-end
(phpinspect-meta-end ,place)))
(if (phpinspect-meta-overlay ,place)
(push (phpinspect-meta-overlay ,place) ,bmap-stack)
,@body)))
(phpinspect-bmap-meta (phpinspect-overlay-bmap ,bmap))))
(maphash (lambda (,_ignored ,place)
(if (phpinspect-meta-overlay ,place)
(push (phpinspect-meta-overlay ,place) ,bmap-stack)
,@body))
(phpinspect-bmap-meta ,bmap)))))))
(defsubst phpinspect-bmap-register (bmap start end token &optional whitespace-before overlay parent)
(let* ((starts (phpinspect-bmap-starts bmap))
(ends (phpinspect-bmap-ends bmap))
(meta (phpinspect-bmap-meta bmap))
(current-row (phpinspect-bmap-current-row bmap))
(current-row-start (phpinspect-bmap-current-row-start bmap))
(current-row-end (phpinspect-bmap-current-row-end bmap))
(existing-end (gethash end ends))
(whitespace-before (phpinspect-bmap-whitespace-before bmap))
(token-meta (phpinspect--make-meta nil start end whitespace-before token)))
(setf (phpinspect-bmap-whitespace-before bmap) "")
(token-meta (phpinspect-make-meta nil start end whitespace-before token overlay)))
(unless whitespace-before
(setq whitespace-before ""))
(puthash start token-meta starts)
@ -96,32 +202,38 @@
(puthash token token-meta meta)
(cond ((not current-row-start)
(setf (phpinspect-bmap-current-row-start bmap) start)
(setf (phpinspect-bmap-current-row-end bmap) end))
((and (>= end current-row-end)
(<= start current-row-start))
(dolist (child current-row)
;; Set parent
(setcar child token-meta))
(setf (phpinspect-bmap-current-row-start bmap) nil)
(setf (phpinspect-bmap-current-row bmap) nil))
((> end current-row-end)
(setf (phpinspect-bmap-current-row-end bmap) end)))
(when parent
(dolist (child current-row)
;; Set parent
(setf (phpinspect-meta-parent child) token-meta))
(setf (phpinspect-bmap-current-row bmap) nil))
(push token-meta (phpinspect-bmap-current-row bmap))))
(defsubst phpinspect-overlay-p (overlay)
(eq 'overlay (car overlay)))
(and (listp overlay)
(eq 'overlay (car overlay))))
(defsubst phpinspect-overlay-wrap-meta (overlay meta)
(when meta
(setq meta (cl-copy-list meta))
(setf (phpinspect--meta-start meta)
(+ (phpinspect--meta-start meta) (phpinspect-overlay-delta overlay)))
(setf (phpinspect--meta-end meta)
(+ (phpinspect--meta-end meta) (phpinspect-overlay-delta overlay)))
(setf (phpinspect--meta-overlayed meta) overlay)
(setf (phpinspect-meta-start meta)
(+ (phpinspect-meta-start meta) (phpinspect-overlay-delta overlay)))
(setf (phpinspect-meta-end meta)
(+ (phpinspect-meta-end meta) (phpinspect-overlay-delta overlay)))
(when (phpinspect-meta-overlay meta)
(let ((meta-overlay (cl-copy-list (phpinspect-meta-overlay meta))))
(setf (phpinspect-overlay-start meta-overlay)
(+ (phpinspect-overlay-start meta-overlay)
(phpinspect-overlay-delta overlay)))
(setf (phpinspect-overlay-end meta-overlay)
(+ (phpinspect-overlay-end meta-overlay)
(phpinspect-overlay-delta overlay)))
(setf (phpinspect-overlay-delta meta-overlay)
(+ (phpinspect-overlay-delta meta-overlay)
(phpinspect-overlay-delta overlay)))
(setf (phpinspect-meta-overlay meta) meta-overlay)))
meta))
@ -143,8 +255,13 @@
(when (phpinspect-overlay-overlaps-point overlay point)
(throw 'found overlay)))))
;; (cl-defmethod phpinspect-bmap-tokens-overlapping ((bmap phpinspect-bmap) point)
;; (
(defsubst phpinspect-bmap-tokens-overlapping (bmap point)
(let ((tokens))
(phpinspect-bmap-iterate (meta bmap)
(when (phpinspect-meta-overlaps-point meta point)
(push meta tokens)))
(sort tokens #'phpinspect-meta-sort-width)))
(cl-defmethod phpinspect-bmap-token-meta ((overlay (head overlay)) token)
(phpinspect-bmap-token-meta (phpinspect-overlay-bmap overlay) token))
@ -161,29 +278,21 @@
(and (listp token)
(symbolp (car token))))
(defsubst phpinspect-overlay-overlaps-point (overlay point)
(and (> (phpinspect-overlay-end overlay) point)
(<= (phpinspect-overlay-start overlay) point)))
(defsubst phpinspect-bmap-last-token-before-point (bmap point)
(let* ((ends (phpinspect-bmap-ends bmap))
(ending))
(unless (hash-table-empty-p ends)
(while (not (or (<= point 0) (setq ending (gethash point ends))))
(setq point (- point 1)))
(car (last ending)))))
(defsubst phpinspect-overlay-bmap (overlay)
(car (nthcdr 4 overlay)))
(defsubst phpinspect-overlay-delta (overlay)
(cadddr overlay))
(defsubst phpinspect-overlay-start (overlay)
(cadr overlay))
(defsubst phpinspect-overlay-end (overlay)
(caddr overlay))
(defsubst phpinspect-bmap-overlay (bmap bmap-overlay token-meta pos-delta)
(defsubst phpinspect-bmap-overlay (bmap bmap-overlay token-meta pos-delta &optional whitespace-before)
(let* ((overlays (phpinspect-bmap-overlays bmap))
(start (+ (phpinspect--meta-start token-meta) pos-delta))
(end (+ (phpinspect--meta-end token-meta) pos-delta))
(start (+ (phpinspect-meta-start token-meta) pos-delta))
(end (+ (phpinspect-meta-end token-meta) pos-delta))
(overlay `(overlay ,start ,end ,pos-delta ,bmap-overlay))
(before))
(phpinspect-bmap-register bmap start end (phpinspect--meta-token token-meta))
(phpinspect-bmap-register bmap start end (phpinspect-meta-token token-meta) whitespace-before overlay)
(if overlays
(progn
@ -193,13 +302,25 @@
(throw 'break nil)
(setq overlays (cdr overlays)))))
(if before
(if (and before (cdr overlays))
;; Append after
(setcdr overlays (cons overlay (cdr overlays)))
(progn
;;(message "appending in the middle")
(setcdr overlays (cons overlay (cdr overlays))))
;; Append at end of overlay list
(setcdr (last (phpinspect-bmap-overlays bmap)) overlay)))
;;(message "appending at the end")
(nconc (phpinspect-bmap-overlays bmap) (list overlay))))
;;(message "appending at the start")
(push overlay (phpinspect-bmap-overlays bmap)))))
(defun phpinspect-bmap-make-location-resolver (bmap)
(lambda (token)
(let ((meta (phpinspect-bmap-token-meta bmap token)))
(if meta
(phpinspect-make-region (phpinspect-meta-start meta)
(phpinspect-meta-end meta))
(phpinspect-make-region 0 0)))))
(provide 'phpinspect-bmap)
;;; phpinspect-bmap.el ends here

@ -23,7 +23,8 @@
;;; Code:
(require 'phpinspect-tree)
;;(require 'phpinspect-tree)
(require 'phpinspect-bmap)
(require 'phpinspect-edtrack)
(defvar-local phpinspect-current-buffer nil
@ -31,76 +32,60 @@
buffer. This variable is only set for buffers where
`phpinspect-mode' is active. Also see `phpinspect-buffer'.")
(cl-defstruct (phpinspect-buffer (:constructor phpinspect-make-buffer))
"An object containing phpinspect related metadata linked to an
emacs buffer."
(buffer nil
:type buffer
:documentation "The associated emacs buffer")
(tree (phpinspect-make-tree)
:type phpinspect-tree
:documentation
"A tree containing metadata associated with tokens.")
(tree nil
:documentation
"Parsed token tree that resulted from last parse")
(map nil
:type phpinspect-bmap)
(edit-tracker (phpinspect-make-edtrack)
:type phpinspect-edtrack)
(whitespace nil
:type string
:documentation
"Whitespace parsed before the next token to be parsed"))
:type phpinspect-edtrack))
(cl-defmethod phpinspect-buffer-parse ((buffer phpinspect-buffer))
"Parse the PHP code in the the emacs buffer that this object is
linked with."
(phpinspect-buffer-propagate-taints buffer)
(with-current-buffer (phpinspect-buffer-buffer buffer)
(let* ((tree (phpinspect-make-tree :start (point-min)
:end (+ 1 (point-max))))
(buffer-tree (phpinspect-buffer-tree buffer))
(let* ((map (phpinspect-make-bmap))
(buffer-map (phpinspect-buffer-map buffer))
(ctx (phpinspect-make-pctx
:tree tree
:bmap map
:incremental t
:previous-tree (unless (phpinspect-tree-empty-p buffer-tree) buffer-tree)
:previous-bmap buffer-map
:edtrack (phpinspect-buffer-edit-tracker buffer))))
(phpinspect-with-parse-context ctx
(let ((parsed (phpinspect-parse-current-buffer)))
;; Set tree root to the child containing the root parsed token.
(setq tree (seq-elt (phpinspect-tree-children tree) 0))
(setf (phpinspect-tree-parent tree) nil)
(setf (phpinspect-buffer-tree buffer) tree)
(setf (phpinspect-buffer-map buffer) map)
(setf (phpinspect-buffer-tree buffer) parsed)
(phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer))
;; return
parsed)))))
(cl-defmethod phpinspect-buffer-reparse ((buffer phpinspect-buffer))
(setf (phpinspect-buffer-tree buffer) (phpinspect-make-tree))
(setf (phpinspect-buffer-map buffer) (phpinspect-make-bmap))
(phpinspect-buffer-parse buffer))
(defsubst phpinspect-buffer-parse-tree (buffer)
(defsubst phpinspect-buffer-parse-map (buffer)
(phpinspect-buffer-parse buffer)
(phpinspect-buffer-tree buffer))
(phpinspect-buffer-map buffer))
(cl-defmethod phpinspect-buffer-register-edit
((buffer phpinspect-buffer) (start integer) (end integer) (pre-change-length integer))
(phpinspect-edtrack-register-edit
(phpinspect-buffer-edit-tracker buffer) start end pre-change-length))
(cl-defmethod phpinspect-buffer-propagate-taints ((buffer phpinspect-buffer))
(let ((tracker (phpinspect-buffer-edit-tracker buffer)))
(when (phpinspect-edtrack-has-taints-p tracker)
(seq-doseq (taint (phpinspect-tree-children (phpinspect-edtrack-taint-pool tracker)))
(let* ((region (phpinspect-make-region (phpinspect-tree-start taint)
(phpinspect-tree-end taint)))
(tainted (phpinspect-tree-traverse-overlapping
(phpinspect-buffer-tree buffer) region)))
(dolist (meta tainted)
(setf (phpinspect-meta-tainted meta) t))))
(cl-defmethod phpinspect-buffer-tokens-enclosing-point ((buffer phpinspect-buffer) point)
(phpinspect-bmap-tokens-overlapping (phpinspect-buffer-map buffer) point))
(phpinspect-edtrack-clear-taints tracker))))
(cl-defmethod phpinspect-buffer-token-meta ((buffer phpinspect-buffer) token)
(phpinspect-bmap-token-meta (phpinspect-buffer-map buffer) token))
(cl-defmethod phpinspect-buffer-tokens-enclosing-point ((buffer phpinspect-buffer) point)
(phpinspect-tree-traverse-overlapping (phpinspect-buffer-tree buffer) point))
(cl-defmethod phpinspect-buffer-location-resover ((buffer phpinspect-buffer))
(phpinspect-bmap-make-location-resolver (phpinspect-buffer-map buffer)))
(provide 'phpinspect-buffer)

@ -33,13 +33,22 @@
(cons (car (phpinspect-edtrack-taint-pool track))
(cl-copy-list (cdr (phpinspect-edtrack-taint-pool track)))))
(gv-define-setter phpinspect-taint-iterator-current (current iter) `(setcar ,iter ,current))
(defsubst phpinspect-taint-iterator-current (iter)
(car iter))
(defsubst phpinspect-taint-iterator-token-is-tainted-p (iter meta)
(let ((current (car iter)))
(when current
(while (and current (> (phpinspect--meta-start meta) (phpinspect-taint-end current)))
(setq current (pop (cdr iter))))
(when (phpinspect-taint-iterator-current iter)
(while (and (phpinspect-taint-iterator-current iter)
(> (phpinspect-meta-start meta)
(phpinspect-taint-end
(phpinspect-taint-iterator-current iter))))
(setf (phpinspect-taint-iterator-current iter) (pop (cdr iter))))
(and current (phpinspect-taint-overlaps-meta current meta)))))
(and (phpinspect-taint-iterator-current iter)
(phpinspect-taint-overlaps-meta
(phpinspect-taint-iterator-current iter) meta))))
(defsubst phpinspect-edit-original-end (edit)
(or (caar edit) 0))
@ -106,10 +115,10 @@
(phpinspect-taint-overlaps-point taint2 (phpinspect-taint-end taint1))))
(defsubst phpinspect-taint-overlaps-meta (taint meta)
(or (phpinspect-taint-overlaps-point taint (phpinspect--meta-start meta))
(phpinspect-taint-overlaps-point taint (phpinspect--meta-end meta))
(phpinspect--meta-overlaps-point meta (phpinspect-taint-start taint))
(phpinspect--meta-overlaps-point meta (phpinspect-taint-end taint))))
(or (phpinspect-taint-overlaps-point taint (phpinspect-meta-start meta))
(phpinspect-taint-overlaps-point taint (phpinspect-meta-end meta))
(phpinspect-meta-overlaps-point meta (phpinspect-taint-start taint))
(phpinspect-meta-overlaps-point meta (phpinspect-taint-end taint))))
(defsubst phpinspect-edtrack-clear-taint-pool (track)
(setf (phpinspect-edtrack-taint-pool track) nil))

@ -35,50 +35,55 @@
(goto-char point)
(insert data)))
(cl-defmethod phpinspect-namespace-body-start ((tree phpinspect-tree))
(if (not (seq-emtpy-p (phpinspect-tree-children tree)))
(let ((block (seq-elt (phpinspect-tree-children tree) 2)))
(if (phpinspect-block-p (phpinspect-tree-meta-token block))
(phpinspect-tree-start block)
(phpinspect-tree-end (seq-elt (phpinspect-tree-children tree) 1))))
0))
(defun phpinspect-add-use (fqn buffer &optional namespace-tree)
(defun phpinspect-add-use (fqn buffer &optional namespace-token)
"Add use statement for FQN to BUFFER.
If NAMESPACE-TREE is non-nil, it is assumed to be an instance of
`phpinspect-tree' containing metadata of a namespace token that
was parsed from BUFFER. Its location will be used to find a
If NAMESPACE-TOKEN is non-nil, it is assumed to be a token that
was parsed from BUFFER and its location will be used to find a
buffer position to insert the use statement at."
(when (string-match "^\\\\" fqn)
(setq fqn (string-trim-left fqn "\\\\")))
(if namespace-tree
(let* ((existing-use (seq-find (phpinspect-tree-meta-token-filter #'phpinspect-use-p)
(phpinspect-namespace-body namespace-tree)))
(if namespace-token
(let* ((meta (phpinspect-bmap-token-meta
(phpinspect-buffer-map buffer) namespace-token))
(existing-use (seq-find #'phpinspect-use-p
(phpinspect-namespace-body namespace-token)))
(namespace-block (phpinspect-namespace-block namespace-token)))
(if existing-use
(phpinspect-insert-at-point
(phpinspect-tree-start existing-use) (format "use %s;%c" fqn ?\n))
(phpinspect-insert-at-point
(+ 1 (phpinspect-namespace-body-start namespace-tree))
(format "%c%cuse %s;%c" ?\n ?\n fqn ?\n))))
(phpinspect-meta-start
(phpinspect-buffer-token-meta buffer existing-use))
(format "use %s;%c" fqn ?\n))
(if namespace-block
(phpinspect-insert-at-point
(+ 1 (phpinspect-meta-start
(phpinspect-buffer-token-meta buffer namespace-block)))
(format "%c%cuse %s;%c" ?\n ?\n fqn ?\n))
(phpinspect-insert-at-point
(phpinspect-meta-end
(phpinspect-buffer-token-meta
buffer (seq-find #'phpinspect-terminator-p namespace-token)))
(format "%c%cuse %s;%c" ?\n ?\n fqn ?\n)))))
;; else
(let ((existing-use (seq-find (phpinspect-tree-meta-token-filter #'phpinspect-use-p)
(let ((existing-use (seq-find #'phpinspect-use-p
(phpinspect-buffer-tree buffer))))
(if existing-use
(phpinspect-insert-at-point
(phpinspect-tree-start existing-use)
(phpinspect-meta-start
(phpinspect-buffer-token-meta buffer existing-use))
(format "use %s;%c" fqn ?\n))
(let ((first-token (seq-elt (phpinspect-tree-children (phpinspect-buffer-tree buffer)) 0)))
(if (and (phpinspect-word-p (phpinspect-tree-meta-token first-token))
(string= "declare" (cadr (phpinspect-tree-meta-token first-token))))
(let ((first-token (cadr (phpinspect-buffer-tree buffer))))
(if (and (phpinspect-word-p first-token)
(string= "declare" (cadr first-token)))
(phpinspect-insert-at-point
(phpinspect-tree-end (seq-find (phpinspect-tree-meta-token-filter #'phpinspect-terminator-p)
(phpinspect-tree-children (phpinspect-buffer-tree buffer))))
(format "%c%cuse %s;%c" ?\n ?\n fqn ?\n))
(phpinspect-meta-end
(phpinspect-buffer-token-meta
buffer (seq-find #'phpinspect-terminator-p (phpinspect-buffer-tree buffer))))
(format "%c%cuse %s;%c" ?\n ?\n fqn ?\n))
(phpinspect-insert-at-point
(phpinspect-tree-start first-token)
(phpinspect-meta-start
(phpinspect-buffer-token-meta buffer first-token))
(format "%c%cuse %s;%c%c" ?\n ?\n fqn ?\n ?\n))))))))
(defun phpinspect-add-use-interactive (typename buffer project &optional namespace-token)
@ -104,9 +109,10 @@ buffer position to insert the use statement at."
that there are import (\"use\") statements for them."
(interactive)
(if phpinspect-current-buffer
(phpinspect-buffer-parse phpinspect-current-buffer)
(let* ((tree (phpinspect-buffer-tree phpinspect-current-buffer))
(index (phpinspect--index-tokens tree))
(let* ((tree (phpinspect-buffer-parse phpinspect-current-buffer))
(index (phpinspect--index-tokens
tree nil (phpinspect-buffer-location-resolver
phpinspect-current-buffer)))
(classes (alist-get 'classes index))
(imports (alist-get 'imports index))
(project (phpinspect--cache-get-project-create
@ -115,10 +121,22 @@ that there are import (\"use\") statements for them."
(dolist (class classes)
(let* ((class-imports (alist-get 'imports class))
(used-types (alist-get 'used-types class))
(meta (alist-get 'token-metadata class)))
(class-name (alist-get 'class-name class))
(region))
(dolist (type used-types)
;; Retrieve latest version of class location data changes with
;; each added use statement + reindex.
(setq region
(alist-get 'location
(phpinspect-index-get-class
index class-name)))
(let ((namespace
(phpinspect-tree-find-parent-meta-matching tree #'phpinspect-namespace-p)))
(seq-find #'phpinspect-namespace-p
(phpinspect-buffer-tokens-enclosing-point
phpinspect-current-buffer (phpinspect-meta-start meta)))))
;; Add use statements for types that aren't imported.
(unless (or (or (alist-get type class-imports)
@ -132,7 +150,6 @@ that there are import (\"use\") statements for them."
(phpinspect-project-autoload project))))
(phpinspect-add-use-interactive
type phpinspect-current-buffer project namespace)
;;;; FIXED?
;; Buffer has been modified by adding type, update tree +
;; location map. This is not optimal but will have to do until
;; partial parsing is implemented.
@ -143,6 +160,11 @@ that there are import (\"use\") statements for them."
;; blocks this could cause problems as a namespace may grow by
;; added import statements and start envelopping the classes
;; below it.
(phpinspect-buffer-parse phpinspect-current-buffer)))))))))
(setq index
(phpinspect--index-tokens
(phpinspect-buffer-parse phpinspect-current-buffer)
nil
(phpinspect-buffer-location-resolver
phpinspect-current-buffer)))))))))))
(provide 'phpinspect-imports)

@ -176,7 +176,7 @@ function (think \"new\" statements, return types etc.)."
methods))
(defun phpinspect--index-class (imports type-resolver class &optional doc-block token-metadata)
(defun phpinspect--index-class (imports type-resolver location-resolver class &optional doc-block)
"Create an alist with relevant attributes of a parsed class."
(phpinspect--log "INDEXING CLASS")
(let ((methods)
@ -324,7 +324,7 @@ function (think \"new\" statements, return types etc.)."
`(,class-name .
(phpinspect--indexed-class
(class-name . ,class-name)
(token-metadata . ,token-metadata)
(location . ,(funcall location-resolver class))
(imports . ,imports)
(methods . ,methods)
(static-methods . ,static-methods)
@ -336,36 +336,15 @@ function (think \"new\" statements, return types etc.)."
(used-types . ,(mapcar #'phpinspect-intern-name
(seq-uniq used-types #'string=))))))))
(cl-defmethod phpinspect-namespace-body (namespace)
(defsubst phpinspect-namespace-body (namespace)
"Return the nested tokens in NAMESPACE tokens' body.
Accounts for namespaces that are defined with '{}' blocks."
(if (phpinspect-block-p (caddr namespace))
(cdaddr namespace)
(cdr namespace)))
(cl-defmethod phpinspect-namespace-body ((namespace phpinspect-tree))
(if (= 3 (seq-length (phpinspect-tree-children namespace)))
(phpinspect-tree-children (seq-elt (phpinspect-tree-children namespace) 2))
(phpinspect-tree-children namespace)))
(cl-defmethod phpinspect--index-classes-in-tokens
(imports (tree phpinspect-tree) type-resolver-factory &optional namespace)
(let ((comment-before)
(indexed))
(seq-doseq (child (phpinspect-tree-children tree))
(let ((token (phpinspect-tree-meta-token child)))
(cond ((phpinspect-doc-block-p token)
(setq comment-before token))
((phpinspect-class-p token)
(push (phpinspect--index-class
imports (funcall type-resolver-factory imports token namespace)
token comment-before (phpinspect-tree-value child))
indexed)
(setq comment-before nil)))))
indexed))
(cl-defmethod phpinspect--index-classes-in-tokens
(imports tokens type-resolver-factory &optional namespace)
(defun phpinspect--index-classes-in-tokens
(imports tokens type-resolver-factory location-resolver &optional namespace indexed)
"Index the class tokens among TOKENS.
NAMESPACE will be assumed the root namespace if not provided"
@ -377,7 +356,7 @@ NAMESPACE will be assumed the root namespace if not provided"
((phpinspect-class-p token)
(push (phpinspect--index-class
imports (funcall type-resolver-factory imports token namespace)
token comment-before)
location-resolver token comment-before)
indexed)
(setq comment-before nil))))
indexed))
@ -398,35 +377,24 @@ NAMESPACE will be assumed the root namespace if not provided"
(defun phpinspect--uses-to-types (uses)
(mapcar #'phpinspect--use-to-type uses))
(cl-defmethod phpinspect--index-namespace
((namespace phpinspect-tree) type-resolver-factory)
(let* ((tokens (phpinspect-meta-token (phpinspect-tree-value namespace)))
(imports (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p tokens))))
(phpinspect--index-classes-in-tokens
imports namespace type-resolver-factory (cadadr tokens))))
(cl-defmethod phpinspect--index-namespace (namespace type-resolver-factory)
(defun phpinspect--index-namespace (namespace type-resolver-factory location-resolver)
(phpinspect--index-classes-in-tokens
(phpinspect--uses-to-types (seq-filter #'phpinspect-use-p namespace))
namespace
type-resolver-factory (cadadr namespace)))
type-resolver-factory location-resolver (cadadr namespace) nil))
(cl-defmethod phpinspect--index-namespaces
(namespaces type-resolver-factory &optional indexed)
(defun phpinspect--index-namespaces
(namespaces type-resolver-factory location-resolver &optional indexed)
(if namespaces
(progn
(push (phpinspect--index-namespace (pop namespaces) type-resolver-factory)
(push (phpinspect--index-namespace (pop namespaces)
type-resolver-factory
location-resolver)
indexed)
(phpinspect--index-namespaces namespaces type-resolver-factory indexed))
(phpinspect--index-namespaces namespaces type-resolver-factory
location-resolver indexed))
(apply #'append (nreverse indexed))))
(cl-defmethod phpinspect--index-namespaces
((namespaces phpinspect-slice) type-resolver-factory &optional indexed)
(seq-doseq (namespace namespaces)
(push (phpinspect--index-namespace namespace type-resolver-factory) indexed))
(nreverse indexed))
(defun phpinspect--index-functions (&rest _args)
"TODO: implement function indexation. This is a stub function.")
@ -462,39 +430,30 @@ Return value is a list of the types that are \"newed\"."
(push token previous-tokens)))
used-types))
(cl-defmethod phpinspect--index-tokens (tokens &optional type-resolver-factory)
(defun phpinspect--index-tokens (tokens &optional type-resolver-factory location-resolver)
"Index TOKENS as returned by `phpinspect--parse-current-buffer`."
(unless type-resolver-factory
(setq type-resolver-factory #'phpinspect--make-type-resolver))
(unless location-resolver
(setq location-resolver (lambda (_) (list 0 0))))
(let ((imports (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p tokens))))
`(phpinspect--root-index
(imports . ,imports)
(classes . (,@(phpinspect--index-namespaces
(seq-filter #'phpinspect-namespace-p tokens)
type-resolver-factory)
,@(phpinspect--index-classes-in-tokens
imports tokens type-resolver-factory)))
(used-types . ,(phpinspect--find-used-types-in-tokens tokens))
,(append
(append '(classes)
(phpinspect--index-namespaces (seq-filter #'phpinspect-namespace-p tokens)
type-resolver-factory
location-resolver)
(phpinspect--index-classes-in-tokens
imports tokens type-resolver-factory location-resolver)))
,(append '(used-types)
(phpinspect--find-used-types-in-tokens tokens))
(functions))
;; TODO: Implement function indexation
))
(cl-defmethod phpinspect--index-tokens ((tree phpinspect-tree) &optional type-resolver-factory)
(unless type-resolver-factory (setq type-resolver-factory #'phpinspect--make-type-resolver))
(let* ((tokens (phpinspect-meta-token (phpinspect-tree-value tree)))
(imports (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p tokens))))
`(phpinspect--root-index
(imports . ,imports)
(classes . (,@(phpinspect--index-namespaces
(seq-filter (phpinspect-tree-meta-token-filter #'phpinspect-namespace-p)
(phpinspect-tree-children tree))
type-resolver-factory)
,@(phpinspect--index-classes-in-tokens imports tree type-resolver-factory)))
(used-types . ,(phpinspect--find-used-types-in-tokens tokens))
(functions))))
(defun phpinspect-get-or-create-cached-project-class (project-root class-fqn)
(when project-root
(let ((project (phpinspect--cache-get-project-create
@ -502,6 +461,12 @@ Return value is a list of the types that are \"newed\"."
project-root)))
(phpinspect-project-get-class-create project class-fqn))))
(cl-defmethod phpinspect-index-get-class
((index (head phpinspect--root-index) (class-name phpinspect--type)))
(alist-get class-name (alist-get 'classes index)
nil nil #'phpinspect--type=))
(defun phpinspect-index-current-buffer ()
"Index a PHP file for classes and the methods they have"
(phpinspect--index-tokens (phpinspect-parse-current-buffer)))

@ -23,7 +23,7 @@
;;; Code:
(require 'phpinspect-tree)
;;(require 'phpinspect-tree)
(require 'phpinspect-edtrack)
(require 'phpinspect-bmap)
@ -181,9 +181,6 @@ Type can be any of the token types returned by
"Get the argument list of a function"
(seq-find #'phpinspect-list-p (seq-find #'phpinspect-declaration-p php-func nil) nil))
(defun phpinspect-function-block (token)
(cadr token))
(defun phpinspect-annotation-p (token)
(phpinspect-token-type-p token :annotation))
@ -457,52 +454,6 @@ token is \";\", which marks the end of a statement in PHP."
;; Return
tokens)))))
(cl-defstruct (phpinspect-meta (:constructor phpinspect-make-meta))
"An object that represents the metadata associated with a parsed token."
(token nil
:type phpinspect-token
:documentation
"The token that metadata is associated with.")
(whitespace-before ""
:type string
:documentation
"Whitespace parsed before this token")
(tree nil
:type phpinspect-tree)
(tainted nil
:type bool
:documentation
"Whether or not the text of this token has been changed in the buffer")
(handler nil
:type phpinspect-handler
:documentation
"The handler that was used to parse token. (see `phpinspect-defhandler')"))
(defsubst phpinspect-meta-token-filter (predicate)
(lambda (meta) (funcall predicate (phpinspect-meta-token meta))))
(defsubst phpinspect-tree-meta-token-filter (predicate)
(lambda (tree)
(funcall predicate (phpinspect-meta-token (phpinspect-tree-value tree)))))
(defsubst phpinspect-tree-meta-token (tree)
(phpinspect-meta-token (phpinspect-tree-value tree)))
(defsubst phpinspect-meta-start (meta)
(phpinspect-tree-start (phpinspect-meta-tree meta)))
(defsubst phpinspect-meta-end (meta)
(phpinspect-tree-end (phpinspect-meta-tree meta)))
(defsubst phpinspect-tree-find-parent-meta-matching-token (tree predicate)
(if (funcall (phpinspect-tree-meta-token-filter predicate) tree)
tree
(catch 'found
(while (phpinspect-tree-parent tree)
(setq tree (phpinspect-tree-parent tree))
(when (funcall (phpinspect-tree-meta-token-filter predicate) tree)
(throw 'found tree))))))
(defvar phpinspect-parse-context nil
"An instance of `phpinspect-pctx' that is used when
parsing. Usually used in combination with
@ -522,123 +473,26 @@ parsing. Usually used in combination with
(incremental nil)
(edtrack nil
:type phpinspect-edtrack)
(tree nil
:type phpinspect-tree)
(bmap (phpinspect-make-bmap)
:type phpinspect-bmap)
(previous-bmap nil
:type phpinspect-bmap)
(previous-tree nil
:type phpinspect-tree)
(query-tree nil)
(whitespace-before ""
:type string))
(defsubst phpinspect-pctx-find-existing-node-at-point (ctx point)
(let ((query-tree (or (phpinspect-pctx-query-tree ctx)
(phpinspect-pctx-previous-tree ctx))))
(when query-tree
(setf (phpinspect-pctx-query-tree ctx)
(phpinspect-tree-find-next-relative-starting-at query-tree point)))))
(cl-defmethod phpinspect-pctx-register-token
((pctx phpinspect-pctx) token start end handler)
(phpinspect-bmap-register (phpinspect-pctx-bmap pctx) start end token))
;; (let* ((meta (phpinspect-make-meta
;; :token token
;; :handler handler
;; :whitespace-before (phpinspect-pctx-whitespace-before pctx)))
;; (node (phpinspect-tree-insert
;; (phpinspect-pctx-tree pctx) start end meta)))
;; (setf (phpinspect-meta-tree meta) node)
;; (setf (phpinspect-pctx-whitespace-before pctx) "")
;; meta))
((pctx phpinspect-pctx) token start end)
(phpinspect-bmap-register
(phpinspect-pctx-bmap pctx) start end token (phpinspect-pctx-consume-whitespace pctx)))
(cl-defmethod phpinspect-pctx-register-whitespace
((pctx phpinspect-pctx) (whitespace string))
(setf (phpinspect-pctx-whitespace-before pctx) whitespace))
(defun phpinspect-make-incremental-parser-function (tree-type handler-list &optional delimiter-predicate)
"Like `phpinspect-make-parser-function', but returned function is able to reuse an already parsed tree."
(let ((handlers (mapcar
(lambda (handler-name)
(let* ((handler-name (symbol-name handler-name))
(handler (intern-soft handler-name phpinspect-handler-obarray)))
(if handler
handler
(error "No handler found by name \"%s\"" handler-name))))
handler-list))
(delimiter-predicate (if (symbolp delimiter-predicate)
`(quote ,delimiter-predicate)
delimiter-predicate)))
`(lambda (context buffer max-point &optional continue-condition root)
(with-current-buffer buffer
(let ((tokens)
(root-start (point))
(edtrack (phpinspect-pctx-edtrack context))
(current-tree (phpinspect-pctx-tree context))
(previous-tree (phpinspect-pctx-previous-tree context))
(delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate)))
(phpinspect-pctx-save-whitespace context
(while (and (< (point) max-point)
(if continue-condition (funcall continue-condition) t)
(not (if delimiter-predicate
(funcall delimiter-predicate (car (last tokens)))
nil)))
(cond ,@(mapcar
(lambda (handler)
`((looking-at ,(plist-get (symbol-value handler) 'regexp))
(let* ((match (match-string 0))
(start-position (point))
(original-position
(when (and previous-tree edtrack)
(phpinspect-edtrack-original-position-at-point edtrack start-position)))
(existing-node)
(existing-meta)
(current-end-position)
(token))
(unless (not previous-tree)
(setq existing-node (phpinspect-pctx-find-existing-node-at-point
context original-position))
(when existing-node
(setq existing-meta (phpinspect-tree-value existing-node)
current-end-position (phpinspect-edtrack-current-position-at-point
edtrack (phpinspect-tree-end existing-node)))))
(if (and existing-node
(not (or (phpinspect-root-p (phpinspect-meta-token existing-meta))
(phpinspect-meta-tainted existing-meta))))
(progn
(setq existing-node (phpinspect-tree-detach existing-node))
(setq token (phpinspect-meta-token existing-meta))
;; Alter regions to current token position in buffer
(let ((delta (- start-position original-position)))
(unless (= 0 delta)
;; (message "Shifting tree with delta %d" delta)
;; (message "point: %d, start position: %d" (point) start-position)
(phpinspect-tree-shift existing-node delta)))
(goto-char current-end-position)
;; Insert existing token into new tree
(phpinspect-tree-insert-node current-tree existing-node))
(progn
(setq token (funcall ,(symbol-function handler) match max-point))
(when token
(phpinspect-pctx-register-token context token start-position (point) ,handler))))
(when token
(if (null tokens)
(setq tokens (list token))
(progn
(nconc tokens (list token))))))))
handlers)
(t (forward-char)))))
(push ,tree-type tokens)
(when root
(phpinspect-pctx-register-token context tokens root-start (point) nil))
;; Return
tokens)))))
(cl-defmethod phpinspect-pctx-consume-whitespace ((pctx phpinspect-pctx))
(let ((whitespace (phpinspect-pctx-whitespace-before pctx)))
(setf (phpinspect-pctx-whitespace-before pctx) "")
whitespace))
(defun phpinspect-make-bmap-parser-function (tree-type handler-list &optional delimiter-predicate)
"Like `phpinspect-make-parser-function', but returned function is able to reuse an already parsed tree."
@ -684,23 +538,25 @@ parsing. Usually used in combination with
(when existing-meta
(setq current-end-position (phpinspect-edtrack-current-position-at-point
edtrack (phpinspect--meta-end existing-meta)))))
edtrack (phpinspect-meta-end existing-meta)))))
(if (and existing-meta
(not (or (phpinspect-root-p (phpinspect--meta-token existing-meta))
(not (or (phpinspect-root-p (phpinspect-meta-token existing-meta))
(phpinspect-taint-iterator-token-is-tainted-p taint-iterator existing-meta))))
(progn
(setq token (phpinspect--meta-token existing-meta))
(setq token (phpinspect-meta-token existing-meta))
;; Re-register existing token
(let ((delta (- start-position original-position)))
(phpinspect-bmap-overlay bmap previous-bmap existing-meta delta))
(phpinspect-bmap-overlay
bmap previous-bmap existing-meta delta
(phpinspect-pctx-consume-whitespace context)))
(goto-char current-end-position))
(progn
(setq token (funcall ,(symbol-function handler) match max-point))
(when token
(phpinspect-pctx-register-token context token start-position (point) ,handler))))
(phpinspect-pctx-register-token context token start-position (point)))))
(when token
(if (null tokens)
(setq tokens (list token))
@ -710,7 +566,7 @@ parsing. Usually used in combination with
(t (forward-char)))))
(push ,tree-type tokens)
(when root
(phpinspect-pctx-register-token context tokens root-start (point) nil))
(phpinspect-pctx-register-token context tokens root-start (point)))
;; Return
tokens)))))

@ -128,75 +128,82 @@ candidate. Candidates can be indexed functions and variables.")
(push enclosing-token (phpinspect--resolvecontext-enclosing-tokens
resolvecontext)))
(cl-defmethod phpinspect-find-statement-before-point
((tree phpinspect-tree) (point integer))
(let ((children (seq-reverse (seq-into (phpinspect-tree-children tree) 'slice))))
(defsubst phpinspect-blocklike-p (token)
(or (phpinspect-block-p token)
(phpinspect-function-p token)
(phpinspect-class-p token)
(phpinspect-namespace-p token)))
(defun phpinspect-find-statement-before-point (bmap meta point)
(message "going through %s" (phpinspect-meta-token meta))
(let ((children (seq-reverse (cdr (phpinspect-meta-token meta)))))
(let ((previous-siblings))
(catch 'break
(seq-doseq (child children)
(when (< (phpinspect-tree-start child) point)
(when (phpinspect-end-of-statement-p (phpinspect-tree-meta-token child))
(throw 'break nil))
(push child previous-siblings))))
(catch 'return
(dolist (child children)
(when (phpinspect-probably-token-p child)
(message "probably token: %s" child)
;; (message "Child: %s" child)
(setq child (phpinspect-bmap-token-meta bmap child))
(when (< (phpinspect-meta-start child) point)
(if (phpinspect-blocklike-p (phpinspect-meta-token child))
(progn
(message "recursing into %s" (phpinspect-meta-token child))
(throw 'return (phpinspect-find-statement-before-point bmap child point)))
(when (phpinspect-end-of-statement-p (phpinspect-meta-token child))
(message "returning %s, end of statement: %s" previous-siblings (phpinspect-meta-token child))
(throw 'return previous-siblings))
(push (phpinspect-meta-token child) previous-siblings)))))
previous-siblings))))
previous-siblings)))
(cl-defmethod phpinspect-get-resolvecontext
((tree phpinspect-tree) (point integer))
(let* ((enclosing (phpinspect-tree-traverse-overlapping tree point))
((bmap phpinspect-bmap) (point integer))
(let* ((enclosing (phpinspect-bmap-tokens-overlapping bmap point))
(enclosing-tokens)
;; When there are no enclosing tokens, point is probably at the absolute
;; end of the buffer, so we find the last child before point.
(subject (or (car enclosing) (phpinspect-tree-find-last-child-before-point tree point)))
(subject (or (car enclosing) (phpinspect-bmap-last-token-before-point bmap point)))
(subject-token)
(siblings))
;; Dig down through tokens that can contain statements
(catch 'break
(while (and subject (phpinspect-enclosing-token-p (phpinspect-meta-token subject)))
(let ((new-subject
(phpinspect-bmap-token-meta
bmap (car (last (phpinspect-meta-token subject))))))
(if new-subject
(setq subject new-subject)
(throw 'break nil)))))
(phpinspect--log "Initial resolvecontext subject token: %s"
(phpinspect-meta-token subject))
(when subject
(when (phpinspect-tree-p subject) (setq subject (phpinspect-tree-value subject)))
;; Dig down through tokens that can contain statements
(catch 'break
(while (phpinspect-enclosing-token-p (phpinspect-meta-token subject))
(let ((new-subject (phpinspect-tree-find-last-child-before-point
(phpinspect-meta-tree subject) point)))
(if new-subject
(setq subject (phpinspect-tree-value new-subject))
(throw 'break nil)))))
(phpinspect--log "Initial resolvecontext subject token: %s" (phpinspect-meta-token subject))
(setq subject-token (mapcar #'phpinspect-tree-meta-token
(phpinspect-find-statement-before-point
(phpinspect-tree-parent
(phpinspect-meta-tree subject))
point)))
(phpinspect--log "Ultimate resolvecontext subject token: %s" subject-token))
;; Iterate through subject parents to build stack of enclosing tokens
(let ((parent (phpinspect-tree-parent (phpinspect-meta-tree subject))))
(while (and parent (phpinspect-tree-value parent))
(let ((granny (phpinspect-tree-parent parent)))
(unless (and (phpinspect-block-p (phpinspect-tree-meta-token parent))
(or (not granny) (not (phpinspect-tree-value granny))
(phpinspect-function-p (phpinspect-tree-meta-token granny))
(phpinspect-class-p (phpinspect-tree-meta-token granny))))
(push (phpinspect-tree-meta-token parent) enclosing-tokens))
(setq parent (phpinspect-tree-parent parent)))))
(setq subject-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
(phpinspect-meta-parent subject)))
;; Iterate through subject parents to build stack of enclosing tokens
(let ((parent (phpinspect-meta-parent subject)))
(while parent
(let ((granny (phpinspect-meta-parent parent)))
(unless (and (phpinspect-block-p (phpinspect-meta-token parent))
(or (not granny)
(phpinspect-function-p (phpinspect-meta-token granny))
(phpinspect-class-p (phpinspect-meta-token granny))))
(push (phpinspect-meta-token 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)
:project-root (phpinspect-current-project-root))))
(defun phpinspect-subject-at-point ()
(interactive)
(unless phpinspect-current-buffer
(setq phpinspect-current-buffer (phpinspect-make-buffer :buffer (current-buffer))))
(phpinspect-get-resolvecontext (phpinspect-buffer-parse-tree phpinspect-current-buffer) (point)))
(defun phpinspect--get-resolvecontext (token &optional resolvecontext)
"Find the deepest nested incomplete token in TOKEN.
If RESOLVECONTEXT is nil, it is created. Returns RESOLVECONTEXT
@ -342,18 +349,15 @@ accompanied by all of its enclosing tokens."
(current-buffer)
(point-max)))
(defun phpinspect-parse-string-to-tree (string)
(with-temp-buffer
(insert string)
(let ((context (phpinspect-make-pctx :incremental t
:tree (phpinspect-make-tree :start (point-min)
:end (point-max)
:grow-root t))))
(phpinspect-with-parse-context context
(phpinspect-parse-current-buffer))
(seq-elt (phpinspect-tree-children (phpinspect-pctx-tree context)) 0))))
(defun phpinspect-parse-string-to-bmap (string)
(with-temp-buffer
(insert string)
(let ((context (phpinspect-make-pctx :incremental t
:bmap (phpinspect-make-bmap))))
(phpinspect-with-parse-context context
(phpinspect-parse-current-buffer))
(phpinspect-pctx-bmap context))))
(defun phpinspect-parse-string (string)
(with-temp-buffer
@ -406,20 +410,30 @@ TODO:
- Respect `eldoc-echo-area-use-multiline-p`
- This function is too big and has repetitive code. Split up and simplify.
"
(let* ((token-tree (phpinspect-buffer-parse-tree phpinspect-current-buffer))
(resolvecontext (phpinspect-get-resolvecontext token-tree (point)))
(let* ((token-map (phpinspect-buffer-parse-map phpinspect-current-buffer))
(resolvecontext (phpinspect-get-resolvecontext token-map (point)))
(parent-token (car (phpinspect--resolvecontext-enclosing-tokens
resolvecontext)))
(enclosing-token (cadr (phpinspect--resolvecontext-enclosing-tokens
resolvecontext)))
(statement (if (phpinspect-list-p (car (phpinspect--resolvecontext-enclosing-tokens
resolvecontext)))
(phpinspect--get-last-statement-in-token enclosing-token)
(phpinspect--resolvecontext-subject resolvecontext)))
(arg-list (seq-find #'phpinspect-list-p (reverse statement)))
(statement (phpinspect--resolvecontext-subject resolvecontext))
(arg-list)
(type-resolver (phpinspect--make-type-resolver-for-resolvecontext
resolvecontext))
(static))
(phpinspect--log "Enclosing token: %s" enclosing-token)
(phpinspect--log "Eldoc statement: %s" statement)
(message "Eldoc statement before checking outside list: %s" statement)
(when (and (phpinspect-list-p parent-token) enclosing-token)
(setq statement
(phpinspect-find-statement-before-point
token-map (phpinspect-bmap-token-meta token-map enclosing-token)
(phpinspect-meta-end
(phpinspect-bmap-token-meta token-map parent-token)))))
(message "Enclosing token: %s" enclosing-token)
(message "Eldoc statement: %s" statement)
(setq arg-list (seq-find #'phpinspect-list-p (reverse statement)))
(when (and (phpinspect-list-p arg-list)
enclosing-token
@ -817,7 +831,7 @@ EXPRESSION."
(enclosing-token)
(type))
(while (and enclosing-tokens (not type))
;;(phpinspect--log "Trying to find type in %s" enclosing-token)
;;(message "Trying to find type in %s" enclosing-token)
(setq enclosing-token (pop enclosing-tokens))
(setq type
@ -1184,10 +1198,16 @@ static variables and static methods."
;; signs (:
(seq-filter #'phpinspect--variable-name variables)))
(defun phpinspect--determine-completion-point ()
(save-excursion
(re-search-backward "[^[:blank:]]" nil t)
(forward-char)
(point)))
(defun phpinspect--suggest-at-point ()
(phpinspect--log "Entering suggest at point." )
(let* ((token-tree (phpinspect-buffer-parse-tree phpinspect-current-buffer))
(resolvecontext (phpinspect-get-resolvecontext token-tree (point)))
(let* ((bmap (phpinspect-buffer-parse-map phpinspect-current-buffer))
(resolvecontext (phpinspect-get-resolvecontext bmap (point)))
(last-tokens (last (phpinspect--resolvecontext-subject resolvecontext) 2)))
(phpinspect--log "Subject: %s" (phpinspect--resolvecontext-subject
resolvecontext))

@ -63,10 +63,10 @@
(ert-deftest phpinspect-get-variable-type-in-block ()
(let* ((code "class Foo { function a(\\Thing $baz) { $foo = new \\DateTime(); $bar = $foo; Whatever comes after don't matter.")
(tree (phpinspect-parse-string-to-tree code))
(bmap (phpinspect-parse-string-to-bmap code))
(tokens (phpinspect-parse-string "class Foo { function a(\\Thing $baz) { $foo = new \\DateTime(); $bar = $foo;"))
(context (phpinspect--get-resolvecontext tokens))
(tree-context (phpinspect-get-resolvecontext tree (- (length code) 36)))
(bmap-context (phpinspect-get-resolvecontext bmap (- (length code) 36)))
(project-root "could never be a real project root")
(phpinspect-project-root-function
(lambda (&rest _ignored) project-root))
@ -82,8 +82,8 @@
(phpinspect-function-block
(car (phpinspect--resolvecontext-enclosing-tokens context)))
(phpinspect--make-type-resolver-for-resolvecontext context)))
(tree-result (phpinspect-get-variable-type-in-block
tree-context "foo"
(bmap-result (phpinspect-get-variable-type-in-block
bmap-context "foo"
(phpinspect-function-block
(car (phpinspect--resolvecontext-enclosing-tokens context)))
(phpinspect--make-type-resolver-for-resolvecontext context))))
@ -91,7 +91,7 @@
result))
(should (phpinspect--type= (phpinspect--make-type :name "\\DateTime")
tree-result)))))
bmap-result)))))
(ert-deftest phpinspect-get-pattern-type-in-block ()
(let* ((tokens (phpinspect-parse-string "class Foo { function a(\\Thing $baz) { $foo = new \\DateTime(); $this->potato = $foo;"))
@ -99,7 +99,7 @@
(project-root "could never be a real project root")
(phpinspect-project-root-function
(lambda (&rest _ignored) project-root))
(project (phpinspect--make-project
(project (phpinspect--make-projectb
:fs (phpinspect-make-virtual-fs)
:root project-root
:worker (phpinspect-make-worker))))
@ -118,9 +118,9 @@
(ert-deftest phpinspect-get-resolvecontext-multi-strategy ()
(let* ((code1 "class Foo { function a(\\Thing $baz) { $foo = []; $foo[] = $baz; $bar = $foo[0]; $bork = [$foo[0]]; $bark = $bork[0]; $borknest = [$bork]; $barknest = $borknest[0][0]; }}")
(code2 "class Foo { function a(\\Thing $baz) { $foo = []; $foo[] = $baz; $bar = $foo[0]; $bork = [$foo[0]]; $bark = $bork[0]; $borknest = [$bork]; $barknest = $borknest[0][0]")
(tree (phpinspect-parse-string-to-tree code1))
(bmap (phpinspect-parse-string-to-bmap code1))
(tokens (phpinspect-parse-string code2))
(context1 (phpinspect-get-resolvecontext tree (- (length code1) 4)))
(context1 (phpinspect-get-resolvecontext bmap (- (length code1) 4)))
(context2 (phpinspect--get-resolvecontext tokens)))
(should (equal (phpinspect--resolvecontext-subject context1)
@ -132,7 +132,7 @@
(ert-deftest phpinspect-get-variable-type-in-block-array-access ()
(let* ((code "class Foo { function a(\\Thing $baz) { $foo = []; $foo[] = $baz; $bar = $foo[0]; $bork = [$foo[0]]; $bark = $bork[0]; $borknest = [$bork]; $barknest = $borknest[0][0]; }}")
(tokens (phpinspect-parse-string-to-tree code))
(tokens (phpinspect-parse-string-to-bmap code))
(context (phpinspect-get-resolvecontext tokens (- (length code) 4)))
(project-root "could never be a real project root")
(phpinspect-project-root-function
@ -508,6 +508,7 @@ class Thing
(backward-char)
(setq-local phpinspect-current-buffer
(phpinspect-make-buffer :buffer (current-buffer)))
(phpinspect-buffer-parse phpinspect-current-buffer)
(phpinspect-eldoc-function))))))
(ert-deftest phpinspect-eldoc-function-for-static-method ()
@ -665,7 +666,6 @@ class Thing
(let ((parsed (phpinspect-parse-string "<?php 'string'")))
(should (equal '(:root (:string "string")) parsed))))
(load-file (concat phpinspect-test-directory "/test-worker.el"))
(load-file (concat phpinspect-test-directory "/test-autoload.el"))
(load-file (concat phpinspect-test-directory "/test-fs.el"))
@ -675,7 +675,7 @@ class Thing
(load-file (concat phpinspect-test-directory "/test-class.el"))
(load-file (concat phpinspect-test-directory "/test-type.el"))
(load-file (concat phpinspect-test-directory "/test-util.el"))
(load-file (concat phpinspect-test-directory "/test-tree.el"))
(load-file (concat phpinspect-test-directory "/test-bmap.el"))
(load-file (concat phpinspect-test-directory "/test-edtrack.el"))
(provide 'phpinspect-test)

@ -3,31 +3,100 @@
(ert-deftest phpinspect-bmap-overlay ()
(let ((bmap (phpinspect-make-bmap))
(bmap2 (phpinspect-make-bmap)))
(bmap2 (phpinspect-make-bmap))
(bmap3 (phpinspect-make-bmap)))
(phpinspect-bmap-register bmap 10 20 'token)
(phpinspect-bmap-register bmap2 20 24 'token2)
(phpinspect-bmap-register bmap3 40 50 'token3)
(should (phpinspect-bmap-token-starting-at bmap 10))
(phpinspect-bmap-overlay
bmap bmap3 (phpinspect-bmap-token-starting-at bmap3 40) 10)
(should (phpinspect-bmap-token-starting-at bmap 50))
(phpinspect-bmap-overlay
bmap2 bmap (phpinspect-bmap-token-starting-at bmap 10) -3)
(should (eq 'token2 (phpinspect--meta-token
(phpinspect-bmap-overlay
bmap2 bmap (phpinspect-bmap-token-starting-at bmap 50) 5)
(should (eq 'token2 (phpinspect-meta-token
(phpinspect-bmap-token-starting-at bmap2 20))))
(should (eq 'token (phpinspect--meta-token
(should (eq 'token (phpinspect-meta-token
(phpinspect-bmap-token-starting-at bmap2 7))))
(should (phpinspect-bmap-token-meta bmap 'token))
(should (phpinspect-bmap-token-meta bmap2 'token2))
(should (phpinspect-bmap-token-meta bmap2 'token))))
(should (phpinspect-bmap-token-meta bmap2 'token))
(should (phpinspect-bmap-token-meta bmap2 'token3))))
(ert-deftest phpinspect-bmap-nest-parent ()
(let ((bmap (phpinspect-make-bmap)))
(phpinspect-bmap-register bmap 10 20 'child)
(phpinspect-bmap-register bmap 5 25 'parent)
(phpinspect-bmap-register bmap 5 25 'parent nil nil t)
(phpinspect-bmap-register bmap 2 30 'granny nil nil t)
(let ((child (phpinspect-bmap-token-meta bmap 'child))
(parent (phpinspect-bmap-token-meta bmap 'parent)))
(should (eq 'parent (phpinspect-meta-token
(phpinspect-meta-parent child))))
(should (eq 'granny (phpinspect-meta-token (phpinspect-meta-parent parent)))))))
(ert-deftest phpinspect-bmap-tokens-overlapping ()
(let ((bmap (phpinspect-make-bmap)))
(phpinspect-bmap-register bmap 9 200 'node1)
(phpinspect-bmap-register bmap 20 200 'node2)
(phpinspect-bmap-register bmap 9 20 'node3)
(phpinspect-bmap-register bmap 21 44 'node4)
(setq result (phpinspect-bmap-tokens-overlapping bmap 22))
(should (equal '(node4 node2 node1) (mapcar #'phpinspect-meta-token result)))))
(ert-deftest phpinspect-bmap-tokens-overlapping-overlayed ()
(let ((bmap (phpinspect-make-bmap))
(bmap2 (phpinspect-make-bmap))
(bmap3 (phpinspect-make-bmap)))
(phpinspect-bmap-register bmap 9 200 'token1)
(phpinspect-bmap-register bmap 20 200 'token2)
(phpinspect-bmap-register bmap 9 20 'token3)
(phpinspect-bmap-register bmap 21 44 'token4)
(phpinspect-bmap-register bmap2 200 230 'token5)
(phpinspect-bmap-register bmap3 300 305 'token6)
;; Should start at 220 of bmap2
(phpinspect-bmap-overlay
bmap2 bmap3 (phpinspect-bmap-token-starting-at bmap3 300) -80)
(setq result (phpinspect-bmap-tokens-overlapping bmap2 220))
(should (equal '(token6 token5) (mapcar #'phpinspect-meta-token result)))
(phpinspect-bmap-overlay
bmap bmap2 (phpinspect-bmap-token-starting-at bmap2 200) 20)
(setq result (phpinspect-bmap-tokens-overlapping bmap 240))
(should (equal '(token6 token5) (mapcar #'phpinspect-meta-token result)))
(setq result (phpinspect-bmap-tokens-overlapping bmap 22))
(should (equal '(token4 token2 token1) (mapcar #'phpinspect-meta-token result)))))
(ert-deftest phpinspect-bmap-register ()
(let* ((bmap (phpinspect-make-bmap))
(token1 `(:word "foo"))
(token2 `(:word "bar"))
(token3 `(:block ,token1 ,token2))
(token4 `(:list ,token3)))
(phpinspect-bmap-register bmap 10 20 token1)
(phpinspect-bmap-register bmap 20 30 token2)
(phpinspect-bmap-register bmap 9 31 token3)
(phpinspect-bmap-register bmap 8 32 token4)
(let ((child (phpinspect-bmap-token-meta bmap 'child)))
(should
(eq 'parent (phpinspect--meta-token
(phpinspect--meta-parent child)))))))
(should (phpinspect-bmap-token-meta bmap token1))
(should (phpinspect-bmap-token-meta bmap token2))
(should (phpinspect-bmap-token-meta bmap token3))
(should (phpinspect-bmap-token-meta bmap token4))))

@ -27,6 +27,7 @@
(require 'phpinspect-parser)
(require 'phpinspect-buffer)
(ert-deftest phpinspect-buffer-region-lookups ()
(let* ((parsed)
(class))
@ -40,11 +41,6 @@
(seq-find #'phpinspect-namespace-p parsed)))
(classname (car (cddadr class))))
;; Root node should be the root parsed token
(should (eq parsed (phpinspect-meta-token
(phpinspect-tree-value (phpinspect-buffer-tree
phpinspect-current-buffer)))))
(let ((tokens (phpinspect-buffer-tokens-enclosing-point
phpinspect-current-buffer 617)))
(should (eq classname
@ -65,29 +61,6 @@
(should (cdr parsed))))
(ert-deftest phpinspect-buffer-register-edit ()
(let ((buffer (phpinspect-make-buffer)))
(with-temp-buffer
(insert-file-contents (concat phpinspect-test-php-file-directory "/NamespacedClass.php"))
(setq phpinspect-current-buffer buffer)
(setf (phpinspect-buffer-buffer buffer) (current-buffer))
(phpinspect-buffer-parse buffer))
;; "Deletes" first curly brace of __construct function block
(phpinspect-buffer-register-edit buffer 1036 1036 1)
(phpinspect-buffer-propagate-taints buffer)
(let* ((region (phpinspect-make-region 1036 1037))
(tainted
(phpinspect-tree-find-smallest-overlapping-set
(phpinspect-buffer-tree buffer) region)))
(dolist (meta tainted)
(should (phpinspect-meta-tainted meta))
(phpinspect-tree-traverse (node (phpinspect-meta-tree meta))
(when (phpinspect-tree-overlaps node region)
(should (phpinspect-meta-tainted (phpinspect-tree-value node)))))))))
(cl-defstruct (phpinspect-document (:constructor phpinspect-make-document))
(buffer (get-buffer-create
(generate-new-buffer-name " **phpinspect-document** shadow buffer") t)
@ -137,7 +110,7 @@
(setq parsed (phpinspect-buffer-parse buffer))
(should parsed)
(setq hello1 (car (phpinspect-buffer-tokens-enclosing-point buffer 18)))
(should (eq hello hello1))
(should (eq (phpinspect-meta-token hello) (phpinspect-meta-token hello1)))
(phpinspect-document-apply-edit document 24 25 1 "{")
(should (string= "<?php function Hello() { echo 'Hello World!'; if ($name) { echo 'Hello ' . $name . '!';} }"
@ -146,6 +119,4 @@
(setq parsed (phpinspect-buffer-parse buffer))
(should parsed)
(setq hello2 (car (phpinspect-buffer-tokens-enclosing-point buffer 18)))
(should (eq hello hello2))
(setq parsed (phpinspect-buffer-parse-tree buffer)))))
(should (eq (phpinspect-meta-token hello) (phpinspect-meta-token hello2))))))

@ -46,4 +46,30 @@
(should (equal (list (cons 0 20)) (phpinspect-edtrack-taint-pool track)))))
;; (should-not (phpinspect-tree-empty-p (phpinspect-edtrack-taint-pool track)))))
(ert-deftest phpinspect-edtrack-taint-iterator ()
(let ((track (phpinspect-make-edtrack))
(iterator))
(phpinspect-edtrack-register-taint track 120 150)
(phpinspect-edtrack-register-taint track 5 30)
(phpinspect-edtrack-register-taint track 25 50)
(phpinspect-edtrack-register-taint track 70 100)
(setq iterator (phpinspect-edtrack-make-taint-iterator track))
(should-not (phpinspect-taint-iterator-token-is-tainted-p
iterator (phpinspect-make-meta nil 1 4 nil nil)))
(should (phpinspect-taint-iterator-token-is-tainted-p
iterator (phpinspect-make-meta nil 4 7 nil nil)))
(should (phpinspect-taint-iterator-token-is-tainted-p
iterator (phpinspect-make-meta nil 20 30 nil nil)))
(should-not (phpinspect-taint-iterator-token-is-tainted-p
iterator (phpinspect-make-meta nil 51 55 nil nil)))
(should (phpinspect-taint-iterator-token-is-tainted-p
iterator (phpinspect-make-meta nil 65 73 nil nil)))
(should (phpinspect-taint-iterator-token-is-tainted-p
iterator (phpinspect-make-meta nil 100 130 nil nil)))))

@ -47,7 +47,7 @@
(,(phpinspect--make-type :name"\\Potato" :fully-qualified t)
phpinspect--indexed-class
(class-name . ,(phpinspect--make-type :name "\\Potato" :fully-qualified t))
(token-metadata . nil)
(location . (0 0))
(imports)
(methods)
(static-methods . (,(phpinspect--make-function
@ -159,16 +159,17 @@ return StaticThing::create(new ThingFactory())->makeThing((((new Potato())->anti
(should (equal (alist-get key index1-class)
(alist-get key index2-class))))))
(ert-deftest phpinspect-index-tree-class ()
(let* ((pctx (phpinspect-make-pctx :incremental t)))
(ert-deftest phpinspect-index-bmap-class ()
(let* ((pctx (phpinspect-make-pctx :incremental t))
(tree))
(with-temp-buffer
(insert-file-contents (concat phpinspect-test-php-file-directory "/IndexClass1.php"))
(setf (phpinspect-pctx-tree pctx) (phpinspect-make-tree :start (point-min)
:end (point-max)
:value 'parse-root))
(phpinspect-with-parse-context pctx (phpinspect-parse-current-buffer)))
(let* ((index1 (phpinspect--index-tokens
(seq-elt (phpinspect-tree-children (phpinspect-pctx-tree pctx)) 0)))
(setf (phpinspect-pctx-bmap pctx) (phpinspect-make-bmap))
(phpinspect-with-parse-context pctx (setq tree (phpinspect-parse-current-buffer))))
(let* ((index1 (phpinspect--index-tokens tree
nil
(phpinspect-bmap-make-location-resolver
(phpinspect-pctx-bmap pctx))))
(index2
(phpinspect-test-read-fixture-serialization "IndexClass1-indexed"))
(index1-class (car (alist-get 'classes index1)))
@ -178,5 +179,5 @@ return StaticThing::create(new ThingFactory())->makeThing((((new Potato())->anti
(should (equal (alist-get key index1-class)
(alist-get key index2-class))))
(should (alist-get 'token-metadata index1-class))
(should (phpinspect-meta-p (alist-get 'token-metadata index1-class))))))
(should (alist-get 'location index1-class))
(should (alist-get 'location index1-class)))))

Loading…
Cancel
Save