diff --git a/README.md b/README.md index d3d6f77..397f55c 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,146 @@ Elapsed time: 0.013878 (0.000000 in 0 GC’s) ``` ## Development +The codebase of phpinspect is relatively large. As a new contributor, you'll +probably feel a bit lost in the many files, functions and datatypes of the +package. Let me tell you a bit about phpinspect's architecture. + +### Domains +There are roughly four main domains under which code in phpinspect can fall: +parsing, indexation, interpetation and user-facing functions. Below is a short +explanation of each domain. + +#### Parsing +The parser provides the underpinnings for almost all of phpinspect's +functionalities. It is implemented with specialized macros and supports two main +parsing modes: bare and incremental. The parser code is located in +`phpinspect-parser.el`. + +##### Bare Parsing +The parser produces a parse result in the form of a basic list, where each +parsed token is a list itself. The car of each list contains a keyword, +describing its meaning in the parsed code. Below is a lisp form and its +resulting insertion to demonstrate the structure of a syntax tree produced by +the bare parser. + +`(insert (pp-to-string (phpinspect-parse-string "function foo(Bar $bar) { return $bar->baz; }")))` + +```elisp +(:root + (:function + (:declaration + (:word "function") + (:word "foo") + (:list + (:word "Bar") + (:variable "bar"))) + (:block + (:word "return") + (:variable "bar") + (:object-attrib + (:word "baz")) + (:terminator ";")))) + +``` + +##### Incremental Parsing +Bare parsing is fast, because it makes use of simple lisp datastructures and +keeps the parser logic simple. A downside of this parsing mode is that the +result lacks any extra metadata about the tokens, like what their start- and +endpoints are in a buffer. It also makes it hard to partially update the tree +after a buffer has been edited. As both are essential for a program that needs +to work efficiently in live-edited buffers, the incremental parser was +implemented. When parsing incrementally, the parser still produces the same +structure of nested lists as a result. But it also stores metadata about each +parsed token in an n-ary tree of `phpinspect-meta` objects (see +`phpinspect-meta.el`). The incremental parser is able to partially update an +existing tree after code has been edited, making it efficient for live buffers. + +##### Parsers Summarised +The incremental parsing is efficient for use with live edited buffers. Due to +its higher complexity it is not as fast at parsing entire files as the bare +parser. For this reason, both the bare and the incremental parser are used for +what they are best at. + +#### Indexation +Within phpinspect, indexation is referred to as the process of extracting +information from parsed code and project configuration files. + +##### Code Indexation +The code in +`phpinspect-index.el` consumes bare syntax trees and extracts information about +PHP functions and types from them. Code in `phpinspect-buffer.el` implements the +same functionality, but for live buffers based on the data produced by the +incremental parser. + +##### Project Indexation +Code in `phpinspect-autoload.el` implements logic for `psr-4`, `psr-0` and +`files` autoload strategies. It is able to read a composer.json file and +generate autoload information based on which a project's types and functions can +be found. + +##### Caching +Code in `phpinspect-cache.el` and `phpinspect-class.el` allows phpinspect to +store the result of code indexations in memory, so that they can be accessed +instantly when a user requests information about their code. + +##### Threading +Indexation takes time. Because emacs is single-threaded, you might think that +indexing a project would lock up your emacs for a while. Do not despair! +`phpinspect-worker.el` contains code for a worker with a job queue that uses +collaborative threads to do work when emacs is idle. When you start interacting +with emacs, it will back off and let you do your thing! `phpinspect-pipeline.el` +contains code for something similar to generators in PHP, combined with +collaborative threading. Pipelines are used for more intense processes that +should be completed with a bit more of a hurry. Emacs should remain responsive +while a pipeline is running, but there may be a slightly noticeable sluggishness +while they run. At the moment of writing, pipelines are mainly used to refresh a +projects autoloader. + +#### Interpretation +Having parsing, indexation and caching infrastructure is all well and good, but +how to we determine what information is actually useful to show to a user? This +is where code interpretation plays a big role. The main goal of interpretation +in phpinspect is the determination of the PHP type to display information +about. Determining this type is referred to as "resolving" in phpinspect's +codebase. Resolving a type is built around the concept of a "resolvecontext". A +resolvecontext is an object that contains information about a location in a +buffer and its surroundings. Based on the informatoin in the resolvecontext, the +type that a statement is expected to evaluate to can be determined. The code for +resolving types is mostly contained in `phpinspect-type.el`, +`phpinspect-resolve.el` and `phpinspect-resolvecontext.el`. The main entrypoints +are the functions `phpinspect-get-resolvecontext` and +`phpinspect-resolve-type-from-context`. + +#### User-facing Functions +User-facing functions in phpinspect are mostly integrations with existing +infrastructure within emacs. For completion there is +`completion-at-point-functions`, for tooltips there is `eldoc` and for +go-to-definition there is `xref`. Aside from these integrations, phpinspect aims +to provide functionalities for code formatting. + +##### Completion +Completion is implemented in `phpinspect-completion.el` as a strategy pattern. A +completion strategy can be added by implementing the methods +`phpinspect-comp-strategy-supports` and +`phpinspect-comp-strategy-execute`. Completion strategies are high level +abstractions that build on top of the type resolving code and the code in +`phpinspect-suggest.el`. + +##### Eldoc +Eldoc support is implemented in a strategy pattern similar to that of +completion. An eldoc strategy can be added by implementing the methods +`phpinspect-eld-strategy-supports` and `phpinspect-eld-strategy-execute`. + +##### Code Formatting +`phpinspect-fix-imports` adds, removes and sorts use statements. At the time of +writing, this is the only code formatting functionality that phpinspect +provides. See `phpinspect-imports.el` for the implementation. + +##### Really Want To But Not Implemented: Xref +A thing that would be possible to implement on top of phpinspect's +infrastructure, but not much time has been spent on yet, is an integration with +`xref`. Xref integration would enable functionalities like go-to-definition. ### Building