Sublime Forum

Help with misbehaving syntax definition

#1

I’m updating the syntax definition for the Just language. It’s very similar to Make, but it focuses on running tasks instead of building things.

Just has if statements which require an else condition: if "a" == "a" {"b"} else {"c"}. You can also chain the if statements. When chained, they look like this:

foo := if "hello" == "goodbye" {
  "xyz"
} else if "a" == "a" {
  "abc"
} else {
  "123"
}

They can be on a single line or stretch across several lines as above. Furthermore, you can put if statements inside an interpolation block in a recipe:

bar foo:
  @echo {{ if foo == "bar" { "hello" } else { "goodbye" } }}

Here is the code I have written to handle this syntax. With this code, nested ifs and interpolation both work well:

However, if chaining does not work:

A recipe name should instead have a scope of entity.name.function.just and some different contexts on the stack.

In looking to resolve this, I changed the push on line 143 (in if-statements) to a set. That solved the chaining issue! However, now the interpolation is broken. :confounded:

It seems like I may not be popping the stack enough or in the right places. Does anyone have ideas on how to go about fixing or even diagnosing this? I’ve been scratching my head and trying different things for hours, but I’m at a loss. It can be hard to think with the context stack when a bunch of contexts are popped (or supposed to be) going from one character to another.

The code is all in the repo above, and I have a bunch of tests. So if some angel were inclined to download the repo and run the tests in syntax_test_just.control_flow.just, it should be easy to see the problem for yourself.

Two things I’m not sure about that could be relevant:

  1. Am I using the correct number of pops and in the correct place on line 194? (I tried lowering to 3 pops, and that didn’t pop enough.) Should that be a set?
  2. I notice that I’m using include: if-statements in one place, but then set: if-statements in another. This seems like a problem, since if-statements is the context which is sticking around in the chaining failure screenshot above. Is the issue with how I’m adding it to the stack, or how I’m failing to take it off?
0 Likes

#2

A simple way would be to handle if and else statements separately and make sure both always start on the same stack level.

  • if -> condition -> block
  • else -> block

This way else would be highlighted fine even if the if block before is missing (due to just being added or manipulated or something along those lines).

The following proposal also simplifies the if-condition by not restricting expression-operator-expression order. Just extending a normal just-expression by comparison operators until opening brace is hit or popping if anything unknown is found via else-pop.

###[ IF STATEMENT ]############################################################

  if-statements:
    - match: 'if\b'
      scope: keyword.control.conditional.if.just
      push: if-statement-condition-body
    - match: 'else\b'
      scope: keyword.control.conditional.else.just
      push: else-statement-block

  if-statement-condition-body:
    - meta_scope: meta.statement.conditional.if.just
    - match: '{'
      scope: punctuation.section.block.begin.just
      push: if-else-block-body
    - match: '!=|==|=~'
      scope: keyword.operator.comparison.just
    - include: just-expressions
    - include: else-pop

  else-statement-block:
    - meta_scope: meta.statement.conditional.else.just
    - match: '{'
      scope: punctuation.section.block.begin.just
      push: if-else-block-body
    - include: else-pop

  if-else-block-body:
    - meta_scope: meta.block.just
    - match: '}'
      scope: punctuation.section.block.end.just
      pop: 2
    - include: just-expressions

Also is it allowed to put an if else statement into the condition part of an if statement or into the arguments list of function calls?

If not I’d sugest to split just-expressions into just-statements (with if-else) and just-expressions (without if-else).

###[ STATEMENTS ]##############################################################

  just-statements:
    - include: if-statements
    - include: just-expressions

  just-expressions:
    - include: groups
    - include: operators
    - include: function-calls
    - include: strings
    - include: operands-variables

also see: https://github.com/nk9/Just-Sublime-Plugin/pull/3

1 Like

#3

Huge thanks, @deathaxe! That’s a perfect solution, and it even shortens and simplifies the if statement section.

And thanks a ton for the PR, I’ve commented there.

0 Likes