github / stack-graphs

Rust implementation of stack graphs
https://docs.rs/stack-graphs/*/stack_graphs/
Apache License 2.0
717 stars 122 forks source link

Python TSG: Chained assignment fails to be recognised #402

Open SubhamPramanik opened 4 months ago

SubhamPramanik commented 4 months ago

Python code:

repeat_hi = repeat_lo = repeat_avg = None

The following Stanza fails:

[
  (assignment
    left: (_) @pattern
    right: (_) @value)
  (with_item
    value:
      (as_pattern
        (_) @value
        alias: (as_pattern_target (_) @pattern)))
]
{
  edge @pattern.input -> @value.output
}

Error thrown:

    0: Error executing statement edge @pattern.input -> @value.output at (1268, 3)
       src/stack-graphs.tsg:1268:3:
       1269 |   edge @pattern.input -> @value.output
            |   ^
       in stanza
       src/stack-graphs.tsg:1258:1:
       1258 | [
            | ^
       matching (assignment) node
       benchmark.py:121:9:
       121 |         repeat_hi = repeat_lo = repeat_avg = None 
           |         ^
    1: Evaluating edge sink
    2: Undefined scoped variable [syntax node assignment (121, 21)].output

I believe that the TS query is not able to work with chained assignments since the first occurrence of right is incorrect.

[expression_statement](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 41]
    [assignment](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 41]
      left: [identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 9]
      right: [assignment](https://tree-sitter.github.io/tree-sitter/playground#) [0, 12] - [0, 41]
        left: [identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 12] - [0, 21]
        right: [assignment](https://tree-sitter.github.io/tree-sitter/playground#) [0, 24] - [0, 41]
          left: [identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 24] - [0, 34]
          right: [none](https://tree-sitter.github.io/tree-sitter/playground#) [0, 37] - [0, 41]
SubhamPramanik commented 4 months ago

@hendrikvanantwerpen For visibility. Thanks!

augmented-fog commented 4 months ago

I was about to report the same issue.

My example is

a = 1
b = 2
c = b = a

The tree-sitter CST for this is

(module [0, 0] - [3, 0]
  (expression_statement [0, 0] - [0, 5]
    (assignment [0, 0] - [0, 5]
      left: (identifier [0, 0] - [0, 1])
      right: (integer [0, 4] - [0, 5])))
  (expression_statement [1, 0] - [1, 5]
    (assignment [1, 0] - [1, 5]
      left: (identifier [1, 0] - [1, 1])
      right: (integer [1, 4] - [1, 5])))
  (expression_statement [2, 0] - [2, 9]
    (assignment [2, 0] - [2, 9]
      left: (identifier [2, 0] - [2, 1])
      right: (assignment [2, 4] - [2, 9]
        left: (identifier [2, 4] - [2, 5])
        right: (identifier [2, 8] - [2, 9])))))

The expression c = b = a results in a nested assignment, which causes the stanza to fail because the syntax node type assignment does not have an output attribute.

The suggested fix is to modify this stanza as follows

[
  ; expressions
++  (assignment)
  (comparison_operator)
  (not_operator)
  (boolean_operator)
  ; ...
] @node {
  node @node.input
  node @node.new_bindings
  node @node.output
}