Fix all byte compilation warnings and errors (for real this time (probably))
ci/woodpecker/push/woodpecker Pipeline failed Details

WIP-cache
Hugo Thunnissen 9 months ago
parent f1e4a5be7d
commit 84ddaf1dc2

@ -12,7 +12,7 @@
(insert-file-contents (concat here "/Response.php")) (insert-file-contents (concat here "/Response.php"))
(message "Incremental parse (warmup):") (message "Incremental parse (warmup):")
(phpinspect-with-parse-context (phpinspect-make-pctx :incremental t) (phpinspect-with-parse-context (phpinspect-make-pctx :incremental t :bmap (phpinspect-make-bmap))
(benchmark 1 '(phpinspect-parse-current-buffer))) (benchmark 1 '(phpinspect-parse-current-buffer)))
(let ((bmap (phpinspect-make-bmap)) (let ((bmap (phpinspect-make-bmap))
@ -24,13 +24,19 @@
(garbage-collect) (garbage-collect)
(message "Incremental parse (no edits):") (message "Incremental parse (no edits):")
(phpinspect-with-parse-context (phpinspect-make-pctx :incremental t :bmap bmap2 :previous-bmap bmap :edtrack (phpinspect-make-edtrack)) (phpinspect-with-parse-context (phpinspect-make-pctx :incremental t
:bmap bmap2
:previous-bmap bmap
:edtrack (phpinspect-make-edtrack))
(benchmark 1 '(phpinspect-parse-current-buffer))) (benchmark 1 '(phpinspect-parse-current-buffer)))
(garbage-collect) (garbage-collect)
(message "Incremental parse repeat (no edits):") (message "Incremental parse repeat (no edits):")
(phpinspect-with-parse-context (phpinspect-make-pctx :incremental t :previous-bmap bmap2 :edtrack (phpinspect-make-edtrack)) (phpinspect-with-parse-context (phpinspect-make-pctx :incremental t
:bmap (phpinspect-make-bmap)
:previous-bmap bmap2
:edtrack (phpinspect-make-edtrack))
(benchmark 1 '(phpinspect-parse-current-buffer))) (benchmark 1 '(phpinspect-parse-current-buffer)))
(garbage-collect) (garbage-collect)
@ -64,7 +70,10 @@
;;(profiler-start 'cpu) ;;(profiler-start 'cpu)
(message "Incremental parse after 2 more edits:") (message "Incremental parse after 2 more edits:")
(phpinspect-with-parse-context (phpinspect-make-pctx :incremental t :previous-bmap bmap-after :edtrack edtrack) (phpinspect-with-parse-context (phpinspect-make-pctx :bmap (phpinspect-make-bmap)
:incremental t
:previous-bmap bmap-after
:edtrack edtrack)
(benchmark 1 '(phpinspect-parse-current-buffer))) (benchmark 1 '(phpinspect-parse-current-buffer)))
;; (save-current-buffer ;; (save-current-buffer

@ -0,0 +1,9 @@
#!/bin/bash
for file in ./*.el; do
cask emacs -batch -L . --eval '(setq byte-compile-error-on-warn t)' -f batch-byte-compile "$file" || break
done
if ! [[ -n 'NO_REMOVE_ELC' ]]; then
rm ./*.elc
fi

@ -24,7 +24,6 @@
;;; Code: ;;; Code:
(require 'cl-lib) (require 'cl-lib)
(require 'phpinspect-project)
(require 'phpinspect-fs) (require 'phpinspect-fs)
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'phpinspect-pipeline) (require 'phpinspect-pipeline)
@ -72,9 +71,12 @@
(:constructor phpinspect-make-autoloader)) (:constructor phpinspect-make-autoloader))
(refresh-thread nil (refresh-thread nil
:type thread) :type thread)
(project nil (fs nil
:type phpinspect-project :type phpinspect-fs)
:documentation "The project that this autoloader can find files for") (file-indexer nil
:type function)
(project-root-resolver nil
:type function)
(own-types (make-hash-table :test 'eq :size 10000 :rehash-size 10000) (own-types (make-hash-table :test 'eq :size 10000 :rehash-size 10000)
:type hash-table :type hash-table
:documentation "The internal types that can be :documentation "The internal types that can be
@ -160,9 +162,9 @@ bareword typenames."))
(cl-defmethod phpinspect-al-strategy-execute ((strat phpinspect-files)) (cl-defmethod phpinspect-al-strategy-execute ((strat phpinspect-files))
(phpinspect--log "indexing files list: %s" (phpinspect-files-list strat)) (phpinspect--log "indexing files list: %s" (phpinspect-files-list strat))
(let* ((project (phpinspect-autoloader-project (phpinspect-files-autoloader strat)))) (let* ((indexer (phpinspect-autoloader-file-indexer (phpinspect-files-autoloader strat))))
(phpinspect-pipeline (phpinspect-files-list strat) (phpinspect-pipeline (phpinspect-files-list strat)
:into (phpinspect-project-add-file-index :with-context project)))) :into (funcall :with-context indexer))))
(cl-defmethod phpinspect-autoloader-put-type-bag ((al phpinspect-autoloader) (type-fqn symbol)) (cl-defmethod phpinspect-autoloader-put-type-bag ((al phpinspect-autoloader) (type-fqn symbol))
(let* ((type-name (phpinspect-intern-name (let* ((type-name (phpinspect-intern-name
@ -175,7 +177,7 @@ bareword typenames."))
(cl-defmethod phpinspect-iterate-composer-jsons (cl-defmethod phpinspect-iterate-composer-jsons
((al phpinspect-autoloader) file) ((al phpinspect-autoloader) file)
(let* ((fs (phpinspect-project-fs (phpinspect-autoloader-project al))) (let* ((fs (phpinspect-autoloader-fs al))
(project-root (file-name-directory (cdr file))) (project-root (file-name-directory (cdr file)))
json autoload batch) json autoload batch)
@ -254,8 +256,8 @@ bareword typenames."))
(cl-defmethod phpinspect-autoloader-refresh ((autoloader phpinspect-autoloader) &optional async-callback) (cl-defmethod phpinspect-autoloader-refresh ((autoloader phpinspect-autoloader) &optional async-callback)
"Refresh autoload definitions by reading composer.json files "Refresh autoload definitions by reading composer.json files
from the project and vendor folders." from the project and vendor folders."
(let* ((project-root (phpinspect-project-root (phpinspect-autoloader-project autoloader))) (let* ((project-root (funcall (phpinspect-autoloader-project-root-resolver autoloader)))
(fs (phpinspect-project-fs (phpinspect-autoloader-project autoloader)))) (fs (phpinspect-autoloader-fs autoloader)))
(setf (phpinspect-autoloader-type-name-fqn-bags autoloader) (setf (phpinspect-autoloader-type-name-fqn-bags autoloader)
(make-hash-table :test 'eq :size 3000 :rehash-size 3000)) (make-hash-table :test 'eq :size 3000 :rehash-size 3000))
(setf (phpinspect-autoloader-own-types autoloader) (setf (phpinspect-autoloader-own-types autoloader)

@ -26,6 +26,7 @@
(require 'phpinspect-splayt) (require 'phpinspect-splayt)
(require 'phpinspect-meta) (require 'phpinspect-meta)
(require 'phpinspect-changeset) (require 'phpinspect-changeset)
(require 'phpinspect-parse-context)
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'compat) (require 'compat)
(require 'phpinspect-token-predicates) (require 'phpinspect-token-predicates)
@ -217,6 +218,13 @@
(setf (phpinspect-bmap-last-token-start bmap) start) (setf (phpinspect-bmap-last-token-start bmap) start)
(push token-meta (phpinspect-bmap-token-stack bmap)))) (push token-meta (phpinspect-bmap-token-stack bmap))))
(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)))))
(defsubst phpinspect-overlay-p (overlay) (defsubst phpinspect-overlay-p (overlay)
(and (listp overlay) (and (listp overlay)
(eq 'overlay (car overlay)))) (eq 'overlay (car overlay))))

@ -23,6 +23,7 @@
;;; Code: ;;; Code:
(require 'phpinspect-class)
(require 'phpinspect-parser) (require 'phpinspect-parser)
(require 'phpinspect-bmap) (require 'phpinspect-bmap)
(require 'phpinspect-edtrack) (require 'phpinspect-edtrack)
@ -77,7 +78,7 @@ linked with."
(let* ((map (phpinspect-make-bmap)) (let* ((map (phpinspect-make-bmap))
(buffer-map (phpinspect-buffer-map buffer)) (buffer-map (phpinspect-buffer-map buffer))
(ctx (phpinspect-make-pctx (ctx (phpinspect-make-pctx
:interrupt-predicate (unless no-interrupt #'input-pending-p) :interrupt-predicate (unless no-interrupt #'phpinspect--input-pending-p)
:bmap map :bmap map
:incremental t :incremental t
:previous-bmap buffer-map :previous-bmap buffer-map

@ -65,6 +65,13 @@ currently opened projects."
((cache phpinspect--cache) (project-root string)) ((cache phpinspect--cache) (project-root string))
(gethash project-root (phpinspect--cache-projects cache))) (gethash project-root (phpinspect--cache-projects cache)))
(defun phpinspect-get-or-create-cached-project-class (project-root class-fqn)
(when project-root
(let ((project (phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
project-root)))
(phpinspect-project-get-class-create project class-fqn))))
(cl-defmethod phpinspect--cache-get-project-create (cl-defmethod phpinspect--cache-get-project-create
((cache phpinspect--cache) (project-root string)) ((cache phpinspect--cache) (project-root string))
"Get a project that is located in PROJECT-ROOT from CACHE. "Get a project that is located in PROJECT-ROOT from CACHE.
@ -78,11 +85,43 @@ then returned."
:root project-root :root project-root
:worker (phpinspect-make-dynamic-worker)) :worker (phpinspect-make-dynamic-worker))
(phpinspect--cache-projects cache))) (phpinspect--cache-projects cache)))
(let ((autoloader (phpinspect-make-autoloader :project project))) (let ((autoloader (phpinspect-make-autoloader
(setf (phpinspect-project-autoload project) autoloader) :fs (phpinspect-project-fs project)
:file-indexer (phpinspect-project-make-file-indexer project)
:project-root-resolver (phpinspect-project-make-root-resolver project)))) (setf (phpinspect-project-autoload project) autoloader)
(phpinspect-autoloader-refresh autoloader) (phpinspect-autoloader-refresh autoloader)
(phpinspect-project-enqueue-include-dirs project))) (phpinspect-project-enqueue-include-dirs project)))
project)) project))
(defun phpinspect-project-enqueue-include-dirs (project)
(interactive (list (phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
(phpinspect-current-project-root))))
(let ((dirs (alist-get 'include-dirs
(alist-get (phpinspect-project-root project)
phpinspect-projects
nil nil #'string=))))
(dolist (dir dirs)
(message "enqueueing dir %s" dir)
(phpinspect-worker-enqueue
(phpinspect-project-worker project)
(phpinspect-make-index-dir-task :dir dir :project project)))))
(defun phpinspect-project-add-include-dir (dir)
"Configure DIR as an include dir for the current project."
(interactive (list (read-directory-name "Include Directory: ")))
(custom-set-variables '(phpinspect-projects))
(let ((existing
(alist-get (phpinspect-current-project-root) phpinspect-projects nil #'string=)))
(if existing
(push dir (alist-get 'include-dirs existing))
(push `(,(phpinspect-current-project-root) . ((include-dirs . (,dir)))) phpinspect-projects)))
(customize-save-variable 'phpinspect-projects phpinspect-projects)
(phpinspect-project-enqueue-include-dirs (phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
(phpinspect-current-project-root))))
(provide 'phpinspect-cache) (provide 'phpinspect-cache)
;;; phpinspect.el ends here ;;; phpinspect.el ends here

@ -23,6 +23,9 @@
;;; Code: ;;; Code:
(eval-when-compile
(require 'phpinspect-meta))
(define-inline phpinspect-make-changeset (meta) (define-inline phpinspect-make-changeset (meta)
(inline-letevals (meta) (inline-letevals (meta)
(inline-quote (inline-quote
@ -48,17 +51,6 @@
(define-inline phpinspect-changeset-meta (set) (define-inline phpinspect-changeset-meta (set)
(inline-quote (car (nthcdr 5 ,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) (define-inline phpinspect-changeset-revert (changeset)
(inline-letevals (changeset) (inline-letevals (changeset)
(inline-quote (inline-quote

@ -0,0 +1,68 @@
;;; phpinspect-class-struct.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--class (:constructor phpinspect--make-class-generated))
(project nil
:type phpinspect-project
:documentaton
"The project that this class belongs to")
(index nil
:type phpinspect--indexed-class
:documentation
"The index that this class is derived from")
(methods (make-hash-table :test 'eq :size 20 :rehash-size 20)
:type hash-table
:documentation
"All methods, including those from extended classes.")
(static-methods (make-hash-table :test 'eq :size 20 :rehash-size 20)
:type hash-table
:documentation
"All static methods this class provides,
including those from extended classes.")
(name nil
:type phpinspect--type)
(variables nil
:type list
:documentation
"Variables that belong to this class.")
(extended-classes nil
:type list
:documentation
"All extended/implemented classes.")
(subscriptions (make-hash-table :test #'eq :size 10 :rehash-size 1.5)
:type hash-table
:documentation
"A list of subscription functions that should be
called whenever anything about this class is
updated")
(declaration nil)
(initial-index nil
:type bool
:documentation
"A boolean indicating whether or not this class
has been indexed yet."))
(provide 'phpinspect-class-struct)

@ -26,10 +26,11 @@
(require 'phpinspect-type) (require 'phpinspect-type)
(cl-defstruct (phpinspect--class (:constructor phpinspect--make-class-generated)) (cl-defstruct (phpinspect--class (:constructor phpinspect--make-class-generated))
(project nil (class-retriever nil
:type phpinspect-project :type lambda
:documentaton :documentaton
"The project that this class belongs to") "A function that returns classes for types
(should accept `phpinspect--type' as argument)")
(index nil (index nil
:type phpinspect--indexed-class :type phpinspect--indexed-class
:documentation :documentation
@ -76,8 +77,7 @@
#'phpinspect--class-p #'phpinspect--class-p
(mapcar (mapcar
(lambda (class-name) (lambda (class-name)
(phpinspect-project-get-class-create (phpinspect--class-project class) (funcall (phpinspect--class-class-retriever class) class-name))
class-name))
extensions))) extensions)))
(dolist (extended (phpinspect--class-extended-classes class)) (dolist (extended (phpinspect--class-extended-classes class))

@ -26,6 +26,7 @@
(require 'phpinspect-util) (require 'phpinspect-util)
(eval-when-compile (eval-when-compile
(require 'phpinspect-meta)
(phpinspect--declare-log-group 'edtrack)) (phpinspect--declare-log-group 'edtrack))
(cl-defstruct (phpinspect-edtrack (:constructor phpinspect-make-edtrack)) (cl-defstruct (phpinspect-edtrack (:constructor phpinspect-make-edtrack))
@ -40,44 +41,9 @@
:type integer :type integer
:documentation "Last registered edit start position")) :documentation "Last registered edit start position"))
(defsubst phpinspect-edtrack-make-taint-iterator (track)
(cons (car (phpinspect-edtrack-taint-pool track))
(cl-copy-list (cdr (phpinspect-edtrack-taint-pool track)))))
(define-inline phpinspect-taint-iterator-current (iter)
(inline-quote (car ,iter)))
(define-inline phpinspect-taint-iterator-follow (iter pos)
(inline-letevals (iter pos)
(inline-quote
(or (while (and (phpinspect-taint-iterator-current ,iter)
(> ,pos (phpinspect-taint-end
(phpinspect-taint-iterator-current ,iter))))
(setf (phpinspect-taint-iterator-current ,iter) (pop (cdr ,iter))))
(phpinspect-taint-iterator-current ,iter)))))
(define-inline phpinspect-taint-iterator-token-is-tainted-p (iter meta)
(inline-letevals (iter meta)
(inline-quote
(and (phpinspect-taint-iterator-follow ,iter (phpinspect-meta-start ,meta))
(phpinspect-taint-overlaps-meta
(phpinspect-taint-iterator-current ,iter) ,meta)))))
(define-inline phpinspect-taint-iterator-region-is-tainted-p (iter start end)
(inline-letevals (iter start end)
(inline-quote
(and (phpinspect-taint-iterator-follow ,iter ,start)
(phpinspect-taint-overlaps-region
(phpinspect-taint-iterator-current ,iter) ,start ,end)))))
(defsubst phpinspect-edit-original-end (edit) (defsubst phpinspect-edit-original-end (edit)
(or (caar edit) 0)) (or (caar edit) 0))
(defsubst phpinspect-edit-end (edit)
(let ((end (or (caar edit) 0))
(previous-edit (cdr edit)))
(+ end (phpinspect-edit-delta previous-edit))))
(defsubst phpinspect-edit-delta (edit) (defsubst phpinspect-edit-delta (edit)
(let ((delta (or (cdar edit) 0)) (let ((delta (or (cdar edit) 0))
(previous-edit edit)) (previous-edit edit))
@ -85,6 +51,11 @@
(setq delta (+ delta (cdar previous-edit)))) (setq delta (+ delta (cdar previous-edit))))
delta)) delta))
(defsubst phpinspect-edit-end (edit)
(let ((end (or (caar edit) 0))
(previous-edit (cdr edit)))
(+ end (phpinspect-edit-delta previous-edit))))
(defsubst phpinspect-edtrack-original-position-at-point (track point) (defsubst phpinspect-edtrack-original-position-at-point (track point)
(let ((edit (phpinspect-edtrack-edits track)) (let ((edit (phpinspect-edtrack-edits track))
(encroached) (encroached)
@ -113,48 +84,14 @@
(- pos encroached) (- pos encroached)
pos))) pos)))
(define-inline phpinspect-taint-start (taint)
(inline-quote (car ,taint)))
(defsubst phpinspect-edtrack-register-edit (track start end pre-change-length) (define-inline phpinspect-taint-end (taint)
(phpinspect--log (inline-quote (cdr ,taint)))
"Edtrack registered change: [start: %d, end: %d, pre-change-length: %d]"
start end pre-change-length)
(let ((original-start (phpinspect-edtrack-original-position-at-point track start)))
(phpinspect-edtrack-register-taint
track original-start (+ original-start pre-change-length)))
(let ((edit-before (phpinspect-edtrack-edits track))) (define-inline phpinspect-make-taint (start end)
(while (and edit-before (< end (phpinspect-edit-end edit-before))) (inline-quote (cons ,start ,end)))
(setq edit-before (cdr edit-before)))
(let ((delta ;; The delta of this edit.
(- (- end start) pre-change-length))
new-edit)
(setq new-edit (cons
;; The end location of the edited region, before being
;; edited, with the delta edits that happened at preceding
;; points in the buffer subtratted. This corresponds with
;; the original position of the region end before the
;; buffer was ever edited.
(phpinspect-edtrack-original-position-at-point
track (+ start pre-change-length))
delta))
(if edit-before
(progn
(setcdr edit-before (cons (car edit-before) (cdr edit-before)))
(setcar edit-before new-edit))
(if (phpinspect-edtrack-edits track)
(push new-edit (cdr (last (phpinspect-edtrack-edits track))))
(push new-edit (phpinspect-edtrack-edits track)))))))
(defsubst phpinspect-taint-start (taint)
(car taint))
(defsubst phpinspect-taint-end (taint)
(cdr taint))
(defsubst phpinspect-make-taint (start end)
(cons start end))
(defsubst phpinspect-taint-overlaps-point (taint point) (defsubst phpinspect-taint-overlaps-point (taint point)
(and (> (phpinspect-taint-end taint) point) (and (> (phpinspect-taint-end taint) point)
@ -180,15 +117,6 @@
(phpinspect-meta-overlaps-point meta (phpinspect-taint-start taint)) (phpinspect-meta-overlaps-point meta (phpinspect-taint-start taint))
(phpinspect-meta-overlaps-point meta (phpinspect-taint-end taint)))) (phpinspect-meta-overlaps-point meta (phpinspect-taint-end taint))))
(defsubst phpinspect-edtrack-clear-taint-pool (track)
(setf (phpinspect-edtrack-taint-pool track) nil))
(defsubst phpinspect-edtrack-clear (track)
(setf (phpinspect-edtrack-edits track) nil)
(setf (phpinspect-edtrack-last-edit track) nil)
(setf (phpinspect-edtrack-last-edit-start track) -1)
(phpinspect-edtrack-clear-taint-pool track))
(defsubst phpinspect-edtrack-register-taint (track start end) (defsubst phpinspect-edtrack-register-taint (track start end)
(let ((pool (phpinspect-edtrack-taint-pool track)) (let ((pool (phpinspect-edtrack-taint-pool track))
(idx 0) (idx 0)
@ -229,5 +157,79 @@
(t (t
(push taint (phpinspect-edtrack-taint-pool track)))))) (push taint (phpinspect-edtrack-taint-pool track))))))
(defsubst phpinspect-edtrack-register-edit (track start end pre-change-length)
(phpinspect--log
"Edtrack registered change: [start: %d, end: %d, pre-change-length: %d]"
start end pre-change-length)
(let ((original-start (phpinspect-edtrack-original-position-at-point track start)))
(phpinspect-edtrack-register-taint
track original-start (+ original-start pre-change-length)))
(let ((edit-before (phpinspect-edtrack-edits track)))
(while (and edit-before (< end (phpinspect-edit-end edit-before)))
(setq edit-before (cdr edit-before)))
(let ((delta ;; The delta of this edit.
(- (- end start) pre-change-length))
new-edit)
(setq new-edit (cons
;; The end location of the edited region, before being
;; edited, with the delta edits that happened at preceding
;; points in the buffer subtratted. This corresponds with
;; the original position of the region end before the
;; buffer was ever edited.
(phpinspect-edtrack-original-position-at-point
track (+ start pre-change-length))
delta))
(if edit-before
(progn
(setcdr edit-before (cons (car edit-before) (cdr edit-before)))
(setcar edit-before new-edit))
(if (phpinspect-edtrack-edits track)
(push new-edit (cdr (last (phpinspect-edtrack-edits track))))
(push new-edit (phpinspect-edtrack-edits track)))))))
(defsubst phpinspect-edtrack-clear-taint-pool (track)
(setf (phpinspect-edtrack-taint-pool track) nil))
(defsubst phpinspect-edtrack-clear (track)
(setf (phpinspect-edtrack-edits track) nil)
(setf (phpinspect-edtrack-last-edit track) nil)
(setf (phpinspect-edtrack-last-edit-start track) -1)
(phpinspect-edtrack-clear-taint-pool track))
(defsubst phpinspect-edtrack-make-taint-iterator (track)
(cons (car (phpinspect-edtrack-taint-pool track))
(cl-copy-list (cdr (phpinspect-edtrack-taint-pool track)))))
(define-inline phpinspect-taint-iterator-current (iter)
(inline-quote (car ,iter)))
(define-inline phpinspect-taint-iterator-follow (iter pos)
(inline-letevals (iter pos)
(inline-quote
(or (while (and (phpinspect-taint-iterator-current ,iter)
(> ,pos (phpinspect-taint-end
(phpinspect-taint-iterator-current ,iter))))
(setf (phpinspect-taint-iterator-current ,iter) (pop (cdr ,iter))))
(phpinspect-taint-iterator-current ,iter)))))
(define-inline phpinspect-taint-iterator-token-is-tainted-p (iter meta)
(inline-letevals (iter meta)
(inline-quote
(and (phpinspect-taint-iterator-follow ,iter (phpinspect-meta-start ,meta))
(phpinspect-taint-overlaps-meta
(phpinspect-taint-iterator-current ,iter) ,meta)))))
(define-inline phpinspect-taint-iterator-region-is-tainted-p (iter start end)
(inline-letevals (iter start end)
(inline-quote
(and (phpinspect-taint-iterator-follow ,iter ,start)
(phpinspect-taint-overlaps-region
(phpinspect-taint-iterator-current ,iter) ,start ,end)))))
(provide 'phpinspect-edtrack) (provide 'phpinspect-edtrack)
;;; phpinspect-edtrack.el ends here ;;; phpinspect-edtrack.el ends here

@ -24,8 +24,9 @@
;;; Code: ;;; Code:
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'phpinspect-meta) (require 'phpinspect-meta)
(require 'phpinspect-parser) (require 'phpinspect-token-predicates)
(require 'phpinspect-resolve) (require 'phpinspect-resolve)
(require 'phpinspect-buffer)
(defvar phpinspect-eldoc-word-width 14 (defvar phpinspect-eldoc-word-width 14
"The maximum width of words in eldoc strings.") "The maximum width of words in eldoc strings.")

@ -25,7 +25,7 @@
;;; Code: ;;; Code:
(require 'phpinspect-parser) (require 'phpinspect-token-predicates)
(require 'phpinspect-index) (require 'phpinspect-index)
(require 'phpinspect-autoload) (require 'phpinspect-autoload)
(require 'phpinspect-buffer) (require 'phpinspect-buffer)
@ -80,15 +80,13 @@ buffer position to insert the use statement at."
(format "use %s;%c" fqn ?\n)) (format "use %s;%c" fqn ?\n))
(let* ((first-token (phpinspect-meta-first-child (phpinspect-buffer-root-meta buffer))) (let* ((first-token (phpinspect-meta-first-child (phpinspect-buffer-root-meta buffer)))
token-after) token-after)
(message "First token %s" (phpinspect-meta-string first-token))
(when (and (phpinspect-word-p (phpinspect-meta-token first-token)) (when (and (phpinspect-word-p (phpinspect-meta-token first-token))
(string= "declare" (cadr (phpinspect-meta-token first-token)))) (string= "declare" (cadr (phpinspect-meta-token first-token))))
(progn (progn
(setq token-after first-token) (setq token-after first-token)
(while (and token-after (not (phpinspect-terminator-p (while (and token-after (not (phpinspect-terminator-p
(phpinspect-meta-token token-after)))) (phpinspect-meta-token token-after))))
(setq token-after (phpinspect-meta-find-right-sibling token-after)) (setq token-after (phpinspect-meta-find-right-sibling token-after)))))
(message "Token after: %s" (phpinspect-meta-string token-after)))))
(if token-after (if token-after
(phpinspect-insert-at-point (phpinspect-insert-at-point
(phpinspect-meta-end token-after) (format "%c%cuse %s;%c" ?\n ?\n fqn ?\n)) (phpinspect-meta-end token-after) (format "%c%cuse %s;%c" ?\n ?\n fqn ?\n))
@ -155,8 +153,6 @@ that there are import (\"use\") statements for them."
(class-name (alist-get 'class-name class)) (class-name (alist-get 'class-name class))
(region (alist-get 'location class)) (region (alist-get 'location class))
token-meta) token-meta)
(message "Region: %s" region)
(message "index: %s" index)
(setq token-meta (phpinspect-meta-find-parent-matching-token (setq token-meta (phpinspect-meta-find-parent-matching-token
(phpinspect-bmap-last-token-before-point (phpinspect-bmap-last-token-before-point
(phpinspect-buffer-map buffer) (phpinspect-buffer-map buffer)

@ -25,9 +25,8 @@
(require 'cl-lib) (require 'cl-lib)
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'phpinspect-project)
(require 'phpinspect-type) (require 'phpinspect-type)
(require 'phpinspect-parser) (require 'phpinspect-token-predicates)
(defun phpinspect--function-from-scope (scope) (defun phpinspect--function-from-scope (scope)
(cond ((and (phpinspect-static-p (cadr scope)) (cond ((and (phpinspect-static-p (cadr scope))
@ -158,15 +157,6 @@ function (think \"new\" statements, return types etc.)."
(defun phpinspect-doc-block-p (token) (defun phpinspect-doc-block-p (token)
(phpinspect-token-type-p token :doc-block)) (phpinspect-token-type-p token :doc-block))
(defun phpinspect--get-class-name-from-token (class-token)
(let ((subtoken (seq-find (lambda (word)
(and (phpinspect-word-p word)
(not (string-match
(concat "^" (phpinspect-handler-regexp class-keyword))
(concat (cadr word) " ")))))
(cadr class-token))))
(cadr subtoken)))
(defsubst phpinspect--index-method-annotations (type-resolver comment) (defsubst phpinspect--index-method-annotations (type-resolver comment)
(let ((annotations (seq-filter #'phpinspect-method-annotation-p comment)) (let ((annotations (seq-filter #'phpinspect-method-annotation-p comment))
@ -195,40 +185,6 @@ function (think \"new\" statements, return types etc.)."
methods))))) methods)))))
methods)) methods))
(defun phpinspect--index-class-declaration (decl type-resolver)
;; Find out what the class extends or implements
(let (encountered-extends encountered-implements encountered-class
class-name extends implements used-types)
(dolist (word decl)
(if (phpinspect-word-p word)
(cond ((string= (cadr word) "extends")
(phpinspect--log "Class %s extends other classes" class-name)
(setq encountered-extends t))
((string= (cadr word) "implements")
(setq encountered-extends nil)
(phpinspect--log "Class %s implements in interface" class-name)
(setq encountered-implements t))
((string= (cadr word) "class")
(setq encountered-class t))
(t
(phpinspect--log "Calling Resolver from index-class on %s" (cadr word))
(cond (encountered-extends
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
extends)
(push (cadr word) used-types))
(encountered-implements
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
implements)
(push (cadr word) used-types))
(encountered-class
(setq class-name (funcall type-resolver (phpinspect--make-type :name (cadr word)))
encountered-class nil)))))))
(list class-name extends implements used-types)))
(defun phpinspect--index-class (imports type-resolver location-resolver class &optional doc-block) (defun phpinspect--index-class (imports type-resolver location-resolver class &optional doc-block)
"Create an alist with relevant attributes of a parsed class." "Create an alist with relevant attributes of a parsed class."
(phpinspect--log "INDEXING CLASS") (phpinspect--log "INDEXING CLASS")
@ -395,22 +351,6 @@ NAMESPACE will be assumed the root namespace if not provided"
(setq comment-before nil)))) (setq comment-before nil))))
indexed)) indexed))
(defun phpinspect--use-to-type (use)
(let* ((fqn (cadr (cadr use)))
(type (phpinspect--make-type :name (if (string-match "^\\\\" fqn)
fqn
(concat "\\" fqn))
:fully-qualified t))
(type-name (if (and (phpinspect-word-p (caddr use))
(string= "as" (cadr (caddr use))))
(cadr (cadddr use))
(progn (string-match "[^\\]+$" fqn)
(match-string 0 fqn)))))
(cons (phpinspect-intern-name type-name) type)))
(defun phpinspect--uses-to-types (uses)
(mapcar #'phpinspect--use-to-type uses))
(defun phpinspect--index-namespace (namespace type-resolver-factory location-resolver) (defun phpinspect--index-namespace (namespace type-resolver-factory location-resolver)
(let* (used-types (let* (used-types
(index (index
@ -530,14 +470,6 @@ Return value is a list of the types that are \"newed\"."
nil)) nil))
'(phpinspect--root-index))) '(phpinspect--root-index)))
(defun phpinspect-get-or-create-cached-project-class (project-root class-fqn)
(when project-root
(let ((project (phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
project-root)))
(phpinspect-project-get-class-create project class-fqn))))
(cl-defmethod phpinspect-index-get-class (cl-defmethod phpinspect-index-get-class
((index (head phpinspect--root-index)) (class-name phpinspect--type)) ((index (head phpinspect--root-index)) (class-name phpinspect--type))
(alist-get class-name (alist-get 'classes index) (alist-get class-name (alist-get 'classes index)

@ -26,7 +26,6 @@
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'phpinspect-meta) (require 'phpinspect-meta)
(require 'phpinspect-changeset) (require 'phpinspect-changeset)
(require 'phpinspect-bmap)
(defvar phpinspect-parse-context nil (defvar phpinspect-parse-context nil
"An instance of `phpinspect-pctx' that is used when "An instance of `phpinspect-pctx' that is used when
@ -55,7 +54,7 @@ thrown.")
:documentation "Metadata change sets executed during this parse") :documentation "Metadata change sets executed during this parse")
(edtrack nil (edtrack nil
:type phpinspect-edtrack) :type phpinspect-edtrack)
(bmap (phpinspect-make-bmap) (bmap nil
:type phpinspect-bmap) :type phpinspect-bmap)
(previous-bmap nil (previous-bmap nil
:type phpinspect-bmap) :type phpinspect-bmap)
@ -94,6 +93,18 @@ thrown.")
(progn (progn
(push ,changeset (phpinspect-pctx-changesets ,pctx))))) (push ,changeset (phpinspect-pctx-changesets ,pctx)))))
(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-pctx-check-interrupt (pctx) (define-inline phpinspect-pctx-check-interrupt (pctx)
(inline-letevals (pctx) (inline-letevals (pctx)
(inline-quote (inline-quote
@ -108,12 +119,6 @@ thrown.")
(phpinspect-pctx-cancel ,pctx) (phpinspect-pctx-cancel ,pctx)
(throw 'phpinspect-parse-interrupted nil)))))) (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) (define-inline phpinspect-pctx-register-whitespace (pctx whitespace)
(inline-quote (inline-quote
(setf (phpinspect-pctx-whitespace-before ,pctx) ,whitespace))) (setf (phpinspect-pctx-whitespace-before ,pctx) ,whitespace)))

@ -53,14 +53,15 @@ If STRING has text properties, they are stripped."
(set-text-properties 0 length nil value) (set-text-properties 0 length nil value)
(list token-keyword value))) (list token-keyword value)))
(defun phpinspect-handler-func-name (handler-name) (eval-when-compile
(intern (concat "phpinspect--" (symbol-name handler-name) "-handler"))) (defun phpinspect-handler-func-name (handler-name)
(intern (concat "phpinspect--" (symbol-name handler-name) "-handler")))
(defun phpinspect-handler-regexp-func-name (handler-name) (defun phpinspect-handler-regexp-func-name (handler-name)
(intern (concat "phpinspect--" (symbol-name handler-name) "-handler-regexp"))) (intern (concat "phpinspect--" (symbol-name handler-name) "-handler-regexp")))
(defun phpinspect-parser-func-name (name &optional suffix) (defun phpinspect-parser-func-name (name &optional suffix)
(intern (concat "phpinspect--parse-" (symbol-name name) (if suffix (concat "-" suffix) "")))) (intern (concat "phpinspect--parse-" (symbol-name name) (if suffix (concat "-" suffix) "")))))
(defmacro phpinspect-defhandler (name arguments docstring attribute-alist &rest body) (defmacro phpinspect-defhandler (name arguments docstring attribute-alist &rest body)
"Define a parser handler that becomes available for use with phpinspect-parse. "Define a parser handler that becomes available for use with phpinspect-parse.
@ -130,8 +131,9 @@ You can purge the parser cache with \\[phpinspect-purge-parser-cache]."
(put (quote ,inline-name) 'phpinspect--handler t)))) (put (quote ,inline-name) 'phpinspect--handler t))))
(defun phpinspect-make-parser-function (name tree-type handlers &optional delimiter-predicate) (eval-when-compile
"Create a parser function using the handlers by names defined in HANDLER-LIST. (defun phpinspect-make-parser-function (name tree-type handlers &optional delimiter-predicate)
"Create a parser function using the handlers by names defined in HANDLER-LIST.
See also `phpinspect-defhandler`. See also `phpinspect-defhandler`.
@ -148,170 +150,170 @@ loop exits. An example use case of this is to determine the end
of a statement. You can use `phpinspect-terminator-p` as of a statement. You can use `phpinspect-terminator-p` as
delimiter predicate and have parsing stop when the last parsed delimiter predicate and have parsing stop when the last parsed
token is \";\", which marks the end of a statement in PHP." token is \";\", which marks the end of a statement in PHP."
(let ((delimiter-predicate (if (symbolp delimiter-predicate) (let ((delimiter-predicate (if (symbolp delimiter-predicate)
`(quote ,delimiter-predicate) `(quote ,delimiter-predicate)
delimiter-predicate))) delimiter-predicate)))
`(defsubst ,(phpinspect-parser-func-name name "simple") (buffer max-point &optional skip-over continue-condition &rest _ignored) `(defsubst ,(phpinspect-parser-func-name name "simple") (buffer max-point &optional skip-over continue-condition &rest _ignored)
(with-current-buffer buffer (with-current-buffer buffer
(let* ((tokens (cons ,tree-type nil)) (let* ((tokens (cons ,tree-type nil))
(tokens-rear tokens) (tokens-rear tokens)
token token
(delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate))) (delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate)))
(when skip-over (forward-char skip-over)) (when skip-over (forward-char skip-over))
(while (and (< (point) max-point) (while (and (< (point) max-point)
(if continue-condition (funcall continue-condition) t) (if continue-condition (funcall continue-condition) t)
(not (if delimiter-predicate (not (if delimiter-predicate
(funcall delimiter-predicate (car (last tokens))) (funcall delimiter-predicate (car (last tokens)))
nil))) nil)))
(cond ,@(mapcar (cond ,@(mapcar
(lambda (handler) (lambda (handler)
`((looking-at (,(phpinspect-handler-regexp-func-name handler))) `((looking-at (,(phpinspect-handler-regexp-func-name handler)))
(setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point)) (setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point))
(when token (when token
(setq tokens-rear (setcdr tokens-rear (cons token nil)))))) (setq tokens-rear (setcdr tokens-rear (cons token nil))))))
handlers) handlers)
(t (forward-char)))) (t (forward-char))))
;; Return ;; Return
tokens))))) tokens)))))
(defun phpinspect-make-incremental-parser-function (name tree-type handlers &optional delimiter-predicate) (defun phpinspect-make-incremental-parser-function (name tree-type handlers &optional delimiter-predicate)
"Like `phpinspect-make-parser-function', but returned function "Like `phpinspect-make-parser-function', but returned function
is able to reuse an already parsed tree." is able to reuse an already parsed tree."
(let ((delimiter-predicate (if (symbolp delimiter-predicate) (let ((delimiter-predicate (if (symbolp delimiter-predicate)
`(quote ,delimiter-predicate) `(quote ,delimiter-predicate)
delimiter-predicate))) delimiter-predicate)))
`(defsubst ,(phpinspect-parser-func-name name "incremental") (context buffer max-point &optional skip-over continue-condition root) `(defsubst ,(phpinspect-parser-func-name name "incremental") (context buffer max-point &optional skip-over continue-condition root)
(with-current-buffer buffer (with-current-buffer buffer
(let* ((tokens (cons ,tree-type nil)) (let* ((tokens (cons ,tree-type nil))
(tokens-rear tokens) (tokens-rear tokens)
(root-start (point)) (root-start (point))
(bmap (phpinspect-pctx-bmap context)) (bmap (phpinspect-pctx-bmap context))
(previous-bmap (phpinspect-pctx-previous-bmap context)) (previous-bmap (phpinspect-pctx-previous-bmap context))
(edtrack (phpinspect-pctx-edtrack context)) (edtrack (phpinspect-pctx-edtrack context))
(taint-iterator (when edtrack (phpinspect-edtrack-make-taint-iterator edtrack))) (taint-iterator (when edtrack (phpinspect-edtrack-make-taint-iterator edtrack)))
(check-interrupt (phpinspect-pctx-interrupt-predicate context)) (check-interrupt (phpinspect-pctx-interrupt-predicate context))
;; Loop variables ;; Loop variables
(start-position) (start-position)
(original-position) (original-position)
(current-end-position) (current-end-position)
(existing-meta) (existing-meta)
(delta) (delta)
(token) (token)
(delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate))) (delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate)))
(when skip-over (forward-char skip-over)) (when skip-over (forward-char skip-over))
(phpinspect-pctx-save-whitespace context (phpinspect-pctx-save-whitespace context
(while (and (< (point) max-point) (while (and (< (point) max-point)
(if continue-condition (funcall continue-condition) t) (if continue-condition (funcall continue-condition) t)
(not (if delimiter-predicate (not (if delimiter-predicate
(funcall delimiter-predicate (car (last tokens))) (funcall delimiter-predicate (car (last tokens)))
nil))) nil)))
(when check-interrupt (when check-interrupt
(phpinspect-pctx-check-interrupt context)) (phpinspect-pctx-check-interrupt context))
(setq start-position (point)) (setq start-position (point))
(cond ((and previous-bmap edtrack (cond ((and previous-bmap edtrack
(setq existing-meta (setq existing-meta
(phpinspect-bmap-token-starting-at (phpinspect-bmap-token-starting-at
previous-bmap previous-bmap
(setq original-position (setq original-position
(phpinspect-edtrack-original-position-at-point edtrack start-position)))) (phpinspect-edtrack-original-position-at-point edtrack start-position))))
(not (or (phpinspect-root-p (phpinspect-meta-token existing-meta)) (not (or (phpinspect-root-p (phpinspect-meta-token existing-meta))
(phpinspect-taint-iterator-token-is-tainted-p taint-iterator existing-meta)))) (phpinspect-taint-iterator-token-is-tainted-p taint-iterator existing-meta))))
(setq delta (- start-position original-position) (setq delta (- start-position original-position)
current-end-position (+ (phpinspect-meta-end existing-meta) delta) current-end-position (+ (phpinspect-meta-end existing-meta) delta)
token (phpinspect-meta-token existing-meta)) token (phpinspect-meta-token existing-meta))
;;(message "Reusing token %s at point %s" (phpinspect-meta-string existing-meta) (point)) ;;(message "Reusing token %s at point %s" (phpinspect-meta-string existing-meta) (point))
;; Re-register existing token ;; Re-register existing token
(phpinspect-bmap-overlay (phpinspect-bmap-overlay
bmap previous-bmap existing-meta delta bmap previous-bmap existing-meta delta
(phpinspect-pctx-consume-whitespace context)) (phpinspect-pctx-consume-whitespace context))
(goto-char current-end-position) (goto-char current-end-position)
;; Skip over whitespace after so that we don't do a full ;; Skip over whitespace after so that we don't do a full
;; run down all of the handlers during the next iteration ;; run down all of the handlers during the next iteration
(when (looking-at (phpinspect-handler-regexp whitespace)) (when (looking-at (phpinspect-handler-regexp whitespace))
(,(phpinspect-handler-func-name 'whitespace) (match-string 0)))) (,(phpinspect-handler-func-name 'whitespace) (match-string 0))))
,@(mapcar ,@(mapcar
(lambda (handler) (lambda (handler)
`((looking-at (,(phpinspect-handler-regexp-func-name handler))) `((looking-at (,(phpinspect-handler-regexp-func-name handler)))
(setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point)) (setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point))
(when token (when token
(phpinspect-pctx-register-token context token start-position (point))))) (phpinspect-pctx-register-token context token start-position (point)))))
handlers) handlers)
(t (forward-char))) (t (forward-char)))
(when token (when token
(setq tokens-rear (setcdr tokens-rear (cons token nil))) (setq tokens-rear (setcdr tokens-rear (cons token nil)))
(setq token nil)))) (setq token nil))))
(when root (when root
(phpinspect-pctx-register-token context tokens root-start (point))) (phpinspect-pctx-register-token context tokens root-start (point)))
;; Return ;; Return
tokens))))) tokens)))))
(cl-defstruct (phpinspect-parser (:constructor phpinspect-make-parser)) (cl-defstruct (phpinspect-parser (:constructor phpinspect-make-parser))
(name 'root (name 'root
:type symbol :type symbol
:read-only t) :read-only t)
(tree-keyword "root" (tree-keyword "root"
:type string :type string
:read-only t :read-only t
:documentation "Name of the keyword that is used as car of the :documentation "Name of the keyword that is used as car of the
root token, in string form without \":\" prefix.") root token, in string form without \":\" prefix.")
(handlers '(array tag equals list comma (handlers '(array tag equals list comma
attribute-reference variable attribute-reference variable
assignment-operator whitespace scope-keyword assignment-operator whitespace scope-keyword
static-keyword const-keyword use-keyword static-keyword const-keyword use-keyword
class-keyword function-keyword word terminator class-keyword function-keyword word terminator
here-doc string comment block) here-doc string comment block)
:type list :type list
:read-only t :read-only t
:documentation "A list of symbols referring to the :documentation "A list of symbols referring to the
handlers that this parser uses.") handlers that this parser uses.")
(delimiter-predicate nil (delimiter-predicate nil
:type function :type function
:read-only t :read-only t
:documentation "A predicate function that is passed each :documentation "A predicate function that is passed each
parsed token. When the predicate returns a non-nil value, the parser stops parsed token. When the predicate returns a non-nil value, the parser stops
executing.") executing.")
(func nil (func nil
:type function :type function
:documentation "The parser function.") :documentation "The parser function.")
(incremental-func nil (incremental-func nil
:type function :type function
:documentation "Incemental parser function")) :documentation "Incemental parser function"))
(cl-defmethod phpinspect-parser-compile ((parser phpinspect-parser)) (cl-defmethod phpinspect-parser-compile ((parser phpinspect-parser))
"Create/return parser function." "Create/return parser function."
(or (phpinspect-parser-func parser) (or (phpinspect-parser-func parser)
(setf (phpinspect-parser-func parser) (setf (phpinspect-parser-func parser)
(phpinspect-make-parser-function (phpinspect-make-parser-function
(phpinspect-parser-name parser) (phpinspect-parser-name parser)
(intern (concat ":" (phpinspect-parser-tree-keyword parser))) (intern (concat ":" (phpinspect-parser-tree-keyword parser)))
(phpinspect-parser-handlers parser) (phpinspect-parser-handlers parser)
(phpinspect-parser-delimiter-predicate parser))))) (phpinspect-parser-delimiter-predicate parser)))))
(cl-defmethod phpinspect-parser-compile-incremental ((parser phpinspect-parser)) (cl-defmethod phpinspect-parser-compile-incremental ((parser phpinspect-parser))
"Like `phpinspect-parser-compile', but for an incremental "Like `phpinspect-parser-compile', but for an incremental
version of the parser function." version of the parser function."
(or (phpinspect-parser-incremental-func parser) (or (phpinspect-parser-incremental-func parser)
(setf (phpinspect-parser-incremental-func parser) (setf (phpinspect-parser-incremental-func parser)
(phpinspect-make-incremental-parser-function (phpinspect-make-incremental-parser-function
(phpinspect-parser-name parser) (phpinspect-parser-name parser)
(intern (concat ":" (phpinspect-parser-tree-keyword parser))) (intern (concat ":" (phpinspect-parser-tree-keyword parser)))
(phpinspect-parser-handlers parser) (phpinspect-parser-handlers parser)
(phpinspect-parser-delimiter-predicate parser))))) (phpinspect-parser-delimiter-predicate parser)))))
(cl-defmethod phpinspect-parser-compile-entry ((parser phpinspect-parser)) (cl-defmethod phpinspect-parser-compile-entry ((parser phpinspect-parser))
(let ((func-name (phpinspect-parser-func-name (phpinspect-parser-name parser))) (let ((func-name (phpinspect-parser-func-name (phpinspect-parser-name parser)))
(incremental-name (phpinspect-parser-func-name (phpinspect-parser-name parser) "incremental")) (incremental-name (phpinspect-parser-func-name (phpinspect-parser-name parser) "incremental"))
(simple-name (phpinspect-parser-func-name (phpinspect-parser-name parser) "simple"))) (simple-name (phpinspect-parser-func-name (phpinspect-parser-name parser) "simple")))
`(defun ,func-name (buffer max-point &optional skip-over continue-condition root) `(defun ,func-name (buffer max-point &optional skip-over continue-condition root)
"Parse BUFFER, starting at point and ending at MAX-POINT. "Parse BUFFER, starting at point and ending at MAX-POINT.
If SKIP-OVER is non-nil, it must be a number of characters that If SKIP-OVER is non-nil, it must be a number of characters that
to skip over before starting to parse. to skip over before starting to parse.
@ -326,10 +328,12 @@ returned token tree. So the parser should register the metadata
of the root of its returned tree itself, before of the root of its returned tree itself, before
returning. Currently, token metadata is only registered when returning. Currently, token metadata is only registered when
parsing incrementally." parsing incrementally."
(if (and phpinspect-parse-context (if (and phpinspect-parse-context
(phpinspect-pctx-incremental phpinspect-parse-context)) (phpinspect-pctx-incremental phpinspect-parse-context))
(,incremental-name phpinspect-parse-context buffer max-point skip-over continue-condition root) (,incremental-name phpinspect-parse-context buffer max-point skip-over continue-condition root)
(,simple-name buffer max-point skip-over continue-condition root))))) (,simple-name buffer max-point skip-over continue-condition root)))))
) ;; End of eval-when-compile
(defmacro phpinspect-defparser (name &rest parameters) (defmacro phpinspect-defparser (name &rest parameters)
(declare (indent 1)) (declare (indent 1))
@ -342,19 +346,20 @@ parsing incrementally."
(simple-name (phpinspect-parser-func-name name "simple")) (simple-name (phpinspect-parser-func-name name "simple"))
(incremental-name (phpinspect-parser-func-name name "incremental"))) (incremental-name (phpinspect-parser-func-name name "incremental")))
`(let ((parser (phpinspect-make-parser ,@parameters))) `(eval-when-compile
(defconst ,simple-name nil) (let ((parser (phpinspect-make-parser ,@parameters)))
(defconst ,incremental-name nil) (defconst ,simple-name nil)
(defconst ,incremental-name nil)
(put (quote ,simple-name) 'phpinspect--parser t) (put (quote ,simple-name) 'phpinspect--parser t)
(put (quote ,incremental-name) 'phpinspect--incremental-parser t) (put (quote ,incremental-name) 'phpinspect--incremental-parser t)
(setf ,simple-name parser) (setf ,simple-name parser)
(setf ,incremental-name parser) (setf ,incremental-name parser)
;; Stub function to please the byte compiler (real function will be ;; Stub function to please the byte compiler (real function will be
;; defined by `phpinspect-define-parser-functions'. ;; defined by `phpinspect-define-parser-functions'.
(defun ,func-name (_buffer _max-point &optional _continue-condition _root))))) (defun ,func-name (_buffer _max-point &optional _skip-over _continue-condition _root))))))
(define-inline phpinspect-parser-func-bound-p (symbol) (define-inline phpinspect-parser-func-bound-p (symbol)
(inline-quote (get ,symbol 'phpinspect--parser))) (inline-quote (get ,symbol 'phpinspect--parser)))
@ -410,6 +415,40 @@ parsing incrementally."
(let ((name (phpinspect-handler-regexp-func-name handler-name))) (let ((name (phpinspect-handler-regexp-func-name handler-name)))
`(,name))) `(,name)))
(phpinspect-defhandler variable (start-token &rest _ignored)
"Handler for tokens indicating reference to a variable"
((regexp . "\\$"))
(forward-char (length start-token))
(if (looking-at (phpinspect-handler-regexp word))
(phpinspect-munch-token-without-attribs (match-string 0) :variable)
(list :variable nil)))
(phpinspect-defparser list
:tree-keyword "list"
:handlers '(array tag equals list comma
attribute-reference variable assignment-operator
whitespace function-keyword word terminator here-doc
string comment block-without-scopes))
(phpinspect-defhandler list (start-token max-point)
"Handler for php syntactic lists (Note: this does not include
datatypes like arrays, merely lists that are of a syntactic
nature like argument lists"
((regexp . "("))
(let* ((complete-list nil)
(php-list (phpinspect--parse-list
(current-buffer)
max-point
(length start-token)
(lambda () (not (and (char-equal (char-after) ?\)) (setq complete-list t)))))))
(if complete-list
;; Prevent parent-lists (if any) from exiting by skipping over the
;; ")" character
(forward-char)
(setcar php-list :incomplete-list))
php-list))
(defsubst phpinspect--parse-annotation-parameters (parameter-amount) (defsubst phpinspect--parse-annotation-parameters (parameter-amount)
(let* ((words) (let* ((words)
(list-regexp (phpinspect-handler-regexp list)) (list-regexp (phpinspect-handler-regexp list))
@ -498,13 +537,6 @@ parsing incrementally."
(let ((end-position (line-end-position))) (let ((end-position (line-end-position)))
(phpinspect--parse-comment (current-buffer) end-position))))) (phpinspect--parse-comment (current-buffer) end-position)))))
(phpinspect-defhandler variable (start-token &rest _ignored)
"Handler for tokens indicating reference to a variable"
((regexp . "\\$"))
(forward-char (length start-token))
(if (looking-at (phpinspect-handler-regexp word))
(phpinspect-munch-token-without-attribs (match-string 0) :variable)
(list :variable nil)))
(phpinspect-defhandler class-variable (start-token &rest _ignored) (phpinspect-defhandler class-variable (start-token &rest _ignored)
"Handler for tokens indicating reference to a variable" "Handler for tokens indicating reference to a variable"
@ -703,31 +735,6 @@ Returns the consumed text string without face properties."
nil t) nil t)
(buffer-substring-no-properties start-point (- (point) 1))))))))) (buffer-substring-no-properties start-point (- (point) 1)))))))))
(phpinspect-defparser list
:tree-keyword "list"
:handlers '(array tag equals list comma
attribute-reference variable assignment-operator
whitespace function-keyword word terminator here-doc
string comment block-without-scopes))
(phpinspect-defhandler list (start-token max-point)
"Handler for php syntactic lists (Note: this does not include
datatypes like arrays, merely lists that are of a syntactic
nature like argument lists"
((regexp . "("))
(let* ((complete-list nil)
(php-list (phpinspect--parse-list
(current-buffer)
max-point
(length start-token)
(lambda () (not (and (char-equal (char-after) ?\)) (setq complete-list t)))))))
(if complete-list
;; Prevent parent-lists (if any) from exiting by skipping over the
;; ")" character
(forward-char)
(setcar php-list :incomplete-list))
php-list))
(phpinspect-defparser declaration (phpinspect-defparser declaration
:tree-keyword "declaration" :tree-keyword "declaration"
@ -855,13 +862,6 @@ the properties of the class"
function-keyword word terminator here-doc string comment function-keyword word terminator here-doc string comment
tag block)) tag block))
(defun phpinspect-parse-buffer-until-point (buffer point)
(with-current-buffer buffer
(save-excursion
(goto-char (point-min))
(re-search-forward "<\\?php\\|<\\?" nil t)
(phpinspect--parse-root (current-buffer) point nil nil 'root))))
(defun phpinspect-parse-current-buffer () (defun phpinspect-parse-current-buffer ()
(phpinspect-parse-buffer-until-point (phpinspect-parse-buffer-until-point
(current-buffer) (current-buffer)
@ -878,7 +878,15 @@ the properties of the class"
(phpinspect-parse-current-buffer))) (phpinspect-parse-current-buffer)))
;; Define all registered parser functions ;; Define all registered parser functions
(phpinspect-define-parser-functions) (eval-and-compile
(phpinspect-define-parser-functions))
(defun phpinspect-parse-buffer-until-point (buffer point)
(with-current-buffer buffer
(save-excursion
(goto-char (point-min))
(re-search-forward "<\\?php\\|<\\?" nil t)
(phpinspect--parse-root (current-buffer) point nil nil 'root))))
(provide 'phpinspect-parser) (provide 'phpinspect-parser)
;;; phpinspect-parser.el ends here ;;; phpinspect-parser.el ends here

@ -129,7 +129,7 @@ directories."
(define-inline phpinspect-pipeline-pause () (define-inline phpinspect-pipeline-pause ()
"Pause the current pipeline thread" "Pause the current pipeline thread"
(inline-quote (inline-quote
(if (input-pending-p) (if (phpinspect--input-pending-p)
(let ((mx (make-mutex))) (let ((mx (make-mutex)))
(phpinspect-thread-pause (phpinspect-thread-pause
phpinspect-pipeline-pause-time mx (make-condition-variable mx "phpinspect-pipeline-pause"))) phpinspect-pipeline-pause-time mx (make-condition-variable mx "phpinspect-pipeline-pause")))

@ -23,6 +23,10 @@
;;; Code: ;;; Code:
(require 'phpinspect-project-struct)
(require 'phpinspect-autoload)
(require 'phpinspect-worker)
(require 'phpinspect-index)
(require 'phpinspect-class) (require 'phpinspect-class)
(require 'phpinspect-type) (require 'phpinspect-type)
(require 'phpinspect-fs) (require 'phpinspect-fs)
@ -45,47 +49,6 @@ serious performance hits. Enable at your own risk (:")
(set (make-local-variable 'phpinspect--buffer-project) (funcall phpinspect-project-root-function))) (set (make-local-variable 'phpinspect--buffer-project) (funcall phpinspect-project-root-function)))
phpinspect--buffer-project) phpinspect--buffer-project)
(cl-defstruct (phpinspect-project (:constructor phpinspect--make-project))
(class-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5)
:type hash-table
:documentation
"A `hash-table` that contains all of the currently
indexed classes in the project")
(function-index (make-hash-table :test 'eq :size 100 :rehash-size 2.0)
:type hash-table
:documentation
"A hash able that contains all of the currently indexed functions
in the project")
(function-token-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
(fs nil
:type phpinspect-fs
:documentation
"The filesystem object through which this project's files
can be accessed.")
(autoload nil
:type phpinspect-autoload
:documentation
"The autoload object through which this project's type
definitions can be retrieved")
(worker (progn
(unless (featurep 'phpinspect-worker)
(require 'phpinspect-worker))
(phpinspect-make-dynamic-worker))
:type phpinspect-worker
:documentation
"The worker that this project may queue tasks for")
(root nil
:type string
:documentation
"The root directory of this project")
(purged nil
:type boolean
:documentation "Whether or not the project has been purged or not.
Projects get purged when they are removed from the global cache.")
(file-watchers (make-hash-table :test #'equal :size 10000 :rehash-size 10000)
:type hash-table
:documentation "All active file watchers in this project,
indexed by the absolute paths of the files they're watching."))
(cl-defmethod phpinspect-project-purge ((project phpinspect-project)) (cl-defmethod phpinspect-project-purge ((project phpinspect-project))
"Disable all background processes for project and put it in a `purged` state." "Disable all background processes for project and put it in a `purged` state."
@ -197,7 +160,8 @@ indexed by the absolute paths of the files they're watching."))
(class (gethash class-name (class (gethash class-name
(phpinspect-project-class-index project)))) (phpinspect-project-class-index project))))
(unless class (unless class
(setq class (phpinspect--make-class-generated :project project))) (setq class (phpinspect--make-class-generated
:class-retriever (phpinspect-project-make-class-retriever project))))
(when index-imports (when index-imports
(phpinspect-project-enqueue-imports (phpinspect-project-enqueue-imports
@ -215,7 +179,8 @@ indexed by the absolute paths of the files they're watching."))
(cl-defmethod phpinspect-project-create-class (cl-defmethod phpinspect-project-create-class
((project phpinspect-project) (class-fqn phpinspect--type)) ((project phpinspect-project) (class-fqn phpinspect--type))
(let ((class (phpinspect--make-class-generated :project project))) (let ((class (phpinspect--make-class-generated
:class-retriever (phpinspect-project-make-class-retriever project))))
(phpinspect-project-set-class project class-fqn class) (phpinspect-project-set-class project class-fqn class)
class)) class))
@ -283,20 +248,6 @@ before the search is executed."
(cl-defmethod phpinspect-project-add-file-index ((project phpinspect-project) (filename string)) (cl-defmethod phpinspect-project-add-file-index ((project phpinspect-project) (filename string))
(phpinspect-project-add-index project (phpinspect-project-index-file project filename))) (phpinspect-project-add-index project (phpinspect-project-index-file project filename)))
(defun phpinspect-project-enqueue-include-dirs (project)
(interactive (list (phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
(phpinspect-current-project-root))))
(let ((dirs (alist-get 'include-dirs
(alist-get (phpinspect-project-root project)
phpinspect-projects
nil nil #'string=))))
(dolist (dir dirs)
(message "enqueueing dir %s" dir)
(phpinspect-worker-enqueue
(phpinspect-project-worker project)
(phpinspect-make-index-dir-task :dir dir :project project)))))
(defcustom phpinspect-projects nil (defcustom phpinspect-projects nil
"PHPInspect Projects." "PHPInspect Projects."
:type '(alist :key-type string :type '(alist :key-type string
@ -304,22 +255,95 @@ before the search is executed."
:options ((include-dirs (repeat string))))) :options ((include-dirs (repeat string)))))
:group 'phpinspect) :group 'phpinspect)
(defun phpinspect-project-add-include-dir (dir) (defun phpinspect-project-make-file-indexer (project)
"Configure DIR as an include dir for the current project." (lambda (filename)
(interactive (list (read-directory-name "Include Directory: "))) (phpinspect-project-add-file-index project filename)))
(custom-set-variables '(phpinspect-projects))
(let ((existing (defun phpinspect-project-make-root-resolver (project)
(alist-get (phpinspect-current-project-root) phpinspect-projects nil #'string=))) (lambda () (phpinspect-project-root project)))
(if existing
(push dir (alist-get 'include-dirs existing)) (defun phpinspect-project-make-class-retriever (project)
(push `(,(phpinspect-current-project-root) . ((include-dirs . (,dir)))) phpinspect-projects))) (lambda (type) (phpinspect-project-get-class-create project type)))
(customize-save-variable 'phpinspect-projects phpinspect-projects) ;;; INDEX TASK
(cl-defstruct (phpinspect-index-task
(phpinspect-project-enqueue-include-dirs (phpinspect--cache-get-project-create (:constructor phpinspect-make-index-task-generated))
(phpinspect--get-or-create-global-cache) "Represents an index task that can be executed by a `phpinspect-worker`."
(phpinspect-current-project-root)))) (project nil
:type phpinspect-project
:documentation
"The project that the task should be executed for.")
(type nil
:type phpinspect--type
:documentation
"The type whose file should be indexed."))
(cl-defgeneric phpinspect-make-index-task ((project phpinspect-project)
(type phpinspect--type))
(phpinspect-make-index-task-generated
:project project
:type type))
(cl-defmethod phpinspect-task-project ((task phpinspect-index-task))
(phpinspect-index-task-project task))
(cl-defmethod phpinspect-task= ((task1 phpinspect-index-task) (task2 phpinspect-index-task))
(and (eq (phpinspect-index-task-project task1)
(phpinspect-index-task-project task2))
(phpinspect--type= (phpinspect-index-task-type task1) (phpinspect-index-task-type task2))))
(cl-defmethod phpinspect-task-execute ((task phpinspect-index-task)
(worker phpinspect-worker))
"Execute index TASK for WORKER."
(let ((project (phpinspect-index-task-project task))
(is-native-type (phpinspect--type-is-native
(phpinspect-index-task-type task))))
(phpinspect--log "Indexing class %s for project in %s as task."
(phpinspect-index-task-type task)
(phpinspect-project-root project))
(cond (is-native-type
(phpinspect--log "Skipping indexation of native type %s as task"
(phpinspect-index-task-type task))
;; We can skip pausing when a native type is encountered
;; and skipped, as we haven't done any intensive work that
;; may cause hangups.
(setf (phpinspect-worker-skip-next-pause worker) t))
(t
(let* ((type (phpinspect-index-task-type task))
(root-index (phpinspect-project-index-type-file project type)))
(when root-index
(phpinspect-project-add-index project root-index)))))))
;;; INDEX FILE TASK
(cl-defstruct (phpinspect-index-dir-task (:constructor phpinspect-make-index-dir-task))
"A task for the indexation of files"
(project nil
:type phpinspect-project)
(dir nil
:type string))
(cl-defmethod phpinspect-task=
((task1 phpinspect-index-dir-task) (task2 phpinspect-index-dir-task))
(and (eq (phpinspect-index-dir-task-project task1)
(phpinspect-index-dir-task-project task2))
(string= (phpinspect-index-dir-task-dir task1)
(phpinspect-index-dir-task-dir task2))))
(cl-defmethod phpinspect-task-project ((task phpinspect-index-dir-task))
(phpinspect-index-dir-task-project task))
(cl-defmethod phpinspect-task-execute ((task phpinspect-index-dir-task)
(_worker phpinspect-worker))
(phpinspect--log "Entering..")
(let* ((project (phpinspect-index-dir-task-project task))
(fs (phpinspect-project-fs project))
(dir (phpinspect-index-dir-task-dir task)))
(phpinspect--log "Indexing directory %s" dir)
(phpinspect-pipeline (phpinspect-fs-directory-files-recursively fs dir "\\.php$")
:into (phpinspect-project-add-file-index :with-context project))))
(provide 'phpinspect-project) (provide 'phpinspect-project)
;;; phpinspect-project.el ends here ;;; phpinspect-project.el ends here

@ -24,8 +24,9 @@
;;; Code: ;;; Code:
(require 'phpinspect-resolvecontext) (require 'phpinspect-resolvecontext)
(require 'phpinspect-cache)
(require 'phpinspect-type) (require 'phpinspect-type)
(require 'phpinspect-parser) (require 'phpinspect-token-predicates)
(cl-defstruct (phpinspect--assignment (cl-defstruct (phpinspect--assignment
(:constructor phpinspect--make-assignment)) (:constructor phpinspect--make-assignment))
@ -36,13 +37,6 @@
:type phpinspect-token :type phpinspect-token
:documentation "The token that is assigned from")) :documentation "The token that is assigned from"))
(define-inline phpinspect-statement-introduction-p (token)
(inline-letevals (token)
(inline-quote
(or (phpinspect-return-p ,token)
(phpinspect-end-of-statement-p ,token)
(phpinspect-function-p ,token)))))
(defsubst phpinspect-block-or-list-p (token) (defsubst phpinspect-block-or-list-p (token)
(or (phpinspect-block-p token) (or (phpinspect-block-p token)
(phpinspect-list-p token))) (phpinspect-list-p token)))

@ -24,12 +24,31 @@
;;; Code: ;;; Code:
(require 'phpinspect-bmap) (require 'phpinspect-bmap)
(require 'phpinspect-cache)
(require 'phpinspect-project) (require 'phpinspect-project)
(require 'phpinspect-parser) (require 'phpinspect-token-predicates)
(require 'phpinspect-type) (require 'phpinspect-type)
(require 'phpinspect-meta) (require 'phpinspect-meta)
(require 'phpinspect-util) (require 'phpinspect-util)
(defsubst phpinspect-blocklike-p (token)
(or (phpinspect-block-p token)
(phpinspect-function-p token)
(phpinspect-class-p token)
(phpinspect-namespace-p token)))
(defsubst phpinspect-return-p (token)
(and (phpinspect-word-p token)
(string= "return" (cadr token))))
(define-inline phpinspect-statement-introduction-p (token)
(inline-letevals (token)
(inline-quote
(or (phpinspect-return-p ,token)
(phpinspect-end-of-statement-p ,token)
(phpinspect-function-p ,token)))))
(cl-defstruct (phpinspect--resolvecontext (cl-defstruct (phpinspect--resolvecontext
(:constructor phpinspect--make-resolvecontext)) (:constructor phpinspect--make-resolvecontext))
(subject nil (subject nil
@ -55,17 +74,6 @@
(push enclosing-token (phpinspect--resolvecontext-enclosing-tokens (push enclosing-token (phpinspect--resolvecontext-enclosing-tokens
resolvecontext))) resolvecontext)))
(defsubst phpinspect-blocklike-p (token)
(or (phpinspect-block-p token)
(phpinspect-function-p token)
(phpinspect-class-p token)
(phpinspect-namespace-p token)))
(defsubst phpinspect-return-p (token)
(and (phpinspect-word-p token)
(string= "return" (cadr token))))
(defun phpinspect-find-statement-before-point (bmap meta point) (defun phpinspect-find-statement-before-point (bmap meta point)
(let ((children (reverse (phpinspect-meta-find-children-before meta point))) (let ((children (reverse (phpinspect-meta-find-children-before meta point)))
token previous-siblings) token previous-siblings)

@ -25,7 +25,7 @@
(require 'phpinspect-resolvecontext) (require 'phpinspect-resolvecontext)
(require 'phpinspect-resolve) (require 'phpinspect-resolve)
(require 'phpinspect-parser) (require 'phpinspect-token-predicates)
(require 'phpinspect-type) (require 'phpinspect-type)
(require 'phpinspect-project) (require 'phpinspect-project)
(require 'phpinspect-class) (require 'phpinspect-class)

@ -24,7 +24,8 @@
;;; Code: ;;; Code:
(require 'phpinspect-splayt) (require 'phpinspect-splayt)
(require 'phpinspect-parser) (eval-when-compile
(require 'phpinspect-meta))
(defun phpinspect-make-toc (&optional tree) (defun phpinspect-make-toc (&optional tree)
(let ((table (make-hash-table :test #'eq :size 20 :rehash-size 2.0))) (let ((table (make-hash-table :test #'eq :size 20 :rehash-size 2.0)))

@ -56,10 +56,6 @@ Type can be any of the token types returned by
(phpinspect-comma-p token) (phpinspect-comma-p token)
(phpinspect-html-p token))) (phpinspect-html-p token)))
(defsubst phpinspect-end-of-statement-p (token)
(or (phpinspect-end-of-token-p token)
(phpinspect-block-p token)))
(defsubst phpinspect-incomplete-block-p (token) (defsubst phpinspect-incomplete-block-p (token)
(phpinspect-token-type-p token :incomplete-block)) (phpinspect-token-type-p token :incomplete-block))
@ -67,6 +63,10 @@ Type can be any of the token types returned by
(or (phpinspect-token-type-p token :block) (or (phpinspect-token-type-p token :block)
(phpinspect-incomplete-block-p token))) (phpinspect-incomplete-block-p token)))
(defsubst phpinspect-end-of-statement-p (token)
(or (phpinspect-end-of-token-p token)
(phpinspect-block-p token)))
(defun phpinspect-end-of-use-p (token) (defun phpinspect-end-of-use-p (token)
(or (phpinspect-block-p token) (or (phpinspect-block-p token)
(phpinspect-end-of-token-p token))) (phpinspect-end-of-token-p token)))
@ -170,11 +170,10 @@ Type can be any of the token types returned by
(or (phpinspect-token-type-p token :array) (or (phpinspect-token-type-p token :array)
(phpinspect-incomplete-array-p token))) (phpinspect-incomplete-array-p token)))
(defsubst phpinspect-incomplete-root-p (token) (defsubst phpinspect-root-p (object)
(and (phpinspect-root-p token) (phpinspect-token-type-p object :root))
(seq-find #'phpinspect-incomplete-token-p (cdr token))))
(defsubst phpinspect-incomplete-token-p (token) (defun phpinspect-incomplete-token-p (token)
(or (phpinspect-incomplete-root-p token) (or (phpinspect-incomplete-root-p token)
(phpinspect-incomplete-class-p token) (phpinspect-incomplete-class-p token)
(phpinspect-incomplete-block-p token) (phpinspect-incomplete-block-p token)
@ -185,6 +184,10 @@ Type can be any of the token types returned by
(phpinspect-incomplete-method-p token) (phpinspect-incomplete-method-p token)
(phpinspect-incomplete-namespace-p token))) (phpinspect-incomplete-namespace-p token)))
(defun phpinspect-incomplete-root-p (token)
(and (phpinspect-root-p token)
(seq-find #'phpinspect-incomplete-token-p (cdr token))))
(defun phpinspect--static-terminator-p (token) (defun phpinspect--static-terminator-p (token)
(or (phpinspect-function-p token) (or (phpinspect-function-p token)
(phpinspect-end-of-token-p token))) (phpinspect-end-of-token-p token)))
@ -214,9 +217,6 @@ Type can be any of the token types returned by
(and (phpinspect-word-p token) (string= (car (last token)) "use"))) (and (phpinspect-word-p token) (string= (car (last token)) "use")))
(defsubst phpinspect-root-p (object)
(phpinspect-token-type-p object :root))
(defsubst phpinspect-namespace-or-root-p (object) (defsubst phpinspect-namespace-or-root-p (object)
(or (phpinspect-namespace-p object) (or (phpinspect-namespace-p object)
(phpinspect-root-p object))) (phpinspect-root-p object)))
@ -247,4 +247,8 @@ Type can be any of the token types returned by
"Apply inverse of `phpinspect-class-p' to TOKEN." "Apply inverse of `phpinspect-class-p' to TOKEN."
(not (phpinspect-class-p token))) (not (phpinspect-class-p token)))
(defsubst phpinspect-probably-token-p (token)
(and (listp token)
(keywordp (car token))))
(provide 'phpinspect-token-predicates) (provide 'phpinspect-token-predicates)

@ -24,6 +24,11 @@
;;; Code: ;;; Code:
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'phpinspect-token-predicates)
(eval-when-compile
(require 'phpinspect-parser))
(cl-defstruct (phpinspect--type (cl-defstruct (phpinspect--type
(:constructor phpinspect--make-type-generated) (:constructor phpinspect--make-type-generated)
@ -279,5 +284,69 @@ mutability of the variable")
(not (or (phpinspect--variable-static-p variable) (not (or (phpinspect--variable-static-p variable)
(phpinspect--variable-const-p variable)))) (phpinspect--variable-const-p variable))))
(defun phpinspect--use-to-type (use)
(let* ((fqn (cadr (cadr use)))
(type (phpinspect--make-type :name (if (string-match "^\\\\" fqn)
fqn
(concat "\\" fqn))
:fully-qualified t))
(type-name (if (and (phpinspect-word-p (caddr use))
(string= "as" (cadr (caddr use))))
(cadr (cadddr use))
(progn (string-match "[^\\]+$" fqn)
(match-string 0 fqn)))))
(cons (phpinspect-intern-name type-name) type)))
(defun phpinspect--uses-to-types (uses)
(mapcar #'phpinspect--use-to-type uses))
(defun phpinspect--get-class-name-from-token (class-token)
(let ((subtoken (seq-find (lambda (word)
(and (phpinspect-word-p word)
(not (string-match
(concat "^" (phpinspect--class-keyword-handler-regexp))
(concat (cadr word) " ")))))
(cadr class-token))))
(cadr subtoken)))
(defun phpinspect--index-class-declaration (decl type-resolver)
;; Find out what the class extends or implements
(let (encountered-extends encountered-implements encountered-class
class-name extends implements used-types)
(dolist (word decl)
(if (phpinspect-word-p word)
(cond ((string= (cadr word) "extends")
(phpinspect--log "Class %s extends other classes" class-name)
(setq encountered-extends t))
((string= (cadr word) "implements")
(setq encountered-extends nil)
(phpinspect--log "Class %s implements in interface" class-name)
(setq encountered-implements t))
((string= (cadr word) "class")
(setq encountered-class t))
(t
(phpinspect--log "Calling Resolver from index-class on %s" (cadr word))
(cond (encountered-extends
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
extends)
(push (cadr word) used-types))
(encountered-implements
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
implements)
(push (cadr word) used-types))
(encountered-class
(setq class-name (funcall type-resolver (phpinspect--make-type :name (cadr word)))
encountered-class nil)))))))
(list class-name extends implements used-types)))
(defun phpinspect-namespace-name (namespace)
(or (and (phpinspect-namespace-p namespace)
(phpinspect-word-p (cadr namespace))
(cadadr namespace))
""))
(provide 'phpinspect-type) (provide 'phpinspect-type)
;;; phpinspect-type.el ends here ;;; phpinspect-type.el ends here

@ -31,31 +31,6 @@ PHP. Used to optimize string comparison.")
'("composer.json" "composer.lock" ".git" ".svn" ".hg") '("composer.json" "composer.lock" ".git" ".svn" ".hg")
"List of files that could indicate a project root directory.") "List of files that could indicate a project root directory.")
(defun phpinspect--find-project-root (&optional start-file)
"(Attempt to) Find the root directory of the visited PHP project.
If a found project root has a parent directory called \"vendor\",
the search continues upwards. See also
`phpinspect--locate-dominating-project-file'.
If START-FILE is provided, searching starts at the directory
level of START-FILE in stead of `default-directory`."
(let ((project-file (phpinspect--locate-dominating-project-file
(or start-file default-directory))))
(phpinspect--log "Checking for project root at %s" project-file)
(when project-file
(let* ((directory (file-name-directory project-file))
(directory-slugs (split-string (expand-file-name directory) "/")))
(if (not (member "vendor" directory-slugs))
(expand-file-name directory)
;; else. Only continue if the parent directory is not "/"
(let ((parent-without-vendor
(string-join (seq-take-while (lambda (s) (not (string= s "vendor" )))
directory-slugs)
"/")))
(when (not (or (string= parent-without-vendor "/")
(string= parent-without-vendor "")))
(phpinspect--find-project-root parent-without-vendor))))))))
(defvar phpinspect--debug nil (defvar phpinspect--debug nil
"Enable debug logs for phpinspect by setting this variable to true") "Enable debug logs for phpinspect by setting this variable to true")
@ -65,10 +40,10 @@ level of START-FILE in stead of `default-directory`."
(message "Enabled phpinspect logging.") (message "Enabled phpinspect logging.")
(message "Disabled phpinspect logging."))) (message "Disabled phpinspect logging.")))
(defvar phpinspect-log-groups nil) (eval-and-compile
(defvar phpinspect-enabled-log-groups nil) (defvar phpinspect-log-groups nil)
(defvar phpinspect-enabled-log-groups nil)
(defvar-local phpinspect--current-log-group nil) (defvar-local phpinspect--current-log-group nil))
(define-inline phpinspect--declare-log-group (group) (define-inline phpinspect--declare-log-group (group)
(unless (and (inline-const-p group) (symbolp (inline-const-val group))) (unless (and (inline-const-p group) (symbolp (inline-const-val group)))
@ -109,6 +84,31 @@ level of START-FILE in stead of `default-directory`."
(interactive) (interactive)
(setq phpinspect-enabled-log-groups nil)) (setq phpinspect-enabled-log-groups nil))
(defun phpinspect--find-project-root (&optional start-file)
"(Attempt to) Find the root directory of the visited PHP project.
If a found project root has a parent directory called \"vendor\",
the search continues upwards. See also
`phpinspect--locate-dominating-project-file'.
If START-FILE is provided, searching starts at the directory
level of START-FILE in stead of `default-directory`."
(let ((project-file (phpinspect--locate-dominating-project-file
(or start-file default-directory))))
(phpinspect--log "Checking for project root at %s" project-file)
(when project-file
(let* ((directory (file-name-directory project-file))
(directory-slugs (split-string (expand-file-name directory) "/")))
(if (not (member "vendor" directory-slugs))
(expand-file-name directory)
;; else. Only continue if the parent directory is not "/"
(let ((parent-without-vendor
(string-join (seq-take-while (lambda (s) (not (string= s "vendor" )))
directory-slugs)
"/")))
(when (not (or (string= parent-without-vendor "/")
(string= parent-without-vendor "")))
(phpinspect--find-project-root parent-without-vendor))))))))
(defsubst phpinspect-intern-name (name) (defsubst phpinspect-intern-name (name)
(intern name phpinspect-name-obarray)) (intern name phpinspect-name-obarray))
@ -251,6 +251,10 @@ context for completion."
(json-key-type 'string)) (json-key-type 'string))
,@body)) ,@body))
(defun phpinspect--input-pending-p (&optional check-timers)
(unless noninteractive
(input-pending-p check-timers)))
(defun phpinspect-thread-pause (pause-time mx continue) (defun phpinspect-thread-pause (pause-time mx continue)
"Pause current thread using MX and CONTINUE for PAUSE-TIME idle seconds. "Pause current thread using MX and CONTINUE for PAUSE-TIME idle seconds.
@ -265,16 +269,5 @@ CONTINUE must be a condition-variable"
(with-mutex mx (condition-wait continue)) (with-mutex mx (condition-wait continue))
(phpinspect--log "Thread '%s' continuing execution" (thread-name (current-thread)))) (phpinspect--log "Thread '%s' continuing execution" (thread-name (current-thread))))
(defun phpinspect-namespace-name (namespace)
(or (and (phpinspect-namespace-p namespace)
(phpinspect-word-p (cadr namespace))
(cadadr namespace))
""))
(defsubst phpinspect-probably-token-p (token)
(and (listp token)
(keywordp (car token))))
(provide 'phpinspect-util) (provide 'phpinspect-util)
;;; phpinspect-util.el ends here ;;; phpinspect-util.el ends here

@ -1,4 +1,4 @@
;;; phpinspect-worker.el --- PHP parsing and completion package -*- lexical-binding: t; -*- ;; phpinspect-worker.el --- PHP parsing and completion package -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Free Software Foundation, Inc ;; Copyright (C) 2021 Free Software Foundation, Inc
@ -25,7 +25,7 @@
(require 'cl-lib) (require 'cl-lib)
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'phpinspect-project) (require 'phpinspect-project-struct)
(require 'phpinspect-index) (require 'phpinspect-index)
(require 'phpinspect-class) (require 'phpinspect-class)
(require 'phpinspect-queue) (require 'phpinspect-queue)
@ -75,7 +75,7 @@ on the worker independent of dynamic variables during testing.")
(cl-defmethod phpinspect-resolve-dynamic-worker ((_worker phpinspect-dynamic-worker)) (cl-defmethod phpinspect-resolve-dynamic-worker ((_worker phpinspect-dynamic-worker))
phpinspect-worker) phpinspect-worker)
(defsubst phpinspect-make-dynamic-worker () (defun phpinspect-make-dynamic-worker ()
(phpinspect-make-dynamic-worker-generated)) (phpinspect-make-dynamic-worker-generated))
(defsubst phpinspect-make-worker () (defsubst phpinspect-make-worker ()
@ -148,7 +148,7 @@ already present in the queue."
;; Pause for a second after indexing something, to allow user input to ;; Pause for a second after indexing something, to allow user input to
;; interrupt the thread. ;; interrupt the thread.
(unless (or (not (input-pending-p)) (unless (or (not (phpinspect--input-pending-p))
(phpinspect-worker-skip-next-pause worker)) (phpinspect-worker-skip-next-pause worker))
(phpinspect-thread-pause phpinspect-worker-pause-time mx continue)) (phpinspect-thread-pause phpinspect-worker-pause-time mx continue))
(setf (phpinspect-worker-skip-next-pause worker) nil))) (setf (phpinspect-worker-skip-next-pause worker) nil)))
@ -225,86 +225,5 @@ already present in the queue."
(cl-defgeneric phpinspect-task-project (task) (cl-defgeneric phpinspect-task-project (task)
"The project that this task belongs to.") "The project that this task belongs to.")
;;; INDEX TASK
(cl-defstruct (phpinspect-index-task
(:constructor phpinspect-make-index-task-generated))
"Represents an index task that can be executed by a `phpinspect-worker`."
(project nil
:type phpinspect-project
:documentation
"The project that the task should be executed for.")
(type nil
:type phpinspect--type
:documentation
"The type whose file should be indexed."))
(cl-defgeneric phpinspect-make-index-task ((project phpinspect-project)
(type phpinspect--type))
(phpinspect-make-index-task-generated
:project project
:type type))
(cl-defmethod phpinspect-task-project ((task phpinspect-index-task))
(phpinspect-index-task-project task))
(cl-defmethod phpinspect-task= ((task1 phpinspect-index-task) (task2 phpinspect-index-task))
(and (eq (phpinspect-index-task-project task1)
(phpinspect-index-task-project task2))
(phpinspect--type= (phpinspect-index-task-type task1) (phpinspect-index-task-type task2))))
(cl-defmethod phpinspect-task-execute ((task phpinspect-index-task)
(worker phpinspect-worker))
"Execute index TASK for WORKER."
(let ((project (phpinspect-index-task-project task))
(is-native-type (phpinspect--type-is-native
(phpinspect-index-task-type task))))
(phpinspect--log "Indexing class %s for project in %s as task."
(phpinspect-index-task-type task)
(phpinspect-project-root project))
(cond (is-native-type
(phpinspect--log "Skipping indexation of native type %s as task"
(phpinspect-index-task-type task))
;; We can skip pausing when a native type is encountered
;; and skipped, as we haven't done any intensive work that
;; may cause hangups.
(setf (phpinspect-worker-skip-next-pause worker) t))
(t
(let* ((type (phpinspect-index-task-type task))
(root-index (phpinspect-project-index-type-file project type)))
(when root-index
(phpinspect-project-add-index project root-index)))))))
;;; INDEX FILE TASK
(cl-defstruct (phpinspect-index-dir-task (:constructor phpinspect-make-index-dir-task))
"A task for the indexation of files"
(project nil
:type phpinspect-project)
(dir nil
:type string))
(cl-defmethod phpinspect-task=
((task1 phpinspect-index-dir-task) (task2 phpinspect-index-dir-task))
(and (eq (phpinspect-index-dir-task-project task1)
(phpinspect-index-dir-task-project task2))
(string= (phpinspect-index-dir-task-dir task1)
(phpinspect-index-dir-task-dir task2))))
(cl-defmethod phpinspect-task-project ((task phpinspect-index-dir-task))
(phpinspect-index-dir-task-project task))
(cl-defmethod phpinspect-task-execute ((task phpinspect-index-dir-task)
(_worker phpinspect-worker))
(phpinspect--log "Entering..")
(let* ((project (phpinspect-index-dir-task-project task))
(fs (phpinspect-project-fs project))
(dir (phpinspect-index-dir-task-dir task)))
(phpinspect--log "Indexing directory %s" dir)
(phpinspect-pipeline (phpinspect-fs-directory-files-recursively fs dir "\\.php$")
:into (phpinspect-project-add-file-index :with-context project))))
(provide 'phpinspect-worker) (provide 'phpinspect-worker)
;;; phpinspect-worker.el ends here ;;; phpinspect-worker.el ends here

@ -217,7 +217,7 @@
(ert-deftest phpinspect-resolve-type-from-context () (ert-deftest phpinspect-resolve-type-from-context ()
(let* ((pctx (phpinspect-make-pctx :incremental t)) (let* ((pctx (phpinspect-make-pctx :incremental t :bmap (phpinspect-make-bmap)))
(code " (code "
namespace Amazing; namespace Amazing;

@ -1,4 +1,4 @@
;; test-autoload.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*- ; test-autoload.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Copyright (C) 2021 Free Software Foundation, Inc.
@ -31,7 +31,11 @@
(ert-deftest phpinspect-find-composer-json-files () (ert-deftest phpinspect-find-composer-json-files ()
(let* ((fs (phpinspect-make-virtual-fs)) (let* ((fs (phpinspect-make-virtual-fs))
(autoloader (phpinspect-make-autoloader (autoloader (phpinspect-make-autoloader
:project (phpinspect--make-project :root "/root" :fs fs)))) :fs fs
:project-root-resolver (lambda () "/root")
:file-indexer
(phpinspect-project-make-file-indexer
(phpinspect--make-project :root "/root" :fs fs)))))
(phpinspect-virtual-fs-set-file fs (phpinspect-virtual-fs-set-file fs
"/root/composer.json" "/root/composer.json"
"{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}") "{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}")
@ -57,9 +61,14 @@
(ert-deftest phpinspect-autoload-composer-json-iterator () (ert-deftest phpinspect-autoload-composer-json-iterator ()
(let* ((fs (phpinspect-make-virtual-fs)) (let* ((fs (phpinspect-make-virtual-fs))
(autoloader (phpinspect-make-autoloader (autoloader (phpinspect-make-autoloader
:project (phpinspect--make-project :root "/root" :fs fs))) :fs fs
:project-root-resolver (lambda () "/root")
:file-indexer
(phpinspect-project-make-file-indexer
(phpinspect--make-project :root "/root" :fs fs))))
result error) result error)
(phpinspect-virtual-fs-set-file fs (phpinspect-virtual-fs-set-file fs
"/root/composer.json" "/root/composer.json"
"{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}") "{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}")
@ -92,7 +101,10 @@
(ert-deftest phpinspect-al-strategy-execute () (ert-deftest phpinspect-al-strategy-execute ()
(let* ((fs (phpinspect-make-virtual-fs)) (let* ((fs (phpinspect-make-virtual-fs))
(project (phpinspect--make-project :root "/project/root" :fs fs)) (project (phpinspect--make-project :root "/project/root" :fs fs))
(autoloader (phpinspect-make-autoloader :project project)) (autoloader (phpinspect-make-autoloader
:fs fs
:project-root-resolver (lambda () "/project/root")
:file-indexer (phpinspect-project-make-file-indexer project)))
result error) result error)
(setf (phpinspect-project-autoload project) autoloader) (setf (phpinspect-project-autoload project) autoloader)
@ -131,7 +143,7 @@
"<?php class FilesList { function list() {} }") "<?php class FilesList { function list() {} }")
(phpinspect-virtual-fs-set-file (phpinspect-virtual-fs-set-file
fs "/project/root/vendor/not-runescape/wow/src/TestClass.php" "") fs "/project/root/vendor/not-runescape/wow/src/TestClass.php" "")
(phpinspect-pipeline (phpinspect-find-composer-json-files fs "/project/root") (phpinspect-pipeline (phpinspect-find-composer-json-files fs "/project/root")
:async (lambda (res err) :async (lambda (res err)

@ -101,7 +101,9 @@
(should (= 1 (length (hash-table-values (phpinspect--class-subscriptions other-class))))))) (should (= 1 (length (hash-table-values (phpinspect--class-subscriptions other-class)))))))
(ert-deftest phpinspect--class-update-declaration () (ert-deftest phpinspect--class-update-declaration ()
(let ((class (phpinspect--make-class-generated :project (phpinspect--make-project)))) (let ((class (phpinspect--make-class-generated
:class-retriever (phpinspect-project-make-class-retriever
(phpinspect--make-project)))))
(phpinspect--class-update-declaration class '(:declaration (:word "class") (:word "TestClass") (phpinspect--class-update-declaration class '(:declaration (:word "class") (:word "TestClass")
(:word "extends") (:word "OtherClass") (:word "extends") (:word "OtherClass")
(:word "implements") (:word "ImplClass")) (:word "implements") (:word "ImplClass"))

@ -169,7 +169,7 @@ return StaticThing::create(new ThingFactory())->makeThing((((new Potato())->anti
(alist-get key index2-class)))))) (alist-get key index2-class))))))
(ert-deftest phpinspect-index-bmap-class () (ert-deftest phpinspect-index-bmap-class ()
(let* ((pctx (phpinspect-make-pctx :incremental t)) (let* ((pctx (phpinspect-make-pctx :incremental t :bmap (phpinspect-make-bmap)))
(tree)) (tree))
(with-temp-buffer (with-temp-buffer
(insert-file-contents (concat phpinspect-test-php-file-directory "/IndexClass1.php")) (insert-file-contents (concat phpinspect-test-php-file-directory "/IndexClass1.php"))

@ -29,7 +29,7 @@
(ert-deftest phpinspect-pctx-cancel () (ert-deftest phpinspect-pctx-cancel ()
(let ((meta (phpinspect-make-meta nil 10 20 " " 'token 'overlay nil)) (let ((meta (phpinspect-make-meta nil 10 20 " " 'token 'overlay nil))
(pctx (phpinspect-make-pctx))) (pctx (phpinspect-make-pctx :bmap (phpinspect-make-bmap))))
(phpinspect-with-parse-context pctx (phpinspect-with-parse-context pctx
(phpinspect-meta-with-changeset meta (phpinspect-meta-with-changeset meta
(setf (phpinspect-meta-absolute-start meta) 222) (setf (phpinspect-meta-absolute-start meta) 222)

@ -42,7 +42,7 @@
(ert-deftest phpinspect-parse-bmap () (ert-deftest phpinspect-parse-bmap ()
(let* ((ctx (phpinspect-make-pctx :incremental t)) (let* ((ctx (phpinspect-make-pctx :incremental t :bmap (phpinspect-make-bmap)))
(code " (code "
class TestClass { class TestClass {
public function getCurrentStatisticAction(): JsonResponse public function getCurrentStatisticAction(): JsonResponse
@ -73,7 +73,7 @@ class TestClass {
(ert-deftest phpinspect-parse-comma () (ert-deftest phpinspect-parse-comma ()
(let* ((code "(,)") (let* ((code "(,)")
(ctx (phpinspect-make-pctx :incremental t)) (ctx (phpinspect-make-pctx :incremental t :bmap (phpinspect-make-bmap)))
(parsed (phpinspect-with-parse-context ctx (parsed (phpinspect-with-parse-context ctx
(phpinspect-parse-string code))) (phpinspect-parse-string code)))
(comma (cadadr parsed)) (comma (cadadr parsed))

@ -2,7 +2,7 @@
(require 'phpinspect-resolvecontext) (require 'phpinspect-resolvecontext)
(ert-deftest phinspect-get-resolvecontext () (ert-deftest phinspect-get-resolvecontext ()
(let* ((ctx (phpinspect-make-pctx :incremental t)) (let* ((ctx (phpinspect-make-pctx :incremental t :bmap (phpinspect-make-bmap)))
(code " (code "
class TestClass { class TestClass {
public function getCurrentStatisticAction(): JsonResponse public function getCurrentStatisticAction(): JsonResponse

Loading…
Cancel
Save