Skip to content
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

Codegen improvements #549

Merged
merged 26 commits into from
Oct 14, 2022
Merged

Codegen improvements #549

merged 26 commits into from
Oct 14, 2022

Conversation

bwrrp
Copy link
Member

@bwrrp bwrrp commented Oct 13, 2022

This started out as implementing codegen for the not() function, but grew into a little bit more...

  • fixed fn:name function not returning empty string for empty sequence argument
  • refactored codegen to generate mostly expressions and automatically manage identifiers rather than having to assign identifiers to everything - this reduced the generated code types to value, generator (paths only) or statement (generator body)
  • refactored codegen to pass and combine PartialCompilationResults everywhere instead of plain strings
  • aligned conversion functions to spec terminology (effective boolean value, atomization) and checked for correctness
  • fixed several instances of variables not being passed / combined (made variables required to reduce errors)
  • fixed a performance issue where the child axis would call getChildNodes for each iteration of the generator - it now loops using getFirstChild and getNextSibling
  • fixed some cases where buckets were not passed correctly to axis domFacade calls
  • fixed some issues in type annotation
  • implemented general comparison for sequence vs single value in order to not regress for attribute = value comparisons (previously only accepted because multiplicity for the attribute axis was not annotated correctly)
  • implemented codegen support for the context item expression
  • implemented codegen support for the node() test
  • implemented codegen support for non-axis path steps (filterExpr)
  • implemented codegen support for calling custom functions
  • implemented codegen support for calling selected built-in functions
  • implemented native codegen for the not() function

Things to note:

  • Built-in functions use an allowlist, as codegen'ed function calls don't currently have the full staticContext, executionParameters etc.
  • I had to add an options argument to executeJavascriptCompiledXPath in order to pass currentContext (required by custom functions)
  • I disabled the no-shadowed-variables tslint rule, because I think renaming the callback argument in the many mapPartialCompilationResult to something other than the var being mapped makes the code confusing and may even invite errors where the callback body tries to use the unchecked expression instead of the argument.

bwrrp added 21 commits October 12, 2022 10:36
This turns the generated code for a path expression into an actual
generator function, which greatly simplifies keeping state between calls
to next(). This also prevents calling getChildNodes for each step for
each call to next(). Instead, the generated code now iterates over
children using getFirstChild / getNextSibling.
This restores the ability to codegen @id = 'value', which was lost with
the earlier annotation fix.
Turns out this was required to make the Closure compiler happy
Support for this is incomplete, only a few argument / return types are
supported and built-in functions use an allowlist as we don't have the
complete execution context available.
@bwrrp bwrrp requested a review from DrRataplan October 13, 2022 10:41
@bundlemon
Copy link

bundlemon bot commented Oct 13, 2022

BundleMon

Files updated (2)
Status Path Size Limits
fontoxpath.js
83.51KB (+1.28KB +1.55%) -
fontoxpath.esm.js
83.62KB (+1.27KB +1.54%) -

Total files change +2.55KB +1.55%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@coveralls
Copy link

coveralls commented Oct 13, 2022

Coverage Status

Coverage increased (+0.3%) to 91.473% when pulling 01eb49e on codegen-not-function into 06b88ed on master.

Copy link
Collaborator

@DrRataplan DrRataplan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! Especially like the yield statements! Makes the code way easier to read.

Left a few small nitpicky comments

mapPartialCompilationResult(nodesExpr, (nodesExpr) =>
acceptAst(
`const ${stepContextItemExpr.code} of ${nodesExpr.code}`,
{ type: GeneratedCodeBaseType.Statement },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Statement? Rather an iteratorHeader or something. But fine for now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, or rename Statement to NonExpressionCodeFragment or something... It's only used here so felt like overkill to introduce a separate type...

) => PartialCompilationResult
> = {
'local-name': emitLocalNameFunction,
name: emitNameFunction,
'local-name/0': emitLocalNameFunction,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick, but I'd replace the / with #: to align with the functionLookup operator

args: UntypedExternalValue[],
options: Options | null
) => unknown;
XPDY0002: typeof XPDY0002;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this used?

acceptAst(contextItemExpr.code, { type: GeneratedCodeBaseType.Value }, [
...contextItemExpr.variables,
`if (${contextItemExpr.code} === undefined || ${contextItemExpr.code} === null) {
throw new Error('XPDY0002: The function which was called depends on dynamic context, which is absent.');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you not using the runtimelib here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To this and the above - error throwing was and still is a bit inconsistent - do you prefer to import all error helpers through runtimeLib or to turn everything into new Error('XP...')?

Copy link
Collaborator

@DrRataplan DrRataplan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Let me know what the performance results do for the queries that are now supported by codegen!

@bwrrp bwrrp merged commit 6f99b73 into master Oct 14, 2022
@bwrrp bwrrp deleted the codegen-not-function branch October 14, 2022 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants