How to restrict rules by line with Lezer

Imagine these two lines:

X | A B
Y | a B

Let’s say that the first character (before the ‘|’) defines the context of the line.

Basically, what I need is to have a token for each character based on the context of its line. Specifically, at the end, I would have something like this in the editor:

<div class="cm-line">
  <span class="ͼ0">X |</span><span class="ͼ1">A</span><span class="ͼ1">B</span>
</div>
<div class="cm-line">
  <span class="ͼ2">Y |</span><span class="ͼ3">a</span><span class="ͼ3">B</span>
</div>

Where “ͼ0” and “ͼ1” define the style for the line with the context “X”, and “ͼ2” and “ͼ3” define the style for the line with the context “Y”."

Here is the grammar I’ve created

@top Program { lines* }

@skip{space}

lines {  xLine |   yLine }

xLine {XHead ( XToken | Delimiter)+}
yLine {YHead ( YToken | Delimiter)+}

@tokens {
  XHead { 'X' @whitespace '|'}
  YHead { 'Y' @whitespace '|'}

  XToken { $[A-Z]+}
  YToken { $[a-zA-Z]+}

  Delimiter { '-' }
  space {@whitespace+}

  @precedence {XHead, YHead, XToken, YToken}
}

@detectDelim

As you can notice the last character of each line are the same. As the ‘B’ match XToken, the result is that both “B” have the class “ͼ1”.

If I reverse the order of the precedence, the problem is still the same, both “B” have the class “ͼ3”

How can I solve my problem ?

Don’t include newlines in your skipped whitespace tokens, but make them a normal part of the grammar, matching between the lines.

Ok, that does the job. Here are the changes I made:

...
xLine {XHead ( XToken | Delimiter)* eol}
yLine {YHead ( YToken | Delimiter)* eol}

@tokens {
  ...
  space { ' '}
  eol { '\n' }
}
...

It is really appreciable this reactivity. Thanks @marijn ! :+1: