branch: externals/phpinspect
commit b68baaec8310eddad1f1e28244758a69032ca310
Author: Hugo Thunnissen <de...@hugot.nl>
Commit: Hugo Thunnissen <de...@hugot.nl>

    Make parse context cancellable and restore state after interrupt
---
 phpinspect-bmap.el          |  33 ++++----
 phpinspect-meta.el          |  78 +++++++++++++++++--
 phpinspect-parse-context.el | 182 ++++++++++++++++++++++++++++++++++++++++++++
 phpinspect-parser.el        |  87 ++++-----------------
 phpinspect.el               |  15 ----
 test/phpinspect-test.el     |  73 +-----------------
 test/test-parse-context.el  |  52 +++++++++++++
 test/test-parser.el         | 125 ++++++++++++++++++++++++++++++
 8 files changed, 465 insertions(+), 180 deletions(-)

diff --git a/phpinspect-bmap.el b/phpinspect-bmap.el
index 44494ca366..8f87c29217 100644
--- a/phpinspect-bmap.el
+++ b/phpinspect-bmap.el
@@ -255,22 +255,23 @@ giving up. If not provided, this is 100."
          (overlay)
          (last-overlay (phpinspect-splayt-node-value 
(phpinspect-splayt-root-node overlays))))
 
-    (phpinspect-meta-detach-parent token-meta)
-    (phpinspect-meta-shift token-meta pos-delta)
-
-    (if (and last-overlay (= (- start (length whitespace-before)) 
(phpinspect-overlay-end last-overlay))
-             (= pos-delta (phpinspect-overlay-delta last-overlay)))
-        (progn
-          (phpinspect--log "Expanding previous overlay from (%d,%d) to (%d,%d)"
-                           (phpinspect-overlay-start last-overlay) 
(phpinspect-overlay-end last-overlay)
-                           (phpinspect-overlay-start last-overlay) end)
-          (setf (phpinspect-overlay-end last-overlay) end)
-          (setf (phpinspect-meta-overlay token-meta) last-overlay))
-      (phpinspect--log "Inserting new overlay at (%d,%d)" start end)
-      (setq overlay `(overlay ,start ,end ,pos-delta ,bmap-overlay 
,token-meta))
-      (setf (phpinspect-meta-overlay token-meta) overlay)
-      (phpinspect-splayt-insert (phpinspect-bmap-overlays bmap) 
(phpinspect-overlay-start overlay) overlay))
-    (phpinspect-bmap-register bmap start end (phpinspect-meta-token 
token-meta) whitespace-before token-meta)))
+    (phpinspect-meta-with-changeset token-meta
+      (phpinspect-meta-detach-parent token-meta)
+      (phpinspect-meta-shift token-meta pos-delta)
+
+      (if (and last-overlay (= (- start (length whitespace-before)) 
(phpinspect-overlay-end last-overlay))
+               (= pos-delta (phpinspect-overlay-delta last-overlay)))
+          (progn
+            (phpinspect--log "Expanding previous overlay from (%d,%d) to 
(%d,%d)"
+                             (phpinspect-overlay-start last-overlay) 
(phpinspect-overlay-end last-overlay)
+                             (phpinspect-overlay-start last-overlay) end)
+            (setf (phpinspect-overlay-end last-overlay) end)
+            (setf (phpinspect-meta-overlay token-meta) last-overlay))
+        (phpinspect--log "Inserting new overlay at (%d,%d)" start end)
+        (setq overlay `(overlay ,start ,end ,pos-delta ,bmap-overlay 
,token-meta))
+        (setf (phpinspect-meta-overlay token-meta) overlay)
+        (phpinspect-splayt-insert (phpinspect-bmap-overlays bmap) 
(phpinspect-overlay-start overlay) overlay))
+      (phpinspect-bmap-register bmap start end (phpinspect-meta-token 
token-meta) whitespace-before token-meta))))
 
 (defun phpinspect-bmap-make-location-resolver (bmap)
   (lambda (token)
diff --git a/phpinspect-meta.el b/phpinspect-meta.el
index 03ce5767b7..f1c877a432 100644
--- a/phpinspect-meta.el
+++ b/phpinspect-meta.el
@@ -105,8 +105,10 @@
     (inline-quote
      (when (phpinspect-meta-parent ,meta)
        ;; Update absolute start and end
-       (setf (phpinspect-meta-absolute-start ,meta) (phpinspect-meta-start 
,meta))
        (setf (phpinspect-meta-absolute-end ,meta) (phpinspect-meta-end ,meta))
+       ;; Note: start should always be updated after end, as end is derived 
from
+       ;; it.
+       (setf (phpinspect-meta-absolute-start ,meta) (phpinspect-meta-start 
,meta))
        (setf (phpinspect-meta-parent ,meta) nil)))))
 
 (defun phpinspect-meta-shift (meta delta)
@@ -114,16 +116,76 @@
   (setf (phpinspect-meta-absolute-end meta) (+ (phpinspect-meta-end meta) 
delta)))
 
 (defun phpinspect-meta-right-siblings (meta)
-  (mapcar #'phpinspect-meta-token
-          (sort
-           (phpinspect-splayt-find-all-after
-            (phpinspect-meta-children (phpinspect-meta-parent meta)) 
(phpinspect-meta-parent-offset meta))
-           #'phpinspect-meta-sort-start)))
+  (sort
+   (phpinspect-splayt-find-all-after
+    (phpinspect-meta-children (phpinspect-meta-parent meta)) 
(phpinspect-meta-parent-offset meta))
+   #'phpinspect-meta-sort-start))
+
+(defun phpinspect-meta-wrap-token-pred (predicate)
+  (lambda (meta) (funcall predicate (phpinspect-meta-token meta))))
+
+(define-inline phpinspect-meta--point-offset (meta point)
+  (inline-quote
+   (- ,point (phpinspect-meta-start ,meta))))
+
+(cl-defmethod phpinspect-meta-find-left-sibling ((meta (head meta)))
+  (when (phpinspect-meta-parent meta)
+    (phpinspect-splayt-find-largest-before (phpinspect-meta-children 
(phpinspect-meta-parent meta))
+                                           (phpinspect-meta-parent-offset 
meta))))
+
+(cl-defmethod phpinspect-meta-find-overlapping-child ((meta (head meta)) 
(point integer))
+  (let ((child (phpinspect-splayt-find-largest-before
+                (phpinspect-meta-children meta) (phpinspect-meta--point-offset 
meta point))))
+    (when (and child (phpinspect-meta-overlaps-point point))
+      child)))
+
+(cl-defmethod phpinspect-meta-find-overlapping-children ((meta (head meta)) 
(point integer))
+  (let ((child meta)
+        children)
+    (while (and (setq child (phpinspect-meta-find-overlapping-child child 
point))
+                (phpinspect-meta-overlaps-point child point))
+      (push child children))
+    children))
+
+(cl-defmethod phpinspect-meta-find-child-starting-at ((meta (head meta)) 
(point integer))
+  (phpinspect-splayt-find (phpinspect-meta-children meta) 
(phpinspect-meta--point-offset meta point)))
+
+(cl-defmethod phpinspect-meta-find-child-starting-at-recursively ((meta (head 
meta)) (point integer))
+  (let ((child (phpinspect-meta-find-child-starting-at meta point)))
+    (if child
+        child
+      (setq child (phpinspect-meta-find-overlapping-child meta point))
+      (when child
+        (phpinspect-meta-find-child-starting-at-recursively child point)))))
+
+(cl-defmethod phpinspect-meta-find-child-before ((meta (head meta)) (point 
integer))
+  (phpinspect-splayt-find-largest-before
+   (phpinspect-meta-children meta) (phpinspect-meta--point-offset meta point)))
+
+(cl-defmethod phpinspect-meta-find-child-before-recursively ((meta (head 
meta)) (point integer))
+  (let ((child meta)
+        last)
+    (while (setq child (phpinspect-meta-find-child-before child point))
+      (setq last child))
+    last))
+
+(cl-defmethod phpinspect-meta-find-children-after ((meta (head meta)) (point 
integer))
+  (sort
+   (phpinspect-splayt-find-all-after
+    (phpinspect-meta-children meta) (phpinspect-meta--point-offset meta point))
+   #'phpinspect-meta-sort-start))
+
+(cl-defmethod phpinspect-meta-find-children-before ((meta (head meta)) (point 
integer))
+  (sort (phpinspect-splayt-find-all-before
+         (phpinspect-meta-children meta) (phpinspect-meta--point-offset meta 
point))
+        #'phpinspect-meta-sort-start))
 
 
 (defun phpinspect-meta-string (meta)
-  (format "[start: %d, end: %d, token: %s]"
-          (phpinspect-meta-start meta) (phpinspect-meta-end meta) 
(phpinspect-meta-token meta)))
+  (if meta
+      (format "[start: %d, end: %d, token: %s]"
+              (phpinspect-meta-start meta) (phpinspect-meta-end meta) 
(phpinspect-meta-token meta))
+    "[nil]"))
 
 
 (provide 'phpinspect-meta)
diff --git a/phpinspect-parse-context.el b/phpinspect-parse-context.el
new file mode 100644
index 0000000000..ded203bb0d
--- /dev/null
+++ b/phpinspect-parse-context.el
@@ -0,0 +1,182 @@
+;;; phpinspect-parse-context.el --- PHP parsing context module  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021  Free Software Foundation, Inc
+
+;; Author: Hugo Thunnissen <de...@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:
+
+(require 'phpinspect-util)
+(require 'phpinspect-meta)
+(require 'phpinspect-bmap)
+
+(defvar phpinspect-parse-context nil
+  "An instance of `phpinspect-pctx' that is used when
+parsing. Usually used in combination with
+`phpinspect-with-parse-context'")
+
+(cl-defstruct (phpinspect-pctx (:constructor phpinspect-make-pctx))
+  "Parser Context"
+  (incremental nil)
+  (interrupt-threshold (time-convert '(2 . 1000))
+                       :documentation
+                       "After how much time `interrupt-predicate'
+should be polled. This is 2ms by default.")
+  (-start-time nil
+               :documentation "The time at which the parse started.
+This variable is for private use and not always set.")
+  (interrupt-predicate nil
+                      :documentation
+                      "A function that is called in intervals during parsing 
when
+set. If this function returns a non-nil value, the parse process
+is interrupted and the symbol `phpinspect-parse-interrupted' is
+thrown.")
+  (changesets nil
+              :type list
+              :documentation "Metadata change sets executed during this parse")
+  (edtrack nil
+           :type phpinspect-edtrack)
+  (bmap (phpinspect-make-bmap)
+        :type phpinspect-bmap)
+  (previous-bmap nil
+                 :type phpinspect-bmap)
+  (whitespace-before ""
+                     :type string))
+
+(defmacro phpinspect-with-parse-context (ctx &rest body)
+  (declare (indent 1))
+  (let ((old-ctx (gensym))
+        (completed (gensym))
+        (result (gensym)))
+    `(let ((,old-ctx phpinspect-parse-context)
+           (,result)
+           (,completed))
+       (unwind-protect
+           (progn
+             (setq phpinspect-parse-context ,ctx
+                   ,result (progn ,@body)
+                   ,completed t)
+             ,result)
+         (progn
+           (unless ,completed (phpinspect-pctx-cancel ,ctx))
+           (setq phpinspect-parse-context ,old-ctx))))))
+(defmacro phpinspect-pctx-save-whitespace (pctx &rest body)
+  (declare (indent 1))
+  (let ((save-sym (gensym)))
+    `(let ((,save-sym (phpinspect-pctx-whitespace-before ,pctx)))
+       (unwind-protect
+           (progn
+             (setf (phpinspect-pctx-whitespace-before ,pctx) nil)
+             ,@body)
+         (setf (phpinspect-pctx-whitespace-before ,pctx) ,save-sym)))))
+
+(define-inline phpinspect-pctx-register-changeset (pctx changeset)
+  (inline-quote
+   (progn
+     (push ,changeset (phpinspect-pctx-changesets ,pctx)))))
+
+(define-inline phpinspect-pctx-check-interrupt (pctx)
+  (inline-letevals (pctx)
+    (inline-quote
+     (progn
+       (unless (phpinspect-pctx--start-time ,pctx)
+         (setf (phpinspect-pctx--start-time ,pctx) (time-convert nil)))
+
+       ;; Interrupt when blocking too long while input is pending.
+       (when (and (time-less-p (phpinspect-pctx-interrupt-threshold ,pctx)
+                               (time-since (phpinspect-pctx--start-time 
,pctx)))
+                  (funcall (phpinspect-pctx-interrupt-predicate ,pctx)))
+         (phpinspect-pctx-cancel ,pctx)
+         (throw 'phpinspect-parse-interrupted nil))))))
+
+(define-inline phpinspect-pctx-register-token (pctx token start end)
+  (inline-letevals (pctx)
+    (inline-quote
+     (phpinspect-bmap-register
+      (phpinspect-pctx-bmap ,pctx) ,start ,end ,token 
(phpinspect-pctx-consume-whitespace ,pctx)))))
+
+(define-inline phpinspect-pctx-register-whitespace (pctx whitespace)
+  (inline-quote
+   (setf (phpinspect-pctx-whitespace-before ,pctx) ,whitespace)))
+
+(defsubst phpinspect-pctx-consume-whitespace (pctx)
+  (let ((whitespace (phpinspect-pctx-whitespace-before pctx)))
+    (setf (phpinspect-pctx-whitespace-before pctx) "")
+    whitespace))
+
+(define-inline phpinspect-make-changeset (meta)
+  (inline-letevals (meta)
+    (inline-quote
+     (list (phpinspect-meta-start ,meta) (phpinspect-meta-end ,meta)
+           (phpinspect-meta-parent ,meta) (phpinspect-meta-overlay ,meta)
+           (phpinspect-meta-parent-offset ,meta) ,meta))))
+
+(define-inline phpinspect-changeset-start (set)
+  (inline-quote (car ,set)))
+
+(define-inline phpinspect-changeset-end (set)
+  (inline-quote (cadr ,set)))
+
+(define-inline phpinspect-changeset-parent (set)
+  (inline-quote (caddr ,set)))
+
+(define-inline phpinspect-changeset-overlay (set)
+  (inline-quote (cadddr ,set)))
+
+(define-inline phpinspect-changeset-parent-offset (set)
+  (inline-quote (car (cddddr ,set))))
+
+(define-inline phpinspect-changeset-meta (set)
+  (inline-quote (car (nthcdr 5 ,set))))
+
+(define-inline phpinspect-meta-with-changeset (meta &rest body)
+  (declare (indent 1))
+  (inline-letevals (meta)
+    (push 'progn body)
+    (inline-quote
+     (progn
+       (when phpinspect-parse-context
+         (phpinspect-pctx-register-changeset
+          phpinspect-parse-context (phpinspect-make-changeset ,meta)))
+       ,body))))
+
+(define-inline phpinspect-changeset-revert (changeset)
+  (inline-letevals (changeset)
+    (inline-quote
+     (progn
+       (setf (phpinspect-meta-parent (phpinspect-changeset-meta ,changeset))
+             (phpinspect-changeset-parent ,changeset))
+       (setf (phpinspect-meta-overlay (phpinspect-changeset-meta ,changeset))
+             (phpinspect-changeset-overlay ,changeset))
+       (setf (phpinspect-meta-absolute-start (phpinspect-changeset-meta 
,changeset))
+             (phpinspect-changeset-start ,changeset))
+       (setf (phpinspect-meta-absolute-end (phpinspect-changeset-meta 
,changeset))
+             (phpinspect-changeset-end ,changeset))
+       (setf (phpinspect-meta-parent-offset (phpinspect-changeset-meta 
,changeset))
+             (phpinspect-changeset-parent-offset ,changeset))))))
+
+(defun phpinspect-pctx-cancel (pctx)
+  (phpinspect--log "Cancelling parse context")
+  (dolist (changeset (phpinspect-pctx-changesets pctx))
+    (phpinspect-changeset-revert changeset))
+  (setf (phpinspect-pctx-changesets pctx) nil))
+
+(provide 'phpinspect-parse-context)
+;;; phpinspect-parse-context.el ends here
diff --git a/phpinspect-parser.el b/phpinspect-parser.el
index 4d75d06a7e..79a61c2141 100644
--- a/phpinspect-parser.el
+++ b/phpinspect-parser.el
@@ -26,6 +26,7 @@
 ;;(require 'phpinspect-tree)
 (require 'phpinspect-edtrack)
 (require 'phpinspect-bmap)
+(require 'phpinspect-parse-context)
 
 (defvar phpinspect-parser-obarray (obarray-make)
   "An obarray containing symbols for all phpinspect (sub)parsers.")
@@ -37,68 +38,6 @@
   (define-inline phpinspect--word-end-regex ()
     (inline-quote "\\([[:blank:]]\\|[^0-9a-zA-Z_]\\)")))
 
-(defvar phpinspect-parse-context nil
-  "An instance of `phpinspect-pctx' that is used when
-parsing. Usually used in combination with
-`phpinspect-with-parse-context'")
-
-(defmacro phpinspect-with-parse-context (ctx &rest body)
-  (declare (indent 1))
-  (let ((old-ctx phpinspect-parse-context))
-    `(unwind-protect
-         (progn
-           (setq phpinspect-parse-context ,ctx)
-           ,@body)
-       (setq phpinspect-parse-context ,old-ctx))))
-
-(cl-defstruct (phpinspect-pctx (:constructor phpinspect-make-pctx))
-  "Parser Context"
-  (incremental nil)
-  (interrupt-threshold (time-convert '(2 . 1000))
-                       :documentation
-                       "After how much time `interrupt-predicate'
-should be polled. This is 2ms by default.")
-  (-start-time nil
-               :documentation "The time at which the parse started.
-This variable is for private use and not always set.")
-  (interrupt-predicate nil
-                      :documentation
-                      "A function that is called in intervals during parsing 
when
-set. If this function returns a non-nil value, the parse process
-is interrupted and the symbol `phpinspect-parse-interrupted' is
-thrown.")
-  (edtrack nil
-           :type phpinspect-edtrack)
-  (bmap (phpinspect-make-bmap)
-        :type phpinspect-bmap)
-  (previous-bmap nil
-                 :type phpinspect-bmap)
-  (whitespace-before ""
-                     :type string))
-
-(defsubst phpinspect-pctx-check-interrupt (pctx)
-  (unless (phpinspect-pctx--start-time pctx)
-    (setf (phpinspect-pctx--start-time pctx) (time-convert nil)))
-
-  ;; Interrupt when blocking too long while input is pending.
-  (when (and (time-less-p (phpinspect-pctx-interrupt-threshold pctx)
-                          (time-since (phpinspect-pctx--start-time pctx)))
-             (funcall (phpinspect-pctx-interrupt-predicate pctx)))
-    (throw 'phpinspect-parse-interrupted nil)))
-
-
-
-(defsubst phpinspect-pctx-register-token (pctx token start end)
-  (phpinspect-bmap-register
-   (phpinspect-pctx-bmap pctx) start end token 
(phpinspect-pctx-consume-whitespace pctx)))
-
-(defsubst phpinspect-pctx-register-whitespace (pctx whitespace)
-  (setf (phpinspect-pctx-whitespace-before pctx) whitespace))
-
-(defsubst phpinspect-pctx-consume-whitespace (pctx)
-  (let ((whitespace (phpinspect-pctx-whitespace-before pctx)))
-    (setf (phpinspect-pctx-whitespace-before pctx) "")
-    whitespace))
 
 (defun phpinspect-list-handlers ()
   (let ((handlers))
@@ -458,15 +397,6 @@ have any effect."
                  (setf (phpinspect-parser-incremental-func (symbol-value 
parser-symbol)) nil))
                phpinspect-parser-obarray))
 
-(defmacro phpinspect-pctx-save-whitespace (pctx &rest body)
-  (declare (indent 1))
-  (let ((save-sym (gensym)))
-    `(let ((,save-sym (phpinspect-pctx-whitespace-before ,pctx)))
-       (unwind-protect
-           (progn
-             (setf (phpinspect-pctx-whitespace-before ,pctx) nil)
-             ,@body)
-         (setf (phpinspect-pctx-whitespace-before ,pctx) ,save-sym)))))
 
 (defun phpinspect-make-parser-function (tree-type handler-list &optional 
delimiter-predicate)
   "Create a parser function using the handlers by names defined in 
HANDLER-LIST.
@@ -1139,5 +1069,20 @@ the properties of the class"
                (current-buffer)
                point nil 'root))))
 
+(defun phpinspect-parse-current-buffer ()
+  (phpinspect-parse-buffer-until-point
+   (current-buffer)
+   (point-max)))
+
+(defun phpinspect-parse-string (string)
+  (with-temp-buffer
+    (insert string)
+    (phpinspect-parse-current-buffer)))
+
+(defun phpinspect-parse-file (file)
+  (with-temp-buffer
+    (insert-file-contents file)
+    (phpinspect-parse-current-buffer)))
+
 (provide 'phpinspect-parser)
 ;;; phpinspect-parser.el ends here
diff --git a/phpinspect.el b/phpinspect.el
index aefdeda345..fd465c8439 100644
--- a/phpinspect.el
+++ b/phpinspect.el
@@ -71,16 +71,6 @@ phpinspect")
                                            project-root)
      indexed-class)))
 
-(defun phpinspect-parse-file (file)
-  (with-temp-buffer
-    (phpinspect-insert-file-contents file)
-    (phpinspect-parse-current-buffer)))
-
-(defun phpinspect-parse-current-buffer ()
-  (phpinspect-parse-buffer-until-point
-   (current-buffer)
-   (point-max)))
-
 (defun phpinspect-parse-string-to-bmap (string)
   (with-temp-buffer
     (insert string)
@@ -91,11 +81,6 @@ phpinspect")
 
       (phpinspect-pctx-bmap context))))
 
-(defun phpinspect-parse-string (string)
-  (with-temp-buffer
-    (insert string)
-    (phpinspect-parse-current-buffer)))
-
 (defun phpinspect-after-change-function (start end pre-change-length)
   (when phpinspect-current-buffer
     (phpinspect-buffer-register-edit phpinspect-current-buffer start end 
pre-change-length)))
diff --git a/test/phpinspect-test.el b/test/phpinspect-test.el
index 53fc8be8e8..86ba1cfa2f 100644
--- a/test/phpinspect-test.el
+++ b/test/phpinspect-test.el
@@ -246,76 +246,6 @@
 
     (should (equal expected assignments))))
 
-(ert-deftest phpinspect-parse-namespaced-class ()
-  "Test phpinspect-parse on a namespaced class"
-  (should
-   (equal (phpinspect-test-read-fixture-data "NamespacedClass")
-          (phpinspect-test-parse-fixture-code "NamespacedClass"))))
-
-(ert-deftest phpinspect-parse-block ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "Block")
-          (phpinspect-test-parse-fixture-code "Block"))))
-
-(ert-deftest phpinspect-parse-functions ()
-  "Test phpinspect-parse for php functions"
-  (should
-   (equal (phpinspect-test-read-fixture-data "Functions")
-          (phpinspect-test-parse-fixture-code "Functions"))))
-
-(ert-deftest phpinspect-parse-namespaced-functions ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "NamespacedFunctions")
-          (phpinspect-test-parse-fixture-code "NamespacedFunctions"))))
-
-(ert-deftest phpinspect-parse-variable ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "Variable")
-          (phpinspect-test-parse-fixture-code "Variable"))))
-
-(ert-deftest phpinspect-parse-word ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "Word")
-          (phpinspect-test-parse-fixture-code "Word"))))
-
-(ert-deftest phpinspect-parse-array ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "Array")
-          (phpinspect-test-parse-fixture-code "Array"))))
-
-
-(ert-deftest phpinspect-parse-short-function ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "ShortFunction")
-          (phpinspect-test-parse-fixture-code "ShortFunction"))))
-
-(ert-deftest phpinspect-parse-two-short-functions ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "TwoShortFunctions")
-          (phpinspect-test-parse-fixture-code "TwoShortFunctions"))))
-
-(ert-deftest phpinspect-parse-small-namespaced-class ()
-  "Test phpinspect-parse for php blocks"
-  (should
-   (equal (phpinspect-test-read-fixture-data "SmallNamespacedClass")
-          (phpinspect-test-parse-fixture-code "SmallNamespacedClass"))))
-
-;; If this test fails, the syntax tree has a breaking change in it. Regenerate 
the
-;; fixtures and fix anything that is broken.
-(ert-deftest phpinspect-syntax-tree-change ()
-  (let ((index (phpinspect--index-tokens
-                (phpinspect-test-parse-fixture-code "IndexClass1")))
-        (expected-result (phpinspect--index-tokens
-                          (phpinspect-test-read-fixture-data "IndexClass1"))))
-    (should (equal index expected-result))))
-
 
 (ert-deftest phpinspect-resolve-type-from-context ()
   (let* ((pctx (phpinspect-make-pctx :incremental t))
@@ -610,7 +540,10 @@ class Thing
 (load-file (concat phpinspect-test-directory "/test-bmap.el"))
 (load-file (concat phpinspect-test-directory "/test-edtrack.el"))
 (load-file (concat phpinspect-test-directory "/test-resolvecontext.el"))
+(load-file (concat phpinspect-test-directory "/test-parser.el"))
+(load-file (concat phpinspect-test-directory "/test-parse-context.el"))
 (load-file (concat phpinspect-test-directory "/test-splayt.el"))
 
+
 (provide 'phpinspect-test)
 ;;; phpinspect-test.el ends here
diff --git a/test/test-parse-context.el b/test/test-parse-context.el
new file mode 100644
index 0000000000..b79db41183
--- /dev/null
+++ b/test/test-parse-context.el
@@ -0,0 +1,52 @@
+;;; phpinspect-test.el --- Unit tests for phpinspect.el  -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Hugo Thunnissen <de...@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-parse-context)
+(require 'phpinspect-meta)
+
+(ert-deftest phpinspect-pctx-cancel ()
+  (let ((meta (phpinspect-make-meta nil 10 20 "    " 'token 'overlay nil))
+        (pctx (phpinspect-make-pctx)))
+    (phpinspect-with-parse-context pctx
+      (phpinspect-meta-with-changeset meta
+        (setf (phpinspect-meta-absolute-start meta) 222)
+        (setf (phpinspect-meta-absolute-end meta) 1234)
+        (phpinspect-meta-set-parent meta (phpinspect-make-meta nil 1 2000 "" 
'parent-token))
+        (setf (phpinspect-meta-overlay meta) 'not-overlay)))
+
+    (should (= 222 (phpinspect-meta-start meta)))
+    (should (= 1234 (phpinspect-meta-end meta)))
+    (should (phpinspect-meta-parent meta))
+    (should (eq 'not-overlay (phpinspect-meta-overlay meta)))
+    (should (= 221 (phpinspect-meta-parent-offset meta)))
+
+    (phpinspect-pctx-cancel pctx)
+
+    (should (= 10 (phpinspect-meta-start meta)))
+    (should (= 20 (phpinspect-meta-end meta)))
+    (should-not (phpinspect-meta-parent meta))
+    (should-not (phpinspect-meta-parent-offset meta))
+    (should (eq 'overlay (phpinspect-meta-overlay meta)))))
diff --git a/test/test-parser.el b/test/test-parser.el
index cc891d2e8c..d2ecf947c3 100644
--- a/test/test-parser.el
+++ b/test/test-parser.el
@@ -1,6 +1,46 @@
+;; test-parser.el --- Unit tests for phpinspect.el  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Hugo Thunnissen <de...@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 'phpinspect-parser)
 
+(defvar phpinspect-test-directory
+  (file-name-directory
+   (or load-file-name
+       buffer-file-name))
+  "Directory that phpinspect tests reside in.")
+
+
+(defvar phpinspect-test-php-file-directory
+  (concat
+   (file-name-directory
+    (or load-file-name
+        buffer-file-name))
+   "/fixtures")
+  "Directory with syntax trees of example PHP files.")
+
+
 (ert-deftest phpinspect-parse-bmap ()
   (let* ((ctx (phpinspect-make-pctx :incremental t))
          (code "
@@ -30,3 +70,88 @@ class TestClass {
       (setq parent (phpinspect-meta-parent (car enclosing)))
       (should (phpinspect-list-p (phpinspect-meta-token parent)))
       (should (phpinspect-block-p (phpinspect-meta-token 
(phpinspect-meta-parent parent)))))))
+
+(ert-deftest phpinspect-parse-comma ()
+  (let* ((code "(,)")
+         (ctx (phpinspect-make-pctx :incremental t))
+         (parsed (phpinspect-with-parse-context ctx
+                   (phpinspect-parse-string code)))
+         (comma (cadadr parsed))
+         (map (phpinspect-pctx-bmap ctx))
+         (comma-meta))
+    (should (equal '(:root (:list (:comma ","))) parsed))
+    (should (equal '(:comma ",") comma))
+
+    (should (setq comma-meta (phpinspect-bmap-token-meta map comma)))
+    (should (= 1 (phpinspect-meta-width comma-meta)))))
+
+
+(ert-deftest phpinspect-parse-namespaced-class ()
+  "Test phpinspect-parse on a namespaced class"
+  (should
+   (equal (phpinspect-test-read-fixture-data "NamespacedClass")
+          (phpinspect-test-parse-fixture-code "NamespacedClass"))))
+
+(ert-deftest phpinspect-parse-block ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "Block")
+          (phpinspect-test-parse-fixture-code "Block"))))
+
+(ert-deftest phpinspect-parse-functions ()
+  "Test phpinspect-parse for php functions"
+  (should
+   (equal (phpinspect-test-read-fixture-data "Functions")
+          (phpinspect-test-parse-fixture-code "Functions"))))
+
+(ert-deftest phpinspect-parse-namespaced-functions ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "NamespacedFunctions")
+          (phpinspect-test-parse-fixture-code "NamespacedFunctions"))))
+
+(ert-deftest phpinspect-parse-variable ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "Variable")
+          (phpinspect-test-parse-fixture-code "Variable"))))
+
+(ert-deftest phpinspect-parse-word ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "Word")
+          (phpinspect-test-parse-fixture-code "Word"))))
+
+(ert-deftest phpinspect-parse-array ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "Array")
+          (phpinspect-test-parse-fixture-code "Array"))))
+
+
+(ert-deftest phpinspect-parse-short-function ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "ShortFunction")
+          (phpinspect-test-parse-fixture-code "ShortFunction"))))
+
+(ert-deftest phpinspect-parse-two-short-functions ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "TwoShortFunctions")
+          (phpinspect-test-parse-fixture-code "TwoShortFunctions"))))
+
+(ert-deftest phpinspect-parse-small-namespaced-class ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-data "SmallNamespacedClass")
+          (phpinspect-test-parse-fixture-code "SmallNamespacedClass"))))
+
+;; If this test fails, the syntax tree has a breaking change in it. Regenerate 
the
+;; fixtures and fix anything that is broken.
+(ert-deftest phpinspect-syntax-tree-change ()
+  (let ((index (phpinspect--index-tokens
+                (phpinspect-test-parse-fixture-code "IndexClass1")))
+        (expected-result (phpinspect--index-tokens
+                          (phpinspect-test-read-fixture-data "IndexClass1"))))
+    (should (equal index expected-result))))

Reply via email to