WIP: new cache implementation

WIP-cache
Hugo Thunnissen 9 months ago
parent 7f2baf2c68
commit c35c647452

@ -286,5 +286,173 @@ then returned."
(puthash "builtins" project (phpinspect--cache-projects phpinspect-stub-cache))
(setf (phpinspect--cache-read-only-p phpinspect-stub-cache) t)))
(cl-defstruct (phpinspect-cache (:constructor phpinspect-make-cache))
(groups (make-hash-table :test #'equal :size 2000 :rehash-size 1.2)))
(eval-and-compile
(defconst phpinspect-cache-types '(interface trait class method
abstract-method function variable namespace)
"Types of entities that the cache can store.")
(defconst phpinspect-cache-containing-types '(class trait interface)
"Types of entities that the cache can store members for.")
(defconst phpinspect-cache-member-types '(method abstract-method function variable)
"Types of entities that the cache can store as members."))
(define-inline phpinspect-cache-query--do-delete (&rest args)
(inline-quote
(message ":delete Args: %s" ,(cons 'list args))))
(define-inline phpinspect-cache-query--do-insert (&rest args)
(inline-quote
(message ":insert Args: %s" ,(cons 'list args))))
(define-inline phpinspect-cache-query--do-get (&rest args)
(inline-quote
(message ":get Args: %s" ,(cons 'list args))))
(cl-defstruct (phpinspect-cache-group (:constructor phpinspect-make-cache-group)))
(defun phpinspect-cache-query--compile-groups (cache group-specs intent)
(cl-assert (phpinspect-cache-p cache))
(let (groups)
(if group-specs
(dolist (spec group-specs)
(cl-assert (listp spec))
(cl-assert (memq (car spec) '(project label))
t "Spec car must be the symbol `project' or `label'")
(let ((group (gethash spec (phpinspect-cache-groups cache))))
(when (and (eq :insert intent) (not group))
(setq group (puthash spec (phpinspect-make-cache-group) (phpinspect-cache-groups cache))))
(push group groups)))
(if (eq :insert intent)
(error "Cannot insert without defining cache group")
(setq groups (hash-table-values (phpinspect-cache-groups cache)))))
groups))
(define-inline phpinspect-cache-transact (cache group-specs &rest query)
(declare (indent 2))
(cl-assert (listp query))
(let (type intent intent-param member namespace implements extends key value)
(condition-case err
(progn
(while (setq key (pop query))
(cl-assert (keywordp key) t "Query keys must be keywords, %s provided" key)
(setq value (pop query))
(cl-assert value t "Key %s has no value" key)
(pcase key
((or :insert :get :delete)
(when intent
(inline-error "Defined duplicate intent: %s, %s" intent key))
(setq intent key
intent-param value))
(:as (cl-assert (and (inline-const-p value)
(memq (inline-const-val value) phpinspect-cache-types))
t ":type must be one of %s" phpinspect-cache-types)
(setq type (inline-const-val value)))
(:member-of (setq member value))
(:in (setq namespace value))
(:implementing (setq implements value))
(:extending (setq extends value))
(_ (error "Unexpected query keyword %s" key))))
;; Query validation
(unless type
(error "Providing entity type with keyword :as is required."))
(when (and member (not (memq type phpinspect-cache-member-types)))
(error "Keyword :member-of can only be usd for types %s" phpinspect-cache-member-types))
(when (and extends (not (memq type '(class trait interface))))
(error "Keyword :extending cannot be used for types other than %s" '(class trait interface)))
(when (and (eq 'variable type) (not member))
(error "Variables outside of classes cannot be stored in the cache."))
(when (and intent (not intent-param))
(error "Intent %s must have a parameter %s" intent)))
(t (inline-error "phpinspect-cache-transact: %s" err)))
(inline-letevals (group-specs intent-param cache type member namespace implements extends)
(let ((action-args `(,intent-param (quote ,type) ,member ,namespace ,implements ,extends))
(action (pcase intent
(:insert 'phpinspect-cache-query--do-insert)
(:delete 'phpinspect-cache-query--do-delete)
(:get 'phpinspect-cache-query--do-get)
(_ (inline-error "Invalid intent %s" intent)))))
(message "action: %s" action)
(inline-quote
(let ((groups (phpinspect-cache-query--compile-groups ,cache ,group-specs ,intent)))
,(cons 'phpinspect-cache-query--validate (cons intent action-args))
(dolist (group groups)
,(cons action (cons 'group action-args)))))))))
(defun phpinspect-cache-query--validate (intent intent-param type member namespace implements extends)
(and
;; Validate intent-param
(cond
((phpinspect--type-p intent-param)
(cond
((not (memq type '(class trait interface)))
(error "Cannot use intent-param of type phpinspect--type when querying for %s" type))
((and (phpinspect--type-fully-qualified intent-param)
namespace)
(error "Use of fully qualified type %s while specifying namespace %s in query"
intent-param namespace)))
t)
((phpinspect-name-p intent-param) t)
((phpinspect--function-p intent-param)
(cond
((not (memq intent '(:insert :delete)))
(error "`phpinspect--function' can only be used as parameter for :insert and :delete intents."))
((not (memq type '(function method abstract-method)))
(error "Inserting/deleting `phpinspect--function' as type %s is not supported" type)))
t)
(t (error "Unsupported intent-param %s" intent-param)))
;; Validate member
(cond
((phpinspect-name-p member) t)
((phpinspect--type-p member) t)
((not member) t)
(t (error "unsupported member type (allowed `phpinspect-name' and `phpinspect--type'): %s" member)))
;; Validate namespace
(cond
((stringp namespace) t)
((phpinspect-name-p namespace) t)
((not namespace) t)
(t (error "unsupported namespace type (allowed `phpinspect-name' and `stringp'): %s" namespace)))
;; Validate implements
(cond
((listp implements)
(unless (seq-every-p #'phpinspect--type-or-name-p implements)
(error "Each parameter of :implementing must be of type `phpinspect--type' or `phpinspect-name'. Got: %s" implements))
t)
((phpinspect-name-p implements) t)
((phpinspect--type-p implements) t)
((not implements) t)
(t (error "unsupported parameter for :implementing (allowed `phpinspect--type' or `phpinspect-name': %s" implements)))
;; Validate extends
(cond
((listp extends)
(unless (seq-every-p #'phpinspect--type-or-name-p extends)
(error "Each parameter of :extending must be of type `phpinspect--type' or `phpinspect-name'. Got: %s" extends))
t)
((phpinspect-name-p extends) t)
((phpinspect--type-p extends) t)
((not extends) t)
(t (error "unsupported parameter for :extending (allowed `phpinspect--type' or `phpinspect-name': %s" extends)))))
;;; phpinspect.el ends here
(provide 'phpinspect-cache)

@ -128,6 +128,12 @@ level of START-FILE in stead of `default-directory`."
(or (gethash name phpinspect-names)
(puthash name name phpinspect-names)))
(define-inline phpinspect-name-p (name)
(inline-letevals (name)
(inline-quote
(and (consp ,name)
(eq 'phpinspect-name (car ,name))))))
(defsubst phpinspect--wrap-plist-name-in-symbol (property-list)
(let ((new-plist)
(wrap-value))

Loading…
Cancel
Save