prometheus icon indicating copy to clipboard operation
prometheus copied to clipboard

WIP: Clean up the Lezer grammar output tree

Open marijnh opened this issue 3 years ago • 2 comments

I have been asked to review the lezer-promql grammar, and noticed that it was creating more nodes and a more complex tree structure than it needed to. The first patch in this PR makes the following changes:

  • Removes the Expr wrapping node around expressions, tagging the (lowercase) expr rule with @isGroup=Expr so that you can still query whether something is an expression.
  • Replaces the MetricIdentifier(Identifier) structure with just Identifier.
  • Makes the binary op modifiers optional, and splits BoolModifier from ignoring/on modifiers (ModifierClause) for clarity.
  • Collapses recursive rules (GroupingLabelList, FunctionCallArgs, LabelMatchList) that just existed to implement a repetition into a simpler rule that uses the * operator and creates a flat tree.

I've adjusted the lezer-promql tests to test for the updated tree shape.

However, after doing this I found out the codemirror-promql package had some code that is very tightly coupled to the way the syntax tree looks. I've tried to adjust this in the second patch, but I was unable to run the test suite, so this is most likely not done. Firstly, the package files for the packages under module/ seem to miss some dev dependencies (jest, rollup) and rely on higher-up packages to also be installed. After doing that, I could start jest, but it still failed to run with messages like...

ReferenceError: exports is not defined

The 'import.meta' meta-property is only allowed when the '--module' option is 'es2020', 'es2022', 'esnext', 'system', 'node16', or 'nodenext'. https://github.com/prometheus/prometheus/pull/11333 ... suggesting some kind of module-system confusion. (I'm using Node 16.13.) Would anybody be able to point me in the right direction regarding how to run these tests?

marijnh avatar Sep 21 '22 12:09 marijnh

Awesome, thanks! I haven't studied the code changes yet (aim to do that soon), but for the tests, this is what works for me:

$ node --version
v16.16.0
$ npm --version
8.11.0

$ cd web/ui
$ npm i
$ npm test # Run tests for all the web stuff
$ cd module/codemirror-promql
$ npm test # Run tests just for codemirror-promql

juliusv avatar Sep 21 '22 13:09 juliusv

Updated with a version that passes the tests. You should probably still review carefully, since some of the code I touched was somewhat opaque to me, not having experience with the system.

marijnh avatar Sep 21 '22 15:09 marijnh

Generally looks great to me besides my one node naming comment, thanks for the extensive changes :+1:

@Nexucis are you fine with the codemirror-promql changes around it as well?

juliusv avatar Sep 29 '22 15:09 juliusv

Perfect, thanks! I'll merge this in the next few days then, unless @Nexucis has any complaints during that time.

juliusv avatar Sep 29 '22 16:09 juliusv

Oops, we're actually getting one linter error now (just some code formatting):

/__w/prometheus/prometheus/web/ui/module/codemirror-promql/src/parser/vector.ts
  16:9  error  Replace `·And,·BinaryExpr,·MatchingModifierClause,·LabelName,·GroupingLabels,·GroupLeft,·GroupRight,·On,·Or,·Unless·` with `⏎··And,⏎··BinaryExpr,⏎··MatchingModifierClause,⏎··LabelName,⏎··GroupingLabels,⏎··GroupLeft,⏎··GroupRight,⏎··On,⏎··Or,⏎··Unless,⏎`  prettier/prettier

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

juliusv avatar Sep 29 '22 16:09 juliusv

Updated the PR with the whitespace change.

marijnh avatar Sep 29 '22 19:09 marijnh

@marijnh This change breaks Grafana's current usage of this module, we are currently using BinModifiers, OnOrIgnoring, LabelMatchList, MetricIdentifier, Expr, FunctionCallArgs, GroupingLabel, and GroupingLabelList which no longer exist as of this merge. Some usages appear to have trivial replacements, but for others it is not clear to me how we should be migrating to support this change.

The unit tests are helpful for seeing how we should update, but most of the previously exported variables above are not covered.

Are there any tips or documentation you can provide for replacing the usages of these exports that are no longer available?

gtk-grafana avatar Jun 07 '23 19:06 gtk-grafana

@gtk-grafana I'm sorry to hear! FWIW, Grafana has started using this module for purposes that it wasn't intended or suited for, and to my knowledge, without consulting with the original developers (myself and @Nexucis) first. Generally I'm not sure if that's a good idea, as lezer trees are optimized towards CodeMirror-like text-editing use cases (optimizing for things like parse error recovery, incremental parsing, etc.), but not as great for doing other high-level interpretation and manipulation of symbolic ASTs, like I understand you're currently using it for in the graphical query builder in Grafana.

See also this excerpt from https://lezer.codemirror.net/docs/guide/:

These trees, represented by data structures from the @lezer/common package, are more limited than the abstract syntax trees you might have seen in other contexts. They are not very abstract. Each node only stores a type, a start and end position, and a flat sequence of children. When writing a grammar, you choose which productions are stored as nodes—the others don't appear in the tree at all.

This means that the tree is very compact in memory and cheap to build. It does make doing refined analysis on it somewhat awkward. The use case guiding the design of this library is an editor system, which keeps a syntax tree of the edited document, and uses it for things like syntax highlighting and smart indentation.

Now given the current reality of Grafana using this (so far, successfully) for the query editor, I'm not sure exactly how to migrate things there, but I hope it's possible of course. But I wanted to clarify that this is not generally a use case we were looking to explicitly support with this package.

juliusv avatar Jun 07 '23 19:06 juliusv

To clarify we're using this package for the promQL code editor (using Monaco) in Grafana, AND the graphical query builder (although it is also used for some novel use cases like adding labels to existing queries via ad-hoc filters and other one-off situations), but I understand that your use case for this package is limited to the code mirror package.

We'll try to figure out if we want to fork an older version or see if we can rewrite things in Grafana to work with these changes. Thank you for the prompt response on this!

gtk-grafana avatar Jun 07 '23 20:06 gtk-grafana