-
-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query: parse as AST #6788
base: v5/develop
Are you sure you want to change the base?
Query: parse as AST #6788
Conversation
- cast data objects to arrays before passing to query runner - allow integers as identifiers of array keys when used after a dot - don't emit warnings when an array key is missing
- Implements the intercept mechanism for both runners - Renames the AST Node classes with a "Node" suffix to avoid confusion with some PHP internal classes (like `Closure` -> `ClosureNode`)
…ompatible with parent
Updates
DiscussionIn regards to intercept, all evaluated objects and variables are now passed through intercept. Even stuff like literal strings or numbers. It could be worth discussing if this is actually useful or just slow. One idea could be to only intercept objects on which a member field or method is accessed. Like:
|
|
Sure, intercept(
intercept(page).files
).first
intercept(
intercept(
intercept(page).files
).first
).delete also intercept(
intercept(foo).callMeBack(() => page('bar'))
).delete |
Having implemented the " $query = new Query('Shipping Address');
$this->assertSame('742 Evergreen Terrace', $query->resolve(['Shipping Address' => '742 Evergreen Terrace'])); I see 4 options:
The index operator obviously gives the most bang for the buck as it allows any kind of expression as index (not just strings), but it either requires an unconventional syntax (the |
- cast data objects to arrays before passing to query runner - allow integers as identifiers of array keys when used after a dot - don't emit warnings when an array key is missing
- Implements the intercept mechanism for both runners - Renames the AST Node classes with a "Node" suffix to avoid confusion with some PHP internal classes (like `Closure` -> `ClosureNode`)
…ompatible with parent
d82b385
to
738674e
Compare
instead of intercepting everything, intercept only objects or array on which the query actually want's to access methods or fields
Dependency Injecting the query cache into runners allows the Query class can manage it, since it's also the Query class which controls the global functions available to queries
I've implememted the intercept logic like described above (see test here) Other notable change would be moving the "resolver cache" (the cache that maps query strings to closures) to the |
@rasteiner we are currently trying to wrap some things up for the v5 beta, that's why I'm not active here much these days, but will get back to it probably next week! :) |
Description
This PR Introduces a new query parser and "runners" which allow Kirby to "compile" queries so that they can subsequently execute faster.
Based on initial tests, the runners seem to be about 30% faster (28% one, 35% the other "more experimental" one).
Summary of changes
There is a new
Kirby\Toolkit\Query
namespace which contains all logic for the new query runners. The general process is as follows:The query string is split into a flat sequence of tokens (see Kirby\Toolkit\Query\Tokenizer).
The tokens are parsed into a recursive abstract syntax tree (see Kirby\Toolkit\Query\Parser).
The AST is then visited by an interpreter (Kirby\Toolkit\Query\Runners\Visitors\Interpreter) that directly evaluates the query, or
a code generator (Kirby\Toolkit\Query\Runners\Visitors\CodeGen) that transpiles it into PHP code.
The whole process and the caching is handled by the two "runner" classes:
Kirby\Toolkit\Query\Runners\Interpreted
Kirby\Toolkit\Query\Runners\Transpiled
The original
Kirby\Query\Query
class remains in place and chooses which runner to use based on thequery.runner
option.Reasoning
Separating the parsing and execution steps allows for more flexibility and better performance, since it allows us to cache the AST, either as PHP code or in memory during a request (or in some other out of process memory cache).
Additional context
The parser is a predictive recursive descent parser, making the parsing step
O(n)
. As such it can't support ambigous code, which leads to the following failing test:kirby/tests/Query/QueryTest.php
Lines 70 to 74 in eb47158
Changelog
Kirby\Toolkit\Query
namespace for query parsing and running.query.runner
option to opt-out of the new parser or switch to the transpiled version (requires File Write access).The "no longer needed" classes in
Kirby\Query
(Argument, Arguments, Expression, Segment, Segments) could be deprecated and removed in a future version when you eventually remove support for the "legacy" runner.Fixes
No fixes, just performance.
Breaking changes
The above mentioned ability of the original parser to match identifiers like
user.username
literally as array key"user.username"
would no longer be valid, as a query like that, which changes "meaning" based on the data context, can't be compiled to an efficient code. An alternative syntax, likeuser\.username
or maybe something likethis['user.username']
would be needed.Docs
Except for the above breaking change and deprecation, this should be a drop-in replacement.
The only new features are:
query.runner
:Ready?
No! This is a work in progress. The proposed API could change.
Also, for some reason VS Code decided to merge the
main
branch into this one... As this PR isn't really ment to be merged "as is" I'll just ignore this mistake: this is mainly a place for dicussion.For review team