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

bug: tree-sitter parses complex declaration as pseudo-class instead of CSS custom property #7

Open
2 tasks done
kensternberg-authentik opened this issue Dec 12, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@kensternberg-authentik
Copy link

Did you check existing issues?

  • I have read all the tree-sitter docs if it relates to using the parser
  • I have searched the existing issues

Tree-Sitter CLI Version, if relevant (output of tree-sitter --version)

tree-sitter 0.24.5

Describe the bug

In the following Sass rule_set.block:

.#{$backdrop} {
  --#{$backdrop}--Position: fixed;
  --#{$backdrop}--ZIndex: var(--#{$pf-global}--ZIndex--lg);
}

tree-sitter-scss correctly parses the first declaration as property name. It ERRORs on the second declaration, and claims its best-fit is as a pseudo_class_selector.

I believe part of the confusion comes from an inappropriate declaration in tree-sitter-css, namely this one:

    _selector: $ => choice(
      $.universal_selector,
      alias($.identifier, $.tag_name),
      $.class_selector,

// ... much later....

    identifier: _ => /(--|-?[a-zA-Z_\xA0-\xFF])[a-zA-Z0-9-_\xA0-\xFF]*/,

To the best of my knowledge, a tag_name cannot start with the -- sequence, yet here it's allowed, creating an ambiguity. Unfortunately, the confusion of tag_name with identifier goes pretty deep and recursive in the definition of _selector, leading to the problem.

Steps To Reproduce/Bad Parse Tree

  1. Attempt to parse this file with $ tree-sitter parse file.scss:
.#{$backdrop} {
  --#{$backdrop}--Position: fixed;
  --#{$backdrop}--ZIndex: var(--#{$pf-global}--ZIndex--lg);
}
  1. See this message:
      (ERROR [2, 2] - [2, 59]
        (pseudo_class_selector [2, 2] - [2, 58]
          (tag_name [2, 2] - [2, 24]
            (identifier [2, 2] - [2, 4])
            (interpolation [2, 4] - [2, 16]

Expected Behavior/Parse Tree

I would expect the second declaration to be correctly interpreted as a declaration.

Repro

The example is given above.

@kensternberg-authentik kensternberg-authentik added the bug Something isn't working label Dec 12, 2024
kensternberg-authentik added a commit to kensternberg-authentik/tree-sitter-scss that referenced this issue Dec 16, 2024
# Related Links:

Addresses [Issue 7: tree-sitter parses complex declaration as pseudo-class instead of CSS custom
property](tree-sitter-grammars#7).

# What

This commit places a guard clause around the scanner expression for detecting a pseudo-class
selector colon.  The guard clause ensures that the character *prior to* any `{` symbol was not the
start of interpolation.

I have also re-run the generate under 0.24.5, so the parser, headr files, and generated grammar have
been updated to the latest & greatest version. A `tree-sitter.json` file has also been generated,
and the corresponding tree-sitter clause removed from `package.json` (automatically, by tooling).

# Why

This declaration, which has been [added to the test cases](./test/corpus/declarations.txt).

```
div {
  --#{$x}--left: var(--#{$y}--right);
}
```

As written, when `PSEUDO_CLASS_SELECTOR_COLON` is a valid possible symbol, the scanner clause for
pseudo-class selector detection passes if a `{` is detected before encountering a `}` or `;` symbol.
The expression `#{$y}` in the test case meets that criteria, the lexer result is marked incorrectly,
and the parser fails to parse the declaration correctly.

Adding a guard that the prior character seen was a `#` and that the `{` is not the start of a nested
block identified by a pseudo-class but is, instead, part of an interpolation, fixes this issue.

# Test steps

1. Run the tests under the old clause and see this failure:

```
correct / expected / unexpected

  1. Interpolation on both sides of a declaration:

    (stylesheet
      (rule_set
        (selectors
          (tag_name))
        (block
          (declaration
            (ERROR)
            (property_name
              (identifier)
              (interpolation
                (variable))
              (identifier))
            (call_expression
              (function_name)
              (arguments
                (identifier)
                (interpolation
                  (variable))
                (identifier)))))))

```

2. Run it with the new clause and there is no more failure.  :-)  In fact, *all* of the tests now
   pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant