@ ProgramNode (location: (0...108))
├── locals: [:x, :a]
└── statements:
    @ StatementsNode (location: (0...108))
    └── body: (length: 5)
        ├── @ CallNode (location: (0...24))
        │   ├── receiver: ∅
        │   ├── call_operator_loc: ∅
        │   ├── message_loc: (0...4) = "puts"
        │   ├── opening_loc: ∅
        │   ├── arguments:
        │   │   @ ArgumentsNode (location: (5...24))
        │   │   └── arguments: (length: 1)
        │   │       └── @ StringConcatNode (location: (5...24))
        │   │           ├── left:
        │   │           │   @ StringNode (location: (5...9))
        │   │           │   ├── opening_loc: (5...6) = "\""
        │   │           │   ├── content_loc: (6...8) = "hi"
        │   │           │   ├── closing_loc: (8...9) = "\""
        │   │           │   └── unescaped: "hi"
        │   │           └── right:
        │   │               @ StringNode (location: (17...24))
        │   │               ├── opening_loc: (17...18) = "\""
        │   │               ├── content_loc: (18...23) = "there"
        │   │               ├── closing_loc: (23...24) = "\""
        │   │               └── unescaped: "there"
        │   ├── closing_loc: ∅
        │   ├── block: ∅
        │   ├── flags: ∅
        │   └── name: "puts"
        ├── @ ArrayNode (location: (28...37))
        │   ├── elements: (length: 1)
        │   │   └── @ SymbolNode (location: (31...36))
        │   │       ├── opening_loc: ∅
        │   │       ├── value_loc: (31...36) = "a\\\r\nb"
        │   │       ├── closing_loc: ∅
        │   │       └── unescaped: "ab"
        │   ├── opening_loc: (28...31) = "%I{"
        │   └── closing_loc: (36...37) = "}"
        ├── @ StringNode (location: (41...45))
        │   ├── opening_loc: (41...45) = "<<-E"
        │   ├── content_loc: (47...70) = "    1 \\\r\n    2\r\n    3\r\n"
        │   ├── closing_loc: (70...73) = "E\r\n"
        │   └── unescaped: "    1     2\r\n    3\r\n"
        ├── @ LocalVariableWriteNode (location: (75...84))
        │   ├── name: :x
        │   ├── depth: 0
        │   ├── name_loc: (75...76) = "x"
        │   ├── value:
        │   │   @ StringNode (location: (79...84))
        │   │   ├── opening_loc: (79...82) = "%\r\n"
        │   │   ├── content_loc: (82...82) = ""
        │   │   ├── closing_loc: (82...84) = "\r\n"
        │   │   └── unescaped: ""
        │   └── operator_loc: (77...78) = "="
        └── @ LocalVariableWriteNode (location: (88...108))
            ├── name: :a
            ├── depth: 0
            ├── name_loc: (88...89) = "a"
            ├── value:
            │   @ CallNode (location: (92...108))
            │   ├── receiver: ∅
            │   ├── call_operator_loc: ∅
            │   ├── message_loc: (92...95) = "foo"
            │   ├── opening_loc: (95...96) = "("
            │   ├── arguments:
            │   │   @ ArgumentsNode (location: (96...107))
            │   │   └── arguments: (length: 1)
            │   │       └── @ CallNode (location: (96...107))
            │   │           ├── receiver:
            │   │           │   @ StringNode (location: (96...102))
            │   │           │   ├── opening_loc: (96...102) = "<<~EOF"
            │   │           │   ├── content_loc: (110...121) = "\r\n    baz\r\n"
            │   │           │   ├── closing_loc: (121...128) = "  EOF\r\n"
            │   │           │   └── unescaped: "\nbaz\r\n"
            │   │           ├── call_operator_loc: (102...103) = "."
            │   │           ├── message_loc: (103...107) = "chop"
            │   │           ├── opening_loc: ∅
            │   │           ├── arguments: ∅
            │   │           ├── closing_loc: ∅
            │   │           ├── block: ∅
            │   │           ├── flags: ∅
            │   │           └── name: "chop"
            │   ├── closing_loc: (107...108) = ")"
            │   ├── block: ∅
            │   ├── flags: ∅
            │   └── name: "foo"
            └── operator_loc: (90...91) = "="
