Garbonzo Gallore
ci/woodpecker/push/woodpecker Pipeline failed Details

WIP-incremental-parsing
Hugo Thunnissen 11 months ago
parent bab8deba01
commit 2e6edd70b2

@ -30,17 +30,18 @@
buffer. This variable is only set for buffers where
`phpinspect-mode' is active. Also see `phpinspect-buffer'.")
(cl-defstruct (phpinspect-token-metadata (:constructor phpinspect-make-token-metadata))
"An object that represents the metadata associated with a parsed token."
(token nil
:type phpinspect-token
:documentation
"The token that metadata is associated with.")
(location nil
:type phpinspect-region
:documentation
"The region that token occupies.")
(region nil
:type phpinspect-region
:documentation
"The region that token occupies.")
(tree nil
:type phpinspect-tree)
(handler nil
:type phpinspect-handler
:documentation
@ -51,64 +52,326 @@ buffer. This variable is only set for buffers where
emacs buffer."
(buffer nil
:type buffer
:documentation "The underlying emacs buffer")
(metadata-map (make-hash-table :test 'eq :size 400 :rehash-size 400)
:documentation "The associated emacs buffer")
(tree (phpinspect-make-tree)
:type phpinspect-tree
:documentation
"A tree containing metadata associated with tokens.")
(metadata-map (make-hash-table :test 'eq :size 3000 :rehash-size 2.0)
:type hash-table
:documentation
"A map containing metadata associated with tokens.")
(tree nil
:type list
:documentation
"An instance of a token tree as returned by
`phpinspect--index-tokens'. Meant to be eventually consistent
with the contents of the buffer."))
(edit-tracker (phpinspect-make-edit-tracker)
:type phpinspect-edit-tracker))
(cl-defmethod phpinspect-buffer-parse ((buffer phpinspect-buffer))
"Parse the PHP code in the the emacs buffer that this object is
linked with."
(with-current-buffer (phpinspect-buffer-buffer buffer)
(setf (phpinspect-buffer-metadata-map buffer)
(make-hash-table :test 'eq
:size 400
:rehash-size 400))
(let ((tree (phpinspect-parse-current-buffer)))
(let ((tree (phpinspect-make-tree :start (point-min)
:end (point-max))))
(setf (phpinspect-buffer-tree buffer) tree)
tree)))
(setf (phpinspect-buffer-metadata-map buffer)
(make-hash-table :test 'eq :size 3000 :rehash-size 1.5))
(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)
;; return
parsed))))
(cl-defmethod phpinspect-buffer-queue-full-parse ((buffer phpinspect-buffer))
(phpinspect--log "Attempted to queue full parse"))
(defmacro phpinspect-buffer-with-tree (buffer tree &rest body)
(declare (indent 2))
(let ((tree-store-sym (gensym)))
`(unwind-protect
(let ((,tree-store-sym (phpinspect-buffer-tree ,buffer)))
(setf (phpinspect-buffer-tree ,buffer ,tree))
,@body)
(setf (phpinspect-buffer-tree buffer) ,tree-store-sym))))
;; (cl-defmethod phpinspect-buffer-reparse
;; ((buffer phpinspect-buffer) (meta phpinspect-token-meta) (edit phpinspect-edit))
(cl-defmethod phpinspect-buffer-parse-incrementally ((buffer phpinspect-buffer))
(let ((edits
(phpinspect-edit-tracker-edits (phpinspect-buffer-edit-tracker buffer)))
(buffer-tree (phpinspect-buffer-tree buffer)))
(seq-doseq (edit edits)
(let* ((edit-region (phpinspect-edit-region edit))
(edit-delta (phpinspect-edit-delta edit))
(parsed-start)
(parsed-end)
(metas (phpinspect-tree-find-smallest-overlapping-set
buffer-tree edit-region)))
(condition-case err
(dolist (meta metas)
(setq meta (gv-deref meta))
(let ((region (phpinspect-token-metadata-region meta))
(handler-function (symbol-function
(phpinspect-token-metadata-handler meta)))
(temp-tree (phpinspect-make-tree
;; We start parsing at the start of the token
:start (phpinspect-region-start region)
;; We expect to end parsing at the end of the
;; edit region, but this could not be the case
;; as some handlers ignore point-max.
:end (point-max)
:value 'temp-tree-root))
(parsed)
(parsed-tree))
(phpinspect-buffer-with-tree buffer temp-tree
(with-current-buffer (phpinspect-buffer-buffer buffer)
(save-excursion
(goto-char (phpinspect-region-start region))
(unless (looking-at
(phpinspect-handler-regexp
(phpinspect-token-metadata-handler meta)))
;; The token type changed, reparsing the parent is
;; required to determine its new nature.
(throw 'recurse-parent))
(setq parsed
(funcall handler-function (match-string 0)
(phpinspect-region-end edit-region)))
(phpinspect-set-token-metadata-when-current-buffer
parsed (phpinspect-region-start region) (point)
(phpinspect-token-metadata-handler meta)))))
(setq parsed-tree
(phpinspect-tree-detach
(seq-elt (phpinspect-tree-children temp-tree) 0)))
(cond ((> (phpinspect-tree-end parsed-tree)
(+ (phpinspect-region-end region) edit-delta))
;; Changes in edit region changed meaning of tokens
;; outside of it.
(throw 'recurse-parent))
((< (phpinspect-tree-end parsed-tree)
(+ (phpinspect-region-end region) edit-delta))
;; No edits after, but token did not grow to expected
;; size.
(unless (phpinspect-edit-tracker-edit-after edit)
(throw 'recurse-parent)))
((
-
;; (with-current-buffer (phpinspect-buffer-buffer buffer)
;; (let ((edits
;; (phpinspect-edit-tracker-edits (phpinspect-buffer-edit-tracker buffer)))
;; (buffer-tree (phpinspect-buffer-tree buffer)))
;; (unwind-protect
;; (progn
;; (seq-doseq (edit edits)
;; (let* ((edit-region (phpinspect-edit-region edit))
;; (metas (phpinspect-tree-find-smallest-overlapping-set
;; buffer-tree edit-region)))
;; (condition-case err
;; (dolist (meta metas)
;; (setq meta (gv-deref meta))
;; (let ((region (phpinspect-token-metadata-region meta))
;; (handler-function (symbol-function
;; (phpinspect-token-metadata-handler meta)))
;; (temp-tree (phpinspect-make-tree
;; ;; We start parsing at the start of the token
;; :start (phpinspect-region-start region)
;; ;; We expect to end parsing at the end of the edit region
;; :end (phpinspect-region-end edit-region)
;; :value 'temp-tree-root))
;; (parse-result)
;; (parse-result-tree))
;; (save-excursion
;; (goto-char (phpinspect-region-start region))
;; ;; Override buffer tree
;; (setf (phpinspect-buffer-tree buffer) temp-tree)
;; (setq parse-result (funcall handler-function))
;; (phpinspect-set-token-metadata-when-current-buffer
;; parse-result (phpinspect-region-start region) (point)
;; (phpinspect-token-metadata-handler meta))
;; (if (eq (phpinspect-tree-value temp-tree) 'temp-tree-root)
;; (setq parse-result-tree
;; (phpinspect-tree-detach
;; (seq-elt (phpinspect-tree-children temp-tree) 0)))
;; ;; New token width exceeds edit region.
;; (phpinspect-buffer-queue-full-parse buffer)
;; (throw 'break))
;; New token region encloses editen region, stop parsing.
;; (let* ((new-meta (gv-deref (phpinspect-tree-value parse-result-tree)))
;; (new-token (phpinspect-token-metadata-token new-meta)))
;; (if (and (phpinspect-incomplete-token-p new-token)
;; (phpinspect-edit-tracker-edit-after
;; (phpinspect-buffer-edit-tracker buffer) edit))
;; ;; The token is incomplete, and there are edits after this token
;; (when (phpinspect-region-encloses new-meta edit-region)
;; (throw 'break))))))
;; (break)))))
;; ;; Restore buffer tree
;; (setf (phpinspect-buffer-tree buffer) buffer-tree)))))
;; (if (< 1 (length metas))
;; (setq reparse-meta (phpinspect-tree-value
;; (phpinspect-tree-parent
;; (phpinspect-token-metadata-tree (car metas)))))
;; (setq reparse-meta (car metas)))
;; (if reparse-meta
;; (phpinspect-buffer-reparse buffer reparse-meta edit)
;; ;; Nothing found to reparse.. Just reparse entire buffer to be sure
;; (phpinspect--log "[WARNING] phpinspect-buffer-parse-incrementally: No reparsable tokens found, reparsing entire buffer.")
;; (phpinspect-buffer-parse buffer))))))
(cl-defmethod phpinspect-buffer-set-token-metadata
((buffer phpinspect-buffer) token (metadata phpinspect-token-metadata))
"Set the METADATA associated with TOKEN that was parsed in BUFFER"
(puthash token metadata (phpinspect-buffer-metadata-map buffer)))
(setf (phpinspect-token-metadata-token metadata) token)
(let ((metadata-existing (gethash token (phpinspect-buffer-metadata-map buffer))))
(if metadata-existing
(setf (gv-deref metadata-existing) metadata)
(progn
(setq metadata-ref (gv-ref metadata))
(puthash token metadata-ref (phpinspect-buffer-metadata-map buffer))
(let* ((region (phpinspect-token-metadata-region metadata))
(tree-node
(phpinspect-tree-insert (phpinspect-buffer-tree buffer)
(phpinspect-region-start region)
(phpinspect-region-end region)
metadata)))
(setf (phpinspect-token-metadata-tree metadata) tree-node))))))
(cl-defmethod phpinspect-buffer-get-token-metadata ((buffer phpinspect-buffer) token)
(gethash token (phpinspect-buffer-metadata-map buffer)))
(let ((ref (gethash token (phpinspect-buffer-metadata-map buffer))))
(when ref (gv-deref ref))))
(cl-defmethod phpinspect-buffer-token-location ((buffer phpinspect-buffer) token)
(phpinspect-token-metadata-location (phpinspect-buffer-get-token-metadata buffer token)))
(phpinspect-token-metadata-region (phpinspect-buffer-get-token-metadata buffer token)))
(cl-defmethod phpinspect-buffer-tokens-enclosing-point ((buffer phpinspect-buffer) point)
(let ((tokens))
(maphash
(lambda (token meta)
(let ((region (phpinspect-token-metdata-location meta)))
(when (and (<= (phpinspect-region-start region) point)
(>= (phpinspect-region-end region) point))
(push token tokens))))
(phpinspect-buffer-metadata-map buffer))
(sort tokens (lambda (tok1 tok2)
(phpinspect-region< (phpinspect-buffer-token-location tok1)
(phpinspect-buffer-token-location tok2))))))
(cl-defmethod phpinspect-buffer-tokens-overlapping-region
((buffer phpinspect-buffer) (start integer) (end integer))
(let ((tokens)
(query-region (phpinspect-make-region start end)))
(maphash (lambda (token metadata)
(when (phpinspect-region-overlaps
query-region (phpinspect-token-metadata-location metadata))
(push token tokens)))
(phpinspect-buffer-metadata-map buffer))
tokens))
(mapcar #'phpinspect-token-metadata-token
(phpinspect-tree-traverse-overlappig (phpinspect-buffer-tree buffer) point)))
(cl-defstruct (phpinspect-edit-tracker (:constructor phpinspect-make-edit-tracker))
(edits (phpinspect-make-ll)))
(cl-defstruct (phpinspect-edit (:constructor phpinspect-make-edit))
(region nil
:type phpinspect-region
:documentation
"The region in which the edit took place")
(delta 0
:type integer
:documentation
"The change in width of the edit region"))
(cl-defmethod phpinspect-edit-concat ((edit1 phpinspect-edit) (edit2 phpinspect-edit))
"Absorb EDIT2 into EDIT1. Returns EDIT1."
(let ((min) (max) (delta)
(region1 (phpinspect-edit-region edit1))
(region2 (phpinspect-edit-region edit2)))
(if (< (phpinspect-region-start region1)
(phpinspect-region-start region2))
(setq min (phpinspect-region-start region1))
(setq min (phpinspect-region-start region2)))
(if (> (phpinspect-region-end region1)
(phpinspect-region-end region2))
(setq max (phpinspect-region-end region1))
(setq max (phpinspect-region-end region2)))
(setq delta (+ (phpinspect-edit-delta edit1)
(phpinspect-edit-delta edit2)))
(setf (phpinspect-edit-delta edit1) delta)
(setf (phpinspect-edit-region edit1) (phpinspect-make-region min max))
edit1))
(cl-defmethod phpinspect-edit-overlaps ((edit1 phpinspect-edit) (edit2 phpinspect-edit))
(phpinspect-region-overlaps (phpinspect-edit-region edit1)
(phpinspect-edit-region edit2)))
(cl-defmethod phpinspect-edit-could-overlap ((edit1 phpinspect-edit) (edit2 phpinspect-edit))
(> (phpinspect-region-end (phpinspect-edit-region edit1))
(phpinspect-region-start (phpinspect-edit-region edit2))))
(cl-defmethod phpinspect-edit-tracker-mark
((tracker phpinspect-edit-tracker) (start integer) (end integer) (pre-change-length integer))
(let* ((edits (phpinspect-edit-tracker-edits tracker))
(edit (phpinspect-make-edit :region (phpinspect-make-region start end)
:delta (- (- end start) pre-change-length)))
(first-in-range (seq-find (lambda (e) (phpinspect-edit-could-overlap edit e))
edits))
(insertion-link)
(first-overlapper)
(overlappers))
(when first-in-range
(if (phpinspect-edit-overlaps edit first-in-range)
(progn
;; If this is the first overlapper, we should insert before it.
(setq insertion-link (phpinspect-llnode-left
(phpinspect-ll-link edits first-in-range)))
(setq first-overlapper first-in-range))
;; If this is not an overlapper, we should insert after it, as the
;; entire region spans a range before the edit.
(setq insertion-link (phpinspect-ll-link edits first-in-range))))
(unless first-overlapper
(setq first-overlapper (seq-find (lambda (e) (phpinspect-edit-overlaps edit e))
(or insertion-link
(phpinspect-ll-link edits first-in-range)))))
(when first-overlapper
(setq overlappers
(seq-take-while (lambda (e) (phpinspect-edit-overlaps e edit))
(phpinspect-ll-link edits first-overlapper)))
;; Break overlappers away from edit list, as they're about to be replaced.
(setq overlappers (phpinspect-slice-detach overlappers)))
;; Absorb all overlapping edits into our newly created edit
(seq-doseq (overlap overlappers)
(phpinspect-edit-concat edit overlap))
(if insertion-link
(phpinspect-ll-insert-right insertion-link edit)
(phpinspect-ll-push edit edits))))
(cl-defmethod phpinspect-edit-tracker-unmark
((tracker phpinspect-edit-tracker) (start integer) (end integer))
(let* ((region (phpinspect-make-region start end))
(edits (phpinspect-edit-tracker-edits tracker))
(first-enclosing
(seq-find (lambda (e) (phpinspect-region-encloses
region (phpinspect-edit-region e)))
edits)))
(when first-enclosing
(phpinspect-slice-detach
(seq-take-while (lambda (e) (phpinspect-region-encloses
region (phpinspect-edit-region e)))
edits)))))
(cl-defmethod phpinspect-edit-tracker-edit-after
((tracker phpinspect-edit-tracker) (edit phpinspect-edit))
(phpinspect-llnode-value
(phpinspect-llnode-right
(phpinspect-ll-link
(phpinspect-edit-tracker-edits tracker) edit))))
(provide 'phpinspect-buffer)

@ -393,6 +393,7 @@ token is \";\", which marks the end of a statement in PHP."
`(lambda (buffer max-point &optional continue-condition)
(with-current-buffer buffer
(let ((tokens)
(root-start (point))
(delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate)))
(while (and (< (point) max-point)
(if continue-condition (funcall continue-condition) t)
@ -412,21 +413,26 @@ token is \";\", which marks the end of a statement in PHP."
(progn
(nconc tokens (list token))))
;; When parsing within a buffer that has
;; `phpinspect-current-buffer` set, update the
;; token metadata maps. Usually, this variable
;; is set when `phpinspect-mode` is active.
(when phpinspect-current-buffer
(phpinspect-buffer-set-token-metadata
phpinspect-current-buffer
token
(phpinspect-make-token-metadata
:location (phpinspect-make-region
start-position (point))
:handler ,handler)))))))
(phpinspect-set-token-metadata-when-current-buffer
token start-position (point) ,handler)))))
handlers)
(t (forward-char))))
(push ,tree-type tokens))))))
(push ,tree-type tokens)
(phpinspect-set-token-metadata-when-current-buffer tokens root-start (point) nil)
;; Return
tokens)))))
(defsubst phpinspect-set-token-metadata-when-current-buffer (token start end handler)
"When parsing within a buffer that has`phpinspect-current-buffer` set,update
the token metadata maps. Usually, this variable is set when `phpinspect-mode` is
active."
(when phpinspect-current-buffer
(phpinspect-buffer-set-token-metadata
phpinspect-current-buffer token (phpinspect-make-token-metadata
:region (phpinspect-make-region start end)
:handler handler))))
(cl-defstruct (phpinspect-parser (:constructor phpinspect-make-parser))
(tree-keyword "root"

@ -121,6 +121,14 @@ belongs to. Return resulting linked list."
start)))
(cl-defmethod phpinspect-llnode-detach ((list phpinspect-llnode))
(let ((left (phpinspect-llnode-left list))
(right (phpinspect-llnode-right list)))
(when left (setf (phpinspect-llnode-right left) right))
(when right (setf (phpinspect-llnode-left right) left))
(phpinspect-ll-unregister-link list)
list))
(cl-defmethod phpinspect-ll-register-link ((list phpinspect-llnode))
(puthash (phpinspect-llnode-value list) list (phpinspect-llnode-link-map list)))
@ -214,6 +222,20 @@ belongs to. Return resulting linked list."
(when list
(phpinspect-llnode-value list))))
(cl-defmethod seq-do (fn (list phpinspect-llnode))
(when (phpinspect-llnode-value list)
(while list
(funcall fn (phpinspect-llnode-value list))
(setq list (phpinspect-llnode-right list)))))
(cl-defmethod seq-do (fn (slice phpinspect-slice))
(let ((list (phpinspect-slice-start slice))
(slice-end (phpinspect-llnode-right (phpinspect-slice-end slice))))
(when (phpinspect-llnode-value list)
(while (and list (not (eq slice-end list)))
(funcall fn (phpinspect-llnode-value list))
(setq list (phpinspect-llnode-right list))))))
(cl-defmethod seq-map (fn (list phpinspect-llnode))
(when (phpinspect-llnode-value list)
(let ((values))
@ -249,7 +271,7 @@ belongs to. Return resulting linked list."
(let ((start list)
(end list))
(while (and list (not (eq slice-end list))
(funcall pred (phpnspect-llnode-value list)))
(funcall pred (phpinspect-llnode-value list)))
(setq end list)
(setq list (phpinspect-llnode-right list)))
@ -339,7 +361,7 @@ belongs to. Return resulting linked list."
(or (phpinspect-tree-overlaps tree1 (phpinspect-tree-start tree2))
(phpinspect-tree-overlaps tree1 (- (phpinspect-tree-end tree2) 1))
(phpinspect-tree-overlaps tree2 (phpinspect-tree-start tree1))
(phpinspect-tree-overlaps tree2 (- (phpinspect-tree-end tree1))))))
(phpinspect-tree-overlaps tree2 (- (phpinspect-tree-end tree1) 1)))))
(cl-defmethod phpinspect-tree-overlaps ((tree phpinspect-tree) region)
(and
@ -348,6 +370,9 @@ belongs to. Return resulting linked list."
(phpinspect-region-overlaps-point region (phpinspect-tree-start tree))
(phpinspect-region-overlaps-point region (- (phpinspect-tree-end tree) 1)))))
(cl-defmethod phpinspect-tree-starts-after ((tree phpinspect-tree) (point integer))
(> (phpinspect-tree-start tree) point))
(cl-defmethod phpinspect-tree-encloses ((tree1 phpinspect-tree) (tree2 phpinspect-tree))
(and (<= (phpinspect-tree-start tree1) (phpinspect-tree-start tree2))
(>= (phpinspect-tree-end tree1) (phpinspect-tree-end tree2))))
@ -390,33 +415,19 @@ belongs to. Return resulting linked list."
(seq-take-while (lambda (child) (phpinspect-tree-overlaps child region))
(phpinspect-ll-link children first-overlapper)))))
(defsubst phpinspect-tree-is-empty (tree)
(and (= 0 (phpinspect-tree-start tree))
(= 0 (phpinspect-tree-end tree))))
(cl-defmethod phpinspect-tree-insert-node ((tree phpinspect-tree) (node phpinspect-tree))
"Insert a new NODE into TREE.
Returns the newly inserted node."
(cond ((phpinspect-tree-encloses node tree)
;; New node encloses entire tree, so it has to become the new root.
(let* ((parent (phpinspect-tree-parent tree)))
(if parent
(progn
(phpinspect-ll-relink
(phpinspect-ll-link (phpinspect-tree-children parent) tree) node)
(phpinspect-tree-insert-node node tree)
;; Return
node)
;; No parent, which means that this is the absolute root node of
;; the tree. To keep things consistent, swap all the attributes of
;; both trees to keep the reference to the root node intact for the
;; caller.
(progn
(phpinspect-tree-switch-attributes node tree)
(phpinspect-tree-insert-node tree node)
(cond ((phpinspect-tree-is-empty tree)
(phpinspect-tree-switch-attributes node tree)
;; Return tree, as this is the node that value of node has been
;; stored in.
tree))))
;; Return
tree)
((phpinspect-tree-encloses tree node)
;; New node is entirely enclosed by tree, check tree's children for
;; overlappings.
@ -443,7 +454,11 @@ Returns the newly inserted node."
(setq insert-after-link (phpinspect-llnode-left
(phpinspect-slice-start enclosed)))
(setq enclosed (phpinspect-slice-detach enclosed))
(phpinspect-ll-insert-right insert-after-link node)
(if insert-after-link
(phpinspect-ll-insert-right insert-after-link node)
;; If there is nothing to the left of the enclosed regions,
;; we can safely push to the tree's children
(phpinspect-ll-push node (phpinspect-tree-children tree)))
(setf (phpinspect-tree-parent node) tree)
(setf (phpinspect-tree-children node) enclosed))))
@ -465,6 +480,29 @@ Returns the newly inserted node."
;; Return
node)
((phpinspect-tree-encloses node tree)
;; New node encloses entire tree, so it has to become the new root.
(let* ((parent (phpinspect-tree-parent tree)))
(if parent
(progn
(phpinspect-ll-relink
(phpinspect-ll-link (phpinspect-tree-children parent) tree) node)
(phpinspect-tree-insert-node node tree)
;; Return
node)
;; No parent, which means that this is the absolute root node of
;; the tree. To keep things consistent, swap all the attributes of
;; both trees to keep the reference to the root node intact for the
;; caller.
(progn
(phpinspect-tree-switch-attributes node tree)
(phpinspect-tree-insert-node tree node)
;; Return tree, as this is the node that value of node has been
;; stored in.
tree))))
(t (throw 'phpinspect-tree-conflict
(format "Tree does not enclose or get enclosed. \nTree: %s \n\nPerspective parent: %s" node tree)))))
@ -481,6 +519,41 @@ width with the smallest interval as car."
`(,@(phpinspect-tree-traverse-overlappig overlapper point) ,(phpinspect-tree-value tree))
`(,(phpinspect-tree-value tree))))))
(cl-defmethod phpinspect-tree-widen-after-point
((tree phpinspect-tree) (point integer) (delta integer) &optional fn)
"Widens all nodes of TREE that start or end after POINT by DELTA.
When FN is set, it is called once for each widened tree node,
with its value as argument."
(let ((tree-children (phpinspect-tree-children tree))
(children))
(cond
((phpinspect-tree-overlaps tree point)
(setf (phpinspect-tree-end tree) (+ (phpispect-tree-end tree) delta))
(let* ((first-match
(seq-find (lambda (child) (or (phpinspect-tree-overlaps child point)
(phpinspect-tree-starts-after child point)))
tree-children)))
(setq children
(seq-take-while (lambda (child) (or (phpinspect-tree-overlaps child point)
(phpinspect-tree-starts-after child point)))
(phpinspect-ll-link
tree-children first-match))))
(when fn (funcall fn (phpinspect-tree-value tree))))
((phpinspect-tree-starts-after tree point)
(setf (phpinspect-tree-start tree) (+ (phpinspect-tree-start tree) delta))
(setf (phpinspect-tree-end tree) (+ (phpinspect-tree-end tree) delta))
(setq children tree-children)
(when fn (funcall fn (phpinspect-tree-value tree)))))
(when children
(seq-doseq (child children)
(phpinspect-tree-widen-after-point child point)))))
(cl-defmethod phpinspect-tree-find-smallest-overlapping-set ((tree phpinspect-tree) region)
"Traverse TREE for smallest set of intervals overlapping REGION,
@ -527,6 +600,15 @@ Returns the newly created and inserted node."
(let ((node (phpinspect-make-tree :start start :end end :value value)))
(phpinspect-tree-insert-node tree node)))
(cl-defmethod phpinspect-tree-detach ((tree phpinspect-tree))
"Detach tree from parent."
(let ((parent (phpinspect-tree-parent tree)))
(when parent
(let ((parent-link (phpinspect-ll-link (phpinspect-tree-children parent)
tree)))
(phpinspect-llnode-detach parent-link)
(setf (phpinspect-tree-parent tree) nil)))))
(defsubst phpinspect-make-region (start end)
(list start end))
@ -552,4 +634,8 @@ Returns the newly created and inserted node."
(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))))
(provide 'phpinspect-tree)

@ -27,8 +27,8 @@
(require 'phpinspect-parser)
(require 'phpinspect-buffer)
(ert-deftest phpinspect-parse-buffer-token-locations ()
"Confirm that the location map of `phpinspect-current-buffer' is
(ert-deftest phpinspect-buffer-parse-token-metadata ()
"Confirm that the metadata map of `phpinspect-current-buffer' is
populated when the variable is set and the data in it is accurate."
(let* ((parsed)
(class))
@ -42,13 +42,16 @@ populated when the variable is set and the data in it is accurate."
(seq-find #'phpinspect-namespace-p parsed)))
(class-meta (phpinspect-buffer-get-token-metadata
phpinspect-current-buffer class))
(class-region (phpinspect-token-metadata-location class-meta))
(class-region (phpinspect-token-metadata-region class-meta))
(classname-meta (phpinspect-buffer-get-token-metadata
phpinspect-current-buffer (car (cddadr class))))
(classname-region (phpinspect-token-metadata-location classname-meta)))
(classname-region (phpinspect-token-metadata-region classname-meta)))
(should class)
(should class-region)
(should classname-region)
(should (eq class (phpinspect-token-metadata-token class-meta)))
;; Character position of the start of the class token.
(should (= 611 (phpinspect-region-start class-region)))
(should (= 2367 (phpinspect-region-end class-region)))
@ -56,6 +59,37 @@ populated when the variable is set and the data in it is accurate."
(should (= 617 (phpinspect-region-start classname-region)))
(should (= 634 (phpinspect-region-end classname-region)))))))
(ert-deftest phpinspect-buffer-region-lookups ()
(let* ((parsed)
(class))
(with-temp-buffer
(insert-file-contents (concat phpinspect-test-php-file-directory "/NamespacedClass.php"))
(setq phpinspect-current-buffer
(phpinspect-make-buffer :buffer (current-buffer)))
(setq parsed (phpinspect-buffer-parse phpinspect-current-buffer))
(let* ((class (seq-find #'phpinspect-class-p
(seq-find #'phpinspect-namespace-p parsed)))
(class-meta (phpinspect-buffer-get-token-metadata
phpinspect-current-buffer class))
(class-region (phpinspect-token-metadata-region class-meta))
(classname-meta (phpinspect-buffer-get-token-metadata
phpinspect-current-buffer (car (cddadr class))))
(classname-region (phpinspect-token-metadata-region classname-meta)))
;; Root node should be the root parsed token
(should (eq parsed (phpinspect-token-metadata-token
(phpinspect-tree-value (phpinspect-buffer-tree
phpinspect-current-buffer)))))
(let ((tokens (phpinspect-buffer-tokens-enclosing-point
phpinspect-current-buffer 617)))
(should (eq (phpinspect-token-metadata-token classname-meta)
(car tokens)))
(should (phpinspect-declaration-p (cadr tokens)))
(should (eq (phpinspect-token-metadata-token class-meta)
(caddr tokens))))))))
(ert-deftest phpinspect-parse-buffer-no-current ()
"Confirm that the parser is still functional with
`phpinspect-current-buffer' unset."

@ -379,3 +379,9 @@ the node iteself if it has been stored intact)."
(let ((tree (phpinspect-make-tree :start 5 :end 10)))
(should (phpinspect-tree-encloses tree (phpinspect-make-tree :start 5 :end 10)))
(should (phpinspect-tree-encloses tree (phpinspect-make-tree :start 5 :end 9)))))
(ert-deftest phpinspect-tree-insert-same-size ()
(let* ((tree (phpinspect-make-tree :start 5 :end 10))
(node (phpinspect-tree-insert-node tree (phpinspect-make-tree :start 5 :end 10))))
(should (eq node (seq-elt (phpinspect-tree-children tree) 0)))))

Loading…
Cancel
Save