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"))
(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)))
(let ((bmap (phpinspect-make-bmap))
@ -24,13 +24,19 @@
(garbage-collect)
(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)))
(garbage-collect)
(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)))
(garbage-collect)
@ -64,7 +70,10 @@
;;(profiler-start 'cpu)
(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)))
;; (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:
(require 'cl-lib)
(require 'phpinspect-project)
(require 'phpinspect-fs)
(require 'phpinspect-util)
(require 'phpinspect-pipeline)
@ -72,9 +71,12 @@
(:constructor phpinspect-make-autoloader))
(refresh-thread nil
:type thread)
(project nil
:type phpinspect-project
:documentation "The project that this autoloader can find files for")
(fs nil
:type phpinspect-fs)
(file-indexer nil
:type function)
(project-root-resolver nil
:type function)
(own-types (make-hash-table :test 'eq :size 10000 :rehash-size 10000)
:type hash-table
:documentation "The internal types that can be
@ -160,9 +162,9 @@ bareword typenames."))
(cl-defmethod phpinspect-al-strategy-execute ((strat phpinspect-files))
(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)
: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))
(let* ((type-name (phpinspect-intern-name
@ -175,7 +177,7 @@ bareword typenames."))
(cl-defmethod phpinspect-iterate-composer-jsons
((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)))
json autoload batch)
@ -254,8 +256,8 @@ bareword typenames."))
(cl-defmethod phpinspect-autoloader-refresh ((autoloader phpinspect-autoloader) &optional async-callback)
"Refresh autoload definitions by reading composer.json files
from the project and vendor folders."
(let* ((project-root (phpinspect-project-root (phpinspect-autoloader-project autoloader)))
(fs (phpinspect-project-fs (phpinspect-autoloader-project autoloader))))
(let* ((project-root (funcall (phpinspect-autoloader-project-root-resolver autoloader)))
(fs (phpinspect-autoloader-fs autoloader)))
(setf (phpinspect-autoloader-type-name-fqn-bags autoloader)
(make-hash-table :test 'eq :size 3000 :rehash-size 3000))
(setf (phpinspect-autoloader-own-types autoloader)

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

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

@ -65,6 +65,13 @@ currently opened projects."
((cache phpinspect--cache) (project-root string))
(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
((cache phpinspect--cache) (project-root string))
"Get a project that is located in PROJECT-ROOT from CACHE.
@ -78,11 +85,43 @@ then returned."
:root project-root
:worker (phpinspect-make-dynamic-worker))
(phpinspect--cache-projects cache)))
(let ((autoloader (phpinspect-make-autoloader :project project)))
(setf (phpinspect-project-autoload project) autoloader)
(let ((autoloader (phpinspect-make-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-project-enqueue-include-dirs 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)
;;; phpinspect.el ends here

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

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

@ -26,6 +26,7 @@
(require 'phpinspect-util)
(eval-when-compile
(require 'phpinspect-meta)
(phpinspect--declare-log-group 'edtrack))
(cl-defstruct (phpinspect-edtrack (:constructor phpinspect-make-edtrack))
@ -40,44 +41,9 @@
:type integer
: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)
(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)
(let ((delta (or (cdar edit) 0))
(previous-edit edit))
@ -85,6 +51,11 @@
(setq delta (+ delta (cdar previous-edit))))
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)
(let ((edit (phpinspect-edtrack-edits track))
(encroached)
@ -113,48 +84,14 @@
(- pos encroached)
pos)))
(define-inline phpinspect-taint-start (taint)
(inline-quote (car ,taint)))
(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)))
(define-inline phpinspect-taint-end (taint)
(inline-quote (cdr ,taint)))
(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-taint-start (taint)
(car taint))
(defsubst phpinspect-taint-end (taint)
(cdr taint))
(defsubst phpinspect-make-taint (start end)
(cons start end))
(define-inline phpinspect-make-taint (start end)
(inline-quote (cons ,start ,end)))
(defsubst phpinspect-taint-overlaps-point (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-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)
(let ((pool (phpinspect-edtrack-taint-pool track))
(idx 0)
@ -229,5 +157,79 @@
(t
(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)
;;; phpinspect-edtrack.el ends here

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

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

@ -25,9 +25,8 @@
(require 'cl-lib)
(require 'phpinspect-util)
(require 'phpinspect-project)
(require 'phpinspect-type)
(require 'phpinspect-parser)
(require 'phpinspect-token-predicates)
(defun phpinspect--function-from-scope (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)
(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)
(let ((annotations (seq-filter #'phpinspect-method-annotation-p comment))
@ -195,40 +185,6 @@ function (think \"new\" statements, return types etc.)."
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)
"Create an alist with relevant attributes of a parsed class."
(phpinspect--log "INDEXING CLASS")
@ -395,22 +351,6 @@ NAMESPACE will be assumed the root namespace if not provided"
(setq comment-before nil))))
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)
(let* (used-types
(index
@ -530,14 +470,6 @@ Return value is a list of the types that are \"newed\"."
nil))
'(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
((index (head phpinspect--root-index)) (class-name phpinspect--type))
(alist-get class-name (alist-get 'classes index)

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

@ -53,14 +53,15 @@ If STRING has text properties, they are stripped."
(set-text-properties 0 length nil value)
(list token-keyword value)))
(defun phpinspect-handler-func-name (handler-name)
(eval-when-compile
(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")))
(defun phpinspect-parser-func-name (name &optional suffix)
(intern (concat "phpinspect--parse-" (symbol-name name) (if suffix (concat "-" suffix) ""))))
(defun phpinspect-parser-func-name (name &optional suffix)
(intern (concat "phpinspect--parse-" (symbol-name name) (if suffix (concat "-" suffix) "")))))
(defmacro phpinspect-defhandler (name arguments docstring attribute-alist &rest body)
"Define a parser handler that becomes available for use with phpinspect-parse.
@ -130,7 +131,8 @@ You can purge the parser cache with \\[phpinspect-purge-parser-cache]."
(put (quote ,inline-name) 'phpinspect--handler t))))
(defun phpinspect-make-parser-function (name tree-type handlers &optional delimiter-predicate)
(eval-when-compile
(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`.
@ -176,10 +178,10 @@ token is \";\", which marks the end of a statement in PHP."
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
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)
delimiter-predicate)))
`(defsubst ,(phpinspect-parser-func-name name "incremental") (context buffer max-point &optional skip-over continue-condition root)
@ -253,7 +255,7 @@ is able to reuse an already parsed tree."
;; Return
tokens)))))
(cl-defstruct (phpinspect-parser (:constructor phpinspect-make-parser))
(cl-defstruct (phpinspect-parser (:constructor phpinspect-make-parser))
(name 'root
:type symbol
:read-only t)
@ -285,7 +287,7 @@ executing.")
:type 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."
(or (phpinspect-parser-func parser)
(setf (phpinspect-parser-func parser)
@ -295,7 +297,7 @@ executing.")
(phpinspect-parser-handlers 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
version of the parser function."
(or (phpinspect-parser-incremental-func parser)
@ -306,7 +308,7 @@ version of the parser function."
(phpinspect-parser-handlers 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)))
(incremental-name (phpinspect-parser-func-name (phpinspect-parser-name parser) "incremental"))
(simple-name (phpinspect-parser-func-name (phpinspect-parser-name parser) "simple")))
@ -331,6 +333,8 @@ parsing incrementally."
(,incremental-name phpinspect-parse-context 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)
(declare (indent 1))
(unless (symbolp name)
@ -342,7 +346,8 @@ parsing incrementally."
(simple-name (phpinspect-parser-func-name name "simple"))
(incremental-name (phpinspect-parser-func-name name "incremental")))
`(let ((parser (phpinspect-make-parser ,@parameters)))
`(eval-when-compile
(let ((parser (phpinspect-make-parser ,@parameters)))
(defconst ,simple-name nil)
(defconst ,incremental-name nil)
@ -354,7 +359,7 @@ parsing incrementally."
;; Stub function to please the byte compiler (real function will be
;; 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)
(inline-quote (get ,symbol 'phpinspect--parser)))
@ -410,6 +415,40 @@ parsing incrementally."
(let ((name (phpinspect-handler-regexp-func-name handler-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)
(let* ((words)
(list-regexp (phpinspect-handler-regexp list))
@ -498,13 +537,6 @@ parsing incrementally."
(let ((end-position (line-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)
"Handler for tokens indicating reference to a variable"
@ -703,31 +735,6 @@ Returns the consumed text string without face properties."
nil t)
(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
:tree-keyword "declaration"
@ -855,13 +862,6 @@ the properties of the class"
function-keyword word terminator here-doc string comment
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 ()
(phpinspect-parse-buffer-until-point
(current-buffer)
@ -878,7 +878,15 @@ the properties of the class"
(phpinspect-parse-current-buffer)))
;; 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)
;;; phpinspect-parser.el ends here

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

@ -23,6 +23,10 @@
;;; Code:
(require 'phpinspect-project-struct)
(require 'phpinspect-autoload)
(require 'phpinspect-worker)
(require 'phpinspect-index)
(require 'phpinspect-class)
(require 'phpinspect-type)
(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)))
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))
"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
(phpinspect-project-class-index project))))
(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
(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
((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)
class))
@ -283,20 +248,6 @@ before the search is executed."
(cl-defmethod phpinspect-project-add-file-index ((project phpinspect-project) (filename string))
(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
"PHPInspect Projects."
:type '(alist :key-type string
@ -304,22 +255,95 @@ before the search is executed."
:options ((include-dirs (repeat string)))))
:group 'phpinspect)
(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)))
(defun phpinspect-project-make-file-indexer (project)
(lambda (filename)
(phpinspect-project-add-file-index project filename)))
(customize-save-variable 'phpinspect-projects phpinspect-projects)
(defun phpinspect-project-make-root-resolver (project)
(lambda () (phpinspect-project-root project)))
(phpinspect-project-enqueue-include-dirs (phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
(phpinspect-current-project-root))))
(defun phpinspect-project-make-class-retriever (project)
(lambda (type) (phpinspect-project-get-class-create project type)))
;;; 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-project)
;;; phpinspect-project.el ends here

@ -24,8 +24,9 @@
;;; Code:
(require 'phpinspect-resolvecontext)
(require 'phpinspect-cache)
(require 'phpinspect-type)
(require 'phpinspect-parser)
(require 'phpinspect-token-predicates)
(cl-defstruct (phpinspect--assignment
(:constructor phpinspect--make-assignment))
@ -36,13 +37,6 @@
:type phpinspect-token
: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)
(or (phpinspect-block-p token)
(phpinspect-list-p token)))

@ -24,12 +24,31 @@
;;; Code:
(require 'phpinspect-bmap)
(require 'phpinspect-cache)
(require 'phpinspect-project)
(require 'phpinspect-parser)
(require 'phpinspect-token-predicates)
(require 'phpinspect-type)
(require 'phpinspect-meta)
(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
(:constructor phpinspect--make-resolvecontext))
(subject nil
@ -55,17 +74,6 @@
(push enclosing-token (phpinspect--resolvecontext-enclosing-tokens
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)
(let ((children (reverse (phpinspect-meta-find-children-before meta point)))
token previous-siblings)

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

@ -24,7 +24,8 @@
;;; Code:
(require 'phpinspect-splayt)
(require 'phpinspect-parser)
(eval-when-compile
(require 'phpinspect-meta))
(defun phpinspect-make-toc (&optional tree)
(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-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)
(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)
(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)
(or (phpinspect-block-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)
(phpinspect-incomplete-array-p token)))
(defsubst phpinspect-incomplete-root-p (token)
(and (phpinspect-root-p token)
(seq-find #'phpinspect-incomplete-token-p (cdr token))))
(defsubst phpinspect-root-p (object)
(phpinspect-token-type-p object :root))
(defsubst phpinspect-incomplete-token-p (token)
(defun phpinspect-incomplete-token-p (token)
(or (phpinspect-incomplete-root-p token)
(phpinspect-incomplete-class-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-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)
(or (phpinspect-function-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")))
(defsubst phpinspect-root-p (object)
(phpinspect-token-type-p object :root))
(defsubst phpinspect-namespace-or-root-p (object)
(or (phpinspect-namespace-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."
(not (phpinspect-class-p token)))
(defsubst phpinspect-probably-token-p (token)
(and (listp token)
(keywordp (car token))))
(provide 'phpinspect-token-predicates)

@ -24,6 +24,11 @@
;;; Code:
(require 'phpinspect-util)
(require 'phpinspect-token-predicates)
(eval-when-compile
(require 'phpinspect-parser))
(cl-defstruct (phpinspect--type
(:constructor phpinspect--make-type-generated)
@ -279,5 +284,69 @@ mutability of the variable")
(not (or (phpinspect--variable-static-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)
;;; phpinspect-type.el ends here

@ -31,31 +31,6 @@ PHP. Used to optimize string comparison.")
'("composer.json" "composer.lock" ".git" ".svn" ".hg")
"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
"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 "Disabled phpinspect logging.")))
(defvar phpinspect-log-groups nil)
(defvar phpinspect-enabled-log-groups nil)
(defvar-local phpinspect--current-log-group nil)
(eval-and-compile
(defvar phpinspect-log-groups nil)
(defvar phpinspect-enabled-log-groups nil)
(defvar-local phpinspect--current-log-group nil))
(define-inline phpinspect--declare-log-group (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)
(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)
(intern name phpinspect-name-obarray))
@ -251,6 +251,10 @@ context for completion."
(json-key-type 'string))
,@body))
(defun phpinspect--input-pending-p (&optional check-timers)
(unless noninteractive
(input-pending-p check-timers)))
(defun phpinspect-thread-pause (pause-time mx continue)
"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))
(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)
;;; 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
@ -25,7 +25,7 @@
(require 'cl-lib)
(require 'phpinspect-util)
(require 'phpinspect-project)
(require 'phpinspect-project-struct)
(require 'phpinspect-index)
(require 'phpinspect-class)
(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))
phpinspect-worker)
(defsubst phpinspect-make-dynamic-worker ()
(defun phpinspect-make-dynamic-worker ()
(phpinspect-make-dynamic-worker-generated))
(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
;; interrupt the thread.
(unless (or (not (input-pending-p))
(unless (or (not (phpinspect--input-pending-p))
(phpinspect-worker-skip-next-pause worker))
(phpinspect-thread-pause phpinspect-worker-pause-time mx continue))
(setf (phpinspect-worker-skip-next-pause worker) nil)))
@ -225,86 +225,5 @@ already present in the queue."
(cl-defgeneric phpinspect-task-project (task)
"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)
;;; phpinspect-worker.el ends here

@ -217,7 +217,7 @@
(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 "
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.
@ -31,7 +31,11 @@
(ert-deftest phpinspect-find-composer-json-files ()
(let* ((fs (phpinspect-make-virtual-fs))
(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
"/root/composer.json"
"{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}")
@ -57,9 +61,14 @@
(ert-deftest phpinspect-autoload-composer-json-iterator ()
(let* ((fs (phpinspect-make-virtual-fs))
(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)
(phpinspect-virtual-fs-set-file fs
"/root/composer.json"
"{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}")
@ -92,7 +101,10 @@
(ert-deftest phpinspect-al-strategy-execute ()
(let* ((fs (phpinspect-make-virtual-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)
(setf (phpinspect-project-autoload project) autoloader)

@ -101,7 +101,9 @@
(should (= 1 (length (hash-table-values (phpinspect--class-subscriptions other-class)))))))
(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")
(:word "extends") (:word "OtherClass")
(:word "implements") (:word "ImplClass"))

@ -169,7 +169,7 @@ return StaticThing::create(new ThingFactory())->makeThing((((new Potato())->anti
(alist-get key index2-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))
(with-temp-buffer
(insert-file-contents (concat phpinspect-test-php-file-directory "/IndexClass1.php"))

@ -29,7 +29,7 @@
(ert-deftest phpinspect-pctx-cancel ()
(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-meta-with-changeset meta
(setf (phpinspect-meta-absolute-start meta) 222)

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

@ -2,7 +2,7 @@
(require 'phpinspect-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 "
class TestClass {
public function getCurrentStatisticAction(): JsonResponse

Loading…
Cancel
Save