Implement strategy pattern for phpinspect-eldoc-function

WIP-cache
Hugo Thunnissen 10 months ago
parent 1ec0e0cfa2
commit bb04e9a0f8

@ -98,9 +98,16 @@
(cl-defmethod phpinspect--class-get-method ((class phpinspect--class) method-name)
(gethash method-name (phpinspect--class-methods class)))
(cl-defmethod phpinspect--class-get-static-method ((class phpinspect--class) method-name)
(cl-defmethod phpinspect--class-get-static-method ((class phpinspect--class) (method-name symbol))
(gethash method-name (phpinspect--class-static-methods class)))
(cl-defmethod phpinspect--class-get-variable
((class phpinspect--class) (variable-name string))
(catch 'found
(dolist (variable (phpinspect--class-variables class))
(when (string= variable-name (phpinspect--variable-name variable))
(throw 'found variable)))))
(cl-defmethod phpinspect--add-method-copy-to-map
((map hash-table)
(class-name phpinspect--type)
@ -179,7 +186,8 @@
(cl-defmethod phpinspect--class-update-method ((class phpinspect--class)
(method phpinspect--function))
(let* ((existing (gethash (phpinspect--function-name-symbol method)
(phpinspect--class-methods class))))
(phpinspect--class-methods class))))
(if existing
(phpinspect--merge-method
(alist-get 'class-name (phpinspect--class-index class))

@ -0,0 +1,200 @@
;;; phpinspect-eldoc.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-eldoc-query (:constructor phpinspect-make-eldoc-query))
(point 0
:type integer
:documentation "Position in buffer for which to provide hints")
(buffer nil
:type phpinspect-buffer))
(cl-defmethod phpinspect-eldoc-query-execute ((query phpinspect-eldoc-query))
(let* ((buffer (phpinspect-eldoc-query-buffer query))
(point (phpinspect-eldoc-query-point query))
(buffer-map (phpinspect-buffer-parse-map buffer))
(rctx (phpinspect-get-resolvecontext buffer-map point)))
(catch 'matched
(dolist (strategy phpinspect-eldoc-strategies)
(when (phpinspect-eld-strategy-supports strategy query rctx)
(throw 'matched (phpinspect-eld-strategy-execute strategy query rctx)))))))
(cl-defgeneric phpinspect-eld-strategy-supports (strategy (query phpinspect-eldoc-query) (context phpinspect--resolvecontext))
"Should return non-nil if STRATEGY should be deployed for QUERY
and CONTEXT. All strategies must implement this method.")
(cl-defgeneric phpinspect-eld-strategy-execute (strategy (query phpinspect-eldoc-query) (context phpinspect--resolvecontext))
"Should return an object for which `phpinspect-eldoc-string' is implemented.")
(cl-defgeneric phpinspect-eldoc-string (response)
"Should return a string to be displayed by eldoc. This needs to
be implemented for return values of `phpinspect-eld-strategy-execute'")
(cl-defstruct (phpinspect-eld-attribute (:constructor phpinspect-make-eld-attribute))
"Eldoc strategy for object attributes.")
(cl-defmethod phpinspect-eld-strategy-supports
((strat phpinspect-eld-attribute) (q phpinspect-eldoc-query) (rctx phpinspect--resolvecontext))
(phpinspect-attrib-p (car (last (phpinspect--resolvecontext-subject rctx)))))
;; (cl-defmethod phpinspect-eld-strategy-execute
;; ((strat phpinspect-eld-attribute) (q phpinspect-eldoc-query) (rctx phpinspect--resolvecontext))
;; (let ((attrib (car (last (phpinspect--resolvecontext-subject rctx))))
;; type-before)
;; (setf (phpinspect--resolvecontext-subject rctx) (butlast (phpinspect--resolvecontext-subject rctx)))
;; (setq type-before (phpinspect-resolve-type-from-context rctx))
;; (when type-before
;; (let ((class (phpinspect-project-get-class-create
;; (phpinspect--resolvecontext-project rctx)
;; type-before))
;; attribute)
;; (cond ((phpinspect-static-attrib-p attrib)
;; (setq attribute (or (phpinspect--class-get-variable
(cl-defstruct (phpinspect-eld-function-args (:constructor phpinspect-make-eld-function-args))
"Eldoc strategy for function arguments.")
(cl-defmethod phpinspect-eld-strategy-supports
((strat phpinspect-eld-function-args) (q phpinspect-eldoc-query) (rctx phpinspect--resolvecontext))
(let ((parent-token (car (phpinspect--resolvecontext-enclosing-tokens rctx))))
;; When our subject is inside a list, it is probably an argument of a
;; function/method call, which is what this strategy provides information for.
(or (phpinspect-list-p parent-token)
;; When our subject IS a list, we're probably in an empty/incomplete
;; argument list.
(and (= 1 (length (phpinspect--resolvecontext-subject rctx)))
(phpinspect-list-p
(car (last (phpinspect--resolvecontext-subject rctx)))))
;; When the last token in our subject is an incomplete list, we're
;; probably at the end of the buffer in an unfinished argument list.
(phpinspect-incomplete-list-p
(car (last (phpinspect--resolvecontext-subject rctx)))))))
(cl-defmethod phpinspect-eld-strategy-execute
((strat phpinspect-eld-function-args) (q phpinspect-eldoc-query) (rctx phpinspect--resolvecontext))
(let* ((token-map (phpinspect-buffer-parse-map (phpinspect-eldoc-query-buffer q)))
(enclosing-token (cadr (phpinspect--resolvecontext-enclosing-tokens
rctx)))
(statement (phpinspect-find-statement-before-point
token-map (phpinspect-bmap-token-meta token-map enclosing-token)
(phpinspect-eldoc-query-point q)))
match-result static arg-list arg-pos)
(when enclosing-token
(cond
;; Method call
((setq match-result (phpinspect--match-sequence (last statement 2)
:f #'phpinspect-attrib-p
:f #'phpinspect-list-p))
(setq arg-list (car (last match-result))
static (phpinspect-static-attrib-p (car match-result))
arg-pos (seq-reduce
(lambda (count token)
(if (and (phpinspect-comma-p token)
(> (phpinspect-eldoc-query-point q)
(phpinspect-meta-end
(phpinspect-bmap-token-meta token-map token))))
(+ count 1)
count))
arg-list 0))
;; Set resolvecontext subject to the statement minus the method
;; name. Point is likely to be at a location inside a method call like
;; "$a->b->doSomething(". The resulting subject should be "$a->b".
(setf (phpinspect--resolvecontext-subject rctx) (butlast statement 2))
(let* ((type-of-previous-statement
(phpinspect-resolve-type-from-context rctx))
(method-name-sym (phpinspect-intern-name (car (cdadar match-result))))
(class (phpinspect-project-get-class-create
(phpinspect--resolvecontext-project rctx)
type-of-previous-statement))
(method (when class
(if static
(phpinspect--class-get-static-method class method-name-sym)
(phpinspect--class-get-method class method-name-sym)))))
(when method
(phpinspect-make-function-doc :fn method :arg-pos arg-pos))))))))
(cl-defstruct (phpinspect-function-doc (:constructor phpinspect-make-function-doc))
(fn nil
:type phpinspect--function)
(arg-pos nil))
(cl-defmethod phpinspect-eldoc-string ((doc phpinspect-function-doc))
(let ((fn (phpinspect-function-doc-fn doc))
(arg-pos (phpinspect-function-doc-arg-pos doc))
(arg-count 0))
(concat (truncate-string-to-width
(phpinspect--function-name fn) phpinspect-eldoc-word-width) ": ("
(mapconcat
(lambda (arg)
(let ((doc-string
(concat "$" (truncate-string-to-width
(car arg) phpinspect-eldoc-word-width)
(if (cadr arg) " " "")
(phpinspect--format-type-name (or (cadr arg) "")))))
(when (and arg-pos (= arg-count arg-pos))
(setq doc-string
(propertize
doc-string 'face 'eldoc-highlight-function-argument)))
(setq arg-count (+ arg-count 1))
doc-string))
(phpinspect--function-arguments fn)
", ")
"): "
(phpinspect--format-type-name
(phpinspect--function-return-type fn)))))
(defvar phpinspect-eldoc-strategies (list ;;(phpinspect-make-eld-attribute)
(phpinspect-make-eld-function-args))
"The eldoc strategies that phpinspect is currently allowed to
employ. Strategies are queried in the order of this list. See
also `phpinspect-eldoc-query-execute'.")
(defun phpinspect-eldoc-function ()
"An `eldoc-documentation-function` implementation for PHP files.
Ignores `eldoc-argument-case` and `eldoc-echo-area-use-multiline-p`.
TODO:
- Respect `eldoc-echo-area-use-multiline-p`
"
(catch 'phpinspect-parse-interrupted
(let ((resp (phpinspect-eldoc-query-execute
(phpinspect-make-eldoc-query
:buffer phpinspect-current-buffer
:point (phpinspect--determine-completion-point)))))
(when resp
(phpinspect-eldoc-string resp)))))
(provide 'phpinspect-eldoc)

@ -911,7 +911,7 @@ static keywords with the same meaning as in a class block."
(continue-condition (lambda ()
(not (and (char-equal (char-after) ?})
(setq complete-block t)))))
(parsed (funcall parser (current-buffer) max-point continue-condition)))
(parsed (funcall parser (current-buffer) max-point continue-condition 'root)))
(if complete-block
(forward-char)
(setcar parsed :incomplete-block))

@ -95,10 +95,6 @@ Projects get purged when they are removed from the global cache.")
:documentation "All active file watchers in this project,
indexed by the absolute paths of the files they're watching."))
(cl-defgeneric phpinspect-project-add-class
((project phpinspect-project) (class (head phpinspect--indexed-class)))
"Add an indexed CLASS to PROJECT.")
(cl-defmethod phpinspect-project-purge ((project phpinspect-project))
"Disable all background processes for project and put it in a `purged` state."
(maphash (lambda (_ watcher) (file-notify-rm-watch watcher))

@ -121,6 +121,11 @@
:enclosing-tokens (nreverse enclosing-tokens)
:project-root (phpinspect-current-project-root))))
(defun phpinspect--resolvecontext-project (rctx)
(phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
(phpinspect--resolvecontext-project-root rctx)))
(defun phpinspect--get-resolvecontext (token &optional resolvecontext)
"Find the deepest nested incomplete token in TOKEN.
If RESOLVECONTEXT is nil, it is created. Returns RESOLVECONTEXT

@ -72,20 +72,22 @@ pattern. See `phpinspect--match-sequence'."
:type list
:documentation "The original code list used to create this pattern"))
(defsubst phpinspect--make-pattern (&rest pattern)
(phpinspect--make-pattern-generated
:matcher (apply #'phpinspect--match-sequence-lambda pattern)
:code pattern))
(defmacro phpinspect--make-pattern (&rest pattern)
`(phpinspect--make-pattern-generated
:matcher (phpinspect--match-sequence-lambda ,@pattern)
:code (list ,@(mapcar (lambda (part) (if (eq '* part) `(quote ,part) part))
pattern))))
(defun phpinspect--match-sequence-lambda (&rest pattern)
(lambda (sequence)
(apply #'phpinspect--match-sequence sequence pattern)))
(defmacro phpinspect--match-sequence-lambda (&rest pattern)
(let ((sequence-sym (gensym)))
`(lambda (,sequence-sym)
(phpinspect--match-sequence ,sequence-sym ,@pattern))))
(cl-defmethod phpinspect--pattern-match ((pattern phpinspect--pattern) sequence)
"Match SEQUENCE to PATTERN."
(funcall (phpinspect--pattern-matcher pattern) sequence))
(defun phpinspect--match-sequence (sequence &rest pattern)
(defmacro phpinspect--match-sequence (sequence &rest pattern)
"Match SEQUENCE to positional matchers defined in PATTERN.
PATTERN is a plist with the allowed keys being :m and :f. Each
@ -107,30 +109,43 @@ element at this position in SEQUENCE.
the function provided as value. The function is executed with the
list element as argument, and will be considered as matching if
it evaluates to a non-nil value."
(declare (indent 1))
(let* ((pattern-length (length pattern))
(count 0)
(sequence-length (/ pattern-length 2))
(sequence-pos 0)
(sequence-length (/ pattern-length 2)))
(and (= sequence-length (length sequence))
(catch 'found
(while (< count pattern-length)
(let ((key (elt pattern count))
(value (elt pattern (+ count 1))))
(unless (keywordp key)
(error (format "Invalid, expected keyword, got %s" key)))
(cond ((eq key :m)
(unless (eq value '*)
(unless (equal value (elt sequence sequence-pos))
(throw 'found nil))))
((eq key :f)
(unless (funcall value (elt sequence sequence-pos))
(throw 'found nil)))
(t (error (format "Invalid keyword: %s" key))))
(setq count (+ count 2)
sequence-pos (+ sequence-pos 1))))
(throw 'found t)))))
(sequence-sym (gensym))
(match-sym (gensym))
checkers key value)
(while (setq key (pop pattern))
(unless (keywordp key)
(error "Invalid pattern argument, expected keyword, got: %s" key))
(unless (setq value (pop pattern))
(error "No value for key %s" key))
(cond ((eq key :m)
(unless (eq value '*)
(setq checkers
(nconc checkers (list `(equal ,value (elt ,sequence-sym ,sequence-pos)))))))
((eq key :f)
(setq checkers
(nconc
checkers (list
(if (symbolp value)
`(,value (elt ,sequence-sym ,sequence-pos))
`(funcall ,value (elt ,sequence-sym ,sequence-pos)))))))
(t (error "Invalid keyword: %s" key)))
(setq checkers (nconc checkers (list `(setq ,match-sym (nconc ,match-sym (list (elt ,sequence-sym ,sequence-pos)))))))
(setq sequence-pos (+ sequence-pos 1)))
`(let ((,sequence-sym ,sequence)
,match-sym)
(and (= ,sequence-length (length ,sequence))
,@checkers)
,match-sym)))
(defun phpinspect--pattern-concat (pattern1 pattern2)
(let* ((pattern1-sequence-length (/ (length (phpinspect--pattern-code pattern1)) 2)))

@ -42,6 +42,7 @@
(require 'phpinspect-imports)
(require 'phpinspect-buffer)
(require 'phpinspect-resolvecontext)
(require 'phpinspect-eldoc)
(defvar phpinspect-auto-reindex nil
"Whether or not phpinspect should automatically search for new
@ -179,12 +180,9 @@ candidate. Candidates can be indexed functions and variables.")
project-root class-fqn variable-name)
(when project-root
(let ((found-variable
(seq-find (lambda (variable)
(string= (phpinspect--variable-name variable) variable-name))
(phpinspect--class-variables
(phpinspect-get-or-create-cached-project-class
project-root
class-fqn)))))
(phpinspect--class-get-variable
(phpinspect-get-or-create-cached-project-class project-root class-fqn)
variable-name)))
(when found-variable
(phpinspect--variable-type found-variable)))))
@ -281,98 +279,6 @@ context for completion."
(forward-char)
(point)))
(defun phpinspect-eldoc-function ()
"An `eldoc-documentation-function` implementation for PHP files.
Ignores `eldoc-argument-case` and `eldoc-echo-area-use-multiline-p`.
TODO:
- Respect `eldoc-echo-area-use-multiline-p`
- This function is too big and has repetitive code. Split up and simplify.
"
(catch 'phpinspect-parse-interrupted
(let* ((token-map (phpinspect-buffer-parse-map phpinspect-current-buffer))
(resolvecontext (phpinspect-get-resolvecontext token-map (phpinspect--determine-completion-point)))
(parent-token (car (phpinspect--resolvecontext-enclosing-tokens
resolvecontext)))
(enclosing-token (cadr (phpinspect--resolvecontext-enclosing-tokens
resolvecontext)))
(statement (phpinspect--resolvecontext-subject resolvecontext))
(arg-list)
(type-resolver (phpinspect--make-type-resolver-for-resolvecontext
resolvecontext))
(static))
(phpinspect--log "Eldoc statement before checking outside list: %s" statement)
(when (and (phpinspect-list-p parent-token) enclosing-token)
(setq statement
(phpinspect-find-statement-before-point
token-map (phpinspect-bmap-token-meta token-map enclosing-token)
(phpinspect-meta-end
(phpinspect-bmap-token-meta token-map parent-token)))))
(phpinspect--log "Enclosing token: %s" enclosing-token)
(phpinspect--log "Eldoc statement: %s" statement)
(setq arg-list (seq-find #'phpinspect-list-p (reverse statement)))
(when (and (phpinspect-list-p arg-list)
enclosing-token
(or (phpinspect-object-attrib-p (car (last statement 2)))
(setq static (phpinspect-static-attrib-p (car (last statement 2))))))
;; Set resolvecontext subject to the last statement in the enclosing token, minus
;; the method name. The last enclosing token is an incomplete list, so point is
;; likely to be at a location inside a method call like "$a->b->doSomething(". The
;; resulting subject would be "$a->b".
(setf (phpinspect--resolvecontext-subject resolvecontext)
(phpinspect--get-last-statement-in-token (butlast statement 2)))
(let* ((type-of-previous-statement
(phpinspect-resolve-type-from-context resolvecontext type-resolver))
(method-name-sym (phpinspect-intern-name (cadr (cadar (last statement 2)))))
(class (phpinspect-project-get-class-create
(phpinspect--cache-get-project-create
(phpinspect--get-or-create-global-cache)
(phpinspect--resolvecontext-project-root resolvecontext))
type-of-previous-statement))
(method (when class
(if static
(phpinspect--class-get-static-method class method-name-sym)
(phpinspect--class-get-method class method-name-sym)))))
(phpinspect--log "Eldoc method name: %s" method-name-sym)
(phpinspect--log "Eldoc type of previous statement: %s"
type-of-previous-statement)
(phpinspect--log "Eldoc method: %s" method)
(when method
(let ((arg-count -1)
(comma-count
(length (seq-filter #'phpinspect-comma-p arg-list))))
(concat (truncate-string-to-width
(phpinspect--function-name method) phpinspect-eldoc-word-width) ": ("
(mapconcat
(lambda (arg)
(setq arg-count (+ arg-count 1))
(if (= arg-count comma-count)
(propertize (concat
"$"
(truncate-string-to-width
(car arg)
phpinspect-eldoc-word-width)
" "
(phpinspect--format-type-name (or (cadr arg) "")))
'face 'eldoc-highlight-function-argument)
(concat "$"
(truncate-string-to-width (car arg)
phpinspect-eldoc-word-width)
(if (cadr arg) " " "")
(phpinspect--format-type-name (or (cadr arg) "")))))
(phpinspect--function-arguments method)
", ")
"): "
(phpinspect--format-type-name
(phpinspect--function-return-type method))))))))))
(cl-defstruct (phpinspect--assignment
(:constructor phpinspect--make-assignment))
(to nil
@ -700,7 +606,10 @@ EXPRESSION."
function-arg-list)))))
(defun phpinspect-resolve-type-from-context (resolvecontext type-resolver)
(defun phpinspect-resolve-type-from-context (resolvecontext &optional type-resolver)
(unless type-resolver
(setq type-resolver
(phpinspect--make-type-resolver-for-resolvecontext resolvecontext)))
(phpinspect--log "Looking for type of statement: %s in nested token"
(phpinspect--resolvecontext-subject resolvecontext))
;; Find all enclosing tokens that aren't classes. Classes do not contain variable

@ -599,6 +599,7 @@ class Thing
(load-file (concat phpinspect-test-directory "/test-worker.el"))
(load-file (concat phpinspect-test-directory "/test-autoload.el"))
(load-file (concat phpinspect-test-directory "/test-eldoc.el"))
(load-file (concat phpinspect-test-directory "/test-fs.el"))
(load-file (concat phpinspect-test-directory "/test-project.el"))
(load-file (concat phpinspect-test-directory "/test-buffer.el"))

@ -0,0 +1,88 @@
;;; test-eldoc.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*-
(require 'phpinspect)
(require 'phpinspect-eldoc)
(ert-deftest phpinspect-eld-method-call ()
(with-temp-buffer
(let* ((php-code "
class Thing
{
function getThis(\\DateTime $moment, Thing $thing, $other): static
{
return $this;
}
function doStuff()
{
$this->getThis(new \\DateTime(), bla)")
(tokens (phpinspect-parse-string php-code))
(index (phpinspect--index-tokens tokens))
(phpinspect-project-root-function (lambda () "phpinspect-test"))
(phpinspect-eldoc-word-width 100)
(buffer (phpinspect-make-buffer :buffer (current-buffer)))
second-arg-pos first-arg-pos)
(phpinspect-ensure-worker)
(phpinspect-purge-cache)
(phpinspect-cache-project-class
(phpinspect-current-project-root)
(cdar (alist-get 'classes (cdr index))))
(insert php-code)
(backward-char)
(setq second-arg-pos (point))
(backward-char 6)
(setq first-arg-pos (point))
(let ((result (phpinspect-eldoc-query-execute
(phpinspect-make-eldoc-query :point second-arg-pos :buffer buffer))))
(should (phpinspect-function-doc-p result))
(should (= 1 (phpinspect-function-doc-arg-pos result)))
(should (string= "getThis" (phpinspect--function-name (phpinspect-function-doc-fn result))))
(setq result (phpinspect-eldoc-query-execute
(phpinspect-make-eldoc-query :point first-arg-pos :buffer buffer)))
(should (phpinspect-function-doc-p result))
(should (= 0 (phpinspect-function-doc-arg-pos result)))
(should (string= "getThis" (phpinspect--function-name (phpinspect-function-doc-fn result))))))))
;; (ert-deftest phpinspect-eld-attribute ()
;; (with-temp-buffer
;; (let* ((php-code "
;; class Thing
;; {
;; /** @var \\DateTime **/
;; public $banana;
;; function getThis(\\DateTime $moment, Thing $thing, $other): static
;; {
;; return $this;
;; }
;; function doStuff()
;; {
;; $this->banana;
;; $this->getThis(new \\DateTime(), bla)")
;; (tokens (phpinspect-parse-string php-code))
;; (index (phpinspect--index-tokens tokens))
;; (phpinspect-project-root-function (lambda () "phpinspect-test"))
;; (phpinspect-eldoc-word-width 100)
;; (buffer (phpinspect-make-buffer :buffer (current-buffer)))
;; getThis-pos banana-pos)
;; (insert php-code)
;; (backward-char 28)
;; (setq getThis-pos (point))
;; (backward-char 22)
;; (setq banana-pos (point))
;; (phpinspect-ensure-worker)
;; (phpinspect-purge-cache)
;; (phpinspect-cache-project-class
;; (phpinspect-current-project-root)
;; (cdar (alist-get 'classes (cdr index))))
;; (let ((result (phpinspect-eldoc-query-execute
;; (phpinspect-make-eldoc-query :point getThis-pos :buffer buffer))))
;; (message "Result: %s" result)))))

@ -25,21 +25,22 @@
(ert-deftest phpinspect--pattern ()
(let* ((a "a")
(pattern1 (phpinspect--make-pattern :m `(,a) :m '* :m "b"))
(pattern2 (phpinspect--make-pattern :f #'listp :m '* :m "b")))
(pattern1 (phpinspect--make-pattern :m `(,a) :m * :m "b"))
(pattern2 (phpinspect--make-pattern :f #'listp :m * :m "b")))
(should (equal '(:m ("a") :m * :m "b") (phpinspect--pattern-code pattern1)))
(should (equal '(:f listp :m * :m "b") (phpinspect--pattern-code pattern2)))
(dolist (pattern `(,pattern1 ,pattern2))
(should (phpinspect--pattern-match pattern '(("a") "c" "b")))
(should (equal '(("a") "c" "b") (phpinspect--pattern-match pattern '(("a") "c" "b"))))
(should (phpinspect--pattern-match pattern '(("a") nil "b")))
(should-not (phpinspect--pattern-match pattern '(1 nil "b")))
(should-not (phpinspect--pattern-match pattern '(("a") nil "b" "c"))))))
(ert-deftest phpinspect--pattern-concat ()
(let* ((pattern1 (phpinspect--make-pattern :m "a" :m '* :m "b"))
(pattern2 (phpinspect--make-pattern :f #'stringp :m '* :m "D"))
(let* ((pattern1 (phpinspect--make-pattern :m "a" :m * :m "b"))
(pattern2 (phpinspect--make-pattern :f #'stringp :m * :m "D"))
(result (phpinspect--pattern-concat pattern1 pattern2)))
(should (equal '(:m "a" :m * :m "b" :f stringp :m * :m "D") (phpinspect--pattern-code result)))

Loading…
Cancel
Save