Remove phpinspect-tree
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
parent
b89ef3611f
commit
55b8a0c562
@ -1,802 +0,0 @@
|
||||
;;; phpinspect-buffer.el --- PHP parsing and completion package -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2021 Free Software Foundation, Inc
|
||||
|
||||
;; Author: Hugo Thunnissen <devel@hugot.nl>
|
||||
;; Keywords: php, languages, tools, convenience
|
||||
;; Version: 0
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(cl-defstruct (phpinspect-tree (:constructor phpinspect-make-tree))
|
||||
"An n-ary tree implementation to store integer intervals.
|
||||
|
||||
Nodes within a layer of the tree are not allowed to overlap each
|
||||
other. Trying to add an overlapping node that cannot enclose or
|
||||
be enclosed in an existing node will result in an error.
|
||||
|
||||
Each node can have an infinite number of child nodes.
|
||||
|
||||
It is advisable for performance to define a root node with a
|
||||
range that encloses all nodes that are going to be added, as this
|
||||
will limit the amount of pointer shuffling to keep the root node
|
||||
reference intact (see also `phininspect-tree-insert-node'). That
|
||||
being said, not doing so will not limit the trees
|
||||
functionalities."
|
||||
(parent nil
|
||||
:type phpinspect-tree)
|
||||
(grow-root nil
|
||||
:type boolean)
|
||||
(children (phpinspect-make-ll)
|
||||
:type phpinspect-llnode)
|
||||
(start 0
|
||||
:type integer)
|
||||
(end 0
|
||||
:type integer)
|
||||
(value nil))
|
||||
|
||||
(cl-defstruct (phpinspect-llnode (:constructor phpinspect-make-ll))
|
||||
"A linked list implementation.
|
||||
|
||||
Links for specific cells are tracked and can be looked up via the
|
||||
link-map. This does assume that no duplicate cells are inserted
|
||||
however (multiple cells that are `eq' to each other). If
|
||||
duplicate cells are inserted, only the last inserted duplicate
|
||||
can be looked up via the link-map.
|
||||
|
||||
A few generic sequence functions have been implemented. Some of
|
||||
these, like `seq-take-while' return an instance of
|
||||
`phpinspect-slice', which is a window into a subsection of the
|
||||
list it was called on."
|
||||
(left nil
|
||||
:type phpinspect-llnode)
|
||||
(right nil
|
||||
:type phpinspect-llnode)
|
||||
(link-map (make-hash-table :test #'eq :size 100 :rehash-size 400)
|
||||
:type hash-table
|
||||
:documentation
|
||||
"Table to lookup the links in which values are stored.")
|
||||
(value nil))
|
||||
|
||||
(cl-defstruct (phpinspect-slice (:constructor phpinspect-make-slice))
|
||||
"A window to a subsection of a (`phpinspect-llnode') linked list. "
|
||||
(reversed nil
|
||||
:type bool
|
||||
:documentation
|
||||
"Whether the slice should be iterated in reverse")
|
||||
(start nil)
|
||||
(end nil))
|
||||
|
||||
(defmacro phpinspect-doslice (place-and-slice &rest body)
|
||||
(declare (indent defun))
|
||||
(let ((list (gensym))
|
||||
(slice-end (gensym))
|
||||
(normal-next-function #'phpinspect-llnode-right)
|
||||
(reverse-next-function #'phpinspect-llnode-left))
|
||||
|
||||
`(if (phpinspect-slice-reversed ,(cadr place-and-slice))
|
||||
(let ((,list (phpinspect-slice-end ,(cadr place-and-slice)))
|
||||
(,slice-end (phpinspect-llnode-left
|
||||
(phpinspect-slice-start ,(cadr place-and-slice)))))
|
||||
(when (phpinspect-llnode-value ,list)
|
||||
(while (and ,list (not (eq ,slice-end ,list)))
|
||||
(let ((,(car place-and-slice) (phpinspect-llnode-value ,list)))
|
||||
,@body)
|
||||
(setq ,list (,reverse-next-function ,list)))))
|
||||
|
||||
(let ((,list (phpinspect-slice-start ,(cadr place-and-slice)))
|
||||
(,slice-end (phpinspect-llnode-right
|
||||
(phpinspect-slice-end ,(cadr place-and-slice)))))
|
||||
(when (phpinspect-llnode-value ,list)
|
||||
(while (and ,list (not (eq ,slice-end ,list)))
|
||||
(let ((,(car place-and-slice) (phpinspect-llnode-value ,list)))
|
||||
,@body)
|
||||
(setq ,list (,normal-next-function ,list))))))))
|
||||
|
||||
(cl-defmethod seq-reverse ((slice phpinspect-slice))
|
||||
(setf (phpinspect-slice-reversed slice) (not (phpinspect-slice-reversed slice)))
|
||||
slice)
|
||||
|
||||
(cl-defmethod phpinspect-slice-detach ((slice phpinspect-slice))
|
||||
"Detach underlying link range from the linked list that it
|
||||
belongs to. Return resulting linked list."
|
||||
(let* ((start (phpinspect-slice-start slice))
|
||||
(end (phpinspect-slice-end slice))
|
||||
(right-neighbour (phpinspect-llnode-right end))
|
||||
(left-neighbour (phpinspect-llnode-left start)))
|
||||
;; No left-linked node means that `start' is the root reference to the
|
||||
;; list. This cannot be detached, so we need to create a new link that will
|
||||
;; serve as root for the detached list.
|
||||
(unless left-neighbour
|
||||
(let ((new-start (phpinspect-make-ll :right (phpinspect-llnode-right start)
|
||||
:value (phpinspect-llnode-value start)
|
||||
:link-map (phpinspect-llnode-link-map start))))
|
||||
(when (phpinspect-llnode-right start)
|
||||
(setf (phpinspect-llnode-left (phpinspect-llnode-right start)) new-start))
|
||||
|
||||
;; Make right neighbour the new root node of the list
|
||||
(if right-neighbour
|
||||
(progn
|
||||
(phpinspect-ll-relink start (phpinspect-llnode-value right-neighbour))
|
||||
(setq right-neighbour (phpinspect-llnode-right right-neighbour)))
|
||||
(phpinspect-ll-relink start nil))
|
||||
|
||||
(setq left-neighbour start)
|
||||
(when (eq start end) (setq end new-start))
|
||||
(setq start new-start)
|
||||
|
||||
;; Update slice itself
|
||||
(setf (phpinspect-slice-start slice) start)
|
||||
(setf (phpinspect-slice-end slice) end)))
|
||||
|
||||
|
||||
(unless (eq start end)
|
||||
(when right-neighbour
|
||||
(setf (phpinspect-llnode-left right-neighbour) left-neighbour))
|
||||
(setf (phpinspect-llnode-right left-neighbour) right-neighbour)
|
||||
|
||||
(setf (phpinspect-llnode-left start) nil)
|
||||
(setf (phpinspect-llnode-right end) nil))
|
||||
|
||||
;; Fix broken references in old link-map and create separate link-map for
|
||||
;; the new detached list.
|
||||
(let ((list start)
|
||||
(link-map (make-hash-table :test #'eq :size 100 :rehash-size 400)))
|
||||
(while list
|
||||
(phpinspect-ll-unregister-link list)
|
||||
(setf (phpinspect-llnode-link-map list) link-map)
|
||||
(phpinspect-ll-register-link list)
|
||||
(setq list (phpinspect-llnode-right 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)))
|
||||
|
||||
(cl-defmethod phpinspect-ll-unregister-link ((list phpinspect-llnode))
|
||||
(remhash (phpinspect-llnode-value list) (phpinspect-llnode-link-map list)))
|
||||
|
||||
(cl-defmethod phpinspect-ll-first ((list phpinspect-llnode))
|
||||
(while (phpinspect-llnode-left list)
|
||||
(setq list (phpinspect-llnode-left list)))
|
||||
(or (phpinspect-llnode-left list) list))
|
||||
|
||||
(cl-defmethod phpinspect-ll-last ((list phpinspect-llnode))
|
||||
(while (phpinspect-llnode-right list)
|
||||
(setq list (phpinspect-llnode-right list)))
|
||||
(or (phpinspect-llnode-right list) list))
|
||||
|
||||
(cl-defmethod phpinspect-ll-link ((list phpinspect-llnode) value)
|
||||
(or (gethash value (phpinspect-llnode-link-map list))
|
||||
(catch 'found
|
||||
(while list
|
||||
(when (eq value (phpinspect-llnode-value list))
|
||||
(phpinspect-ll-register-link list)
|
||||
(throw 'found list))
|
||||
(setq list (phpinspect-llnode-right list))))))
|
||||
|
||||
(cl-defmethod phpinspect-ll-relink ((list phpinspect-llnode) value)
|
||||
(phpinspect-ll-unregister-link list)
|
||||
(setf (phpinspect-llnode-value list) value)
|
||||
(phpinspect-ll-register-link list))
|
||||
|
||||
(cl-defmethod phpinspect-ll-push (value (list phpinspect-llnode))
|
||||
(setq list (phpinspect-ll-first list))
|
||||
|
||||
(if (phpinspect-llnode-value list)
|
||||
(let* ((old-right (phpinspect-llnode-right list))
|
||||
(new-right (phpinspect-make-ll
|
||||
:left list
|
||||
:link-map (phpinspect-llnode-link-map list)
|
||||
:value (phpinspect-llnode-value list)
|
||||
:right old-right)))
|
||||
(phpinspect-ll-register-link new-right)
|
||||
(setf (phpinspect-llnode-value list) value)
|
||||
(setf (phpinspect-llnode-right list) new-right)
|
||||
(phpinspect-ll-register-link list)
|
||||
(when old-right
|
||||
(setf (phpinspect-llnode-left old-right) new-right)))
|
||||
;; else
|
||||
(setf (phpinspect-llnode-value list) value)
|
||||
(phpinspect-ll-register-link list))
|
||||
list)
|
||||
|
||||
(cl-defmethod phpinspect-ll-insert-right ((list phpinspect-llnode) value)
|
||||
(let* ((original-right (phpinspect-llnode-right list))
|
||||
(new-link (phpinspect-make-ll :left list
|
||||
:link-map (phpinspect-llnode-link-map list)
|
||||
:right original-right
|
||||
:value value)))
|
||||
(phpinspect-ll-register-link new-link)
|
||||
(setf (phpinspect-llnode-right list) new-link)
|
||||
(when original-right
|
||||
(setf (phpinspect-llnode-left original-right) new-link))))
|
||||
|
||||
(cl-defmethod phpinspect-ll-insert-left ((list phpinspect-llnode) value)
|
||||
(let* ((original-left (phpinspect-llnode-left list))
|
||||
(new-link (phpinspect-make-ll :right list
|
||||
:link-map (phpinspect-llnode-link-map list)
|
||||
:left original-left
|
||||
:value value)))
|
||||
(phpinspect-ll-register-link new-link)
|
||||
(setf (phpinspect-llnode-left list) new-link)
|
||||
(when original-left
|
||||
(setf (phpinspect-llnode-right original-left) new-link))))
|
||||
|
||||
(cl-defmethod seq-elt ((list phpinspect-llnode) (n integer))
|
||||
(setq list (phpinspect-ll-first list))
|
||||
|
||||
(let ((current-elt 0))
|
||||
(while (and list (not (= current-elt n)))
|
||||
(setq list (phpinspect-llnode-right list)
|
||||
current-elt (+ current-elt 1)))
|
||||
|
||||
(when list
|
||||
(phpinspect-llnode-value list))))
|
||||
|
||||
(cl-defmethod seq-elt ((slice phpinspect-slice) (n integer))
|
||||
(let ((list (phpinspect-slice-start slice))
|
||||
(end (phpinspect-llnode-right (phpinspect-slice-end slice))))
|
||||
|
||||
(let ((current-elt 0))
|
||||
(while (and list (not (= current-elt n)))
|
||||
(setq list (phpinspect-llnode-right list)
|
||||
current-elt (+ current-elt 1)))
|
||||
(when (eq end list)
|
||||
(setq list nil)))
|
||||
|
||||
(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))
|
||||
(phpinspect-doslice (val slice)
|
||||
(funcall fn val)))
|
||||
|
||||
(cl-defmethod seq-take-while (pred (list phpinspect-llnode))
|
||||
(when (phpinspect-llnode-value list)
|
||||
(let ((start list)
|
||||
(end list))
|
||||
(while (and list (funcall pred (phpinspect-llnode-value list)))
|
||||
(setq end list)
|
||||
(setq list (phpinspect-llnode-right list)))
|
||||
|
||||
(phpinspect-make-slice :start start :end end))))
|
||||
|
||||
(cl-defmethod seq-take-while (pred (slice phpinspect-slice))
|
||||
(let ((start (phpinspect-slice-start slice))
|
||||
(end (phpinspect-slice-start slice)))
|
||||
(catch 'break
|
||||
(phpinspect-doslice (val slice)
|
||||
(if (funcall pred val)
|
||||
(setq end (phpinspect-ll-link start val))
|
||||
(throw 'break nil))))
|
||||
|
||||
(phpinspect-make-slice :start start :end end)))
|
||||
|
||||
(cl-defmethod seq-length ((list phpinspect-llnode))
|
||||
(let ((count 0))
|
||||
(while (and list (phpinspect-llnode-value list))
|
||||
(setq count (+ 1 count)
|
||||
list (phpinspect-llnode-right list)))
|
||||
count))
|
||||
|
||||
(cl-defmethod seq-length ((slice phpinspect-slice))
|
||||
(let ((count 0)
|
||||
(list (phpinspect-slice-start slice))
|
||||
(end (phpinspect-llnode-right (phpinspect-slice-end slice))))
|
||||
(while (and list (not (eq end list))
|
||||
(phpinspect-llnode-value list))
|
||||
(setq count (+ 1 count)
|
||||
list (phpinspect-llnode-right list))
|
||||
(when (eq end list)
|
||||
(setq list nil)))
|
||||
|
||||
count))
|
||||
|
||||
(cl-defmethod seq-into ((list phpinspect-llnode) type)
|
||||
(if (eq 'slice type)
|
||||
(phpinspect-make-slice :start list :end (phpinspect-ll-last list))
|
||||
(let ((destination)
|
||||
(list (phpinspect-ll-last list)))
|
||||
(while list
|
||||
(push (phpinspect-llnode-value list) destination)
|
||||
(setq list (phpinspect-llnode-left list)))
|
||||
|
||||
(cond ((eq 'vector type) (vconcat destination))
|
||||
((eq 'list type) destination)
|
||||
((eq 'string type) (concat destination))
|
||||
(t (error "Not a sequence type name: %S" type))))))
|
||||
|
||||
(cl-defmethod seq-into ((slice phpinspect-slice) type)
|
||||
(let ((destination))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(seq-reverse slice)
|
||||
(phpinspect-doslice (val slice)
|
||||
(push val destination)))
|
||||
(seq-reverse slice))
|
||||
|
||||
(cond ((eq 'vector type) (vconcat destination))
|
||||
((eq 'list type) destination)
|
||||
((eq 'string type) (concat destination))
|
||||
(t (error "Not a sequence type name: %S" type)))))
|
||||
|
||||
(cl-defmethod seq-find (pred (list phpinspect-llnode) &optional default)
|
||||
(if (phpinspect-llnode-value list)
|
||||
(while (and list (not (funcall pred (phpinspect-llnode-value list))))
|
||||
(setq list (phpinspect-llnode-right list)))
|
||||
(setq list nil))
|
||||
|
||||
(if list
|
||||
(phpinspect-llnode-value list)
|
||||
default))
|
||||
|
||||
(cl-defmethod seq-find (pred (slice phpinspect-slice) &optional default)
|
||||
(or
|
||||
(catch 'found
|
||||
(phpinspect-doslice (val slice)
|
||||
(when (funcall pred val)
|
||||
(throw 'found val))))
|
||||
default))
|
||||
|
||||
(cl-defmethod phpinspect-ll-pp ((list phpinspect-llnode))
|
||||
(message "(phpinspect-ll %s)"
|
||||
(string-join (seq-map (lambda (x) (format "%s" x)) list) ", ")))
|
||||
|
||||
(cl-defmethod phpinspect-llnode-is-tail ((list phpinspect-llnode))
|
||||
(not (phpinspect-llnode-right list)))
|
||||
|
||||
(cl-defmethod seq-empty-p ((list phpinspect-llnode))
|
||||
(and (not (phpinspect-llnode-value list))
|
||||
(phpinspect-llnode-is-tail list)))
|
||||
|
||||
(cl-defmethod phpinspect-tree-overlaps ((tree phpinspect-tree) (point integer))
|
||||
(and (> (phpinspect-tree-end tree) point)
|
||||
(<= (phpinspect-tree-start tree) point)))
|
||||
|
||||
(cl-defmethod phpinspect-tree-overlaps ((tree1 phpinspect-tree) (tree2 phpinspect-tree))
|
||||
(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) 1))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-overlaps ((tree phpinspect-tree) region)
|
||||
(or (phpinspect-tree-overlaps tree (phpinspect-region-start region))
|
||||
(phpinspect-tree-overlaps tree (- (phpinspect-region-end region) 1))
|
||||
(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))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-switch-attributes ((tree1 phpinspect-tree) (tree2 phpinspect-tree))
|
||||
(let ((parent (phpinspect-tree-parent tree1))
|
||||
(children (phpinspect-tree-children tree1))
|
||||
(start (phpinspect-tree-start tree1))
|
||||
(end (phpinspect-tree-end tree1))
|
||||
(value (phpinspect-tree-value tree1)))
|
||||
|
||||
(setf (phpinspect-tree-parent tree1) (phpinspect-tree-parent tree2))
|
||||
(setf (phpinspect-tree-children tree1) (phpinspect-tree-children tree2))
|
||||
(setf (phpinspect-tree-start tree1) (phpinspect-tree-start tree2))
|
||||
(setf (phpinspect-tree-end tree1) (phpinspect-tree-end tree2))
|
||||
(setf (phpinspect-tree-value tree1) (phpinspect-tree-value tree2))
|
||||
|
||||
(seq-map (lambda (child)
|
||||
(setf (phpinspect-tree-parent child) tree1))
|
||||
children)
|
||||
|
||||
(setf (phpinspect-tree-parent tree2) parent)
|
||||
(setf (phpinspect-tree-children tree2) children)
|
||||
(setf (phpinspect-tree-start tree2) start)
|
||||
(setf (phpinspect-tree-end tree2) end)
|
||||
(setf (phpinspect-tree-value tree2) value)
|
||||
|
||||
(seq-map (lambda (child)
|
||||
(setf (phpinspect-tree-parent child) tree2))
|
||||
children)))
|
||||
|
||||
(cl-defmethod phpinspect-tree-find-overlapping-children
|
||||
((tree phpinspect-tree) (start integer) (end integer))
|
||||
(let* ((region (phpinspect-make-region start end))
|
||||
(children (phpinspect-tree-children tree))
|
||||
(first-overlapper
|
||||
(seq-find (lambda (child) (phpinspect-tree-overlaps child region))
|
||||
children)))
|
||||
(when first-overlapper
|
||||
(seq-take-while (lambda (child) (phpinspect-tree-overlaps child region))
|
||||
(phpinspect-ll-link children first-overlapper)))))
|
||||
|
||||
(defsubst phpinspect-tree-empty-p (tree)
|
||||
(and (= 0 (phpinspect-tree-start tree))
|
||||
(= 0 (phpinspect-tree-end tree))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-find-next-relative-starting-at ((tree phpinspect-tree) (point integer))
|
||||
(when (< point (phpinspect-tree-start tree))
|
||||
(error "Can't find next relative when point is before tree start"))
|
||||
|
||||
(let ((parent (phpinspect-tree-parent tree))
|
||||
(found?))
|
||||
(catch 'found
|
||||
;; First check own children
|
||||
(when (and (> (phpinspect-tree-end tree) point)
|
||||
(setq found? (phpinspect-tree-find-node-starting-at tree point)))
|
||||
(throw 'found found?))
|
||||
|
||||
(while parent
|
||||
(when (> (phpinspect-tree-end parent) point)
|
||||
;; Check siblings after
|
||||
(let ((parent-link (phpinspect-ll-link (phpinspect-tree-children parent) tree)))
|
||||
(seq-doseq (sibling parent-link)
|
||||
(when (setq found? (phpinspect-tree-find-node-starting-at sibling point))
|
||||
(throw 'found found?)))))
|
||||
|
||||
(setq tree parent)
|
||||
(setq parent (phpinspect-tree-parent parent))))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-envelop ((tree phpinspect-tree) (node phpinspect-tree))
|
||||
|
||||
(when (< (phpinspect-tree-start node) (phpinspect-tree-start tree))
|
||||
(setf (phpinspect-tree-start tree) (phpinspect-tree-start node)))
|
||||
|
||||
(when (> (phpinspect-tree-end node) (phpinspect-tree-end tree))
|
||||
(setf (phpinspect-tree-end tree) (phpinspect-tree-end node))))
|
||||
|
||||
|
||||
(cl-defmethod phpinspect-tree-find-last-child-before-point ((tree phpinspect-tree) (point integer))
|
||||
(catch 'found
|
||||
(seq-doseq (child (seq-reverse (seq-into (phpinspect-tree-children tree) 'slice)))
|
||||
(when (<= (phpinspect-tree-end child) point)
|
||||
(throw 'found child)))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-insert-node ((tree phpinspect-tree) (node phpinspect-tree))
|
||||
"Insert a new NODE into TREE.
|
||||
|
||||
Returns the newly inserted node."
|
||||
(when (phpinspect-tree-grow-root tree)
|
||||
(phpinspect-tree-envelop tree node))
|
||||
|
||||
(cond ((phpinspect-tree-empty-p tree)
|
||||
(phpinspect-tree-switch-attributes node tree)
|
||||
|
||||
;; Return
|
||||
tree)
|
||||
((phpinspect-tree-encloses tree node)
|
||||
;; New node is entirely enclosed by tree, check tree's children for
|
||||
;; overlappings.
|
||||
(let* ((overlappers (phpinspect-tree-find-overlapping-children
|
||||
tree (phpinspect-tree-start node) (phpinspect-tree-end node)))
|
||||
(overlap-count (seq-length overlappers)))
|
||||
(if overlappers
|
||||
(cond
|
||||
((or (< 1 overlap-count)
|
||||
(and (= 1 overlap-count)
|
||||
(phpinspect-tree-encloses node (seq-elt overlappers 0))))
|
||||
;; There are multiple overlapping children. They need to all
|
||||
;; fit within node, or the hierarchy is broken.
|
||||
(let ((enclosed
|
||||
(seq-take-while
|
||||
(lambda (child) (phpinspect-tree-encloses node child))
|
||||
overlappers))
|
||||
(insert-after-link))
|
||||
|
||||
(unless (= (seq-length enclosed) overlap-count)
|
||||
(throw 'phpinspect-tree-conflict
|
||||
"Node overlaps multiple children, but does not enclose them all"))
|
||||
|
||||
;; Find the list link that the first enclosed node is attached to.
|
||||
(setq insert-after-link (phpinspect-llnode-left
|
||||
(phpinspect-slice-start enclosed)))
|
||||
|
||||
;; Remove enclosed nodes from parent
|
||||
(setq enclosed (phpinspect-slice-detach enclosed))
|
||||
|
||||
(if insert-after-link
|
||||
;; Insert new node into old enclosed node position
|
||||
(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)
|
||||
|
||||
(seq-doseq (child enclosed)
|
||||
(setf (phpinspect-tree-parent child) node))
|
||||
(setf (phpinspect-tree-children node) enclosed)))
|
||||
((= 1 overlap-count)
|
||||
(phpinspect-tree-insert-node (seq-elt overlappers 0)
|
||||
node))
|
||||
)
|
||||
|
||||
;; ELSE: No overlap, node can safely be added as child
|
||||
(setf (phpinspect-tree-parent node) tree)
|
||||
(let* ((left-neighbour (phpinspect-tree-children tree))
|
||||
(left-neighbour-value
|
||||
(phpinspect-tree-find-last-child-before-point tree (phpinspect-tree-start node))))
|
||||
|
||||
(if left-neighbour-value
|
||||
(progn
|
||||
(setq left-neighbour (phpinspect-ll-link left-neighbour left-neighbour-value))
|
||||
(phpinspect-ll-insert-right left-neighbour node))
|
||||
(phpinspect-ll-push node left-neighbour)))))
|
||||
|
||||
;; 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)
|
||||
(setf (phpinspect-tree-parent node) parent)
|
||||
(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: (%d,%d,%s) \n\nPerspective child: (%d,%d,%s)"
|
||||
(phpinspect-tree-start tree)
|
||||
(phpinspect-tree-end tree)
|
||||
(if (phpinspect-tree-parent tree) "non-root" "root")
|
||||
(phpinspect-tree-start node)
|
||||
(phpinspect-tree-end node)
|
||||
(if (phpinspect-tree-parent node) "non-root" "root"))))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-traverse-overlapping ((tree phpinspect-tree) (point integer))
|
||||
"Traverse TREE for intervals overlapping POINT.
|
||||
|
||||
Returns list of values from overlapping trees, sorted by interval
|
||||
width with the smallest interval as car."
|
||||
(when (phpinspect-tree-overlaps tree point)
|
||||
(let* ((from-end (- (phpinspect-tree-end tree) point))
|
||||
(from-start (- point (phpinspect-tree-start tree)))
|
||||
(overlapper
|
||||
(catch 'found
|
||||
(let ((children (seq-into (phpinspect-tree-children tree) 'slice)))
|
||||
(when (> from-start from-end)
|
||||
(setq children (seq-reverse children)))
|
||||
|
||||
(phpinspect-doslice (child children)
|
||||
(when (phpinspect-tree-overlaps child point)
|
||||
(throw 'found child)))))))
|
||||
|
||||
(if overlapper
|
||||
`(,@(phpinspect-tree-traverse-overlapping overlapper point) ,(phpinspect-tree-value tree))
|
||||
`(,(phpinspect-tree-value tree))))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-traverse-overlapping ((tree phpinspect-tree) region)
|
||||
"Traverse TREE for intervals overlapping POINT.
|
||||
|
||||
Returns list of values from overlapping trees, sorted by interval
|
||||
width with the smallest interval as car."
|
||||
(when (phpinspect-tree-overlaps tree region)
|
||||
(let* ((overlappers (phpinspect-tree-find-overlapping-children
|
||||
tree
|
||||
(phpinspect-region-start region)
|
||||
(phpinspect-region-end region))))
|
||||
(if overlappers
|
||||
(let ((all-overlappers))
|
||||
(seq-doseq (overlapper overlappers)
|
||||
(setq all-overlappers
|
||||
(append all-overlappers (phpinspect-tree-traverse-overlapping overlapper region))))
|
||||
`(,@all-overlappers ,(phpinspect-tree-value tree)))
|
||||
`(,(phpinspect-tree-value tree))))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-shift ((tree phpinspect-tree) (delta integer))
|
||||
(phpinspect-tree-traverse (node tree)
|
||||
(setf (phpinspect-tree-start node) (+ (phpinspect-tree-start node) delta))
|
||||
(setf (phpinspect-tree-end node) (+ (phpinspect-tree-end node) delta))))
|
||||
|
||||
(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 delta)))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-find-node-starting-at ((tree phpinspect-tree) (point integer))
|
||||
(if (= (phpinspect-tree-start tree) point)
|
||||
tree
|
||||
(catch 'found
|
||||
(let ((overlapped))
|
||||
(seq-doseq (child (phpinspect-tree-children tree))
|
||||
(if (phpinspect-tree-overlaps tree point)
|
||||
(progn
|
||||
(setq overlapped t)
|
||||
(let ((found? (phpinspect-tree-find-node-starting-at child point)))
|
||||
(when found? (throw 'found found?))))
|
||||
|
||||
;; Stop iterating when overlap stops
|
||||
(when overlapped (throw 'found nil))))))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-width ((tree phpinspect-tree))
|
||||
(- (phpinspect-tree-start tree) (phpinspect-tree-end tree)))
|
||||
|
||||
(cl-defmethod phpinspect-tree-find-smallest-overlapping-set ((tree phpinspect-tree) region)
|
||||
"Traverse TREE for smallest set of intervals overlapping REGION,
|
||||
|
||||
Returns list of values from the set of overlapping trees that
|
||||
collectively have the smallest width."
|
||||
(when (phpinspect-tree-overlaps tree region)
|
||||
(let* ((tree-start (phpinspect-tree-start tree))
|
||||
(tree-end (phpinspect-tree-end tree))
|
||||
(overlappers (phpinspect-tree-find-overlapping-children
|
||||
tree (phpinspect-region-start region)
|
||||
(phpinspect-region-end region)))
|
||||
(overlap-count (seq-length overlappers))
|
||||
(overlap-start tree-start)
|
||||
(overlap-end tree-end))
|
||||
|
||||
(when overlappers
|
||||
(setq overlap-start
|
||||
(phpinspect-tree-start
|
||||
(phpinspect-llnode-value (phpinspect-slice-start overlappers))))
|
||||
(setq overlap-end
|
||||
(phpinspect-tree-end
|
||||
(phpinspect-llnode-value (phpinspect-slice-end overlappers)))))
|
||||
|
||||
(if (or (> overlap-start tree-start)
|
||||
(< overlap-end tree-end))
|
||||
(cond
|
||||
((< 1 overlap-count)
|
||||
;; Overlap of children is smaller, but no point recursing if it already
|
||||
;; spans two children. Return overlappers.
|
||||
(seq-map #'phpinspect-tree-value overlappers))
|
||||
((= 1 overlap-count)
|
||||
;; Overlap of single child is smaller, recurse.
|
||||
(phpinspect-tree-find-smallest-overlapping-set (seq-elt overlappers 0)
|
||||
region)))
|
||||
;; Overlap spans the entire tree, so this already is the smallest
|
||||
;; overlapping set (of one).
|
||||
`(,(phpinspect-tree-value tree))))))
|
||||
|
||||
(cl-defmethod phpinspect-tree-insert
|
||||
((tree phpinspect-tree) (start integer) (end integer) value)
|
||||
"Insert a new interval from START to END linked to VALUE into TREE.
|
||||
|
||||
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 without renewing its value map."
|
||||
(let ((parent (phpinspect-tree-parent tree)))
|
||||
(when parent
|
||||
(let ((parent-link (phpinspect-ll-link (phpinspect-tree-children parent)
|
||||
tree)))
|
||||
(unless parent-link
|
||||
(phpinspect--log "No parent link for node, trying to find it manually")
|
||||
(message "No parent link for tree of %s" (phpinspect-tree-meta-token tree))
|
||||
(message "Parent: %s" (phpinspect-tree-meta-token parent))
|
||||
(setq parent-link
|
||||
(seq-find (lambda (child) (eq child tree))
|
||||
(phpinspect-tree-children parent))))
|
||||
|
||||
(if parent-link
|
||||
(phpinspect-llnode-detach parent-link)
|
||||
(phpinspect--log "[WARNING] No parent link for node."))
|
||||
|
||||
|
||||
(setf (phpinspect-tree-parent tree) nil)))
|
||||
tree))
|
||||
|
||||
(defmacro phpinspect-tree-traverse (place-and-tree &rest body)
|
||||
(declare (indent defun))
|
||||
(let ((stack (gensym))
|
||||
(child (gensym))
|
||||
(children (gensym)))
|
||||
`(let ((,stack (list ,(cadr place-and-tree)))
|
||||
(,(car place-and-tree)))
|
||||
(while (setq ,(car place-and-tree) (pop ,stack))
|
||||
,@body
|
||||
(let ((,children (phpinspect-tree-children ,(car place-and-tree))))
|
||||
(unless (seq-empty-p ,children)
|
||||
(seq-doseq (,child ,children)
|
||||
(push ,child ,stack))))))))
|
||||
|
||||
(defsubst phpinspect-make-region (start end)
|
||||
(list start end))
|
||||
|
||||
(defalias 'phpinspect-region-start #'car)
|
||||
(defalias 'phpinspect-region-end #'cadr)
|
||||
|
||||
(defsubst phpinspect-region-size (region)
|
||||
(- (phpinspect-region-end region) (phpinspect-region-start region)))
|
||||
|
||||
(defsubst phpinspect-region> (reg1 reg2)
|
||||
(> (phpinspect-region-size reg1) (phpinspect-region-size reg2)))
|
||||
|
||||
(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))))
|
||||
|
||||
(provide 'phpinspect-tree)
|
@ -1,475 +0,0 @@
|
||||
;;; test-buffer.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Hugo Thunnissen <devel@hugot.nl>
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'ert)
|
||||
(require 'phpinspect-tree)
|
||||
(require 'phpinspect-buffer)
|
||||
|
||||
|
||||
(ert-deftest phpinspect-ll-seq-elt ()
|
||||
"Test `seq-elt' implementation for linked list."
|
||||
|
||||
(let ((list (phpinspect-make-ll
|
||||
:value "a"
|
||||
:right (phpinspect-make-ll :value "b"
|
||||
:right (phpinspect-make-ll :value "c")))))
|
||||
(should (string= "a" (seq-elt list 0)))
|
||||
(should (string= "b" (seq-elt list 1)))
|
||||
(should (string= "c" (seq-elt list 2)))
|
||||
(should-not (seq-elt list 3))))
|
||||
|
||||
(ert-deftest phpinspect-ll-push ()
|
||||
(let ((list (phpinspect-make-ll)))
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
|
||||
|
||||
(should (string= "c" (seq-elt list 0)))
|
||||
(should (string= "b" (seq-elt list 1)))
|
||||
(should (string= "a" (seq-elt list 2)))
|
||||
(should (string= "c" (phpinspect-llnode-value
|
||||
(phpinspect-llnode-left
|
||||
(phpinspect-ll-link list (seq-elt list 1))))))
|
||||
(should (string= "b" (phpinspect-llnode-value
|
||||
(phpinspect-llnode-left
|
||||
(phpinspect-ll-link list (seq-elt list 2))))))))
|
||||
|
||||
|
||||
(ert-deftest phpinspect-ll-link ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(link-value)
|
||||
(link))
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
|
||||
(setq link-value (seq-elt list 1))
|
||||
(setq link (phpinspect-ll-link list link-value))
|
||||
|
||||
(should (eq link-value (phpinspect-llnode-value link)))))
|
||||
|
||||
(ert-deftest phpinspect-ll-insert-right ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(link-value)
|
||||
(link))
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
|
||||
(setq link-value (seq-elt list 1))
|
||||
(setq link (phpinspect-ll-link list link-value))
|
||||
|
||||
(phpinspect-ll-insert-right link "aba")
|
||||
(should (string= "aba" (seq-elt list 2)))
|
||||
(should (string= "a" (seq-elt list 3)))))
|
||||
|
||||
(ert-deftest phpinspect-ll-insert-left ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(link-value)
|
||||
(link))
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
|
||||
(setq link-value (seq-elt list 1))
|
||||
(setq link (phpinspect-ll-link list link-value))
|
||||
|
||||
(phpinspect-ll-insert-left link "aba")
|
||||
(should (string= "aba" (seq-elt list 1)))
|
||||
(should (string= "c" (seq-elt list 0)))
|
||||
|
||||
(should (string= "b" (seq-elt list 2)))))
|
||||
|
||||
(ert-deftest phpinspect-ll-seq-into ()
|
||||
(let ((list (phpinspect-make-ll)))
|
||||
(phpinspect-ll-push "d" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
|
||||
(should (equal '("a" "b" "c" "d") (seq-into list 'list)))))
|
||||
|
||||
(ert-deftest phpinspect-slice-reverse ()
|
||||
(let ((list (phpinspect-make-ll)))
|
||||
(phpinspect-ll-push "d" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
|
||||
(let ((slice (seq-into list 'slice)))
|
||||
(should (equal '("a" "b" "c" "d") (seq-into slice 'list)))
|
||||
(should (equal '("d" "c" "b" "a") (seq-into (seq-reverse slice) 'list))))))
|
||||
|
||||
|
||||
(ert-deftest phpinspect-ll-seq-take-while ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(result))
|
||||
(phpinspect-ll-push "bla" list)
|
||||
(phpinspect-ll-push "foo" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
|
||||
(setq result (seq-take-while (lambda (a) (string= a "a"))
|
||||
list))
|
||||
|
||||
(seq-map (lambda (a) (should (string= a "a")))
|
||||
result)
|
||||
|
||||
(should (string= "aaa" (apply #'concat (seq-into result 'list))))))
|
||||
|
||||
(ert-deftest phpinspect-ll-seq-take-while-subset ()
|
||||
"seq-take-while should also work from a different start link than
|
||||
the start of the list."
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(start-link)
|
||||
(result))
|
||||
(phpinspect-ll-push "bla" list)
|
||||
(phpinspect-ll-push "foo" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
|
||||
(setq start-link (phpinspect-ll-link list (seq-elt list 2)))
|
||||
|
||||
(setq result (seq-take-while (lambda (a) (string= a "a"))
|
||||
start-link))
|
||||
|
||||
(seq-map (lambda (a) (should (string= a "a")))
|
||||
result)
|
||||
|
||||
(should (string= "aaa" (apply #'concat (seq-into result 'list))))))
|
||||
|
||||
(ert-deftest phpinspect-ll-seq-find ()
|
||||
(let ((list (phpinspect-make-ll)))
|
||||
(phpinspect-ll-push "d" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
|
||||
(should (string= "c" (seq-find (lambda (c) (string= "c" c)) list)))))
|
||||
|
||||
(ert-deftest phpinspect-ll-link ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(value1 "a")
|
||||
(value2 "b")
|
||||
(value3 "c")
|
||||
(value4 "d"))
|
||||
(phpinspect-ll-push value1 list)
|
||||
(should (phpinspect-ll-link list value1))
|
||||
(phpinspect-ll-push value2 list)
|
||||
(should (phpinspect-ll-link list value2))
|
||||
|
||||
(phpinspect-ll-insert-right (phpinspect-ll-link list value1) value3)
|
||||
(should (phpinspect-ll-link list value3))
|
||||
|
||||
(phpinspect-ll-insert-left (phpinspect-ll-link list value3) value4)
|
||||
(should (phpinspect-ll-link list value3))))
|
||||
|
||||
(ert-deftest phpinspect-ll-seq-length ()
|
||||
(let ((list (phpinspect-make-ll)))
|
||||
(phpinspect-ll-push "d" list)
|
||||
(phpinspect-ll-push "c" list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push "a" list)
|
||||
|
||||
(should (= 4 (seq-length list)))))
|
||||
|
||||
(ert-deftest phpinspect-ll-seq-find ()
|
||||
(let ((list (phpinspect-make-ll)))
|
||||
(phpinspect-ll-push "target1" list)
|
||||
(phpinspect-ll-push "target2" list)
|
||||
(phpinspect-ll-push "target3" list)
|
||||
(phpinspect-ll-push "target4" list)
|
||||
|
||||
(should-not (seq-find #'not list))
|
||||
(should (string= "target1" (seq-find (lambda (s) (string= "target1" s))
|
||||
list)))
|
||||
(should (string= "target2" (seq-find (lambda (s) (string= "target2" s))
|
||||
list)))
|
||||
(should (string= "target3" (seq-find (lambda (s) (string= "target3" s))
|
||||
list)))
|
||||
(should (string= "target4" (seq-find (lambda (s) (string= "target4" s))
|
||||
list)))))
|
||||
|
||||
(ert-deftest phpinspect-slice-seq-find ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(target1 "target1")
|
||||
(target4 "target4")
|
||||
(slice))
|
||||
(phpinspect-ll-push target1 list)
|
||||
(phpinspect-ll-push "target2" list)
|
||||
(phpinspect-ll-push "target3" list)
|
||||
(phpinspect-ll-push target4 list)
|
||||
|
||||
(setq slice (phpinspect-make-slice :start (phpinspect-ll-link list target4)
|
||||
:end (phpinspect-ll-link list target1)))
|
||||
|
||||
(should-not (seq-find #'not slice))
|
||||
(should (string= "target1" (seq-find (lambda (s) (string= "target1" s))
|
||||
slice)))
|
||||
(should (string= "target2" (seq-find (lambda (s) (string= "target2" s))
|
||||
slice)))
|
||||
(should (string= "target3" (seq-find (lambda (s) (string= "target3" s))
|
||||
slice)))
|
||||
(should (string= "target4" (seq-find (lambda (s) (string= "target4" s))
|
||||
slice)))))
|
||||
|
||||
(ert-deftest phpinspect-slice-detach ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(val1 "c")
|
||||
(val2 "a")
|
||||
(d "d")
|
||||
(slice)
|
||||
(detached-list))
|
||||
(phpinspect-ll-push d list)
|
||||
(phpinspect-ll-push val1 list)
|
||||
(phpinspect-ll-push "b" list)
|
||||
(phpinspect-ll-push val2 list)
|
||||
|
||||
(setq slice (phpinspect-make-slice :start list
|
||||
:end (phpinspect-ll-link list val1)))
|
||||
|
||||
(setq detached-list (phpinspect-slice-detach slice))
|
||||
|
||||
(should-not (eq detached-list list))
|
||||
(should (string= "d" (apply #'concat (seq-into list 'list))))
|
||||
(should (string= "abc" (apply #'concat (seq-into detached-list 'list))))
|
||||
|
||||
(should-not (phpinspect-ll-link list val1))
|
||||
(should (phpinspect-ll-link list d))
|
||||
(should (phpinspect-ll-link detached-list val1))
|
||||
(should (phpinspect-ll-link detached-list val2))))
|
||||
|
||||
(ert-deftest phpinspect-slice-detach-single-member ()
|
||||
(let ((list (phpinspect-make-ll))
|
||||
(val1 "a")
|
||||
(slice)
|
||||
(detached-list))
|
||||
(phpinspect-ll-push val1 list)
|
||||
|
||||
(setq slice (phpinspect-make-slice :start list :end list))
|
||||
(should (string= "a" (apply #'concat (seq-into slice 'list))))
|
||||
(should (string= "a" (apply #'concat (seq-into list 'list))))
|
||||
|
||||
(setq detached-list (phpinspect-slice-detach slice))
|
||||
(should (string= "a" (apply #'concat (seq-into slice 'list))))
|
||||
(should (string= "a" (apply #'concat (seq-into detached-list 'list))))
|
||||
(should (seq-empty-p list))
|
||||
(should-not (phpinspect-ll-link list val1))
|
||||
(should (phpinspect-ll-link detached-list val1))))
|
||||
|
||||
|
||||
(ert-deftest phpinspect-tree-insert-enclosing-node ()
|
||||
(let ((tree (phpinspect-make-tree :start 10 :end 100))
|
||||
(node (phpinspect-make-tree :start 9 :end 200)))
|
||||
(phpinspect-tree-insert-node tree node)
|
||||
|
||||
(should (= 9 (phpinspect-tree-start tree)))
|
||||
(should (= 200 (phpinspect-tree-end tree)))
|
||||
(should (= 10 (phpinspect-tree-start node)))
|
||||
(should (= 100 (phpinspect-tree-end node)))
|
||||
|
||||
(should (eq node (phpinspect-llnode-value
|
||||
(phpinspect-tree-children tree))))))
|
||||
|
||||
(ert-deftest phpinspect-tree-insert-enclosing-node-into-tree-with-parent ()
|
||||
(let* ((parent (phpinspect-make-tree :start 0 :end 200))
|
||||
(tree (phpinspect-make-tree :start 10 :end 100))
|
||||
(node (phpinspect-make-tree :start 11 :end 50)))
|
||||
(phpinspect-tree-insert-node parent tree)
|
||||
(phpinspect-tree-insert-node tree node)
|
||||
|
||||
(should (eq parent (phpinspect-tree-parent tree)))
|
||||
(should (eq tree (phpinspect-tree-parent node)))
|
||||
(should (eq node (phpinspect-llnode-value
|
||||
(phpinspect-tree-children tree))))))
|
||||
|
||||
(ert-deftest phpinspect-tree-insert-nested ()
|
||||
(let ((tree (phpinspect-make-tree :start 0 :end 500))
|
||||
(node2 (phpinspect-make-tree :start 20 :end 200))
|
||||
(node3 (phpinspect-make-tree :start 9 :end 20))
|
||||
(node4 (phpinspect-make-tree :start 21 :end 44))
|
||||
(node1 (phpinspect-make-tree :start 9 :end 200)))
|
||||
|
||||
(should (phpinspect-tree-parent (phpinspect-tree-insert-node tree node1)))
|
||||
(should (phpinspect-tree-parent(phpinspect-tree-insert-node tree node2)))
|
||||
(should (phpinspect-tree-parent (phpinspect-tree-insert-node tree node3)))
|
||||
(should (phpinspect-tree-parent (phpinspect-tree-insert-node tree node4)))
|
||||
|
||||
(should (phpinspect-ll-link (phpinspect-tree-children (phpinspect-tree-parent node1)) node1))
|
||||
(should (phpinspect-ll-link (phpinspect-tree-children (phpinspect-tree-parent node2)) node2))
|
||||
(should (phpinspect-ll-link (phpinspect-tree-children (phpinspect-tree-parent node3)) node3))
|
||||
(should (phpinspect-ll-link (phpinspect-tree-children (phpinspect-tree-parent node4)) node4))
|
||||
|
||||
(should (= 0 (phpinspect-tree-start tree)))
|
||||
(should (= 500 (phpinspect-tree-end tree)))
|
||||
|
||||
(should (= 1 (seq-length (phpinspect-tree-children tree))))
|
||||
(let ((firstchild (seq-elt (phpinspect-tree-children tree) 0)))
|
||||
(should (eq node1 firstchild))
|
||||
(should (= 2 (seq-length (phpinspect-tree-children firstchild))))
|
||||
(should (eq node3 (seq-elt (phpinspect-tree-children firstchild) 0)))
|
||||
(should (eq node2 (seq-elt (phpinspect-tree-children firstchild) 1))))
|
||||
|
||||
(should (eq node4 (seq-elt (phpinspect-tree-children node2) 0)))))
|
||||
|
||||
(ert-deftest phpinspect-tree-insert-returns-node ()
|
||||
"Because returning things from lisp functions can be kind of a hassle sometimes ;).
|
||||
|
||||
Tests whether phpinspect-tree-insert-node actually returns the
|
||||
correct node (the one that the nodes values were stored in, or
|
||||
the node iteself if it has been stored intact)."
|
||||
(let* ((tree (phpinspect-make-tree :start 0 :end 500))
|
||||
(node1 (phpinspect-make-tree :start 0 :end 800))
|
||||
(node2 (phpinspect-make-tree :start 20 :end 200))
|
||||
(node3 (phpinspect-make-tree :start 9 :end 20))
|
||||
(node4 (phpinspect-make-tree :start 21 :end 44))
|
||||
(node1-return (phpinspect-tree-insert-node tree node1))
|
||||
(node2-return (phpinspect-tree-insert-node tree node2))
|
||||
(node3-return (phpinspect-tree-insert-node tree node3))
|
||||
(node4-return (phpinspect-tree-insert-node tree node4)))
|
||||
|
||||
|
||||
(should (eq tree node1-return))
|
||||
(should (= 800 (phpinspect-tree-end tree)))
|
||||
(should (eq node2 node2-return))
|
||||
(should (= 20 (phpinspect-tree-start node2-return)))
|
||||
(should (eq node3 node3-return))
|
||||
(should (= 9 (phpinspect-tree-start node3-return)))
|
||||
(should (eq node4 node4-return))
|
||||
(should (= 21 (phpinspect-tree-start node4-return)))))
|
||||
|
||||
(ert-deftest phpinspect-tree-traverse-overlapping-point ()
|
||||
(let ((tree (phpinspect-make-tree :start 0 :end 500 :value "tree"))
|
||||
(node1 (phpinspect-make-tree :start 9 :end 200 :value "node1"))
|
||||
(node2 (phpinspect-make-tree :start 20 :end 200 :value "node2"))
|
||||
(node3 (phpinspect-make-tree :start 9 :end 20 :value "node3"))
|
||||
(node4 (phpinspect-make-tree :start 21 :end 44 :value "node4"))
|
||||
(result))
|
||||
|
||||
(phpinspect-tree-insert-node tree node1)
|
||||
(phpinspect-tree-insert-node tree node2)
|
||||
(phpinspect-tree-insert-node tree node3)
|
||||
(phpinspect-tree-insert-node tree node4)
|
||||
|
||||
(setq result (phpinspect-tree-traverse-overlapping tree 22))
|
||||
(should (equal '("node4" "node2" "node1" "tree") result))))
|
||||
|
||||
(ert-deftest phpinspect-tree-traverse-overlapping-region ()
|
||||
(let ((tree (phpinspect-make-tree :start 0 :end 500 :value "tree"))
|
||||
(node1 (phpinspect-make-tree :start 9 :end 200 :value "node1"))
|
||||
(node2 (phpinspect-make-tree :start 20 :end 200 :value "node2"))
|
||||
(node3 (phpinspect-make-tree :start 9 :end 20 :value "node3"))
|
||||
(node4 (phpinspect-make-tree :start 21 :end 44 :value "node4"))
|
||||
(result))
|
||||
|
||||
(phpinspect-tree-insert-node tree node1)
|
||||
(phpinspect-tree-insert-node tree node2)
|
||||
(phpinspect-tree-insert-node tree node3)
|
||||
(phpinspect-tree-insert-node tree node4)
|
||||
|
||||
(setq result (phpinspect-tree-traverse-overlapping tree (phpinspect-make-region 18 22)))
|
||||
(should (equal '("node3" "node4" "node2" "node1" "tree") result))))
|
||||
|
||||
(ert-deftest phpinspect-tree-find-smallest-overlapping-set ()
|
||||
(let ((tree (phpinspect-make-tree :start 0 :end 500 :value "tree"))
|
||||
(node1 (phpinspect-make-tree :start 9 :end 200 :value "node1"))
|
||||
(node2 (phpinspect-make-tree :start 20 :end 200 :value "node2"))
|
||||
(node3 (phpinspect-make-tree :start 44 :end 60 :value "node3"))
|
||||
(node4 (phpinspect-make-tree :start 21 :end 44 :value "node4"))
|
||||
(result))
|
||||
(phpinspect-tree-insert-node tree node1)
|
||||
(phpinspect-tree-insert-node tree node2)
|
||||
(phpinspect-tree-insert-node tree node3)
|
||||
(phpinspect-tree-insert-node tree node4)
|
||||
|
||||
(should (phpinspect-tree-overlaps tree (phpinspect-make-region 24 55)))
|
||||
|
||||
(setq result (phpinspect-tree-find-smallest-overlapping-set
|
||||
tree (phpinspect-make-region 24 55)))
|
||||
(should (equal '("node4" "node3") result))))
|
||||
|
||||
(ert-deftest phpinspect-tree-find-node-starting-at ()
|
||||
(let ((tree (phpinspect-make-tree :start 0 :end 500 :value "tree"))
|
||||
(node1 (phpinspect-make-tree :start 9 :end 200 :value "node1"))
|
||||
(node2 (phpinspect-make-tree :start 20 :end 200 :value "node2"))
|
||||
(node3 (phpinspect-make-tree :start 44 :end 60 :value "node3"))
|
||||
(node4 (phpinspect-make-tree :start 21 :end 44 :value "node4"))
|
||||
(result))
|
||||
(phpinspect-tree-insert-node tree node1)
|
||||
(phpinspect-tree-insert-node tree node2)
|
||||
(phpinspect-tree-insert-node tree node3)
|
||||
(phpinspect-tree-insert-node tree node4)
|
||||
|
||||
(setq result (phpinspect-tree-find-node-starting-at tree 44))
|
||||
(should (eq node3 result))
|
||||
(should-not (phpinspect-tree-find-node-starting-at tree 45))))
|
||||
|
||||
(ert-deftest phpinspect-tree-overlaps-point ()
|
||||
(let ((tree (phpinspect-make-tree :start 5 :end 10)))
|
||||
(should (phpinspect-tree-overlaps tree 5))
|
||||
|
||||
;; An interval's end is its delimtiter and should not be regarded as part of
|
||||
;; it.
|
||||
(should-not (phpinspect-tree-overlaps tree 10))
|
||||
|
||||
(should-not (phpinspect-tree-overlaps tree 4))
|
||||
(should-not (phpinspect-tree-overlaps tree 11))))
|
||||
|
||||
(ert-deftest phpinspect-tree-overlaps-region ()
|
||||
(let ((tree (phpinspect-make-tree :start 5 :end 10)))
|
||||
(should (phpinspect-tree-overlaps tree (phpinspect-make-region 0 6)))
|
||||
(should-not (phpinspect-tree-overlaps tree (phpinspect-make-region 0 5)))
|
||||
(should (phpinspect-tree-overlaps tree (phpinspect-make-region 9 11)))
|
||||
(should-not (phpinspect-tree-overlaps tree (phpinspect-make-region 10 11)))))
|
||||
|
||||
(ert-deftest phpinspect-tree-encloses ()
|
||||
(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)))
|
||||
(should-not (phpinspect-tree-parent tree))
|
||||
(should (eq tree (phpinspect-tree-parent node)))))
|
||||
|
||||
(ert-deftest phpinspect-tree-insert-sorted ()
|
||||
(let ((tree (phpinspect-make-tree :start 0 :end 1000 :value 'root)))
|
||||
(phpinspect-tree-insert tree 1 33 'one)
|
||||
(phpinspect-tree-insert tree 50 60 'three)
|
||||
(phpinspect-tree-insert tree 40 50 'two)
|
||||
(phpinspect-tree-insert tree 71 90 'five)
|
||||
(phpinspect-tree-insert tree 60 70 'four)
|
||||
|
||||
(should (equal '(one two three four five)
|
||||
(mapcar #'phpinspect-tree-value
|
||||
(seq-into (phpinspect-tree-children tree) 'list))))))
|
Loading…
Reference in New Issue