tree-sitter-supercollider icon indicating copy to clipboard operation
tree-sitter-supercollider copied to clipboard

Fix: method-call and flatten binary operators precedence, Add: List Comprehension

Open smoge opened this issue 2 months ago • 3 comments

Fix method-call precedence, unify binary operators, and implement list comprehensions

Summary

  • Operators: All binary operators now use consistent left-to-right evaluation
  • Method chains bind tightly: New _primary/_postfix rules ensure method calls attach to the right expression
  • List comprehensions: Full support for {: syntax with generators, guards, bindings, side effects, and termination
  • Fixed named arguments: parameter: value syntax now correctly stores values
  • Control flow: if, while, switch handle expressions consistently
  • Block syntax: Code blocks use { … }, parentheses use ( … )
  • Added dedicated rules for nil-check operators

Up to discussion:

  • ~~Keyword messages: Separated from binary operators into dedicated rule for [1,2,3] collect: {...} syntax~~

Motivation

Problems fixed:

  • No support for list comprehensions ({: x*2, x <- (1..10)})
  • identifier: patterns conflated with binary operators
  • { … } and (…) confusion
  • .midiratio binding to entire expressions instead of grouped RHS
  • curve: -1 stored incorrectly under name: instead of value:
  • Operator precedence tiers that don't exist in sclang

This branch is organized into small commits:

Some changes span over different (non-)consecutive commits. But it is easy to distinguish logical changes:

  1. Introduce block/group distinction (1)
  2. Add _primary/_postfix hierarchy (2-3)
  3. Flatten binary precedence (4-6)
  4. Fix argument handling (7)
  5. Update control structures (10)
  6. Clean up unused code (8-9, 11-13)
  7. Add keyword messages (14-15)
  8. Add list comprehensions (15-18)
  9. reorganized _expression_statement and _object (21)
  10. Dedicated rules for nil-check operators (22)

List comprehensions

List comprehension syntax:

{: body, qualifier, qualifier, ... }

Supported qualifiers:

  • Generators: x <- (1..10)
  • Guards: x.odd
  • Variable bindings: var z = x*x
  • Side effects: :: x.postln
  • Termination: :while x < 100

Keyword messages

Separated identifier: patterns from binary operators:

keyword_message: $ => prec.left(PRECEDENCE.keyword_message, seq(
  field('receiver', $._postfix),
  field('selector', alias(/[a-zA-Z_]\w*:/, $.keyword_selector)),
  field('argument', $._postfix)
))

This handles [1,2,3] select: {|x| x > 1} as a distinct syntactic form.

Blocks & grouping

  • code_block: '{' parameter_list? expression_sequence? '}'
  • group: '(' expression ')'
  • function_block now uses code_block directly

Chains > binops

  • Introduce _primary (atoms) and _postfix (primary + chain)
  • Method chains parse left-associatively with high CALL precedence
  • function_call receivers restricted to _primary

Flat binary operators (left-to-right)

All symbolic binary operators now share one BIN tier:

binary_expression: $ => prec.left(PRECEDENCE.BIN, seq(
  field('left',  $._postfix),
  field('operator', choice(
    '||','&&','|','^','&','==','!=','<','<=','>','>=',
    '<<','>>','+','-','++','+/+','*','/','%','**'
  )),
  field('right', $._postfix)
))

Arguments

  • Drop argument_calls/unnamed_argument
  • named_argument: name ':' value with RHS under value:

Control structures

  • if, while, switch expressions take _postfix (chains bind)

Before / After

List comprehensions

  • Before: Not supported
  • After: Supported
{: [x,y], x <- (1..5), y <- (1..x), (x+y).isPrime }

Keyword messages

  • Dedicated AST node with receiver/selector/argument fields

.midiratio binding

  • Before: Could attach to \freq.kr(440) * (…) as a whole
  • After: Attaches to grouped RHS term:
\freq.kr(440) * (Env.perc(...).ar * 48).midiratio
                 └────── group ────────┘└postfix┘

Named argument

  • Before: curve: -1 created two name: fields
  • After: name: curve, value: -1

Testing

Needs tests for:

  • List comprehension qualifiers
  • Keyword message vs binary operator disambiguation
  • Postfix vs group binding
  • Named args with negative values
  • Left-to-right operator evaluation

smoge avatar Sep 20 '25 11:09 smoge

Amazing @smoge !! I am completly swamped in my life atm but just wanna say this looks so good. Will give it a bit more comment later. Maybe @bsssssss could look at this overhaul ?

madskjeldgaard avatar Sep 24 '25 15:09 madskjeldgaard

Just had a quick look at this, that is awesome work ! Feels somewhat more natural to follow to me :)

I had trouble with neovim's tree-sitter complaining about queries in highlights.scm due to some typos and non-existing nodes. I also added some keywords. Here is the patch. Curious to know what editor are you using @smoge ?

From limited testing i noticed some things,

groups are not parsed correctly at the top level it seems like

(
v = 2;
)

gives us this AST

(source_file ; [0, 0] - [3, 0]
  (ERROR ; [0, 0] - [3, 0]
    (group ; [0, 0] - [2, 1]
      (variable_definition ; [1, 0] - [1, 5]
        name: (variable ; [1, 0] - [1, 1]
          (instance_var ; [1, 0] - [1, 1]
            name: (identifier))) ; [1, 0] - [1, 1]
        value: (literal ; [1, 4] - [1, 5]
          (number ; [1, 4] - [1, 5]
            (integer))))))) ; [1, 4] - [1, 5]

Maybe because group it is not part of expression ?

With ~clock = TempoClock(180/60); , we get

(source_file ; [0, 0] - [1, 0]
  (variable_definition ; [0, 0] - [0, 27]
    name: (variable ; [0, 0] - [0, 6]
      (environment_var ; [0, 0] - [0, 6]
        name: (identifier) ; [0, 0] - [0, 1]
        name: (identifier))) ; [0, 1] - [0, 6]
    (ERROR ; [0, 9] - [0, 19]
      (identifier)) ; [0, 9] - [0, 19]
    value: (group ; [0, 19] - [0, 27]
      (binary_expression ; [0, 20] - [0, 26]
        left: (literal ; [0, 20] - [0, 23]
          (number ; [0, 20] - [0, 23]
            (integer))) ; [0, 20] - [0, 23]
        right: (literal ; [0, 24] - [0, 26]
          (number ; [0, 24] - [0, 26]
            (integer))))))) ; [0, 24] - [0, 26]

Not sure why ?

bsssssss avatar Sep 25 '25 14:09 bsssssss

#63

smoge avatar Oct 07 '25 02:10 smoge