diff --git a/benchmarks/parse-file.el b/benchmarks/parse-file.el index 604ba2e..960b601 100644 --- a/benchmarks/parse-file.el +++ b/benchmarks/parse-file.el @@ -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 diff --git a/compile.bash b/compile.bash new file mode 100644 index 0000000..32ca4cd --- /dev/null +++ b/compile.bash @@ -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 diff --git a/phpinspect-autoload.el b/phpinspect-autoload.el index f0a2ceb..995ec2f 100644 --- a/phpinspect-autoload.el +++ b/phpinspect-autoload.el @@ -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) diff --git a/phpinspect-bmap.el b/phpinspect-bmap.el index a2ad9ec..d38dd9b 100644 --- a/phpinspect-bmap.el +++ b/phpinspect-bmap.el @@ -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)))) diff --git a/phpinspect-buffer.el b/phpinspect-buffer.el index 67cf60f..fee8228 100644 --- a/phpinspect-buffer.el +++ b/phpinspect-buffer.el @@ -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 diff --git a/phpinspect-cache.el b/phpinspect-cache.el index 1b94774..9bc2e8c 100644 --- a/phpinspect-cache.el +++ b/phpinspect-cache.el @@ -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 diff --git a/phpinspect-changeset.el b/phpinspect-changeset.el index 7f19ed2..406a9ba 100644 --- a/phpinspect-changeset.el +++ b/phpinspect-changeset.el @@ -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 diff --git a/phpinspect-class-struct.el b/phpinspect-class-struct.el new file mode 100644 index 0000000..9b91aaa --- /dev/null +++ b/phpinspect-class-struct.el @@ -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 +;; 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 . + +;;; 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) diff --git a/phpinspect-class.el b/phpinspect-class.el index d5e7221..d40a902 100644 --- a/phpinspect-class.el +++ b/phpinspect-class.el @@ -26,10 +26,11 @@ (require 'phpinspect-type) (cl-defstruct (phpinspect--class (:constructor phpinspect--make-class-generated)) - (project nil - :type phpinspect-project - :documentaton - "The project that this class belongs to") + (class-retriever nil + :type lambda + :documentaton + "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)) diff --git a/phpinspect-edtrack.el b/phpinspect-edtrack.el index bd06593..45baa3a 100644 --- a/phpinspect-edtrack.el +++ b/phpinspect-edtrack.el @@ -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 diff --git a/phpinspect-eldoc.el b/phpinspect-eldoc.el index b60bb88..0de18be 100644 --- a/phpinspect-eldoc.el +++ b/phpinspect-eldoc.el @@ -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.") diff --git a/phpinspect-imports.el b/phpinspect-imports.el index df37ec6..fb42af3 100644 --- a/phpinspect-imports.el +++ b/phpinspect-imports.el @@ -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) diff --git a/phpinspect-index.el b/phpinspect-index.el index 6c76a52..a4b7c91 100644 --- a/phpinspect-index.el +++ b/phpinspect-index.el @@ -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) diff --git a/phpinspect-parse-context.el b/phpinspect-parse-context.el index bc07444..a42add3 100644 --- a/phpinspect-parse-context.el +++ b/phpinspect-parse-context.el @@ -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))) diff --git a/phpinspect-parser.el b/phpinspect-parser.el index 34561a2..59b9aa3 100644 --- a/phpinspect-parser.el +++ b/phpinspect-parser.el @@ -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) - (intern (concat "phpinspect--" (symbol-name handler-name) "-handler"))) +(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) - (intern (concat "phpinspect--" (symbol-name handler-name) "-handler-regexp"))) + (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,8 +131,9 @@ 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) - "Create a parser function using the handlers by names defined in HANDLER-LIST. +(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`. @@ -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 delimiter predicate and have parsing stop when the last parsed token is \";\", which marks the end of a statement in PHP." - (let ((delimiter-predicate (if (symbolp delimiter-predicate) - `(quote ,delimiter-predicate) - delimiter-predicate))) - `(defsubst ,(phpinspect-parser-func-name name "simple") (buffer max-point &optional skip-over continue-condition &rest _ignored) - (with-current-buffer buffer - (let* ((tokens (cons ,tree-type nil)) - (tokens-rear tokens) - token - (delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate))) - (when skip-over (forward-char skip-over)) - (while (and (< (point) max-point) - (if continue-condition (funcall continue-condition) t) - (not (if delimiter-predicate - (funcall delimiter-predicate (car (last tokens))) - nil))) - (cond ,@(mapcar - (lambda (handler) - `((looking-at (,(phpinspect-handler-regexp-func-name handler))) - (setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point)) - (when token - (setq tokens-rear (setcdr tokens-rear (cons token nil)))))) - handlers) - (t (forward-char)))) - - ;; Return - tokens))))) - - -(defun phpinspect-make-incremental-parser-function (name tree-type handlers &optional delimiter-predicate) - "Like `phpinspect-make-parser-function', but returned function + (let ((delimiter-predicate (if (symbolp delimiter-predicate) + `(quote ,delimiter-predicate) + delimiter-predicate))) + `(defsubst ,(phpinspect-parser-func-name name "simple") (buffer max-point &optional skip-over continue-condition &rest _ignored) + (with-current-buffer buffer + (let* ((tokens (cons ,tree-type nil)) + (tokens-rear tokens) + token + (delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate))) + (when skip-over (forward-char skip-over)) + (while (and (< (point) max-point) + (if continue-condition (funcall continue-condition) t) + (not (if delimiter-predicate + (funcall delimiter-predicate (car (last tokens))) + nil))) + (cond ,@(mapcar + (lambda (handler) + `((looking-at (,(phpinspect-handler-regexp-func-name handler))) + (setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point)) + (when token + (setq tokens-rear (setcdr tokens-rear (cons token nil)))))) + handlers) + (t (forward-char)))) + + ;; Return + tokens))))) + + + (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) - `(quote ,delimiter-predicate) - delimiter-predicate))) - `(defsubst ,(phpinspect-parser-func-name name "incremental") (context buffer max-point &optional skip-over continue-condition root) - (with-current-buffer buffer - (let* ((tokens (cons ,tree-type nil)) - (tokens-rear tokens) - (root-start (point)) - (bmap (phpinspect-pctx-bmap context)) - (previous-bmap (phpinspect-pctx-previous-bmap context)) - (edtrack (phpinspect-pctx-edtrack context)) - (taint-iterator (when edtrack (phpinspect-edtrack-make-taint-iterator edtrack))) - (check-interrupt (phpinspect-pctx-interrupt-predicate context)) - - ;; Loop variables - (start-position) - (original-position) - (current-end-position) - (existing-meta) - (delta) - (token) - (delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate))) - (when skip-over (forward-char skip-over)) - (phpinspect-pctx-save-whitespace context - (while (and (< (point) max-point) - (if continue-condition (funcall continue-condition) t) - (not (if delimiter-predicate - (funcall delimiter-predicate (car (last tokens))) - nil))) - (when check-interrupt - (phpinspect-pctx-check-interrupt context)) - - (setq start-position (point)) - (cond ((and previous-bmap edtrack - (setq existing-meta - (phpinspect-bmap-token-starting-at - previous-bmap - (setq original-position - (phpinspect-edtrack-original-position-at-point edtrack start-position)))) - (not (or (phpinspect-root-p (phpinspect-meta-token existing-meta)) - (phpinspect-taint-iterator-token-is-tainted-p taint-iterator existing-meta)))) - (setq delta (- start-position original-position) - current-end-position (+ (phpinspect-meta-end existing-meta) delta) - token (phpinspect-meta-token existing-meta)) - - ;;(message "Reusing token %s at point %s" (phpinspect-meta-string existing-meta) (point)) - ;; Re-register existing token - (phpinspect-bmap-overlay - bmap previous-bmap existing-meta delta - (phpinspect-pctx-consume-whitespace context)) - - (goto-char current-end-position) - - ;; Skip over whitespace after so that we don't do a full - ;; run down all of the handlers during the next iteration - (when (looking-at (phpinspect-handler-regexp whitespace)) - (,(phpinspect-handler-func-name 'whitespace) (match-string 0)))) - ,@(mapcar - (lambda (handler) - `((looking-at (,(phpinspect-handler-regexp-func-name handler))) - (setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point)) - (when token - (phpinspect-pctx-register-token context token start-position (point))))) - handlers) - (t (forward-char))) - (when token - (setq tokens-rear (setcdr tokens-rear (cons token nil))) - (setq token nil)))) - (when root - (phpinspect-pctx-register-token context tokens root-start (point))) - - ;; Return - tokens))))) - -(cl-defstruct (phpinspect-parser (:constructor phpinspect-make-parser)) - (name 'root - :type symbol - :read-only t) - (tree-keyword "root" - :type string - :read-only t - :documentation "Name of the keyword that is used as car of the + (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) + (with-current-buffer buffer + (let* ((tokens (cons ,tree-type nil)) + (tokens-rear tokens) + (root-start (point)) + (bmap (phpinspect-pctx-bmap context)) + (previous-bmap (phpinspect-pctx-previous-bmap context)) + (edtrack (phpinspect-pctx-edtrack context)) + (taint-iterator (when edtrack (phpinspect-edtrack-make-taint-iterator edtrack))) + (check-interrupt (phpinspect-pctx-interrupt-predicate context)) + + ;; Loop variables + (start-position) + (original-position) + (current-end-position) + (existing-meta) + (delta) + (token) + (delimiter-predicate (when (functionp ,delimiter-predicate) ,delimiter-predicate))) + (when skip-over (forward-char skip-over)) + (phpinspect-pctx-save-whitespace context + (while (and (< (point) max-point) + (if continue-condition (funcall continue-condition) t) + (not (if delimiter-predicate + (funcall delimiter-predicate (car (last tokens))) + nil))) + (when check-interrupt + (phpinspect-pctx-check-interrupt context)) + + (setq start-position (point)) + (cond ((and previous-bmap edtrack + (setq existing-meta + (phpinspect-bmap-token-starting-at + previous-bmap + (setq original-position + (phpinspect-edtrack-original-position-at-point edtrack start-position)))) + (not (or (phpinspect-root-p (phpinspect-meta-token existing-meta)) + (phpinspect-taint-iterator-token-is-tainted-p taint-iterator existing-meta)))) + (setq delta (- start-position original-position) + current-end-position (+ (phpinspect-meta-end existing-meta) delta) + token (phpinspect-meta-token existing-meta)) + + ;;(message "Reusing token %s at point %s" (phpinspect-meta-string existing-meta) (point)) + ;; Re-register existing token + (phpinspect-bmap-overlay + bmap previous-bmap existing-meta delta + (phpinspect-pctx-consume-whitespace context)) + + (goto-char current-end-position) + + ;; Skip over whitespace after so that we don't do a full + ;; run down all of the handlers during the next iteration + (when (looking-at (phpinspect-handler-regexp whitespace)) + (,(phpinspect-handler-func-name 'whitespace) (match-string 0)))) + ,@(mapcar + (lambda (handler) + `((looking-at (,(phpinspect-handler-regexp-func-name handler))) + (setq token (,(phpinspect-handler-func-name handler) (match-string 0) max-point)) + (when token + (phpinspect-pctx-register-token context token start-position (point))))) + handlers) + (t (forward-char))) + (when token + (setq tokens-rear (setcdr tokens-rear (cons token nil))) + (setq token nil)))) + (when root + (phpinspect-pctx-register-token context tokens root-start (point))) + + ;; Return + tokens))))) + + (cl-defstruct (phpinspect-parser (:constructor phpinspect-make-parser)) + (name 'root + :type symbol + :read-only t) + (tree-keyword "root" + :type string + :read-only t + :documentation "Name of the keyword that is used as car of the root token, in string form without \":\" prefix.") - (handlers '(array tag equals list comma - attribute-reference variable - assignment-operator whitespace scope-keyword - static-keyword const-keyword use-keyword - class-keyword function-keyword word terminator - here-doc string comment block) - :type list - :read-only t - :documentation "A list of symbols referring to the + (handlers '(array tag equals list comma + attribute-reference variable + assignment-operator whitespace scope-keyword + static-keyword const-keyword use-keyword + class-keyword function-keyword word terminator + here-doc string comment block) + :type list + :read-only t + :documentation "A list of symbols referring to the handlers that this parser uses.") - (delimiter-predicate nil - :type function - :read-only t - :documentation "A predicate function that is passed each + (delimiter-predicate nil + :type function + :read-only t + :documentation "A predicate function that is passed each parsed token. When the predicate returns a non-nil value, the parser stops executing.") - (func nil - :type function - :documentation "The parser function.") - (incremental-func nil - :type function - :documentation "Incemental parser function")) - -(cl-defmethod phpinspect-parser-compile ((parser phpinspect-parser)) - "Create/return parser function." - (or (phpinspect-parser-func parser) - (setf (phpinspect-parser-func parser) - (phpinspect-make-parser-function - (phpinspect-parser-name parser) - (intern (concat ":" (phpinspect-parser-tree-keyword parser))) - (phpinspect-parser-handlers parser) - (phpinspect-parser-delimiter-predicate parser))))) - -(cl-defmethod phpinspect-parser-compile-incremental ((parser phpinspect-parser)) - "Like `phpinspect-parser-compile', but for an incremental + (func nil + :type function + :documentation "The parser function.") + (incremental-func nil + :type function + :documentation "Incemental parser function")) + + (cl-defmethod phpinspect-parser-compile ((parser phpinspect-parser)) + "Create/return parser function." + (or (phpinspect-parser-func parser) + (setf (phpinspect-parser-func parser) + (phpinspect-make-parser-function + (phpinspect-parser-name parser) + (intern (concat ":" (phpinspect-parser-tree-keyword parser))) + (phpinspect-parser-handlers parser) + (phpinspect-parser-delimiter-predicate 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) - (setf (phpinspect-parser-incremental-func parser) - (phpinspect-make-incremental-parser-function - (phpinspect-parser-name parser) - (intern (concat ":" (phpinspect-parser-tree-keyword parser))) - (phpinspect-parser-handlers parser) - (phpinspect-parser-delimiter-predicate 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"))) - `(defun ,func-name (buffer max-point &optional skip-over continue-condition root) - "Parse BUFFER, starting at point and ending at MAX-POINT. + (or (phpinspect-parser-incremental-func parser) + (setf (phpinspect-parser-incremental-func parser) + (phpinspect-make-incremental-parser-function + (phpinspect-parser-name parser) + (intern (concat ":" (phpinspect-parser-tree-keyword parser))) + (phpinspect-parser-handlers parser) + (phpinspect-parser-delimiter-predicate 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"))) + `(defun ,func-name (buffer max-point &optional skip-over continue-condition root) + "Parse BUFFER, starting at point and ending at MAX-POINT. If SKIP-OVER is non-nil, it must be a number of characters that 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 returning. Currently, token metadata is only registered when parsing incrementally." - (if (and phpinspect-parse-context - (phpinspect-pctx-incremental phpinspect-parse-context)) - (,incremental-name phpinspect-parse-context buffer max-point skip-over continue-condition root) - (,simple-name buffer max-point skip-over continue-condition root))))) + (if (and phpinspect-parse-context + (phpinspect-pctx-incremental phpinspect-parse-context)) + (,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)) @@ -342,19 +346,20 @@ parsing incrementally." (simple-name (phpinspect-parser-func-name name "simple")) (incremental-name (phpinspect-parser-func-name name "incremental"))) - `(let ((parser (phpinspect-make-parser ,@parameters))) - (defconst ,simple-name nil) - (defconst ,incremental-name nil) + `(eval-when-compile + (let ((parser (phpinspect-make-parser ,@parameters))) + (defconst ,simple-name nil) + (defconst ,incremental-name nil) - (put (quote ,simple-name) 'phpinspect--parser t) - (put (quote ,incremental-name) 'phpinspect--incremental-parser t) + (put (quote ,simple-name) 'phpinspect--parser t) + (put (quote ,incremental-name) 'phpinspect--incremental-parser t) - (setf ,simple-name parser) - (setf ,incremental-name parser) + (setf ,simple-name parser) + (setf ,incremental-name parser) - ;; 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))))) + ;; Stub function to please the byte compiler (real function will be + ;; defined by `phpinspect-define-parser-functions'. + (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 diff --git a/phpinspect-pipeline.el b/phpinspect-pipeline.el index 6084c65..d13c667 100644 --- a/phpinspect-pipeline.el +++ b/phpinspect-pipeline.el @@ -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"))) diff --git a/phpinspect-project.el b/phpinspect-project.el index 6f8b228..dded436 100644 --- a/phpinspect-project.el +++ b/phpinspect-project.el @@ -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))) - - (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)))) - +(defun phpinspect-project-make-file-indexer (project) + (lambda (filename) + (phpinspect-project-add-file-index project filename))) + +(defun phpinspect-project-make-root-resolver (project) + (lambda () (phpinspect-project-root project))) + +(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 diff --git a/phpinspect-resolve.el b/phpinspect-resolve.el index 76e2159..2c722c7 100644 --- a/phpinspect-resolve.el +++ b/phpinspect-resolve.el @@ -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))) diff --git a/phpinspect-resolvecontext.el b/phpinspect-resolvecontext.el index 2a95575..557069e 100644 --- a/phpinspect-resolvecontext.el +++ b/phpinspect-resolvecontext.el @@ -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) diff --git a/phpinspect-suggest.el b/phpinspect-suggest.el index aff9c81..d94b885 100644 --- a/phpinspect-suggest.el +++ b/phpinspect-suggest.el @@ -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) diff --git a/phpinspect-toc.el b/phpinspect-toc.el index f27f6df..b8f7d4e 100644 --- a/phpinspect-toc.el +++ b/phpinspect-toc.el @@ -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))) diff --git a/phpinspect-token-predicates.el b/phpinspect-token-predicates.el index f03883d..9ae912d 100644 --- a/phpinspect-token-predicates.el +++ b/phpinspect-token-predicates.el @@ -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) diff --git a/phpinspect-type.el b/phpinspect-type.el index fbc9415..abb2e44 100644 --- a/phpinspect-type.el +++ b/phpinspect-type.el @@ -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 diff --git a/phpinspect-util.el b/phpinspect-util.el index ca5b971..0f6e6ad 100644 --- a/phpinspect-util.el +++ b/phpinspect-util.el @@ -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 diff --git a/phpinspect-worker.el b/phpinspect-worker.el index 60977c0..b9bfe4f 100644 --- a/phpinspect-worker.el +++ b/phpinspect-worker.el @@ -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 diff --git a/test/phpinspect-test.el b/test/phpinspect-test.el index 88f2070..c1ca072 100644 --- a/test/phpinspect-test.el +++ b/test/phpinspect-test.el @@ -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; diff --git a/test/test-autoload.el b/test/test-autoload.el index 876f12a..481c06e 100644 --- a/test/test-autoload.el +++ b/test/test-autoload.el @@ -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) @@ -131,7 +143,7 @@ "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")) diff --git a/test/test-parse-context.el b/test/test-parse-context.el index b79db41..82ae1cf 100644 --- a/test/test-parse-context.el +++ b/test/test-parse-context.el @@ -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) diff --git a/test/test-parser.el b/test/test-parser.el index d2ecf94..83e5fca 100644 --- a/test/test-parser.el +++ b/test/test-parser.el @@ -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)) diff --git a/test/test-resolvecontext.el b/test/test-resolvecontext.el index 75c6806..894f684 100644 --- a/test/test-resolvecontext.el +++ b/test/test-resolvecontext.el @@ -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