Constant STACK_GRAPHS_TSG_SOURCE

Source
pub const STACK_GRAPHS_TSG_SOURCE: &str = ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Stack graphs definition for JavaScript\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n;; Global Variables\n;; ^^^^^^^^^^^^^^^^\n\nglobal ROOT_NODE\nglobal JUMP_TO_SCOPE_NODE\n\nglobal FILE_PATH\nglobal PROJECT_NAME = \"\"\n\n\n;; Attribute Shorthands\n;; ^^^^^^^^^^^^^^^^^^^^\n\nattribute node_definition = node        => type = \"pop_symbol\", node_symbol = node, is_definition\nattribute node_reference = node         => type = \"push_symbol\", node_symbol = node, is_reference\nattribute pop_node = node               => type = \"pop_symbol\", node_symbol = node\nattribute pop_scoped_node = node        => type = \"pop_scoped_symbol\", node_symbol = node\nattribute pop_scoped_symbol = symbol    => type = \"pop_scoped_symbol\", symbol = symbol\nattribute pop_symbol = symbol           => type = \"pop_symbol\", symbol = symbol\nattribute push_node = node              => type = \"push_symbol\", node_symbol = node\nattribute push_scoped_node = node       => type = \"push_scoped_symbol\", node_symbol = node\nattribute push_scoped_symbol = symbol   => type = \"push_scoped_symbol\", symbol = symbol\nattribute push_symbol = symbol          => type = \"push_symbol\", symbol = symbol\nattribute scoped_node_definition = node => type = \"pop_scoped_symbol\", node_symbol = node, is_definition\nattribute scoped_node_reference = node  => type = \"push_scoped_symbol\", node_symbol = node, is_reference\nattribute symbol_definition = symbol    => type = \"pop_symbol\", symbol = symbol, is_definition\nattribute symbol_reference = symbol     => type = \"push_symbol\", symbol = symbol, is_reference\n\nattribute node_symbol = node            => symbol = (source-text node), source_node = node\n\n;; Stack Graph Rules\n;; ^^^^^^^^^^^^^^^^^\n\n;; # JavaScript\n\n;; This file defines StackGraph queries for JavaScript. It is written as a\n;; semi-literate file, which is to say, comments starting with `;;` can be\n;; treated as Markdown. This file can therefore be converted into a\n;; corresponding pure Markdown document by removing the StackGraph comments, and\n;; wrapping the uncommented code in Markdown code blocks.\n\n;; This file has a number of sections that it\'s divided into, and it\'s useful to\n;; provide an overview here. Aside from conventions, the queries are broken up\n;; into groups by what kind of syntactic objects the group covers. There are\n;; Programs, Statements, Expressions, Patterns, and Special Cases.\n\n;; Within each major section, we break things down by the particular syntactic\n;; form under consideration. Some particular syntactic forms are not one of the\n;; main forms listed, but are tightly associated with other forms -- for\n;; example, the branches of an `if` statement are not statements nor\n;; expressions, they\'re simply components of an `if` statement. In that\n;; situation, we group them with the primary statement that they\'re associated\n;; with, where possible, and nearby when not.\n\n;; Additionally, some syntactic constructs have arbitrary numbers of child\n;; nodes,  which requires us to explain how to relate them as sequences of\n;; nodes. In such cases, we have associated queries with the node type in\n;; question.\n\n;; ## Design Conventions\n\n;; The general convention for how JavaScript is translated into a Stack Graph is\n;; to treat the graph as a reverse Control Flow Graph. There are some corner\n;; cases for which that analogy doesn\'t quite work, but it\'s sufficient for\n;; conveying the overall approach. Many things matter for name resolution in a\n;; Control Flow Graph, but one of the only ones we can really encode into a\n;; Stack Graph, and arguably the most important one, is the flow of the variable\n;; environment, and so we create scope nodes for those.\n\n;; In particular, for each node, during an execution traversal, there is an\n;; incoming variable environment that the node will be executed in, and an\n;; outgoing variable environment that resulted from executing the node and all\n;; the various variable assignments and updates inside it.\n\n;; An example helps, so let\'s consider a simplified case: `if` statement with a\n;; mandatory `else` branch. If we were to implement an execution function for\n;; this fictionalized language, there would be some environment that goes into\n;; the execution at the whole `if-then-else` statement, an environment that goes\n;; into the evaluation of the test, an environment that comes out of the test\n;; (because the test could be something like `x++` which changes the\n;; environment), an environment which goes into each branch (which happens to be\n;; the same one that came out of the test), and an environment that comes out of\n;; each of the branches. So each major AST node has a pair of environments\n;; associated with it: the incoming one to execute it in, and the outcoming node\n;; that resulted from executing.\n\n;; We therefore would implement `if-then-else` statements like so:\n\n;; ``````stgdoc\n;; (if_then_else\n;;   (_)@test\n;;   (_)@consequent\n;;   (_)alternative)@if_stmt {\n;;\n;;   edge @test.before_scope -> @if_stmt.before_scope\n;;   edge @consequent.before_scope -> @test.after_scope\n;;   edge @alternative.before_scope -> @test.after_scope\n;;   edge @if_stmt.after_scope -> @consequent.after_scope\n;;   edge @if_stmt.after_scope -> @alternative.after_scope\n;;\n;; }\n;; ``````\n;;\n;; Another important way that things build scopes is through values. When an\n;; expression is executed and returns a value, that value in many ways acts like\n;; a sub-environment, at least in that the value has different parts that can be\n;; accessed in various ways. For a simple value, as constructed by a number\n;; literal expression, the number itself has no parts. So it has an associated\n;; value scope node in the graph, but no edges coming off that:\n\n;; ``````stgdoc\n;; (number)@num {\n;;   attr (@num.value) pop_symbol = \"NUM_VAL\"\n;; }\n;; ``````\n\n;; Why we use a `pop` attribute here isn\'t deeply important so we\'ll gloss over\n;; it.\n\n;; All kinds of expressions have values, what precisely goes into them depends\n;; on what the expression is. Objects, for instance, would have corresponding\n;; values that point to the values of each of the keys in the object. Arrays\n;; would have values that point to the values of each of the indexes.\n\n;; The primary purpose of values is to act as the targets of assignments, so\n;; that names can resolve to something in code. Normally we care only about the\n;; location of the assignment, of course, but we also need to be able to do\n;; further lookup on the values. For instance, in an expression like `x.y.z`,\n;; we need to look up `x` of course, but also then further look up `y` on that,\n;; and then `z`. So whatever `x` is assigned to has to also be present in the\n;; graph as something which can itself have stuff hanging off it that can be\n;; used for lookup.\n\n;; If you were to run some JavaScript to test whether or not number literals\n;; have parts (really, members/fields), you\'d discover that actually they do,\n;; but not because of which number they are. Rather, their parts are for builtin\n;; functionality like `toString`. To handle this, we can point the value to some\n;; shared global variable that represents the prototype for the number, like so:\n\n;; ``````stgdoc\n;; (number)@num {\n;;   attr (@num.value) pop_symbol = \"NUM_VAL\"\n;;   edge @num.value -> @num.number_prototype\n;; }\n;; ``````\n\n;; In the preamble definition for the `program` node type, we could then also\n;; want to define number prototype, something like this:\n\n;; ``````stgdoc\n;; inherit .number_prototype\n;;\n;; (program)@prog {\n;;\n;;   ...\n;;\n;;   node @prog.number_prototype\n;;   edge @prog.number_prototype -> @prog.number_prototype_toString_method_value\n;;   edge @prog.number_prototype -> @prog.number_prototype_valueOf_method_value\n;;   ...etc\n;;\n;;   ...\n;;\n;; }\n;; ``````\n\n;; We would then also want to have a bunch of hand-encoded graphs for the values\n;; of those fields. That would then allow the number values to point to their\n;; prototypes where the fields could be found and used for further lookup on\n;; methods.\n\n;; One caveat of this is that we don\'t want to get too deep into explaining how\n;; some method might be implemented. Indeed, sometimes we *can\'t*, because it\'s\n;; not implementable in JavaScript at all and is instead some primitive function\n;; implemented in the host language. What we want to do, instead, is to provide\n;; just enough implementation that other data can flow through as much as\n;; possible, to prevent calls to primitive methods from blocking downstream name\n;; resolution. For instance, it would be unfortunate if calling `toString` on a\n;; number did not let you look up string fields on the resultant value of the\n;; call, i.e. if `length` in `(5).toString().length` just simply could not be\n;; resolved at all. In such cases, the ideal approach is to implement a bare\n;; minimum of `toString` so that we can recover the fact that its returned\n;; value is a string. E.g.:\n\n;; ``````stgdoc\n;; (program)@prog {\n;;\n;;   ...\n;;\n;;   edge @prog.number_prototype -> @prog.number_prototype_toString_method_value\n;;   edge @prog.number_prototype_toString_method_value -> @prog.number_prototype_toString_method_value_return\n;;   attr (@prog.number_prototype_toString_method_value_return) pop_symbol = \"GUARD:RETURN\"\n;;   edge @prog.number_prototype_toString_method_value_return -> @prog.string_prototype\n;;\n;;   ...\n;;\n;; }\n;; ``````\n\n;; As currently implemented, this document does not contain any rules for\n;; builtins because of the scope of that task, but they are currently in the\n;; pipeline, using the above approach.\n\n;; Something you may notice in the above code snippet is this pop node labelled\n;; `GUARD:RETURN`. This is another part of the design conventions for this\n;; library. We often want to use nodes in the graph to constrain name lookup.\n;; In this case, we want to be able to pinpoint some of the graph nodes\n;; associated with the body of a function as being the values returned by the\n;; function. We do this by creating a so-called guard node, which will only be\n;; traversed if there is a corresponding push somewhere else. We would generate\n;; such a push node precisely when we call a function. This lets us treat the\n;; function *ASTs* as if they have parts that we can inspect *in the graph*.\n\n;; By convention, this library of queries prefixes all guard nodes with \"GUARD:\"\n;; to distinguish them from nodes that more directly correspond to aspects of\n;; execution such as member lookup (labelled with \"GUARD:MEMBER\") or variable lookup\n;; (labelled with the variable name itself). The current names used for guard\n;; nodes are\n\n;; - `GUARD:CONSTRUCTOR` - used for the constructor method inside a `Class`\n;; - `GUARD:DEFAULT` - used for the default export value\n;; - `GUARD:EXPORTS` - used for the names exported by the module\n;; - `GUARD:GANDALF` - used for situations where parts of a graph must be accessible\n;;   in order to avoid pruning, but which never the less should not be actually reached\n;;   during any normal traversals. By only ever popping, and never pushing, we can get\n;;   a connected subgraph that is never the less never traversed.\n;; - `GUARD:LABEL` - used for the names of labels\n;; - `GUARD:MEMBER` - used for the members/fields/properties of objects\n;; - `GUARD:MODULE` - used for module names\n;; - `GUARD:RETURN` - used for the AST nodes for values returned by a function\n;;   in the function body\n;; - `GUARD:THIS` - used for the implicit `this` argument of a function inside\n;; - `GUARD:PKG_INTERNAL` - used for the package internal structure that should not\n;;   be accessible directly from the root\n\n; ## Inherited\n\ninherit .builtins_Regex_prototype\ninherit .builtins_arguments_prototype\ninherit .builtins_boolean\ninherit .builtins_empty_object\ninherit .builtins_null\ninherit .builtins_number\ninherit .builtins_string\ninherit .builtins_undefined\ninherit .class_value\ninherit .constructor\ninherit .export_statement\ninherit .exports\ninherit .hoist_point\ninherit .closure_point\ninherit .import_statement\ninherit .pkg_pop\ninherit .pkg_push\ninherit .return_or_yield\ninherit .containing_class_value\n\n\n\n\n\n\n\n\n\n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}       \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}  \u{2588}\u{2588}      \u{2588}\u{2588} \n;; \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; ## Programs\n\n;; ### Attributes Defined on Programs\n;; TODO\n\n(program)@prog {\n  node @prog.after_scope\n  node @prog.before_scope\n  let @prog.closure_point = @prog.after_scope\n\n  ; apparently it\'s perfectly cromulent to `return` from the top level scope (because control flow happens there too), so we make a top-level return node.\n  node @prog.return_or_yield\n}\n\n;; ### Program Queries\n\n(program)@prog {\n\n    node prog_module_pop\n    node prog_exports_pop\n    node prog_pkg_pop_guard\n    node prog_pkg_push_guard\n    node prog_legacy_qname_guard\n    node @prog.exports\n    node @prog.hoist_point\n    node @prog.pkg_pop\n    node @prog.pkg_push\n\n    attr (prog_pkg_pop_guard) pop_symbol = \"GUARD:PKG_INTERNAL\"\n    attr (@prog.pkg_pop) pop_symbol = PROJECT_NAME\n    edge ROOT_NODE -> prog_pkg_pop_guard\n    edge prog_pkg_pop_guard -> @prog.pkg_pop\n\n    attr (@prog.pkg_push) push_symbol = PROJECT_NAME\n    attr (prog_pkg_push_guard) push_symbol = \"GUARD:PKG_INTERNAL\"\n    edge @prog.pkg_push -> prog_pkg_push_guard\n    edge prog_pkg_push_guard -> ROOT_NODE\n\n    node module_guard_pop\n    attr (module_guard_pop) pop_symbol = \"GUARD:MODULE\"\n    edge @prog.pkg_pop -> module_guard_pop\n\n    node prog_module_pop_start\n    edge module_guard_pop -> prog_module_pop_start\n    var module_pop_end = prog_module_pop_start\n    let module_name = (replace FILE_PATH \"\\.js$\" \"\")\n    scan module_name {\n      \"([^/]+)/\" {\n        attr (module_pop_end) pop_symbol = $1\n        node module_pop_end_next\n        edge module_pop_end -> module_pop_end_next\n        set module_pop_end = module_pop_end_next\n      }\n      \"([^/]+)$\" {\n        attr (module_pop_end) symbol_definition = $1, source_node = @prog\n        attr (module_pop_end) empty_source_span\n        attr (module_pop_end) definiens_node = @prog\n      }\n    }\n\n    edge @prog.before_scope -> @prog.pkg_push\n    edge @prog.before_scope -> @prog.hoist_point\n\n\n    attr (prog_legacy_qname_guard) push_symbol = \"GUARD:LEGACY_QNAME\"\n    edge @prog.before_scope -> prog_legacy_qname_guard\n    edge prog_legacy_qname_guard -> ROOT_NODE\n\n    attr (prog_module_pop) empty_source_span\n    attr (@prog.exports) empty_source_span\n    attr (prog_exports_pop) empty_source_span\n    attr (@prog.before_scope) empty_source_span\n    attr (@prog.after_scope) empty_source_span\n\n    attr (prog_exports_pop) pop_symbol = \"GUARD:EXPORTS\"\n    edge module_pop_end -> prog_exports_pop\n    edge prog_exports_pop -> @prog.exports\n\n    ;; builtin types\n    node @prog.builtins_number\n    node @prog.builtins_string\n    node @prog.builtins_boolean\n    node @prog.builtins_null\n    node @prog.builtins_undefined\n    node @prog.builtins_Regex_prototype\n    node @prog.builtins_arguments_prototype\n    node @prog.builtins_empty_object\n    ; !!!! HACK\n    ; stack graphs currently make it impossible to test if an inherited variable\n    ; like this is defined or not\n    let @prog.containing_class_value = @prog.builtins_null\n\n}\n\n; programs, first statement\n(program\n  .\n  (_)@first_stmt)@prog {\n\n  ; scopes flow from the program into the first statement\n  edge @first_stmt.before_scope -> @prog.before_scope\n}\n\n; program, between statements\n(program\n  (_)@left_stmt\n  .\n  (_)@right_stmt) {\n\n  ; scopes flow from the left statement to the right one\n  edge @right_stmt.before_scope -> @left_stmt.after_scope\n}\n\n; program, last statement\n(program\n  (_)@last_stmt\n  .)@prog {\n\n  ; scopes flow from the last statement to the program\n  edge @prog.after_scope -> @last_stmt.after_scope\n}\n\n(hash_bang_line)@hashbang {\n  node @hashbang.after_scope\n  node @hashbang.before_scope\n  edge @hashbang.after_scope -> @hashbang.before_scope\n}\n\n(comment)@comment {\n  node @comment.after_scope\n  node @comment.before_scope\n  node @comment.value\n  node @comment.covalue\n  node @comment.new_bindings ; for object patterns\n  edge @comment.after_scope -> @comment.before_scope\n  node @comment.source ; for export clauses with multiple exports\n}\n\n(identifier) @identifier {\n  node @identifier.before_scope\n  node @identifier.after_scope\n  node @identifier.value\n  node @identifier.covalue\n  node @identifier.new_bindings\n  edge @identifier.after_scope -> @identifier.before_scope\n}\n\n\n\n\n\n\n\n\n\n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}         \u{2588}\u{2588}    \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;;      \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \u{2588}\u{2588}  \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588}         \u{2588}\u{2588} \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; ## Statements\n\n;; ### Attributes Defined on Statements\n;; TODO\n\n[\n  (export_statement)\n  (import_statement)\n  (debugger_statement)\n  (expression_statement)\n  (function_declaration)\n  (generator_function_declaration)\n  (class_declaration)\n  (lexical_declaration)\n  (variable_declaration)\n  (statement_block)\n  (if_statement)\n  (switch_statement)\n  (for_statement)\n  (for_in_statement)\n  (while_statement)\n  (do_statement)\n  (try_statement)\n  (with_statement)\n  (break_statement)\n  (continue_statement)\n  (return_statement)\n  (throw_statement)\n  (empty_statement)\n  (labeled_statement)\n]@stmt {\n  node @stmt.after_scope\n  node @stmt.before_scope\n}\n\n;; ### Statement Queries\n\n\n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}       \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}     \u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}     \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}       \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}      \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}         \u{2588}\u{2588} \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}       \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; #### Export\n\n(export_statement)@export_stmt {\n  let @export_stmt.export_statement = @export_stmt\n}\n\n; exports of just names\n; eg\n;  export { foo, bar as baz };\n(export_statement\n  (export_clause)@export_clause\n  !source)@export_stmt {\n\n  edge @export_clause.source -> @export_clause.before_scope\n\n  ; scope flows through the export clause\n  edge @export_clause.before_scope -> @export_stmt.before_scope\n  edge @export_stmt.after_scope -> @export_clause.after_scope\n}\n\n(export_statement\n  (export_clause)@export_clause\n  source:(_)@source)@export_stmt {\n\n  edge @export_clause.source -> @source.exports\n\n  edge @export_clause.before_scope -> @export_stmt.before_scope\n  edge @export_stmt.after_scope -> @export_clause.after_scope\n}\n\n(export_statement\n  (declaration)@decl)@export_stmt {\n\n  edge @decl.before_scope -> @export_stmt.before_scope\n  edge @export_stmt.after_scope -> @decl.after_scope\n\n}\n\n(export_statement \"default\"\n  (declaration)@decl)@export_stmt {\n\n  node pop_guard_default\n  attr (pop_guard_default) symbol_definition = \"GUARD:DEFAULT\", source_node = @decl, definiens_node = @export_stmt\n  edge @export_stmt.exports -> pop_guard_default\n  ;; edge export_stmt_pop_guard_default -> @decl.value ;; FIXME declarations have no .value\n\n  ; !!!! HACK These detour nodes are a massive hack to allow find all refs land on defs\n  ; for the default values of modules that have useful names like the module name or\n  ; package name\n\n  node detour_push\n  node detour_pop\n\n  scan FILE_PATH {\n\n    \"^(.+/)?([^/]+)/index\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (detour_pop) symbol_definition = module_name, source_node = @decl, definiens_node = @export_stmt\n      edge pop_guard_default -> detour_push\n      edge detour_push -> detour_pop\n      ; edge detour_pop -> @decl.value ;; FIXME declarations have no .value\n    }\n\n    \"^(.+/)?([^/]+)\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (detour_pop) symbol_definition = module_name, source_node = @decl, definiens_node = @export_stmt\n      edge pop_guard_default -> detour_push\n      edge detour_push -> detour_pop\n      ; edge detour_pop -> @decl.value ;; FIXME declarations have no .value\n    }\n\n  }\n\n  node default_detour_push\n  node default_detour_pop\n\n  attr (default_detour_push) push_symbol = \"default\"\n  attr (default_detour_pop) symbol_definition = \"default\", source_node = @decl, definiens_node = @export_stmt\n  edge pop_guard_default -> default_detour_push\n  edge default_detour_push -> default_detour_pop\n  ; edge default_detour_pop -> @decl.value ;; FIXME declarations have no .value\n\n}\n\n(export_statement \"default\"\n  value:(_)@value)@export_stmt {\n\n  node @export_stmt.pop_guard_default\n  attr (@export_stmt.pop_guard_default) symbol_definition = \"GUARD:DEFAULT\", source_node = @value, definiens_node = @export_stmt\n  edge @export_stmt.exports -> @export_stmt.pop_guard_default\n  edge @export_stmt.pop_guard_default -> @value.value\n\n  ; !!!! HACK These detour nodes are a massive hack to allow find all refs land on defs\n  ; for the default values of modules that have useful names like the module name or\n  ; package name\n\n  node detour_push\n  node @export_stmt.detour_pop\n\n  scan FILE_PATH {\n\n    \"^(.+/)?([^/]+)/index\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (@export_stmt.detour_pop) symbol_definition = module_name, source_node = @value, definiens_node = @export_stmt\n      edge @export_stmt.pop_guard_default -> detour_push\n      edge detour_push -> @export_stmt.detour_pop\n      edge @export_stmt.detour_pop -> @value.value\n    }\n\n    \"^(.+/)?([^/]+)\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (@export_stmt.detour_pop) symbol_definition = module_name, source_node = @value, definiens_node = @export_stmt\n      edge @export_stmt.pop_guard_default -> detour_push\n      edge detour_push -> @export_stmt.detour_pop\n      edge @export_stmt.detour_pop -> @value.value\n    }\n\n  }\n\n  node default_detour_push\n  node @export_stmt.default_detour_pop\n\n  attr (default_detour_push) push_symbol = \"default\"\n  attr (@export_stmt.default_detour_pop) symbol_definition = \"default\", source_node = @value, definiens_node = @export_stmt\n  edge @export_stmt.pop_guard_default -> default_detour_push\n  edge default_detour_push -> @export_stmt.default_detour_pop\n  edge @export_stmt.default_detour_pop -> @value.value\n\n}\n\n(export_statement\n  declaration: [\n    (function_declaration name:(identifier)@name)\n    (generator_function_declaration name:(identifier)@name)\n    (class_declaration name:(identifier)@name)\n    (lexical_declaration (variable_declarator name:(identifier)@name))\n    (variable_declaration (variable_declarator name:(identifier)@name))\n  ]@_decl)@export_stmt {\n\n  ; TODO this doesn\'t support destructuring exports\n\n  edge @export_stmt.exports -> @name.pop\n\n}\n\n; TODO\n; export let [x,y] = [1,2];\n(export_statement\n  declaration: [\n    (lexical_declaration\n      (variable_declarator\n        name: [\n          (object_pattern)\n          (array_pattern)\n        ]@pattern))\n    (variable_declaration\n      (variable_declarator\n        name: [\n          (object_pattern)\n          (array_pattern)\n        ]@pattern))\n  ])@export_stmt {\n\n  edge @export_stmt.exports -> @pattern.new_bindings\n\n}\n\n(export_clause)@export_clause {\n  node @export_clause.after_scope\n  node @export_clause.before_scope\n  node @export_clause.source\n}\n\n(export_clause (_)* @clauses)@export_clause {\n  if (is-empty @clauses) {\n    edge @export_clause.after_scope -> @export_clause.before_scope\n  }\n}\n\n(export_clause\n  (_)@export)@export_clause {\n\n  edge @export.source -> @export_clause.source\n}\n\n(export_clause\n  .\n  (_)@first_export)@export_clause {\n\n  edge @first_export.before_scope -> @export_clause.before_scope\n}\n\n(export_clause\n  (_)@left_export\n  .\n  (_)@right_export) {\n\n  edge @right_export.before_scope -> @left_export.after_scope\n}\n\n(export_clause\n  (_)@last_export\n  .)@export_clause {\n\n  edge @export_clause.after_scope -> @last_export.after_scope\n}\n\n;; Export specifiers have several cases:\n;;  - the reference into the source module can be default or named\n;;  - the definition from this module can be default or named.\n;;\n;; We model this using seperate sets of rules, two rules for the reference,\n;; and two rules for the definition. The `.def_to_ref` node is used to connect\n;; the two.\n\n(export_specifier)@export_specifier {\n\n  node @export_specifier.after_scope\n  node @export_specifier.before_scope\n  node @export_specifier.def_to_ref\n  node @export_specifier.source\n\n  edge @export_specifier.after_scope -> @export_specifier.before_scope\n\n}\n\n;; Export specifier reference rules\n\n; export { default } from ...\n; export { default as ... } from ...\n(\n  (export_specifier\n    name:(_)@name\n  )@export_specifier\n\n  (#not-eq? @name \"default\")\n) {\n\n  node name_push\n  attr (name_push) node_reference = @name\n  edge @export_specifier.def_to_ref -> name_push\n  edge name_push -> @export_specifier.source\n\n}\n\n; export { foo } from ...\n; export { foo as ... } from ...\n(\n  (export_specifier\n    name:(_)@name\n  )@export_specifier\n\n  (#eq? @name \"default\")\n) {\n\n  node push_guard_default\n\n  attr (push_guard_default) symbol_reference = \"GUARD:DEFAULT\", source_node = @name\n  edge @export_specifier.def_to_ref -> push_guard_default\n  edge push_guard_default -> @export_specifier.source\n\n}\n\n;; Export specifier definition rules\n\n; export { foo } from ...\n; export { ... as foo } from ...\n( [\n    (export_specifier\n      name:(_)@alias\n      !alias)@export_specifier\n    (export_specifier\n      name:(_)\n      alias:(_)@alias)@export_specifier\n  ]\n\n  (#not-eq? @alias \"default\")\n) {\n\n  node name_pop\n\n  attr (name_pop) node_definition = @alias, definiens_node = @export_specifier.export_statement\n  edge @export_specifier.exports -> name_pop\n  edge name_pop -> @export_specifier.def_to_ref\n\n}\n\n; export { default } from ...\n; export { ... as default } from ...\n( [\n    (export_specifier\n      name:(_)@alias\n      !alias)@export_specifier\n    (export_specifier\n      name:(_)\n      alias:(_)@alias)@export_specifier\n  ]\n\n  (#eq? @alias \"default\")\n) {\n\n  node pop_guard_default\n\n  attr (pop_guard_default) symbol_definition = \"GUARD:DEFAULT\", source_node = @alias, definiens_node = @export_specifier.export_statement\n  edge @export_specifier.exports -> pop_guard_default\n  edge pop_guard_default -> @export_specifier.def_to_ref\n\n}\n\n; simple default exports\n; export default ...;\n\n(export_statement\n  value:(_)@default_expr)@export_stmt {\n\n  edge @default_expr.before_scope -> @export_stmt.before_scope\n  edge @export_stmt.after_scope -> @default_expr.after_scope\n\n}\n\n; aggregated exports\n; export * from \"foo.js\";\n(export_statement\n  .\n  source:(_)@source)@export_statement {\n\n  edge @export_statement.after_scope -> @export_statement.before_scope\n\n  edge @export_statement.exports -> @source.exports\n\n}\n\n; namespace exports\n; export * as foo from \"bar.js\";\n(export_statement\n  (namespace_export (_)@alias)\n  source:(_)@source)@export_statement {\n\n  node alias_pop\n  node alias_pop_dot\n  node source_push\n  node source_push_guard_exports\n\n  edge @export_statement.after_scope -> @export_statement.before_scope\n\n  attr (alias_pop) node_definition = @alias, definiens_node = @export_statement.export_statement\n  attr (alias_pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge @export_statement.exports -> alias_pop\n  edge alias_pop -> alias_pop_dot\n  edge alias_pop_dot -> @source.exports\n\n}\n\n\n\n;; \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \n;; \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}     \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}         \u{2588}\u{2588} \n;; \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}       \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; #### Import\n\n;; We distinguish two kinds of imports, based on the shape of the path:\n;;\n;;  - Relative imports, whose path starts with `.` or `..`. These are resolved relative\n;;    to the current module, in the same package.\n;;  - Non-relative or bare imports, which do not start with `.`, `..`, or `/`. These are\n;;    resolved as package names. Note that the package definitions are introduced in the\n;;    Go code based on `package.json`, not in this query file.\n;;\n;; Import paths may include optional `.js` extensions, but behave the same regardless of\n;; whether the extension is present.\n;;\n;; ## Limitations\n;;\n;;  - Absolute imports, whose paths start with `/`, are not supported.\n;;  - Non-relative imports can resolve into a package (i.e., start with package name\n;;    components and then module name components inside that package). However, because\n;;    we don\'t detect source roots for JavaScript, this might not always work. For example,\n;;    a module `mod.js` inside a `src/` directory of package `foo` would be accessible as\n;;    `foo/src/mod`, while `foo/mod` is probably intended.\n;;\n;; ## References\n;;\n;;  - ES6: https://nodejs.org/api/esm.html, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import\n;;  - CommonJS: https://nodejs.org/api/modules.html\n\n(import_statement)@import_stmt {\n  let @import_stmt.import_statement = @import_stmt\n}\n\n[\n  (import_statement source:(_)@source)\n  (export_statement source:(_)@source)\n  ( (call_expression function:(_)@_require arguments:(arguments (string)@source)) (#eq? @_require \"require\") )\n  ( (call_expression function:(_)@_import arguments:(arguments (string)@source)) (#eq? @_import \"import\") )\n] {\n\n  node source_push_guard_exports\n  node source_push_guard_pkg\n  node @source.exports\n\n  attr (source_push_guard_exports) push_symbol = \"GUARD:EXPORTS\"\n\n  scan (source-text @source) {\n    \"^[\\\"\']((\\.|\\.\\.)/.*)[\\\"\']$\" {\n      ; relative import\n      let name = (replace (path-normalize (path-join (path-dir FILE_PATH) $1)) \"\\.js$\" \"\")\n\n      node module_guard_push\n      attr (module_guard_push) push_symbol = \"GUARD:MODULE\"\n      edge module_guard_push -> @source.pkg_push\n\n      node source_push_end\n      edge source_push_end -> module_guard_push\n      var push_start = source_push_end\n      scan name {\n        \"([^/]+)/\" {\n          attr (push_start) push_symbol = $1\n          node push_start_prev\n          edge push_start_prev -> push_start\n          set push_start = push_start_prev\n        }\n        \"([^/]+)$\" {\n          attr (push_start) push_symbol = $1\n        }\n      }\n      scan $1 {\n        \"/$\" {\n          node push_start_prev\n          edge push_start_prev -> push_start\n          set push_start = push_start_prev\n          attr (push_start) push_symbol = \"index\"\n        }\n      }\n      attr (push_start) is_reference, source_node = @source\n\n      edge source_push_guard_exports -> push_start\n    }\n    \"^[\\\"\']([^\\./].*)[\\\"\']$\" {\n      ; package import\n      let name = (replace $1 \"\\.js$\" \"\")\n\n      node source_push_end\n      var push_start = source_push_end\n      scan name {\n        \"([^/]+)/\" {\n          attr (push_start) push_symbol = $1\n          node push_start_prev\n          edge push_start_prev -> push_start\n          set push_start = push_start_prev\n        }\n        \"([^/]+)$\" {\n          attr (push_start) symbol_reference = $1, source_node = @source\n        }\n      }\n\n      edge source_push_guard_exports -> push_start\n      edge source_push_end -> source_push_guard_pkg\n      attr (source_push_guard_pkg) push_symbol = \"GUARD:PKG\"\n      edge source_push_guard_pkg -> @source.pkg_push\n    }\n  }\n\n  edge @source.exports -> source_push_guard_exports\n\n}\n\n; import \"foo.js\";\n; only used for side effects not imports.\n(import_statement . source:(_))@import_stmt {\n  edge @import_stmt.after_scope -> @import_stmt.before_scope\n}\n\n(import_clause)@import_clause {\n  node @import_clause.after_scope\n  node @import_clause.before_scope\n  node @import_clause.source\n}\n\n; import * as name from \"module-name\";\n(import_clause\n  (namespace_import)@namespace_import)@import_clause {\n\n  edge @namespace_import.before_scope -> @import_clause.before_scope\n  edge @import_clause.after_scope -> @namespace_import.after_scope\n  edge @namespace_import.source -> @import_clause.source\n}\n\n(namespace_import (identifier)@imported_as)@namespace_import {\n\n  node imported_as_pop\n  node imported_as_pop_dot\n  node @namespace_import.after_scope\n  node @namespace_import.before_scope\n  node @namespace_import.source\n\n  edge @namespace_import.after_scope -> @namespace_import.before_scope\n\n  attr (imported_as_pop) node_definition = @imported_as, definiens_node = @namespace_import.import_statement\n  attr (imported_as_pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge imported_as_pop -> imported_as_pop_dot\n  edge imported_as_pop_dot -> @namespace_import.source\n\n  edge @namespace_import.after_scope -> imported_as_pop\n\n}\n\n; import { export1 } from \"module-name\";\n; import { export1 as alias1 } from \"module-name\";\n; import { export1 , export2 } from \"module-name\";\n; import { export1 , export2 as alias2 , [...] } from \"module-name\";\n\n(import_statement\n  (import_clause)@import_clause\n  source:(_)@source)@import_stmt {\n\n  edge @import_stmt.after_scope -> @import_stmt.before_scope\n\n  edge @import_clause.before_scope -> @import_stmt.before_scope\n  edge @import_stmt.hoist_point -> @import_clause.after_scope\n\n  edge @import_clause.source -> @source.exports\n\n}\n\n(import_clause\n  (named_imports)@named_imports)@import_clause {\n\n  edge @named_imports.before_scope -> @import_clause.before_scope\n  edge @import_clause.after_scope -> @named_imports.after_scope\n  edge @named_imports.source -> @import_clause.source\n\n}\n\n(named_imports)@named_imports {\n  node @named_imports.after_scope\n  node @named_imports.before_scope\n  node @named_imports.source\n}\n\n(named_imports (_)* @specs)@named_imports {\n  if (is-empty @specs) {\n    edge @named_imports.after_scope -> @named_imports.before_scope\n  }\n}\n\n(named_imports\n  (import_specifier)@import_specifier)@named_imports {\n\n  edge @import_specifier.source -> @named_imports.source\n}\n\n(named_imports\n  .\n  (import_specifier)@first_import)@named_imports {\n\n  edge @first_import.before_scope -> @named_imports.before_scope\n}\n\n(named_imports\n  (import_specifier)@left_import\n  .\n  (import_specifier)@right_import) {\n\n  edge @right_import.before_scope -> @left_import.after_scope\n}\n\n(named_imports\n  (import_specifier)@last_import\n  .)@named_imports {\n\n  edge @named_imports.after_scope -> @last_import.after_scope\n}\n\n;; Import specifiers have several cases:\n;;  - the reference into the source module can be default or named\n;;  - the definition from this module can be default or named.\n;; The case where the definition is default instead of named is invalid.\n;;\n;; We model this using seperate sets of rules, two rules for the reference,\n;; and one rules for the definition. The `.def_to_ref` node is used to connect\n;; the two.\n\n(import_specifier)@import_specifier {\n  node @import_specifier.after_scope\n  node @import_specifier.before_scope\n  node @import_specifier.def_to_ref\n  node @import_specifier.source\n\n  edge @import_specifier.after_scope -> @import_specifier.before_scope\n}\n\n;; Import specifier reference rules\n\n(\n  (import_specifier\n    name:(_)@name\n  )@import_specifier\n\n  (#not-eq? @name \"default\")\n) {\n\n  node name_push\n\n  attr (name_push) node_reference = @name\n  edge name_push -> @import_specifier.source\n  edge @import_specifier.def_to_ref -> name_push\n\n}\n\n(\n  (import_specifier\n    name:(_)@name\n  )@import_specifier\n\n  (#eq? @name \"default\")\n) {\n\n  node push_guard_default\n\n  attr (push_guard_default) symbol_reference = \"GUARD:DEFAULT\", source_node = @name\n  edge push_guard_default -> @import_specifier.source\n  edge @import_specifier.def_to_ref -> push_guard_default\n\n}\n\n;; Import specifier definition rules\n\n( [\n    (import_specifier\n      name:(_)@alias\n      !alias)@import_specifier\n    (import_specifier\n      name:(_)\n      alias:(_)@alias)@import_specifier\n  ]\n\n  (#not-eq? @alias \"default\")\n) {\n\n  node name_pop\n\n  attr (name_pop) node_definition = @alias, definiens_node = @import_specifier.import_statement\n  edge name_pop -> @import_specifier.def_to_ref\n  edge @import_specifier.after_scope -> name_pop\n\n}\n\n; (import_statement\n;   (import_clause\n;     (named_imports\n;       (import_specifier\n;         name:(_)@name\n;         alias:(_)@alias)))\n;   source: (_)@mod_name)@import_stmt {\n;\n;   ; scope passes through, augmented by the identifier\n;   scan @mod_name {\n;     \"\\\"([^/\\\"]+)\\.js\\\"$\" {\n;       attr (@mod_name.push) symbol_reference = $1, source_node = @mod_name\n;     }\n;   }\n;   edge @mod_name.push -> @import_stmt.pkg_push\n;\n;   attr (@name) node_reference = @name\n;   attr (name_push_dot) push_symbol = \"GUARD:MEMBER\"\n;   edge name_push_dot -> @mod_name.push\n;   edge name -> @name_push_dot\n;\n;   attr (@alias) node_definition = @alias\n;   edge @alias -> @name\n;\n;   edge @import_stmt.after_scope -> @alias\n; }\n\n\n; TODO import defaultExport, { export1 [ , [...] ] } from \"module-name\";\n; TODO import defaultExport, * as name from \"module-name\";\n; TODO var promise = import(\"module-name\");\n\n; import defaultExport from \"module-name\";\n(import_clause\n  (identifier)@default_name)@import_clause {\n\n  node default_name_pop\n  node default_name_push_guard_default\n\n  edge @import_clause.after_scope -> @import_clause.before_scope\n\n  attr (default_name_pop) node_definition = @default_name, definiens_node = @import_clause.import_statement\n  attr (default_name_push_guard_default) symbol_reference = \"GUARD:DEFAULT\", source_node = @default_name\n  edge default_name_pop -> default_name_push_guard_default\n  edge default_name_push_guard_default -> @import_clause.source\n\n  edge @import_clause.after_scope -> default_name_pop\n\n}\n\n\n\n;; \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}                                        \n;; \u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}                                        \n;; \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}                                        \n;; \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}                                        \n;; \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}                                   \n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}         \u{2588}\u{2588}    \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;;      \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}      \u{2588}\u{2588}  \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588}         \u{2588}\u{2588} \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n\n;; #### Debugger\n\n(debugger_statement)@debugger_stmt {\n  ; scopes flow through unchanged\n  edge @debugger_stmt.after_scope -> @debugger_stmt.before_scope\n}\n\n\n\n;; #### Expression\n\n(expression_statement (_)@inner)@expr_stmt {\n\n  ; scopes flow in then back out\n  edge @inner.before_scope -> @expr_stmt.before_scope\n  edge @expr_stmt.after_scope -> @inner.after_scope\n}\n\n\n\n;; #### Declarations\n\n;; ##### Variable Declarations\n\n(variable_declaration\n  (variable_declarator\n    name:(identifier)@name))@variable_decl\n{\n\n    node @name.pop\n    attr (@name.pop) node_definition = @name\n    edge @variable_decl.after_scope -> @name.pop\n    attr (@variable_decl.after_scope -> @name.pop) precedence = 1\n\n}\n\n(lexical_declaration\n  (variable_declarator\n    name:(identifier)@name))@lexical_decl\n{\n\n    node @name.pop\n    attr (@name.pop) node_definition = @name\n    edge @lexical_decl.after_scope -> @name.pop\n    attr (@lexical_decl.after_scope -> @name.pop) precedence = 1\n\n}\n\n(variable_declaration\n  (variable_declarator\n    !value))@decl {\n\n  edge @decl.after_scope -> @decl.before_scope\n}\n\n(lexical_declaration\n  (variable_declarator\n    !value))@decl {\n\n  edge @decl.after_scope -> @decl.before_scope\n}\n\n(variable_declaration\n  (variable_declarator\n    name:(identifier)@name\n    value:(_)@initializer))@variable_decl\n{\n\n  edge @name.pop -> @initializer.value\n  edge @initializer.before_scope -> @variable_decl.before_scope\n  edge @variable_decl.after_scope -> @initializer.after_scope\n\n}\n\n(lexical_declaration\n  (variable_declarator\n    name:(identifier)@name\n    value:(_)@initializer))@lexical_decl\n{\n\n    edge @name.pop -> @initializer.value\n    edge @initializer.before_scope -> @lexical_decl.before_scope\n    edge @lexical_decl.after_scope -> @initializer.after_scope\n    attr (@lexical_decl.after_scope -> @initializer.after_scope) precedence = 0\n\n}\n\n(variable_declaration\n  (variable_declarator\n    name:[(object_pattern) (array_pattern)]@pat\n    value:(_)@initializer))@decl {\n\n  edge @initializer.before_scope -> @decl.before_scope\n  edge @pat.before_scope -> @initializer.after_scope\n  edge @decl.after_scope -> @pat.after_scope\n\n  edge @pat.covalue -> @initializer.value\n}\n\n(lexical_declaration\n  (variable_declarator\n    name:[(object_pattern) (array_pattern)]@pat\n    value:(_)@initializer))@decl {\n\n  edge @initializer.before_scope -> @decl.before_scope\n  edge @pat.before_scope -> @initializer.after_scope\n  edge @decl.after_scope -> @pat.after_scope\n\n  edge @pat.covalue -> @initializer.value\n}\n\n\n\n;; ##### Function Declarations\n\n(function_declaration\n  name:(_)@name\n  parameters:(_)@call_sig\n  body:(_)@body)@fun_decl {\n\n  node call_sig_arguments_pop\n  node call_sig_arguments_push\n  node call_sig_this_pop\n  node call_sig_this_push\n  node @name.pop\n  node fun_decl_function_value\n  node @fun_decl.return_or_yield\n  node @fun_decl.value_arg_scope\n  node fun_decl_value_call\n  node fun_decl_value_drop\n  node fun_decl_value_return\n  node fun_decl_value_this\n  node fun_decl_value_this_guard\n  let @body.closure_point = @body.after_scope\n\n  attr (@name.pop) syntax_type = \"function\"\n\n  ; scope flows across the decl\n  edge @fun_decl.after_scope -> @fun_decl.before_scope\n\n  ; with an augmentation for the function\n  attr (@name.pop) node_definition = @name\n  edge @fun_decl.hoist_point -> @name.pop\n  edge @name.pop -> fun_decl_function_value\n\n  ; function values have drop nodes that handle closures, that points to the\n  ; before scope for the function\n  attr (fun_decl_value_drop) type = \"drop_scopes\"\n  edge fun_decl_value_drop -> @fun_decl.closure_point\n\n  ; the call sig\'s before scope comes from the drop node then flows into the body\n  edge @call_sig.before_scope -> fun_decl_value_drop\n  attr (call_sig_this_pop) symbol_definition = \"this\", source_node = @call_sig\n  attr (call_sig_this_push) push_symbol = \"this\"\n  edge call_sig_this_pop -> call_sig_this_push\n  edge call_sig_this_push -> @fun_decl.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_this_pop\n  attr (call_sig_arguments_pop) symbol_definition = \"arguments\", source_node = @call_sig\n  attr (call_sig_arguments_push) push_symbol = \"arguments\"\n  edge call_sig_arguments_pop -> call_sig_arguments_push\n  edge call_sig_arguments_push -> @fun_decl.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_arguments_pop\n  edge @body.before_scope -> @call_sig.after_scope\n\n\n  ; function values have call nodes\n  attr (fun_decl_value_call) pop_scoped_symbol = \"()\"\n  edge fun_decl_function_value -> fun_decl_value_call\n\n  ; function values have return nodes which need to be visible for returns\n  attr (fun_decl_value_return) pop_symbol = \"GUARD:RETURN\"\n  edge fun_decl_value_call -> fun_decl_value_return\n  let @body.return_or_yield = fun_decl_value_return\n\n  ; method values have this nodes which need to be visible for constructor calls\n  attr (fun_decl_value_this) push_symbol = \"this\"\n  attr (fun_decl_value_this_guard) pop_symbol = \"GUARD:THIS\"\n  edge fun_decl_value_call -> fun_decl_value_this_guard\n  edge fun_decl_value_this_guard -> fun_decl_value_this\n  edge fun_decl_value_this -> @body.after_scope\n\n  ; function values have a jump node that lets params connect up to actual arguments\n  edge @fun_decl.value_arg_scope -> JUMP_TO_SCOPE_NODE\n}\n\n(function_declaration\n  parameters:\n    (formal_parameters (_)@param))@fun_decl {\n\n  node param_arg_index\n\n  ; parameters jump to the pushed argument scope\n  attr (param_arg_index) push_symbol = (named-child-index @param)\n  edge @param.covalue -> param_arg_index\n  edge param_arg_index -> @fun_decl.value_arg_scope\n}\n\n\n;; ##### Generator Function Declarations\n\n(generator_function_declaration\n  name:(_)@name\n  parameters:(_)@call_sig\n  body:(_)@body)@fun_decl {\n\n  node call_sig_arguments_pop\n  node call_sig_arguments_push\n  node call_sig_this_pop\n  node call_sig_this_push\n  node @name.pop\n  node fun_decl_function_value\n  node @fun_decl.return_or_yield\n  node @fun_decl.value_arg_scope\n  node fun_decl_value_call\n  node fun_decl_value_drop\n  node fun_decl_value_return\n  node fun_decl_value_this\n  node fun_decl_value_this_guard\n  let @body.closure_point = @body.after_scope\n\n  attr (@name.pop) syntax_type = \"function\"\n\n  ; scope flows across the decl\n  edge @fun_decl.after_scope -> @fun_decl.before_scope\n\n  ; with an augmentation for the function\n  attr (@name.pop) node_definition = @name\n  edge @fun_decl.hoist_point -> @name.pop\n  edge @name.pop -> fun_decl_function_value\n\n  ; function values have drop nodes that handle closures, that points to the\n  ; before scope of the declaration\n  attr (fun_decl_value_drop) type = \"drop_scopes\"\n  edge fun_decl_value_drop -> @fun_decl.closure_point\n\n\n  ; the call sig\'s before scope comes from the drop node then flows into the body\n  edge @call_sig.before_scope -> fun_decl_value_drop\n  attr (call_sig_this_pop) symbol_definition = \"this\", source_node = @call_sig\n  attr (call_sig_this_push) push_symbol = \"this\"\n  edge call_sig_this_pop -> call_sig_this_push\n  edge call_sig_this_push -> @fun_decl.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_this_pop\n  attr (call_sig_arguments_pop) symbol_definition = \"arguments\", source_node = @call_sig\n  attr (call_sig_arguments_push) push_symbol = \"arguments\"\n  edge call_sig_arguments_pop -> call_sig_arguments_push\n  edge call_sig_arguments_push -> @fun_decl.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_arguments_pop\n  edge @body.before_scope -> @call_sig.after_scope\n\n  ; function values have call nodes\n  attr (fun_decl_value_call) pop_scoped_symbol = \"()\"\n  edge fun_decl_function_value -> fun_decl_value_call\n\n  ; function values have return nodes which need to be visible for returns\n  attr (fun_decl_value_return) pop_symbol = \"GUARD:RETURN\"\n  edge fun_decl_value_call -> fun_decl_value_return\n  let @body.return_or_yield = fun_decl_value_return\n\n  ; method values have this nodes which need to be visible for constructor calls\n  attr (fun_decl_value_this) push_symbol = \"this\"\n  attr (fun_decl_value_this_guard) pop_symbol = \"GUARD:THIS\"\n  edge fun_decl_value_call -> fun_decl_value_this_guard\n  edge fun_decl_value_this_guard -> fun_decl_value_this\n  edge fun_decl_value_this -> @body.after_scope\n\n  ; function values have a jump node that lets params connect up to actual arguments\n  edge @fun_decl.value_arg_scope -> JUMP_TO_SCOPE_NODE\n}\n\n(generator_function_declaration\n  parameters:\n    (formal_parameters (_)@param))@fun_decl {\n\n  node param_arg_index\n\n  ; parameters jump to the pushed argument scope\n  attr (param_arg_index) push_symbol = (named-child-index @param)\n  edge @param.covalue -> param_arg_index\n  edge param_arg_index -> @fun_decl.value_arg_scope\n}\n\n\n\n;; #### Classes\n\n(class_declaration\n  name:(_)@name\n  body:(_)@body)@class_decl {\n\n  node @name.pop\n  node @class_decl.class_value\n  let @class_decl.containing_class_value = @class_decl.class_value\n  node guard_prototype\n  node @class_decl.prototype\n  node @class_decl.constructor\n\n  attr (@name.pop) syntax_type = \"class\"\n\n  attr (@name.pop) node_definition = @name\n  attr (guard_prototype) pop_symbol = \"GUARD:PROTOTYPE\"\n  edge @class_decl.after_scope -> @name.pop\n  edge @name.pop -> @class_decl.class_value\n  edge @class_decl.class_value -> guard_prototype\n  edge guard_prototype -> @class_decl.prototype\n\n  edge @body.before_scope -> @class_decl.closure_point\n  edge @class_decl.prototype -> @body.after_scope\n  edge @class_decl.after_scope -> @class_decl.before_scope\n}\n\n(class_declaration\n  (class_heritage (_)@name))@class_decl {\n\n  node guard_prototype\n  node guard_constructor\n  attr (guard_prototype) push_symbol = \"GUARD:PROTOTYPE\"\n  attr (guard_constructor) push_symbol = \"GUARD:CONSTRUCTOR\"\n  edge @name.before_scope -> @class_decl.before_scope\n  edge @class_decl.prototype -> guard_prototype\n  edge guard_prototype -> @name.value\n  edge @class_decl.constructor -> guard_constructor\n  edge guard_constructor -> @name.value\n}\n\n\n(class_body)@class_body {\n  node @class_body.after_scope\n  node @class_body.before_scope\n}\n\n(class_body (_)* @decls)@class_body {\n  if (is-empty @decls) {\n    edge @class_body.after_scope -> @class_body.before_scope\n  }\n}\n\n(class_body\n  .\n  (_)@first_decl)@class_body {\n\n  edge @first_decl.before_scope -> @class_body.before_scope\n}\n\n(class_body\n  (_)@left_decl\n  .\n  (_)@right_decl) {\n\n  edge @right_decl.before_scope -> @left_decl.after_scope\n}\n\n(class_body\n  (_)@last_decl\n  .)@class_body {\n\n  edge @class_body.after_scope -> @last_decl.after_scope\n}\n\n(method_definition name:(_)@name)@method_def {\n\n  node @name.pop\n  node @method_def.after_scope\n  node @method_def.before_scope\n  node @method_def.method_value\n\n}\n\n(\n  (method_definition\n    name:(_)@name)@method_def\n  (#eq? @name \"constructor\")\n) {\n\n  ; augmentation for the constructor\n  attr (@name.pop) symbol_definition = \"GUARD:CONSTRUCTOR\", source_node = @name\n  edge @method_def.class_value -> @name.pop\n  edge @name.pop -> @method_def.constructor\n  edge @method_def.constructor -> @method_def.method_value\n}\n\n(\n  (method_definition\n    name:(_)@name)@method_def\n  (#not-eq? @name \"constructor\")\n) {\n\n  node name_pop_dot\n  ; augmentation for the method\n  attr (@name.pop) node_definition = @name\n  attr (name_pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge @method_def.after_scope -> name_pop_dot\n  edge name_pop_dot -> @name.pop\n  edge @name.pop -> @method_def.method_value\n}\n\n(method_definition\n  name:(_)@name\n  parameters:(_)@call_sig\n  body:(_)@body)@method_def {\n\n  node call_sig_arguments_pop\n  node call_sig_arguments_push\n  node @method_def.method_value_arg_scope\n  node method_def_method_value_call\n  node method_def_method_value_drop\n  node method_def_method_value_return\n  node method_def_method_value_this\n  node method_def_method_value_this_guard\n\n  attr (@name.pop) syntax_type = \"method\"\n\n  ; scope flows across the decl\n  edge @method_def.after_scope -> @method_def.before_scope\n\n  ; method values have drop nodes that handle closures, that points to the\n  ; before scope from method def\n  attr (method_def_method_value_drop) type = \"drop_scopes\"\n  edge method_def_method_value_drop -> @method_def.before_scope\n\n  ; the call sig\'s before scope comes from the drop node then flows into the body\n  edge @call_sig.before_scope -> method_def_method_value_drop\n  attr (call_sig_arguments_pop) symbol_definition = \"arguments\", source_node = @call_sig\n  attr (call_sig_arguments_push) push_symbol = \"arguments\"\n  edge call_sig_arguments_pop -> call_sig_arguments_push\n  edge call_sig_arguments_push -> @method_def.method_value_arg_scope\n  edge @call_sig.before_scope -> call_sig_arguments_pop\n  edge @body.before_scope -> @call_sig.after_scope\n\n  ; method values have call nodes\n  attr (method_def_method_value_call) pop_scoped_symbol = \"()\"\n  edge @method_def.method_value -> method_def_method_value_call\n\n  ; method values have return nodes which need to be visible for returns\n  attr (method_def_method_value_return) pop_symbol = \"GUARD:RETURN\"\n  edge method_def_method_value_call -> method_def_method_value_return\n  let @body.return_or_yield = method_def_method_value_return\n\n  ; method values have this nodes which need to be visible for constructor calls\n  attr (method_def_method_value_this) push_symbol = \"this\"\n  attr (method_def_method_value_this_guard) pop_symbol = \"GUARD:THIS\"\n  edge method_def_method_value_call -> method_def_method_value_this_guard\n  edge method_def_method_value_this_guard -> method_def_method_value_this\n  edge method_def_method_value_this -> @body.after_scope\n\n  ; method values have a jump node that lets params connect up to actual arguments\n  edge @method_def.method_value_arg_scope -> JUMP_TO_SCOPE_NODE\n}\n\n(method_definition\n  parameters:\n    (formal_parameters (_)@param))@method_def {\n\n  node param_arg_index\n\n  ; parameters jump to the pushed argument scope\n  attr (param_arg_index) push_symbol = (named-child-index @param)\n  edge @param.covalue -> param_arg_index\n  edge param_arg_index -> @method_def.method_value_arg_scope\n}\n\n\n\n(field_definition)@field_def {\n  node @field_def.after_scope\n  node @field_def.before_scope\n}\n\n(field_definition\n  property:(_)@property)@field_def {\n\n  node @property.pop\n  node property_pop_dot\n\n  attr (@property.pop) node_definition = @property\n  attr (property_pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge @field_def.after_scope -> property_pop_dot\n  edge property_pop_dot -> @property.pop\n}\n\n(field_definition\n  !value)@field_def {\n\n  edge @field_def.after_scope -> @field_def.before_scope\n}\n\n(field_definition\n  property:(_)@property\n  value:(_)@value)@field_def {\n\n  edge @value.before_scope -> @field_def.before_scope\n  edge @field_def.after_scope -> @value.after_scope\n  edge @property.pop -> @value.value\n}\n\n(class_static_block body: (_) @body) @static_block {\n  node @static_block.before_scope\n  node @static_block.after_scope\n\n  edge @body.before_scope -> @static_block.before_scope\n\n  edge @static_block.after_scope -> @static_block.before_scope\n}\n\n\n\n;; #### Statement Block\n\n(statement_block)@statement_block {\n\n  node @statement_block.hoist_point\n  edge @statement_block.before_scope -> @statement_block.hoist_point\n\n}\n\n(statement_block (_)* @stmts)@statement_block {\n  if (is-empty @stmts) {\n    edge @statement_block.after_scope -> @statement_block.before_scope\n  }\n}\n\n; statement block, first statement\n(statement_block\n  .\n  (_)@first_stmt)@block {\n\n  ; scope flows from block to first statement\n  edge @first_stmt.before_scope -> @block.before_scope\n}\n\n; statement block, between statements\n(statement_block\n  (_)@left_stmt\n  .\n  (_)@right_stmt) {\n  ; scope flows from left to right\n  edge @right_stmt.before_scope -> @left_stmt.after_scope\n}\n\n; statement block, last statement\n(statement_block\n  (_)@last_stmt\n  .)@block {\n  ; scope flows from last statement to block\n  edge @block.after_scope -> @last_stmt.after_scope\n}\n\n\n\n\n\n;; #### If\n\n(if_statement\n  consequence:(_)@consequence)@if_stmt {\n\n    let @if_stmt.hoist_point = @consequence.before_scope\n\n}\n\n(if_statement condition:(_)@condition)@if_stmt {\n    ; scopes flow from the if statement to the condition\n    edge @condition.before_scope -> @if_stmt.before_scope\n}\n\n(if_statement\n  condition:(_)@condition\n  consequence:(_)@consequence)@if_stmt\n{\n    ; scopes flow from the condition to the consequence, then to the if statement\n    edge @consequence.before_scope -> @condition.after_scope\n    edge @if_stmt.after_scope -> @consequence.after_scope\n\n}\n\n(if_statement\n  condition:(_)@condition\n  alternative:(_)@alternative)@if_stmt\n{\n    ; scopes flow from the condition to the alternative, then to the if statement\n    edge @alternative.before_scope -> @condition.after_scope\n    edge @if_stmt.after_scope -> @alternative.after_scope\n}\n\n(else_clause)@else_clause {\n    node @else_clause.after_scope\n    node @else_clause.before_scope\n}\n\n(else_clause\n  . (_)@inner)@else_clause {\n\n    let @else_clause.hoist_point = @inner.before_scope\n\n}\n\n(else_clause (_)@inner)@else_clause {\n    ; scopes flow in and right back out\n    edge @inner.before_scope -> @else_clause.before_scope\n    edge @else_clause.after_scope -> @inner.after_scope\n}\n\n\n\n\n;; #### Switch\n\n(switch_statement\n  value:(_)@value\n  body:(switch_body)@body)@switch_stmt\n{\n    ; scopes flow into the value then into the body then back out to the switch\n    edge @value.before_scope -> @switch_stmt.before_scope\n    edge @body.before_scope -> @value.after_scope\n    edge @switch_stmt.after_scope -> @body.after_scope\n}\n\n(switch_body)@switch_body {\n  node @switch_body.after_scope\n  node @switch_body.before_scope\n  node @switch_body.hoist_point\n\n  edge @switch_body.before_scope -> @switch_body.hoist_point\n}\n\n(switch_body (_)* @choices)@switch_body {\n  if (is-empty @choices) {\n    edge @switch_body.after_scope -> @switch_body.before_scope\n  }\n}\n\n; switch body, first choice\n(switch_body\n  .\n  (_)@first_choice)@switch_body\n{\n    ; scopes flow from the body into the first choice\n    edge @first_choice.before_scope -> @switch_body.before_scope\n}\n\n; switch body, between choices\n(switch_body\n  (_)@left_choice\n  .\n  (_)@right_choice)\n{\n    ; scopes flow left to right\n    edge @right_choice.before_scope -> @left_choice.after_scope\n}\n\n; switch body, last choice\n(switch_body\n  (_)@last_choice\n  .)@switch_body\n{\n    ; scope flows out to the switch body\n    edge @switch_body.after_scope -> @last_choice.after_scope\n}\n\n(switch_case)@switch_case {\n  node @switch_case.after_scope\n  node @switch_case.before_scope\n}\n\n(switch_case (_)* @stmts)@switch_case {\n  if (is-empty @stmts) {\n    edge @switch_case.after_scope -> @switch_case.before_scope\n  }\n}\n\n; switch case, non-empty statements, first statement\n(switch_case\n  value:(_)@value\n  .\n  (_)@first_stmt)@switch_case\n{\n    ; scopes flow into the value then into the first statement\n    edge @value.before_scope -> @switch_case.before_scope\n    edge @first_stmt.before_scope -> @value.after_scope\n}\n\n; switch case, non-empty statements, between statement\n(switch_case\n  value:(_)\n  (_)@left_stmt\n  .\n  (_)@right_stmt)\n{\n    ; scopes flow left to right\n    edge @right_stmt.before_scope -> @left_stmt.after_scope\n}\n\n; switch case, non-empty statements, last statement\n(switch_case\n  value:(_)\n  (_)@last_stmt\n  .)@switch_case {\n\n  ; scopes flow out from the last statement to the case\n  edge @switch_case.after_scope -> @last_stmt.after_scope\n}\n\n(switch_default)@switch_default {\n  node @switch_default.after_scope\n  node @switch_default.before_scope\n}\n\n(switch_default (_)* @defaults)@switch_default {\n  if (is-empty @defaults) {\n    edge @switch_default.after_scope -> @switch_default.before_scope\n  }\n}\n\n; switch default, non-empty statements, first statement\n(switch_default\n  .\n  (_)@first_stmt)@switch_default\n{\n    ; scopes flow into the first statement\n    edge @first_stmt.before_scope -> @switch_default.before_scope\n}\n\n; switch default, non-empty statements, between statements\n(switch_default\n  (_)@left_stmt\n  .\n  (_)@right_stmt)\n{\n\n    ; scopes flow left to right\n    edge @right_stmt.before_scope -> @left_stmt.after_scope\n}\n\n; switch default, non-empty statements, last statement\n(switch_default\n  (_)@last_stmt\n  .)@switch_default\n{\n\n    ; scopes flow out to the default\n    edge @switch_default.after_scope -> @last_stmt.after_scope\n}\n\n\n\n;; #### For\n\n(for_statement\n  body:(_)@body)@for_stmt {\n\n    let @for_stmt.hoist_point = @body.before_scope\n\n}\n\n(for_statement\n  initializer:(_)@initializer\n  condition:(_)@condition\n  increment:(_)@increment\n  body:(_)@body)@for_stmt\n{\n\n    ; scopes flow from statement to initializer then test then body then increment\n    edge @initializer.before_scope -> @for_stmt.before_scope\n    edge @condition.before_scope -> @initializer.after_scope\n    edge @body.before_scope -> @condition.after_scope\n    edge @increment.before_scope -> @body.after_scope\n\n    ; scopes also from from the body back into the condition\n    edge @condition.before_scope -> @increment.after_scope\n\n    ; scopes also flow from condition out to statement\n    edge @for_stmt.after_scope -> @condition.after_scope\n\n}\n\n\n\n;; #### For In\n\n(for_in_statement\n  body:(_)@body)@for_in_stmt {\n\n    let @for_in_stmt.hoist_point = @body.before_scope\n\n}\n\n(for_in_statement\n  left:(_)@_left\n  right:(_)@right\n  body:(_)@body)@for_in_stmt\n{\n\n    ; scopes flow from statement to right then to body then back out\n    edge @right.before_scope -> @for_in_stmt.before_scope\n    edge @body.before_scope -> @right.after_scope\n    edge @for_in_stmt.after_scope -> @body.after_scope\n}\n\n(for_in_statement\n  left:(identifier)@left\n  right:(_)@right\n  body:(_)@body)@_for_in_stmt\n{\n\n    node for_in_stmt_pop\n    attr (for_in_stmt_pop) node_definition = @left\n    edge for_in_stmt_pop -> @right.value\n    edge @body.before_scope -> for_in_stmt_pop\n\n}\n\n\n\n;; #### While\n\n(while_statement\n  body:(_)@body)@while_stmt {\n\n    let @while_stmt.hoist_point = @body.before_scope\n\n}\n\n(while_statement\n  condition:(_)@condition\n  body:(_)@body)@while_stmt\n{\n\n    ; scopes flow from while to condition then to body then back out\n    edge @condition.before_scope -> @while_stmt.before_scope\n    edge @body.before_scope -> @condition.after_scope\n    edge @while_stmt.after_scope -> @body.after_scope\n\n    ; scopes also flow back into the condition\n    edge @condition.before_scope -> @body.after_scope\n\n}\n\n\n\n;; #### Do\n\n(do_statement\n  body:(_)@body)@do_stmt {\n\n    let @do_stmt.hoist_point = @body.before_scope\n\n}\n\n(do_statement\n  body:(_)@body\n  condition:(_)@condition)@do_stmt\n{\n\n    ; scopes flow from statement to body then condition then back to statement\n    edge @body.before_scope -> @do_stmt.before_scope\n    edge @condition.before_scope -> @body.after_scope\n    edge @do_stmt.after_scope -> @condition.after_scope\n\n    ; scopes also flow back to the body from the condition\n    edge @body.before_scope -> @condition.after_scope\n\n}\n\n\n\n;; #### Try\n\n(try_statement\n  body:(_)@body)@try_stmt\n{\n\n    ; scopes flow into the body then back out\n    edge @body.before_scope -> @try_stmt.before_scope\n    edge @try_stmt.after_scope -> @body.after_scope\n\n}\n\n(try_statement\n  body:(_)@body\n  handler:(_)@handler)@try_stmt\n{\n\n    ; scopes flow from body to handler then back out\n    edge @handler.before_scope -> @body.after_scope\n    edge @try_stmt.after_scope -> @handler.after_scope\n}\n\n(try_statement\n  body:(_)@body\n  finalizer:(_)@finalizer)@_try_stmt\n{\n\n    ; scopes flow from body to finalizer then back out\n    edge @finalizer.before_scope -> @body.after_scope\n\n}\n\n(try_statement\n  handler:(_)@handler\n  finalizer:(_)@finalizer)@try_stmt\n{\n\n    ; scopes flow from handler to finalizer then back out\n    edge @finalizer.before_scope -> @handler.after_scope\n    edge @try_stmt.after_scope -> @finalizer.after_scope\n}\n\n(catch_clause body:(_)@body)@catch_clause {\n    node @catch_clause.after_scope\n    node @catch_clause.before_scope\n    ; scopes flow in then back out\n    edge @body.before_scope -> @catch_clause.before_scope\n    edge @catch_clause.after_scope -> @body.after_scope\n}\n\n(catch_clause\n  parameter:(identifier)@name\n  body:(_)@body)@_catch_clause\n{\n\n    node catch_clause_pop\n    attr (catch_clause_pop) node_definition = @name\n    edge @body.before_scope -> catch_clause_pop\n\n}\n\n(finally_clause body:(_)@body)@finally_clause {\n    node @finally_clause.after_scope\n    node @finally_clause.before_scope\n    ; scopes flow in thenback out\n    edge @body.before_scope -> @finally_clause.before_scope\n    edge @finally_clause.after_scope -> @body.after_scope\n}\n\n\n\n;; #### With\n\n(with_statement body:(_)@body)@with_stmt {\n\n  let @with_stmt.hoist_point = @body.before_scope\n\n}\n\n(with_statement\n  object:(_)@object\n  body:(_)@body)@with_stmt\n{\n\n    node with_stmt_push_dot\n\n    ; scopes flow from the statement into the object then into the body then back out\n    edge @object.before_scope -> @with_stmt.before_scope\n    edge @body.before_scope -> @object.after_scope\n    edge @with_stmt.after_scope -> @body.after_scope\n    edge @with_stmt.after_scope -> @with_stmt.before_scope\n    attr (@with_stmt.after_scope -> @with_stmt.before_scope) precedence = 1\n\n    attr (with_stmt_push_dot) push_symbol = \"GUARD:MEMBER\"\n    edge with_stmt_push_dot -> @object.value\n    edge @body.before_scope -> with_stmt_push_dot\n    attr (@body.before_scope -> with_stmt_push_dot) precedence = 1\n}\n\n\n\n;; #### Break\n\n(break_statement)@break_stmt {\n    ; scopes flow through unchanged\n    edge @break_stmt.after_scope -> @break_stmt.before_scope\n}\n\n(break_statement (_)@label)@break_stmt {\n\n    node break_stmt_label_guard\n    node break_stmt_label_push\n\n    attr (break_stmt_label_guard) push_symbol = \"GUARD:LABEL\"\n    attr (break_stmt_label_push) node_reference = @label\n\n    edge break_stmt_label_push -> break_stmt_label_guard\n    edge break_stmt_label_guard -> @break_stmt.before_scope\n}\n\n\n\n;; #### Continue\n\n(continue_statement)@continue_stmt {\n    ; scopes flow through unchanged\n    edge @continue_stmt.after_scope -> @continue_stmt.before_scope\n}\n\n(continue_statement (_)@label)@continue_stmt {\n\n    node continue_stmt_label_guard\n    node continue_stmt_label_push\n\n    attr (continue_stmt_label_guard) push_symbol = \"GUARD:LABEL\"\n    attr (continue_stmt_label_push) node_reference = @label\n\n    edge continue_stmt_label_push -> continue_stmt_label_guard\n    edge continue_stmt_label_guard -> @continue_stmt.before_scope\n}\n\n\n\n;; #### Return\n\n; LATER-TODO tree sitter doesn\'t let us express empty returns currently\n(return_statement)@return_stmt {\n  ; scopes flow through unchanged\n  edge @return_stmt.after_scope -> @return_stmt.before_scope\n}\n\n(return_statement\n  (_)@returned_expr)@return_stmt {\n  ; scopes flow through the returned expresssion\n  edge @returned_expr.before_scope -> @return_stmt.before_scope\n  edge @return_stmt.after_scope -> @returned_expr.after_scope\n\n  ; return statements hook up to the call node of the function value\n  edge @return_stmt.return_or_yield -> @returned_expr.value\n}\n\n\n\n;; #### Throw\n\n(throw_statement (_)@thrown_expr)@throw_stmt {\n  ; scopes flow through the returned expresssion\n  edge @thrown_expr.before_scope -> @throw_stmt.before_scope\n  edge @throw_stmt.after_scope -> @thrown_expr.after_scope\n}\n\n\n\n;; #### Empty\n\n(empty_statement)@empty_stmt {\n  ; scopes flow through unchaged\n  edge @empty_stmt.after_scope -> @empty_stmt.before_scope\n}\n\n\n\n;; #### Labeled\n\n(labeled_statement\n    label:(_)@label\n    body:(_)@inner)@labeled_stmt\n{\n\n    node labeled_stmt_label_guard\n    node labeled_stmt_label_pop\n\n    attr (labeled_stmt_label_guard) pop_symbol = \"GUARD:LABEL\"\n    attr (labeled_stmt_label_pop) node_definition = @label\n\n    ; scopes flow through the inner statement then back out\n    edge @inner.before_scope -> @labeled_stmt.before_scope\n    edge @inner.before_scope -> labeled_stmt_label_guard\n    edge labeled_stmt_label_guard -> labeled_stmt_label_pop\n    edge @labeled_stmt.after_scope -> @inner.after_scope\n}\n\n\n\n\n\n\n\n\n\n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}       \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}      \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}     \u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}       \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}           \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; ## Expressions\n\n;; ### Attributes Defined on Expressions\n;; TODO\n\n[\n  (subscript_expression)\n  (member_expression)\n  (parenthesized_expression)\n  (undefined)\n  (this)\n  (super)\n  (number)\n  (string)\n  (template_string)\n  (template_substitution)\n  (string_fragment)\n  (escape_sequence)\n  (regex)\n  (true)\n  (false)\n  (null)\n  (sequence_expression)\n  (import)\n  (object)\n  (array)\n  (function_expression)\n  (arrow_function)\n  (generator_function)\n  (class)\n  (meta_property)\n  (call_expression)\n  (assignment_expression)\n  (augmented_assignment_expression)\n  (await_expression)\n  (unary_expression)\n  (binary_expression)\n  (ternary_expression)\n  (update_expression)\n  (new_expression)\n  (yield_expression)\n  (spread_element)\n]@expr {\n\n  node @expr.after_scope\n  node @expr.before_scope\n  node @expr.value\n\n}\n\n[\n  (function_expression body:(_)@body)\n  (arrow_function body:(_)@body)\n  (generator_function body:(_)@body)\n] {\n\n  let @body.closure_point = @body.after_scope\n\n}\n\n;; ### Expression Queries\n\n\n;; #### Parenthesized\n\n(parenthesized_expression (_)@inner)@parens {\n  ; scopes flow right through\n  edge @inner.before_scope -> @parens.before_scope\n  edge @parens.after_scope -> @inner.after_scope\n\n  ; as do values\n  edge @parens.value -> @inner.value\n}\n\n\n;; #### Strings\n\n(string)@string {\n  ; scopes don\'t change\n  edge @string.after_scope -> @string.before_scope\n\n  ; the value of a string is the string primitive\n  edge @string.value -> @string.builtins_string\n}\n\n\n;; #### Template Strings\n\n; template_strings w/ no substitutions\n(template_string (_)* @parts)@template_string {\n  if (is-empty @parts) {\n    edge @template_string.after_scope -> @template_string.before_scope\n  }\n}\n\n; nonempty template string, value\n; LATER-TODO this isn\'t really right, but it gets flows through the template string\n; which may be useful\n(template_string (_)@part)@template_string {\n  ; the value of a template string is a template string value built from the values of its substitutions\n  ; attr (@template_string.value) \"template_string_value\"\n  edge @template_string.value -> @part.value\n}\n\n; nonempty template string, first substitution\n(template_string . (_)@first)@template_string {\n  ; scopes propagate into the first subtitution of the template string\n  edge @first.before_scope -> @template_string.before_scope\n}\n\n; nonempty template string, between substitutions\n(template_string\n  (_) @left\n  .\n  (_) @right) {\n  ; scopes propagate from left substitutions to right substitutions\n  edge @right.before_scope -> @left.after_scope\n}\n\n; nonempty template string, last substitution\n(template_string (_) @last .)@template_string {\n  ; scopes propagate out of the last substitution to the template string\n  edge @template_string.after_scope -> @last.after_scope\n}\n\n[\n  (string_fragment)\n  (escape_sequence)\n]@part {\n  edge @part.after_scope -> @part.before_scope\n}\n\n(template_substitution (_)@expr)@subst {\n  edge @expr.before_scope -> @subst.before_scope\n  edge @subst.after_scope -> @expr.after_scope\n  edge @subst.value -> @expr.value\n}\n\n\n;; #### Numbers\n\n(number)@number {\n  ; scopes don\'t change\n  edge @number.after_scope -> @number.before_scope\n\n  ; the value of a number is the number primitive\n  edge @number.value -> @number.builtins_number\n}\n\n\n;; #### Variables\n\n[\n  (primary_expression/identifier)@variable\n  (member_expression object:(identifier)@variable)\n] {\n  ; value is a lookup, ie a push\n  attr (@variable.value) node_reference = @variable\n  edge @variable.value -> @variable.before_scope\n}\n\n\n;; #### Booleans\n\n(true)@true {\n  ; scopes don\'t change\n  edge @true.after_scope -> @true.before_scope\n\n  ; the value of true is a boolean primitive\n  edge @true.value -> @true.builtins_boolean\n}\n\n(false)@false {\n  ; scopes don\'t change\n  edge @false.after_scope -> @false.before_scope\n\n  ; the value of false is a boolean primitive\n  edge @false.value -> @false.builtins_boolean\n}\n\n\n;; #### This\n\n(this)@this {\n  ; scopes don\'t change\n  edge @this.after_scope -> @this.before_scope\n\n  ; this is a lookup, ie a push\n  attr (@this.value) symbol_reference = \"this\", source_node = @this\n  edge @this.value -> @this.before_scope\n\n  node pop_this\n  attr (pop_this) symbol_definition = \"this\"\n  node guard_prototype\n  attr (guard_prototype) push_symbol = \"GUARD:PROTOTYPE\"\n  edge @this.value -> pop_this\n  edge pop_this -> guard_prototype\n  edge guard_prototype -> @this.containing_class_value\n}\n\n\n;; #### Super\n\n(super)@super {\n  ; scopes don\'t change\n  edge @super.after_scope -> @super.before_scope\n}\n\n\n;; #### Null\n\n(null)@null {\n  ; scopes don\'t change\n  edge @null.after_scope -> @null.before_scope\n\n  ; the value of null is the null primitive\n  edge @null.value -> @null.builtins_null\n}\n\n\n;; #### Undefined\n\n(undefined)@undefined {\n  ; scopes don\'t change\n  edge @undefined.after_scope -> @undefined.before_scope\n\n  ; the value of undefined is the undefined primitive\n  edge @undefined.value -> @undefined.builtins_undefined\n\n  ; !!!! HACK: `undefined` is a perfectly cromulent name for a parameter, but the parser thinks it means this node instead. For the moment, work around the problem this causes by giving all `undefined` nodes covalues like parameters enjoy.\n  node @undefined.covalue\n}\n\n\n;; #### Regular Expressions\n\n(regex)@regex {\n  ; scopes don\'t change\n  edge @regex.after_scope -> @regex.before_scope\n\n  ; the value of a regex is the Regex prototype\n  edge @regex.value -> @regex.builtins_Regex_prototype\n}\n\n\n;; #### Spread Elements\n\n(spread_element (_)@expr)@spread_elem {\n  ; scopes flow in then right back out\n  edge @expr.before_scope -> @spread_elem.before_scope\n  edge @spread_elem.after_scope -> @expr.after_scope\n}\n\n\n;; #### Objects\n\n(object)@object {\n\n    node @object.member_pop\n    attr (@object.member_pop) pop_symbol = \"GUARD:MEMBER\"\n    edge @object.value -> @object.member_pop\n\n    node @object.class_value\n    node @object.constructor\n\n}\n\n; empty objects\n(object (_)* @entries)@object_expr {\n  if (is-empty @entries) {\n    edge @object_expr.after_scope -> @object_expr.before_scope\n  }\n}\n\n; non-empty objects, scopes, first entry\n(object\n  .\n  (_)@first_entry)@object_expr {\n  ; scopes propagate from the object to the first entry\n  edge @first_entry.before_scope -> @object_expr.before_scope\n}\n\n; non-empty objects, scopes, between entries\n(object\n  (_)@left_entry\n  .\n  (_)@right_entry\n)@_object_expr {\n  ; scopes propagate from left entries to right entries\n  edge @right_entry.before_scope -> @left_entry.after_scope\n}\n\n; non-empty objects, scopes, last entry\n(object\n  (_)@last_entry\n  .)@object_expr {\n  ; scopes propagate from the last entry back to the object\n  edge @object_expr.after_scope -> @last_entry.after_scope\n}\n\n; shorthand property identifier\n(shorthand_property_identifier)@shorthand_property_identifier {\n\n  node @shorthand_property_identifier.after_scope\n  node @shorthand_property_identifier.before_scope\n\n}\n\n(object (shorthand_property_identifier)@keyval)@object {\n\n  node rhsvar_before_scope\n  node rhsvar_after_scope\n  node rhsvar_value\n  node key_pop\n\n  attr (rhsvar_value) node_reference = @keyval\n  attr (key_pop) node_definition = @keyval\n\n  ; scopes flow into rhsvar, and also straight across b/c they can\'t be modified\n  edge rhsvar_before_scope -> @keyval.before_scope\n  edge rhsvar_after_scope -> rhsvar_before_scope\n  edge @keyval.after_scope -> rhsvar_after_scope\n\n  edge rhsvar_value -> rhsvar_before_scope\n\n  ; shorthand property identifiers augment the object value with a member binding\n  edge key_pop -> rhsvar_value\n  edge @object.member_pop -> key_pop\n}\n\n; pairs\n\n(computed_property_name)@computed_property_name {\n    node @computed_property_name.after_scope\n    node @computed_property_name.before_scope\n}\n\n(computed_property_name (_)@expr)@computed_property_name {\n\n    edge @expr.before_scope -> @computed_property_name.before_scope\n    edge @computed_property_name.after_scope -> @expr.after_scope\n\n}\n\n(object\n  (pair\n    key:(_)@_key\n    value: (_)@value)@pair)@object {\n\n    ; pairs augment the object value with a member binding\n\n    ; This is done differently depending on what the key is. See next rules.\n    ; attr @key.pop \"pop\" = @key, \"definition\"\n\n    node @pair.key_pop\n    edge @pair.key_pop -> @value.value\n    edge @object.member_pop -> @pair.key_pop\n\n}\n\n(pair)@pair {\n  node @pair.after_scope\n  node @pair.before_scope\n}\n\n(pair\n    key:(property_identifier)@key\n    value:(_)@value)@pair\n{\n\n    attr (@pair.key_pop) node_definition = @key\n\n    ; scopes flow into the value, then back to the pair\n    edge @value.before_scope -> @pair.before_scope\n    edge @pair.after_scope -> @value.after_scope\n\n}\n\n(pair\n  key:(string)@key\n    value:(_)@value)@pair\n{\n\n  node @key.pop\n  attr (@key.pop) pop_symbol = (replace (source-text @key) \"\\\"\" \"\")\n\n    ; scopes flow into the value, then back to the pair\n    edge @value.before_scope -> @pair.before_scope\n    edge @pair.after_scope -> @value.after_scope\n\n}\n\n(pair\n    key:(number)@key\n    value:(_)@value)@pair\n{\n\n    attr (@pair.key_pop) node_definition = @key\n\n    ; scopes flow into the value, then back to the pair\n    edge @value.before_scope -> @pair.before_scope\n    edge @pair.after_scope -> @value.after_scope\n\n}\n\n(pair\n    key:(computed_property_name)@key\n    value:(_)@value)@pair\n{\n\n    ; scopes flow into the key, then out to the value, then back to the pair\n    edge @key.before_scope -> @pair.before_scope\n    edge @value.before_scope -> @key.after_scope\n    edge @pair.after_scope -> @value.after_scope\n\n}\n\n\n\n;; #### Arrays\n\n(array)@array_expr {\n\n    node @array_expr.element_pop_dot\n    attr (@array_expr.element_pop_dot) pop_symbol = \"GUARD:MEMBER\"\n    edge @array_expr.value -> @array_expr.element_pop_dot\n\n}\n\n; empty arrays\n(array (_)* @elems)@array_expr {\n  if (is-empty @elems) {\n    edge @array_expr.after_scope -> @array_expr.before_scope\n  }\n}\n\n; nonempty arrays, first element\n(array\n  .\n  (_)@first_element)@array_expr {\n  ; scopes propagate into the first element of the array\n  edge @first_element.before_scope -> @array_expr.before_scope\n}\n\n; nonempty arrays, between elements\n(array\n  (_)@left_element\n  .\n  (_)@right_element) {\n  ; scopes propagate from left elements to right elements\n  edge @right_element.before_scope -> @left_element.after_scope\n}\n\n; nonempty arrays, last element\n(array\n  (_)@last_element\n  .)@array_expr {\n  ; scopes propagate out of the last element to the array\n  edge @array_expr.after_scope -> @last_element.after_scope\n}\n\n; elements at indices\n(array (_)@element)@array_expr {\n\n    node element_index_pop\n\n    attr (element_index_pop) pop_symbol = (named-child-index @element)\n    edge @array_expr.element_pop_dot -> element_index_pop\n    edge element_index_pop -> @element.value\n\n}\n\n\n\n;; #### Formal Parameters\n\n(formal_parameters)@formal_params {\n  node @formal_params.after_scope\n  node @formal_params.before_scope\n}\n\n(formal_parameters (_)* @params)@formal_params {\n  if (is-empty @params) {\n    edge @formal_params.after_scope -> @formal_params.before_scope\n  }\n}\n\n; first parameter\n(formal_parameters\n  .\n  (_)@first_param)@formal_params {\n\n  edge @first_param.before_scope -> @formal_params.before_scope\n}\n\n; between parameters\n(formal_parameters\n  (_)@left_param\n  .\n  (_)@right_param) {\n\n  ; scope flows left to right\n  edge @right_param.before_scope -> @left_param.after_scope\n}\n\n; last parameter\n(formal_parameters\n  (_)@last_param\n  .)@formal_params {\n\n  ; scope flows from the param to the call sig\n  edge @formal_params.after_scope -> @last_param.after_scope\n}\n\n\n\n;; #### Function Literals\n\n; functions with names\n(function_expression\n  name:(_)@name\n  parameters:(_)@call_sig)@fun {\n\n  node @name.pop\n  attr (@name.pop) syntax_type = \"function\"\n\n  ; if the function has a name, this is bound the callsig\'s before scope\n  attr (@name.pop) node_definition = @name\n  edge @call_sig.before_scope -> @name.pop\n  edge @name.pop -> @fun.value\n}\n\n\n; function\n(function_expression\n  parameters:(_)@call_sig\n  body:(_)@body)@fun {\n\n  node call_sig_arguments_pop\n  node call_sig_arguments_push\n  node call_sig_this_pop\n  node call_sig_this_push\n  node @fun.return_or_yield\n  node @fun.value_arg_scope\n  node fun_value_call\n  node fun_value_drop\n  node fun_value_return\n  node fun_value_this\n  node fun_value_this_guard\n\n  ; scope flows across the decl\n  edge @fun.after_scope -> @fun.before_scope\n\n  ; function values have drop nodes that handle closures, that points to the\n  ; before scope from the function\n  attr (fun_value_drop) type = \"drop_scopes\"\n  edge fun_value_drop -> @fun.closure_point\n\n  ; the call sig\'s before scope comes from the drop node,\n  ; then flows into the body, and includes a variable binding for \"this\"\n  edge @call_sig.before_scope -> fun_value_drop\n  attr (call_sig_this_pop) symbol_definition = \"this\", source_node = @call_sig\n  attr (call_sig_this_push) push_symbol = \"this\"\n  edge call_sig_this_pop -> call_sig_this_push\n  edge call_sig_this_push -> @fun.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_this_pop\n  attr (call_sig_arguments_pop) symbol_definition = \"arguments\", source_node = @call_sig\n  attr (call_sig_arguments_push) push_symbol = \"arguments\"\n  edge call_sig_arguments_pop -> call_sig_arguments_push\n  edge call_sig_arguments_push -> @fun.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_arguments_pop\n  edge @body.before_scope -> @call_sig.after_scope\n\n  ; function values have call nodes\n  attr (fun_value_call) pop_scoped_symbol = \"()\"\n  edge @fun.value -> fun_value_call\n\n  ; function values have return nodes which need to be visible for returns\n  attr (fun_value_return) pop_symbol = \"GUARD:RETURN\"\n  edge fun_value_call -> fun_value_return\n  let @body.return_or_yield = fun_value_return\n\n  ; function values have this nodes which need to be visible for method calls\n  attr (fun_value_this) push_symbol = \"this\"\n  attr (fun_value_this_guard) pop_symbol = \"GUARD:THIS\"\n  edge fun_value_call -> fun_value_this_guard\n  edge fun_value_this_guard -> fun_value_this\n  edge fun_value_this -> @body.after_scope\n\n  ; function values have a jump node that lets params connect up to actual arguments\n  edge @fun.value_arg_scope -> JUMP_TO_SCOPE_NODE\n}\n\n(function_expression\n  parameters:\n    (formal_parameters (_)@param))@fun {\n\n  node param_arg_index\n\n  ; parameters jump to the pushed argument scope\n  attr (param_arg_index) push_symbol = (named-child-index @param)\n  edge @param.covalue -> param_arg_index\n  edge param_arg_index -> @fun.value_arg_scope\n}\n\n\n\n;; #### Arrow Function Literals\n\n; function\n[\n  (arrow_function\n    parameters:(_)@call_sig\n    body:(_)@body)@fun\n\n  (arrow_function\n    parameter:(_)@call_sig\n      body:(_)@body)@fun\n] {\n\n  node @fun.return_or_yield\n  node @fun.value_arg_scope\n  node fun_value_call\n  node fun_value_drop\n  node fun_value_return\n  node fun_value_this\n  node fun_value_this_guard\n\n  ; scope flows across the decl\n  edge @fun.after_scope -> @fun.before_scope\n\n  ; function values have drop nodes that handle closures, that points to the\n  ; before scope from the function\n  attr (fun_value_drop) type = \"drop_scopes\"\n  edge fun_value_drop -> @fun.closure_point\n\n  ; the call sig\'s before scope comes from the drop node then flows into the body\n  edge @call_sig.before_scope -> fun_value_drop\n  edge @body.before_scope -> @call_sig.after_scope\n\n  ; function values have call nodes\n  attr (fun_value_call) pop_scoped_symbol = \"()\"\n  edge @fun.value -> fun_value_call\n\n  ; function values have return nodes which need to be visible for returns\n  attr (fun_value_return) pop_symbol = \"GUARD:RETURN\"\n  edge fun_value_call -> fun_value_return\n  edge fun_value_return -> @fun.return_or_yield\n\n  ; function values have this nodes which need to be visible for method calls\n  attr (fun_value_this) push_symbol = \"this\"\n  attr (fun_value_this_guard) pop_symbol = \"GUARD:THIS\"\n  edge fun_value_call -> fun_value_this_guard\n  edge fun_value_this_guard -> fun_value_this\n  edge fun_value_this -> @body.after_scope\n\n  ; function values have a jump node that lets params connect up to actual arguments\n  edge @fun.value_arg_scope -> JUMP_TO_SCOPE_NODE\n}\n\n; arrow functions returning exprs need special rules for getting the return value hooked up\n(arrow_function\n  body:(expression)@return_expr) {\n  edge @return_expr.return_or_yield -> @return_expr.value\n}\n\n(arrow_function\n  parameter:(_)@param)@fun {\n  node param_arg_index\n  node param_pop\n\n  ; but augmented with a pop, b/c it\'s not a pattern\n  attr (param_pop) node_definition = @param\n  edge param_pop -> @param.covalue\n  edge @param.after_scope -> param_pop\n\n  ; parameters jump to the pushed argument scope\n  attr (param_arg_index) push_symbol = \"0\"\n  edge @param.covalue -> param_arg_index\n  edge param_arg_index -> @fun.value_arg_scope\n}\n\n(arrow_function\n  parameters:\n    (formal_parameters (_)@param))@fun {\n\n  node param_arg_index\n\n  ; parameters jump to the pushed argument scope\n  attr (param_arg_index) push_symbol = (named-child-index @param)\n  edge @param.covalue -> param_arg_index\n  edge param_arg_index -> @fun.value_arg_scope\n}\n\n\n\n;; #### Generator Function Literals\n\n; generator functions with names\n(generator_function\n  name:(_)@name\n  parameters:(_)@call_sig)@fun {\n\n  node @name.pop\n  attr (@name.pop) syntax_type = \"function\"\n\n  ; if the function has a name, this is bound the callsig\'s before scope\n  attr (@name.pop) node_definition = @name\n  edge @call_sig.before_scope -> @name.pop\n  edge @name.pop -> @fun.value\n}\n\n\n; generator function\n(generator_function\n  parameters:(_)@call_sig\n  body:(_)@body)@fun {\n\n  node call_sig_arguments_pop\n  node call_sig_arguments_push\n  node call_sig_this_pop\n  node call_sig_this_push\n  node @fun.return_or_yield\n  node @fun.value_arg_scope\n  node fun_value_call\n  node fun_value_drop\n  node fun_value_return\n  node fun_value_this\n  node fun_value_this_guard\n\n  ; scope flows across the decl\n  edge @fun.after_scope -> @fun.before_scope\n\n  ; function values have drop nodes that handle closures, that points to the\n  ; before scope from the function\n  attr (fun_value_drop) type = \"drop_scopes\"\n  edge fun_value_drop -> @fun.closure_point\n\n  ; the call sig\'s before scope comes from the drop node,\n  ; then flows into the body, and includes a variable binding for \"this\"\n  edge @call_sig.before_scope -> fun_value_drop\n  attr (call_sig_this_pop) symbol_definition = \"this\", source_node = @call_sig\n  attr (call_sig_this_push) push_symbol = \"this\"\n  edge call_sig_this_pop -> call_sig_this_push\n  edge call_sig_this_push -> @fun.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_this_pop\n  attr (call_sig_arguments_pop) symbol_definition = \"arguments\", source_node = @call_sig\n  attr (call_sig_arguments_push) push_symbol = \"arguments\"\n  edge call_sig_arguments_pop -> call_sig_arguments_push\n  edge call_sig_arguments_push -> @fun.value_arg_scope\n  edge @call_sig.before_scope -> call_sig_arguments_pop\n  edge @body.before_scope -> @call_sig.after_scope\n\n  ; function values have call nodes\n  attr (fun_value_call) pop_scoped_symbol = \"()\"\n  edge @fun.value -> fun_value_call\n\n  ; function values have return nodes which need to be visible for returns\n  attr (fun_value_return) pop_symbol = \"GUARD:RETURN\"\n  edge fun_value_call -> fun_value_return\n  let @body.return_or_yield = fun_value_return\n\n  ; function values have this nodes which need to be visible for method calls\n  attr (fun_value_this) push_symbol = \"this\"\n  attr (fun_value_this_guard) pop_symbol = \"GUARD:THIS\"\n  edge fun_value_call -> fun_value_this_guard\n  edge fun_value_this_guard -> fun_value_this\n  edge fun_value_this -> @body.after_scope\n\n  ; function values have a jump node that lets params connect up to actual arguments\n  edge @fun.value_arg_scope -> JUMP_TO_SCOPE_NODE\n}\n\n(generator_function\n  parameters:\n    (formal_parameters (_)@param))@fun {\n\n  node param_arg_index\n\n  ; parameters jump to the pushed argument scope\n  attr (param_arg_index) push_symbol = (named-child-index @param)\n  edge @param.covalue -> param_arg_index\n  edge param_arg_index -> @fun.value_arg_scope\n}\n\n\n;; #### Function Calls\n\n; calls, functions\n(call_expression\n  function:(_)@function\n  arguments:(_)@arguments)@call_expr {\n\n  ; scopes flow from call expressions into the function\n  edge @function.before_scope -> @call_expr.before_scope\n  edge @arguments.before_scope -> @function.after_scope\n  edge @call_expr.after_scope -> @arguments.after_scope\n}\n\n; calls, values\n(call_expression\n  function:(_)@function\n  arguments:(_)@arguments)@call_expr {\n\n  node arguments_arg_arguments\n  node arguments_arg_arguments_dot\n  node @arguments.arg_scope\n  attr (@arguments.arg_scope) is_exported\n  node @arguments.arg_scope_no_this\n  node @arguments.arg_this\n  node call_expr_call\n  node call_expr_return_guard\n\n  ; value is a call, ie a push \"()\" node w/ \"push-scope\" @arguments\n  attr (call_expr_return_guard) push_symbol = \"GUARD:RETURN\"\n  attr (call_expr_call) push_scoped_symbol = \"()\", scope = @arguments.arg_scope\n  edge @call_expr.value -> call_expr_return_guard\n  edge call_expr_return_guard -> call_expr_call\n  edge call_expr_call -> @function.value\n\n  attr (@arguments.arg_this) symbol_definition = \"this\", source_node = @arguments\n  edge @arguments.arg_scope -> @arguments.arg_this\n\n  edge @arguments.arg_scope -> @arguments.arg_scope_no_this\n\n  attr (arguments_arg_arguments) symbol_definition = \"arguments\", source_node = @arguments\n  attr (arguments_arg_arguments_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge @arguments.arg_scope -> arguments_arg_arguments\n  edge arguments_arg_arguments -> arguments_arg_arguments_dot\n  edge arguments_arg_arguments_dot -> @arguments.arg_scope_no_this\n  edge arguments_arg_arguments -> @call_expr.builtins_arguments_prototype\n}\n\n; special case to make `this` bind correctly in calls of the forms `x.f(...)`\n; and `x[f](...)`\n(call_expression\n  function:[\n    (member_expression object:(_)@object)\n    (subscript_expression object:(_)@object)\n  ]\n  arguments:(_)@arguments) {\n\n  edge @arguments.arg_this -> @object.value\n}\n\n\n; TODO this should eventually be removed and replaced with a version that only\n; applies to the negation of (member_expression), but that\'s not supported by\n; tree-sitter currently\n(call_expression\n  function: (_)@_function\n  arguments:(_)@arguments)@call_expr {\n\n  edge @arguments.arg_this -> @call_expr.builtins_null\n}\n(call_expression\n  arguments:(arguments (_)@arg)@arguments) {\n\n  node arg_arg_index\n  attr (arg_arg_index) pop_symbol = (named-child-index @arg)\n  edge @arguments.arg_scope_no_this -> arg_arg_index\n  edge arg_arg_index -> @arg.value\n}\n\n\n\n;; #### Arguments\n\n(arguments)@arguments {\n  node @arguments.after_scope\n  node @arguments.before_scope\n}\n\n(arguments (_)* @args)@arguments {\n  if (is-empty @args) {\n    edge @arguments.after_scope -> @arguments.before_scope\n  }\n}\n\n(arguments\n  .\n  (_)@first_arg)@arguments {\n\n  edge @first_arg.before_scope -> @arguments.before_scope\n}\n\n(arguments\n  (_)@left_arg\n  .\n  (_)@right_arg) {\n\n  edge @right_arg.before_scope -> @left_arg.after_scope\n}\n\n(arguments\n  (_)@last_arg\n  .)@arguments {\n\n  edge @arguments.after_scope -> @last_arg.after_scope\n}\n\n\n\n;; #### Property Access\n\n;; ##### Member Expressions\n\n(member_expression\n  object:(_)@object property:(_)@property)@member_expr\n{\n\n    node member_push\n    node property_push\n\n  ; scopes flow into object then back out\n  edge @object.before_scope -> @member_expr.before_scope\n  edge @member_expr.after_scope -> @object.after_scope\n\n  ; value is a member projection on the value of the object ie. a push then push dot\n    attr (member_push) push_symbol = \"GUARD:MEMBER\"\n    attr (property_push) node_reference = @property\n    edge property_push -> member_push\n    edge @member_expr.value -> property_push\n    edge member_push -> @object.value\n\n  ; (member_expression) nodes can occur in patterns\n  node @member_expr.covalue\n  node @member_expr.new_bindings\n}\n\n;; ##### Subscript Expressions\n\n(subscript_expression\n  object: (_)@object\n  index: (_)@index)@subscript_expr {\n\n  node @subscript_expr.index_push\n  node subscript_expr_push_dot\n\n  ; scopes flow left to right\n  edge @object.before_scope -> @subscript_expr.before_scope\n  edge @index.before_scope -> @object.after_scope\n  edge @subscript_expr.after_scope -> @index.after_scope\n\n  ; value is a subscript lookup, ie a push then push dot\n  attr (subscript_expr_push_dot) push_symbol = \"GUARD:MEMBER\"\n  edge subscript_expr_push_dot -> @object.value\n\n  ; this is done differently depending on what the index is\n  edge @subscript_expr.value -> @subscript_expr.index_push\n  edge @subscript_expr.index_push -> subscript_expr_push_dot\n\n  ; subscript expressions can appear in array patterns, on the left, and thus require a covalue & bindings\n  node @subscript_expr.covalue\n  node @subscript_expr.new_bindings\n}\n\n(subscript_expression\n  object: (_)@_object\n  index: (string)@index)@subscript_expr\n{\n\n    attr (@subscript_expr.index_push) symbol_reference = (replace (source-text @index) \"[\\\"\\\']\" \"\"), source_node = @index\n\n}\n\n(subscript_expression\n  object: (_)@_object\n  index: (number)@index)@subscript_expr\n{\n\n    attr (@subscript_expr.index_push) node_reference = @index\n\n}\n\n\n\n;; #### Constructor Calls\n\n(new_expression\n  constructor:(_)@constructor\n  arguments:(_)@arguments)@new_expr {\n\n  node @arguments.arg_scope\n  attr (@arguments.arg_scope) is_exported\n  node @arguments.arg_this\n  node constructor_constructor\n  node new_expr_call\n  node new_expr_guard_this\n\n  edge @constructor.before_scope -> @new_expr.before_scope\n  edge @arguments.before_scope -> @constructor.after_scope\n  edge @new_expr.after_scope -> @arguments.after_scope\n\n  attr (new_expr_call) push_scoped_symbol = \"()\", scope = @arguments.arg_scope\n\n  ; we guard for constructors for the case where we have a \"true\" class\n  attr (constructor_constructor) push_symbol = \"GUARD:CONSTRUCTOR\"\n  edge new_expr_call -> constructor_constructor\n  edge constructor_constructor -> @constructor.value\n\n  ; and also just go right to the value incase we have a function-as-constructor\n  edge new_expr_call -> @constructor.value\n\n\n\n  ; value coming from the constructor call\n  attr (new_expr_guard_this) push_symbol = \"GUARD:THIS\"\n  edge @new_expr.value -> new_expr_guard_this\n  edge new_expr_guard_this -> new_expr_call\n\n  ; value also coming from the prototype\n  node guard_prototype\n  attr (guard_prototype) push_symbol = \"GUARD:PROTOTYPE\"\n  edge @new_expr.value -> guard_prototype\n  edge guard_prototype -> @constructor.value\n\n  attr (@arguments.arg_this) symbol_definition = \"this\", source_node = @arguments\n  edge @arguments.arg_scope -> @arguments.arg_this\n  edge @arguments.arg_this -> @new_expr.builtins_empty_object\n}\n\n(new_expression\n  arguments:(arguments (_)@arg)@arguments) {\n\n  node arg_arg_index\n\n  attr (arg_arg_index) pop_symbol = (named-child-index @arg)\n  edge @arguments.arg_scope -> arg_arg_index\n  edge arg_arg_index -> @arg.value\n}\n\n\n\n;; #### Await\n\n(await_expression (_)@awaited)@await_expr {\n  ; scopes flow into the inner expression then back out\n  edge @awaited.before_scope -> @await_expr.before_scope\n  edge @await_expr.after_scope -> @awaited.after_scope\n\n  ; value is just propagated up\n  edge @await_expr.value -> @awaited.value\n}\n\n\n\n;; #### Update Expressions\n\n(update_expression argument: (_)@argument)@update_expr {\n\n  node update_expr_pop\n  ; scope propagates through the operand then is updated by the expr\n  edge @argument.before_scope -> @update_expr.before_scope\n  edge @update_expr.after_scope -> @argument.after_scope\n  ; LATER-TODO this isn\'t quite right because the update argument can\'t be an arbitrary expr\n  ; eg f(x)++ doesn\'t make any sense, you have to have something more like\n  ; (update_expression argument: (lvar)@argument)\n  attr (update_expr_pop) node_definition = @argument\n  edge @update_expr.value -> @argument.value\n  edge @update_expr.after_scope -> update_expr_pop\n  edge update_expr_pop -> @argument.value\n\n}\n\n\n;; #### Binary Expressions\n\n(binary_expression left: (_)@left right: (_)@right)@binary_expr {\n  ; scopes propagate left to right through the operands unchanged by the binop itself\n  edge @left.before_scope -> @binary_expr.before_scope\n  edge @right.before_scope -> @left.after_scope\n  edge @binary_expr.after_scope -> @right.after_scope\n\n  ; value is a binary op value built from the operands\n  ; LATER-TODO this isn\'t quite correct but it permits flow through the expression\n  ; which can be useful\n  ; attr (@binary_expr.value) \"binary_operation_value\"\n  edge @binary_expr.value -> @left.value\n  edge @binary_expr.value -> @right.value\n}\n\n\n;; #### Unary Expressions\n\n(unary_expression argument: (_)@argument)@unary_expr {\n  ; scope propagates through the operand\n  edge @argument.before_scope -> @unary_expr.before_scope\n  edge @unary_expr.after_scope -> @argument.after_scope\n\n  ; value is a unaryop value built from the operand\n  ; LATER-TODO this isn\'t quite correct but it permits flow through the expression\n  ; which can be useful\n  ; attr (@unary_expr.value) \"unary_operation_value\"\n  edge @unary_expr.value -> @argument.value\n}\n\n\n\n;; #### Assignment Expressions;\n\n; scopes on RHS, values\n(assignment_expression\n  left: (_)@_left\n  right: (_)@right)@assignment_expr {\n\n  ; scopes flow into the RHS then back out to the whole expr,\n  ; augmented (in subsequent rules) by the LHS\n  edge @right.before_scope -> @assignment_expr.before_scope\n\n  ; value of the whole thing is value of the RHS\n  edge @assignment_expr.value -> @right.value\n}\n\n; augmentation of scope via identifiers\n(assignment_expression\n  left: (identifier)@name\n  right: (_)@right)@assignment_expr {\n\n    node @name.pop\n\n    ; augments the scope by adding a lookup edge, ie. a pop\n    attr (@name.pop) node_definition = @name\n    edge @assignment_expr.after_scope -> @name.pop\n    edge @name.pop -> @right.value\n\n    ; ensure the scope flows through the identifier\n    edge @assignment_expr.after_scope -> @right.after_scope\n\n}\n\n(assignment_expression\n  left: [\n    (member_expression)\n    (subscript_expression)\n  ]@left\n  right: (_)@right)@assignment_expr {\n\n    ; scope flows from LHS into pattern then back to assignment\n    edge @left.before_scope -> @assignment_expr.before_scope\n\n    ; ensure the scope flows through the identifier\n    edge @assignment_expr.after_scope -> @right.after_scope\n\n}\n\n; assignment to direct fields on `this`\n(assignment_expression\n  left: (member_expression\n    object:(this)@_this\n    property:(_)@property)\n  right: (_)@right)@assignment_expr {\n\n  node property_pop\n  node this_drop\n  node this_pop\n  node this_pop_dot\n\n  ; HACK\n  attr (this_drop) type = \"drop_scopes\"\n  edge this_drop -> this_pop\n  attr (this_pop) pop_symbol = \"this\"\n  attr (this_pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  attr (property_pop) node_definition = @property\n  edge @assignment_expr.after_scope -> this_drop\n  edge @assignment_expr.after_scope -> this_pop\n  edge this_pop -> this_pop_dot\n  edge this_pop_dot -> property_pop\n  edge property_pop -> @right.value\n}\n\n; augmentation of scope via _destructuring_patterns\n(assignment_expression\n  left: [\n    (object_pattern)\n    (array_pattern)\n    (assignment_pattern)\n  ]@left\n  right: (_)@right)@assignment_expr {\n\n  ; scope flows from LHS into pattern then back to assignment\n  edge @left.before_scope -> @right.after_scope\n  edge @assignment_expr.after_scope -> @left.after_scope\n\n}\n\n\n\n;; #### Augmented Assignment Expressions\n\n(augmented_assignment_expression\n  left: (_)@_left\n  right: (_)@right)@augmented_assignment_expr {\n\n  ; scopes flow into the RHS then back out to the whole expr, augmented by the LHS\n  edge @right.before_scope -> @augmented_assignment_expr.before_scope\n  edge @augmented_assignment_expr.after_scope -> @right.after_scope\n}\n\n(augmented_assignment_expression\n  left:(identifier)@left\n  right:(_)@right)@augmented_assignment_expr {\n\n  node augmented_assignment_expr_pop\n  node augmented_assignment_expr_push\n\n  ; augment the scope\n    attr (augmented_assignment_expr_pop) node_definition = @left\n    attr (augmented_assignment_expr_push) node_reference = @left\n    edge augmented_assignment_expr_push -> @augmented_assignment_expr.before_scope\n    edge augmented_assignment_expr_pop -> augmented_assignment_expr_push\n    edge augmented_assignment_expr_pop -> @right.value\n    edge @augmented_assignment_expr.after_scope -> augmented_assignment_expr_pop\n\n}\n\n\n;; #### Comma Operator / Sequence Expressions\n\n(sequence_expression (_)* @elems)@sequence_expr {\n  if (is-empty @elems) {\n    edge @sequence_expr.after_scope -> @sequence_expr.before_scope\n  }\n}\n\n(sequence_expression . (_)@first)@sequence_expr {\n  edge @first.before_scope -> @sequence_expr.before_scope\n}\n\n(sequence_expression (_)@left . (_)@right) {\n  edge @right.before_scope -> @left.after_scope\n}\n\n(sequence_expression (_)@last .)@sequence_expr {\n  edge @sequence_expr.after_scope -> @last.after_scope\n  edge @sequence_expr.value -> @last.value\n}\n\n\n\n;; #### Ternary Expression\n\n(ternary_expression\n  condition: (_)@condition\n  consequence: (_)@consequence\n  alternative: (_)@alternative)@ternary_expr {\n\n  ; scopes propagate into condition, then into each branch\n  edge @condition.before_scope -> @ternary_expr.before_scope\n  edge @consequence.before_scope -> @condition.after_scope\n  edge @alternative.before_scope -> @condition.after_scope\n  edge @ternary_expr.after_scope -> @consequence.after_scope\n  edge @ternary_expr.after_scope -> @alternative.after_scope\n\n  ; value of the whole thing is a conditional value from the operands\n  edge @ternary_expr.value -> @consequence.value\n  edge @ternary_expr.value -> @alternative.value\n}\n\n\n\n;; #### Yield\n\n(yield_expression (_)@yielded_expr)@yield_expr {\n  ; scopes flow in to the yielded expression then back out\n  edge @yielded_expr.before_scope -> @yield_expr.before_scope\n  edge @yield_expr.after_scope -> @yielded_expr.after_scope\n\n  ; yield expressions hook up to the call node of the function value\n  edge @yield_expr.return_or_yield -> @yielded_expr.value\n}\n\n\n\n;; #### Class Expressions\n\n(class\n  body:(_)@body)@class {\n\n  node @class.class_value\n  let @class.containing_class_value = @class.class_value\n  node guard_prototype\n  node @class.prototype\n  node @class.constructor\n  attr (guard_prototype) pop_symbol = \"GUARD:PROTOTYPE\"\n\n  edge @body.before_scope -> @class.closure_point\n  edge @class.value -> @class.class_value\n  edge @class.class_value -> guard_prototype\n  edge guard_prototype -> @class.prototype\n  edge @class.class_value -> @class.constructor\n  edge @class.prototype -> @body.after_scope\n  edge @class.after_scope -> @class.before_scope\n}\n\n(class\n  name:(_)@name\n  body:(_)@body)@class {\n\n  node @name.pop\n  attr (@name.pop) syntax_type = \"class\"\n\n  attr (@name.pop) node_definition = @name\n  edge @body.before_scope -> @name.pop\n  edge @name.pop -> @class.value\n}\n\n(class\n  (class_heritage (_)@name))@class {\n\n  node guard_prototype\n  node guard_constructor\n  attr (guard_prototype) push_symbol = \"GUARD:PROTOTYPE\"\n  attr (guard_constructor) push_symbol = \"GUARD:CONSTRUCTOR\"\n  edge @name.before_scope -> @class.before_scope\n  edge @class.prototype -> guard_prototype\n  edge guard_prototype -> @name.value\n  edge @class.constructor -> guard_constructor\n  edge guard_constructor -> @name.value\n  edge @class.after_scope -> @name.after_scope\n}\n\n(jsx_element\n  open_tag:(_)@open_tag\n  close_tag:(_)@close_tag\n  (_)*@children)@jsx_element {\n\n  node @jsx_element.before_scope\n  node @jsx_element.after_scope\n  node @jsx_element.value\n\n  edge @open_tag.before_scope -> @jsx_element.before_scope\n  edge @jsx_element.after_scope -> @close_tag.after_scope\n\n  if (is-empty @children) {\n    edge @close_tag.before_scope -> @open_tag.after_scope\n  }\n\n}\n\n(jsx_element\n  open_tag:(_)@open_tag\n  .\n  [\n    (jsx_text)\n    (jsx_element)\n    (jsx_self_closing_element)\n    (jsx_expression)\n  ]@first_child\n) {\n  edge @first_child.before_scope -> @open_tag.after_scope\n}\n\n(jsx_element\n  [\n    (jsx_text)\n    (jsx_element)\n    (jsx_self_closing_element)\n    (jsx_expression)\n  ]@left_child\n  .\n  [\n    (jsx_text)\n    (jsx_element)\n    (jsx_self_closing_element)\n    (jsx_expression)\n  ]@right_child\n) {\n  edge @right_child.before_scope -> @left_child.after_scope\n}\n\n(jsx_element\n  [\n    (jsx_text)\n    (jsx_element)\n    (jsx_self_closing_element)\n    (jsx_expression)\n  ]@last_child\n  .\n  close_tag:(_)@close_tag\n) {\n  edge @close_tag.before_scope -> @last_child.after_scope\n}\n\n(jsx_text)@jsx_text {\n  node @jsx_text.before_scope\n  node @jsx_text.after_scope\n\n  edge @jsx_text.after_scope -> @jsx_text.before_scope\n}\n\n(jsx_opening_element)@jsx_opening_element {\n\n  node @jsx_opening_element.before_scope\n  node @jsx_opening_element.after_scope\n\n}\n\n(jsx_opening_element\n  name:(_)@element_name)@jsx_opening_element {\n\n  edge @element_name.before_scope -> @jsx_opening_element.before_scope\n\n}\n\n(jsx_opening_element\n  !name)@jsx_opening_element\n{\n\n  edge @jsx_opening_element.after_scope -> @jsx_opening_element.before_scope\n\n}\n\n(jsx_opening_element\n  name:(_)@element_name\n  !attribute)@jsx_opening_element\n{\n\n  edge @jsx_opening_element.after_scope -> @element_name.after_scope\n\n}\n\n(jsx_opening_element\n  name:(_)@element_name\n  .\n  attribute:(_)@first_attr\n) {\n\n  edge @first_attr.before_scope -> @element_name.after_scope\n\n}\n\n(jsx_opening_element\n  attribute:(_)@left_attr\n  .\n  attribute:(_)@right_attr\n) {\n\n  edge @right_attr.before_scope -> @left_attr.after_scope\n\n}\n\n(jsx_opening_element\n  attribute:(_)@last_attr\n  .)@jsx_opening_element\n{\n\n  edge @jsx_opening_element.after_scope -> @last_attr.after_scope\n\n}\n\n(jsx_attribute (_) . (_)?@attr_value)@jsx_attribute {\n\n  node @jsx_attribute.before_scope\n  node @jsx_attribute.after_scope\n\n  if none @attr_value {\n    edge @jsx_attribute.after_scope -> @jsx_attribute.before_scope\n  } else {\n    edge @attr_value.before_scope -> @jsx_attribute.before_scope\n    edge @jsx_attribute.after_scope -> @attr_value.after_scope\n  }\n\n}\n\n(jsx_namespace_name (_) @lhs (_) @rhs)@name {\n  node @name.before_scope\n  node @name.after_scope\n\n  edge @lhs.before_scope -> @name.before_scope\n  edge @rhs.before_scope -> @lhs.after_scope\n  edge @name.after_scope -> @name.before_scope\n}\n\n(jsx_self_closing_element\n  name:(_)@element_name)@jsx_self_closing_element {\n\n  node @jsx_self_closing_element.before_scope\n  node @jsx_self_closing_element.after_scope\n  node @jsx_self_closing_element.value\n\n  edge @element_name.before_scope -> @jsx_self_closing_element.before_scope\n\n}\n\n(jsx_self_closing_element\n  !name\n  !attribute)@jsx_self_closing_element\n{\n\n  edge @jsx_self_closing_element.after_scope -> @jsx_self_closing_element.before_scope\n\n}\n\n(jsx_self_closing_element\n  name:(_)@element_name\n  !attribute)@jsx_self_closing_element\n{\n\n  edge @jsx_self_closing_element.after_scope -> @element_name.after_scope\n\n}\n\n(jsx_self_closing_element\n  name:(_)@element_name\n  .\n  attribute:(_)@first_attr\n) {\n\n  edge @first_attr.before_scope -> @element_name.after_scope\n\n}\n\n(jsx_self_closing_element\n  attribute:(_)@left_attr\n  .\n  attribute:(_)@right_attr\n) {\n\n  edge @right_attr.before_scope -> @left_attr.after_scope\n\n}\n\n(jsx_self_closing_element\n  attribute:(_)@last_attr\n  .)@jsx_self_closing_element\n{\n\n  edge @jsx_self_closing_element.after_scope -> @last_attr.after_scope\n\n}\n\n(jsx_expression)@jsx_expression {\n\n  node @jsx_expression.before_scope\n  node @jsx_expression.after_scope\n\n}\n\n(jsx_expression (_)?@child)@jsx_expression {\n\n  if none @child {\n    edge @jsx_expression.after_scope -> @jsx_expression.before_scope\n  } else {\n    edge @child.before_scope -> @jsx_expression.before_scope\n    edge @jsx_expression.after_scope -> @child.after_scope\n  }\n\n}\n\n(jsx_closing_element)@jsx_closing_element\n{\n\n  node @jsx_closing_element.before_scope\n  node @jsx_closing_element.after_scope\n\n}\n\n(jsx_closing_element\n  !name)@jsx_closing_element\n{\n\n  edge @jsx_closing_element.after_scope -> @jsx_closing_element.before_scope\n\n}\n\n(jsx_closing_element\n  name:(_)@element_name)@jsx_closing_element\n{\n\n  edge @element_name.before_scope -> @jsx_closing_element.before_scope\n  edge @jsx_closing_element.after_scope -> @element_name.after_scope\n\n}\n\n[\n  (jsx_opening_element\n    name:(identifier)@element_name)\n  (jsx_self_closing_element\n    name:(identifier)@element_name)\n  (jsx_closing_element\n    name:(identifier)@element_name)\n]\n{\n  scan (source-text @element_name) {\n    ; standard HTML elements\n    \"^(a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdi|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|data|datalist|dd|del|details|dfn|dialog|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|input|ins|kbd|label|legend|li|link|main|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|picture|pre|progress|q|rp|rt|ruby|s|samp|script|search|section|select|small|source|span|strike|strong|style|sub|summary|sup|svg|table|tbody|td|template|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video|wbr)$\" {\n      ; do nothing!\n    }\n\n    ; everything else\n    \"^.+$\" {\n      node element_name_pop\n      attr (element_name_pop) node_reference = @element_name\n      edge element_name_pop -> @element_name.before_scope\n    }\n  }\n\n}\n\n\n\n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}       \u{2588}\u{2588}    \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}    \u{2588}\u{2588}       \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}       \u{2588}\u{2588}    \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \n;; \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588}    \u{2588}\u{2588}       \u{2588}\u{2588}    \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; ## Patterns\n\n;; Patterns introduce at least two interesting problems to the task of name\n;; resolution. On the one hand, patterns by themselves are rich in structure\n;; and binding possibilities. On the other, they function to pull apart\n;; structure in ways that we would like to make use of in resolving names. Let\'s\n;; look at these in order.\n\n;; ### Binding Possibilities\n\n;; If names could only be bound directly either on the LHS of an assignment, or\n;; as the formal parameters to a function, or in related places like as\n;; arguments to increment or decrement operators, then there would be little\n;; trouble saying where a name is bound. But consider a destructuring assignment\n;; such as this:\n\n;; ``````javascript\n;; let [x,y,z] = arr;\n;; ``````\n\n;; This assignment has variable names on the LHS of an assignment, sure, but not\n;; directly as the LHS. Rather they\'re buried down inside a pattern. Here they\n;; aren\'t very deep, just one node below the root of the LHS, but they can be\n;; arbitrarily far down:\n\n;; ``````javascript\n;; let [x, [y, [z, w], q], r] = arr;\n;; ``````\n\n;; On top of this, patterns in JavaScript permit default assignments, such as\n\n;; ``````javascript\n;; let [x, y = 1] = arr;\n;; ``````\n\n;; These default values can be the result of a computation itself containing\n;; variables, such as\n\n;; ``````javascript\n;; let [x, y = 2*z] = arr;\n;; ``````\n\n;; Additionally, those variables referenced in the default value are evaluated\n;; *after* the RHS of the assignment. In the following code, `z` is incremented\n;; and becomes `2`, and then `x` is assigned to that value. The array on the RHS\n;; is only one element long, so the `y` variable gets assigned the default value\n;; of `2*z`, which is computed *after* the increment, and so is `2*2` or `4`.\n\n;; ``````javascript\n;; let z = 1;\n;; let [x, y = 2*z] = [z++];\n;; ``````\n\n;; To complicated matters further, the default value can reference the *bound\n;; variables to its left*. For instance:\n\n;; ``````javascript\n;; let [x, y = x+1] = arr;\n;; ``````\n\n;; All of this leads to some very interesting and tricky problems for name\n;; resolution. The flow of the environment is as follows: First, the environment\n;; flows into the RHS of the assignment and is updated by whatever evaluations\n;; happen there, then it flows out of the RHS and into the LHS, where it goes\n;; through each pattern in the LHS parse tree, in a left-to-right, depth-first\n;; traversal. Patterns with no default assignments do nothing to the environment\n;; but patterns with a default will pass the environment to the default value,\n;; where it may be updated by the evaluation, and then passed further along.\n;; Each variable, whether bare or on the left of an assignment, also has to\n;; extend the environment because those variables come into scope further along.\n\n;; ### Structure Decomposition\n\n;; Let\'s now look at how patterns decompose structure. Let\'s consider the effect\n;; of an assignment such as this:\n\n;; ``````javascript\n;; let [x,y] = [1,2];\n;; ``````\n\n;; This assignment binds `x` to `1` and `y` to `2`. It\'s equivalent to doing\n\n;; ``````javascript\n;; let x = 1, y = 2;\n;; ``````\n\n;; Except, unlike the latter, the array destructuring does not have any obvious\n;; pairing up of the names with the expressions that give them their values.\n;; Now, perhaps there\'s some clever hack we can perform for this special case\n;; where the RHS is a structure like `[1,2]` where it\'s manifestly clear out to\n;; pair things up, but of course the RHS can come from anywhere. It can come\n;; from a local variable assignment:\n\n;; ``````javascript\n;; let arr = [1,2];\n;; let [x,y] = arr;\n;; ``````\n\n;; Or a function call:\n\n;; ``````javascript\n;; function foo(arr) {\n;;   let [x,y] = arr;\n;;   ...\n;; }\n;; foo([1,2]);\n;; ``````\n\n;; Or any other number of places. We would like *all* of these to permit at\n;; least *some* amount of name resolution so that we can find that `x` is `1`\n;; and `y` is `2`. This should extend also to objects, not just arrays.\n\n;; The approach we take is to recognize a general pattern of equivalence, which\n;; the above double-let assignment is related special case. For arrays, all\n;; destructuring assignments of the form\n\n;; ``````javascript\n;; let [..., pat_i, ...] = arr;\n;; ``````\n\n;; are equivalent to\n\n;; ``````javascript\n;; let pat_i = arr[i];\n;; ``````\n\n;; For any pattern `pat` and expression `arr`. So for instance the simple case\n;; of a pattern expression and an array literal\n\n;; ``````javascript\n;; let [x,y] = [1,2];\n;; ``````\n\n;; is equivalent to a pair of lets\n\n;; ``````javascript\n;; let x = [1,2][0];\n;; let y = [1,2][1];\n;; ``````\n\n;; Modulo any change in side effects from duplicating the array syntactically,\n;; these two are equivalent and this would be a valid code transformation. Or if\n;; the pattern were an embedded array destructuring like so:\n\n;; ``````javascript\n;; let [x, [y,z]] = [1, [2,3]];\n;; ``````\n\n;; then this would be equivalent to\n\n;; ``````javascript\n;; let x = [1, [2,3]][0];\n;; let [y,z] = [1, [2,3]][1];\n;; ``````\n\n;; And of course the second let here would similarly unfold to be equivalent to\n;; a pair of assignments, giving us\n\n;; ``````javascript\n;; let x = [1, [2,3]][0];\n;; let y = [1, [2,3]][1][0];\n;; let z = [1, [2,3]][1][1];\n;; ``````\n\n;; Similarly for objects, we have the following destructuring equivalence that\n;; says an assignment like this:\n\n;; ``````javascript\n;; let {..., k: pat, ...} = obj;\n;; ``````\n\n;; is equivalent to\n\n;; ``````javascript\n;; let pat = obj[k];\n;; ``````\n\n;; for all patterns `pat` and expressions `obj`.\n\n;; This lets us then conclude that whatever the graphs are that we generate for\n;; patterns ought to be equivalent to the graphs we would general for using\n;; array indexing and object indexing. Since array and object indexing are fully\n;; capable of participating in name resolution, if we can achieve this\n;; equivalence, patterns can also fully participate as well, and we\'ll be able\n;; to say that the assignment `let [x,y] = [1,2]` yields the name `x` resolving\n;; to `1` and `y` to `2`, as well as many many more complicated cases.\n\n;; As mentioned in the intro to this doc, assignments point to values. The\n;; simplest way to do this, in the absence of patterns, is just to have an edge\n;; from the after scope of the assignment to a pop node for the variable,\n;; and then to the value node of the RHS, so for `let x = 1;` it\'d be like so:\n\n;; ``````\n;; after_scope ---> POP \"x\" ---> value_node_for_1\n;; ``````\n\n;; But the above discussion of destructuring complicates this. What we do to\n;; address this is introduce the notion of a \"covalue\". Just as we can say that\n;; an expression *has* a value, or produces a value, etc., we\'ll say that a\n;; pattern *consumes* a value. Expressions have values going \"out\", while\n;; patterns have values coming \"in\". And so like expressions have an associated\n;; `value` node in the graph, patterns have an associated `covalue` node. The\n;; covalue corresponds to an incoming value.\n\n;; We build covalues similar to how we build values. Consider the value for an\n;; array such as `[\"foo\", \"bar\"]`, which will be a scope node with pop nodes\n;; going out to the values of the strings, like so:\n\n;; ``````\n;;                            ,---> POP 0 ---> value_node_of_foo\n;; value_node_of_the_array ---|\n;;                            `---> POP 1 ---> value_node_of_bar\n;; ``````\n\n;; Similarly, a covalue for an array pattern will also have nodes for the\n;; sub-patterns and nodes for the first and second indexes. But rather than pop\n;; nodes, which show you where the 0th and 1st elements are, they\'ll be push\n;; nodes to establish the lookup of those elements. The edges will therefore\n;; go the other way around. So for a pattern like `[x,y]`, we have the graph\n\n;; ``````\n;;                                 ,--- PUSH 0 <--- covalue_node_of_x\n;; covalue_node_of_the_pattern <---|\n;;                                 `--- PUSH 1 <--- covalue_node_of_y\n;; ``````\n\n;; For readers familiar with category theory\'s notion of duality, this explains\n;; why these are called \"covalues\". The general schema here is that where values\n;; have pops, covalues have pushes, and all the arrows get flipped.\n\n;; ### Attributes Defined on Patterns\n;; TODO\n[\n  (assignment_pattern)@pattern\n  (object_pattern)@pattern\n  (array_pattern)@pattern\n  (rest_pattern)@pattern\n  (pair_pattern)@pattern\n  (pattern/property_identifier)@pattern\n  (object_assignment_pattern)@pattern\n  (shorthand_property_identifier_pattern)@pattern\n] {\n\n  node @pattern.after_scope\n  node @pattern.before_scope\n  node @pattern.covalue\n  node @pattern.new_bindings\n\n}\n\n;; ### Pattern Queries\n\n;; #### Variable Patterns\n\n; scope propagation through identifier patterns\n(pattern/identifier)@ident_pat {\n\n  node ident_pat_pop\n\n  ; scope flows through, binding via a pop edge that goes to an unknown value\n  attr (ident_pat_pop) node_definition = @ident_pat\n  edge ident_pat_pop -> @ident_pat.covalue\n  edge @ident_pat.after_scope -> ident_pat_pop\n\n  edge @ident_pat.new_bindings -> ident_pat_pop\n}\n\n\n;; #### Object Patterns\n\n(object_pattern (_)* @entries)@object_pat {\n  if (is-empty @entries) {\n    edge @object_pat.after_scope -> @object_pat.before_scope\n  }\n}\n\n; scope propagation through object patterns, first entry\n(object_pattern\n  .\n  (_)@first_entry)@object_pat {\n\n  ; scope propagates from object pattern to entry\n  edge @first_entry.before_scope -> @object_pat.before_scope\n}\n\n; scope propagation through object patterns, between entries\n(object_pattern\n  (_)@left_entry\n  .\n  (_)@right_entry) {\n\n  ; scope propagates from left entry to right entry\n  edge @right_entry.before_scope -> @left_entry.after_scope\n}\n\n; scope propagation through object patterns, last entry\n(object_pattern\n  (_)@last_entry\n  .)@object_pat {\n\n  ; scope propagates out from last entry to object pattern\n  edge @object_pat.after_scope -> @last_entry.after_scope\n}\n\n; covalue propagation through object patterns\n(object_pattern\n  (_)@entry)@object_pat {\n\n  ; covalues flow into entries unchanged\n  edge @entry.covalue -> @object_pat.covalue\n\n  edge @object_pat.new_bindings -> @entry.new_bindings\n}\n\n; object entry pair patterns\n(pair_pattern\n  key:(_)@key\n  value:(_)@value_pat)@pair_pat {\n\n  node @key.push\n  node key_push_dot\n\n  ; covalues flow in dotted\n  attr (key_push_dot) push_symbol = \"GUARD:MEMBER\"\n  edge @value_pat.covalue -> @key.push\n  edge @key.push -> key_push_dot\n  edge key_push_dot -> @pair_pat.covalue\n  ; scope flows into value pattern then back out\n  edge @value_pat.before_scope -> @pair_pat.before_scope\n  edge @pair_pat.after_scope -> @value_pat.after_scope\n\n  edge @pair_pat.new_bindings -> @value_pat.new_bindings\n}\n\n(pair_pattern\n  key:(property_identifier)@key)@_pair_pattern {\n\n    attr (@key.push) node_reference = @key\n}\n\n(pair_pattern\n  key:(string)@key)@_pair_pattern {\n\n    attr (@key.push) symbol_reference = (replace (source-text @key) \"\\\"\" \"\"), source_node = @key\n}\n\n; LATER-TODO the left pattern has to be a name, it cant be another pattern\n; object entry assignment patterns\n(object_assignment_pattern\n  left:(_)@left_pat\n  right:(_)@right_expr)@object_assignment_pat {\n\n  ; scope flows both THROUGH and AROUND the RHS, because it\'s a\n  ; by-passable default not a guaranteed value\n\n  ; here we go around\n  edge @left_pat.before_scope -> @object_assignment_pat.before_scope\n\n  ; and here we go through\n  edge @right_expr.before_scope -> @object_assignment_pat.before_scope\n  edge @left_pat.before_scope -> @right_expr.after_scope\n\n  ; and in either case we come out the LHS\n  edge @object_assignment_pat.after_scope -> @left_pat.after_scope\n\n  ; covalues flow both in from the outside and also from the right expression\n  edge @left_pat.covalue -> @object_assignment_pat.covalue\n  edge @left_pat.covalue -> @right_expr.value\n\n  edge @object_assignment_pat.new_bindings -> @left_pat.new_bindings\n\n}\n\n(shorthand_property_identifier_pattern)@shorthand_prop_pat {\n  node pat_pop\n  node pat_push\n  node pat_push_dot\n\n  edge @shorthand_prop_pat.after_scope -> @shorthand_prop_pat.before_scope\n\n  attr (pat_push) node_reference = @shorthand_prop_pat\n  attr (pat_push_dot) push_symbol = \"GUARD:MEMBER\"\n  attr (pat_pop) node_definition = @shorthand_prop_pat\n  edge pat_pop -> pat_push\n  edge pat_push -> pat_push_dot\n  edge pat_push_dot -> @shorthand_prop_pat.covalue\n  edge @shorthand_prop_pat.after_scope -> pat_pop\n\n  edge @shorthand_prop_pat.new_bindings -> pat_pop\n}\n\n\n;; #### Array Patterns\n\n(array_pattern (_)* @pats)@array_pat {\n  if (is-empty @pats) {\n    edge @array_pat.after_scope -> @array_pat.before_scope\n  }\n}\n\n; scope propagation through array patterns, first element\n(array_pattern\n  .\n  (_)@first_el_pat)@array_pat {\n\n  ; scope flows into the first element\n  edge @first_el_pat.before_scope -> @array_pat.before_scope\n}\n\n; scope propagation through array patterns, between element\n(array_pattern\n  (_)@left_el_pat\n  .\n  (_)@right_el_pat) {\n\n  ; scope flows from left to right\n  edge @right_el_pat.before_scope -> @left_el_pat.after_scope\n}\n\n; scope propagation through array patterns, last element\n(array_pattern\n  (_)@last_el_pat\n  .)@array_pat {\n\n  ; scope flow out from the last element\n  edge @array_pat.after_scope -> @last_el_pat.after_scope\n}\n\n; array pattern\n(array_pattern)@array_pat {\n  node @array_pat.element_index_push_dot\n  edge @array_pat.element_index_push_dot -> @array_pat.covalue\n  attr (@array_pat.element_index_push_dot) push_symbol = \"GUARD:MEMBER\"\n}\n\n; array pattern elements\n(array_pattern (_)@element_pat)@array_pat {\n\n  node element_pat_element_index_push\n\n  attr (element_pat_element_index_push) push_symbol = (named-child-index @element_pat)\n  edge @element_pat.covalue -> element_pat_element_index_push\n  edge element_pat_element_index_push -> @array_pat.element_index_push_dot\n\n  edge @array_pat.new_bindings -> @element_pat.new_bindings\n}\n\n\n;; #### Assignment Patterns\n\n; scope propagation through assignment patterns\n(assignment_pattern\n  left:(_)@left_pat\n  right:(_)@right_expr)@assignment_pat {\n\n  ; scope flows both THROUGH and AROUND the RHS, because it\'s a\n  ; by-passable default not a guaranteed value\n\n  ; here we go around\n  edge @left_pat.before_scope -> @assignment_pat.before_scope\n\n  ; and here we go through\n  edge @right_expr.before_scope -> @assignment_pat.before_scope\n  edge @left_pat.before_scope -> @right_expr.after_scope\n\n  ; the pattern\'s covalue is the whole thing\'s, and also the RHS\n  edge @left_pat.covalue -> @assignment_pat.covalue\n  edge @left_pat.covalue -> @right_expr.value\n\n  ; and in either case we come out the LHS\n  edge @assignment_pat.after_scope -> @left_pat.after_scope\n\n  edge @assignment_pat.new_bindings -> @left_pat.new_bindings\n}\n\n\n;; #### Rest Patterns\n\n(rest_pattern (_)@name)@rest_pat {\n  node rest_pat_pop\n  ; scope flows through, binding via a pop edge that goes to an unknown value\n\n  attr (rest_pat_pop) node_definition = @name\n  edge @rest_pat.after_scope -> @rest_pat.before_scope\n  edge @rest_pat.after_scope -> rest_pat_pop\n}\n\n\n\n\n\n\n\n\n\n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}      \n;; \u{2588}\u{2588}      \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \n;;      \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}      \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; ## Special Cases\n;;\n;; There are a number of annoying features that libraries make use of to\n;; effectively add features to JavaScript. While they don\'t technically change\n;; the language in any way, they\'re broad design patterns that are meant to be\n;; used *as if* these things were more language level than not. These often make\n;; it hard to do analysis without actually running code, and so instead, we\n;; define some special case queries that treat these techniques as if they were\n;; indeed core features of the language.\n;;\n;; ### Extend\n;;\n;; The extend method is a mass assignment of values to keys on objects and gets\n;; used a bunch for building module export objects. We special case it here so\n;; that we can do lookup on it because the extend method itself is dependent on\n;; state and mutability, and has no good analytical explanation within the\n;; Stack Graph formalism.\n;;\n;; Since we can\'t extend the actual value, but only the syntactic references to\n;; it in the SG formalism, we treat extend as a kind of shadowing binder,\n;; similar to how we treat `+=` or `*=`.\n\n(\n  (call_expression\n    function: (member_expression\n      object: (identifier)@object\n      property: (_)@_extend)\n    arguments: (arguments (object)@new_fields))@call_expr\n  (#eq? @_extend \"extend\")\n) {\n\n  node object_pop\n  attr (object_pop) node_definition = @object\n  edge @call_expr.after_scope -> object_pop\n  edge object_pop -> @new_fields.value\n\n}\n\n;; ### CommonJS-style Exports\n\n;; CommonJS introduced an export style for pre-ES6 JavaScript that permitted\n;; modules to export functions using an exports object bound to a top-level\n;; variable `exports`. For instance, to export something as `foo`, we would do:\n\n;; ``````javascript\n;; exports.foo = 1;\n;; ``````\n\n;; If we then imported with `require`, the exports object would have `foo` as\n;; a field. Alternatively, we can also specify the entire export object, using\n\n;; ``````javascript\n;; module.exports = my_exported_object;\n;; ``````\n\n(\n  (assignment_expression\n    left: [\n      ( ; exports.foo = ...\n        (member_expression\n          object:(_)@exports\n          property:(_)@property)\n        (#eq? @exports \"exports\")\n      )\n      ( ; module.exports.foo = ...\n        (member_expression\n          object:(member_expression\n            object:(_)@_module\n            property:(_)@exports)\n          property:(_)@property)\n        (#eq? @_module \"module\")\n        (#eq? @exports \"exports\")\n      )\n    ]\n    right: (_)@right)@assignment_expr\n\n) {\n\n  node pop_default_guard\n  node pop_dot\n  node @assignment_expr.pop_name\n\n  attr (pop_default_guard) symbol_definition = \"GUARD:DEFAULT\", source_node = @exports\n  edge @assignment_expr.exports -> pop_default_guard\n\n  attr (pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge pop_default_guard -> pop_dot\n\n  attr (@assignment_expr.pop_name) node_definition = @property\n  attr (@assignment_expr.pop_name) definiens_node = @assignment_expr\n  edge pop_dot -> @assignment_expr.pop_name\n  edge @assignment_expr.pop_name -> @right.value\n\n  ;; For ES6 interoperability, expose members as named exports\n  edge @assignment_expr.exports -> @assignment_expr.pop_name\n\n  node detour_push\n  node @assignment_expr.detour_pop\n\n  scan FILE_PATH {\n\n    \"^(.+/)?([^/]+)/index\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (@assignment_expr.detour_pop) symbol_definition = module_name, source_node = @assignment_expr, definiens_node = @assignment_expr\n      edge pop_default_guard -> detour_push\n      edge detour_push -> @assignment_expr.detour_pop\n      edge @assignment_expr.detour_pop -> @right.value\n    }\n\n    \"^(.+/)?([^/]+)\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (@assignment_expr.detour_pop) symbol_definition = module_name, source_node = @assignment_expr, definiens_node = @assignment_expr\n      edge pop_default_guard -> detour_push\n      edge detour_push -> @assignment_expr.detour_pop\n      edge @assignment_expr.detour_pop -> @right.value\n    }\n\n  }\n\n  node default_detour_push\n  node @assignment_expr.default_detour_pop\n\n  attr (default_detour_push) push_symbol = \"default\"\n  attr (@assignment_expr.default_detour_pop) symbol_definition = \"default\", source_node = @assignment_expr, definiens_node = @assignment_expr\n  edge pop_default_guard -> default_detour_push\n  edge default_detour_push -> @assignment_expr.default_detour_pop\n  edge @assignment_expr.default_detour_pop -> @right.value\n\n}\n\n(\n  (assignment_expression\n    left: (member_expression\n      object:(_)@_module\n      property:(_)@exports)\n    right: (_)@right)@assignment_expr\n  (#eq? @_module \"module\")\n  (#eq? @exports \"exports\")\n) {\n\n  node @assignment_expr.pop_default_guard\n  node pop_dot\n\n  attr (@assignment_expr.pop_default_guard) symbol_definition = \"GUARD:DEFAULT\", source_node = @exports\n  attr (@assignment_expr.pop_default_guard) definiens_node = @assignment_expr\n  edge @assignment_expr.exports -> @assignment_expr.pop_default_guard\n  edge @assignment_expr.pop_default_guard -> @right.value\n\n  ;; For ES6 interoperability, expose members as named exports\n  attr (pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge @assignment_expr.exports -> pop_dot\n  edge pop_dot -> @right.value\n\n  node detour_push\n  node @assignment_expr.detour_pop\n\n  scan FILE_PATH {\n\n    \"^(.+/)?([^/]+)/index\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (@assignment_expr.detour_pop) symbol_definition = module_name, source_node = @assignment_expr, definiens_node = @assignment_expr\n      edge @assignment_expr.pop_default_guard -> detour_push\n      edge detour_push -> @assignment_expr.detour_pop\n      edge @assignment_expr.detour_pop -> @right.value\n    }\n\n    \"^(.+/)?([^/]+)\\.js$\" {\n      let module_name = $2\n      attr (detour_push) push_symbol = module_name\n      attr (@assignment_expr.detour_pop) symbol_definition = module_name, source_node = @assignment_expr, definiens_node = @assignment_expr\n      edge @assignment_expr.pop_default_guard -> detour_push\n      edge detour_push -> @assignment_expr.detour_pop\n      edge @assignment_expr.detour_pop -> @right.value\n    }\n\n  }\n\n  node default_detour_push\n  node @assignment_expr.default_detour_pop\n\n  attr (default_detour_push) push_symbol = \"default\"\n  attr (@assignment_expr.default_detour_pop) symbol_definition = \"default\", source_node = @assignment_expr, definiens_node = @assignment_expr\n  edge @assignment_expr.pop_default_guard -> default_detour_push\n  edge default_detour_push -> @assignment_expr.default_detour_pop\n  edge @assignment_expr.default_detour_pop -> @right.value\n\n}\n\n;; ### CommonJS-style Imports\n\n;; Similar to exports, CommonJS also defines a way to do imports. In general,\n;; these look like `require(expr)`, but in practice the expression is a string\n;; constant, which is the only case we handle.\n\n(\n  (call_expression\n    function:(identifier)@_require\n    arguments:(arguments (string)@source))@call_expr\n  (#eq? @_require \"require\")\n) {\n\n  node default_guard_push\n\n  attr (default_guard_push) symbol_reference = \"GUARD:DEFAULT\", source_node = @source\n  edge @call_expr.value -> default_guard_push\n  edge default_guard_push -> @source.exports\n\n}\n\n;; ### Dynamic Imports\n\n;; Both ES6 and CommonJS modules can be imported using an import function.\n;; In general, these look like `import(expr)`, but in practice the expression\n;; is a string constant, which is the only case we handle.\n;;\n;; The return value of the import function is an object whose properties are\n;; the exports of the module. The default export is assigned to the `default`\n;; property.\n;;\n;; The import function is async and returns a promise. Since we do not support\n;; async functions and promises, we only support the case where the function\n;; is called as `await import(...)`.\n\n(\n  (await_expression\n    (call_expression\n      function:(_)@_import\n      arguments:(arguments (string)@source))\n  )@await_expr\n  (#eq? @_import \"import\")\n) {\n\n  node pop_dot\n  node pop_default\n  node push_guard_default\n\n  attr (pop_dot) pop_symbol = \"GUARD:MEMBER\"\n  edge @await_expr.value -> pop_dot\n  edge pop_dot -> @source.exports\n\n  attr (pop_default) pop_symbol = \"default\"\n  edge pop_dot -> pop_default\n\n  attr (push_guard_default) symbol_reference = \"GUARD:DEFAULT\", source_node = @source\n  edge pop_default -> push_guard_default\n  edge push_guard_default -> @source.exports\n\n}\n\n;; ### ES6 and CommonJS interoperability\n\n;; Nodes supports some interoperability between ES6 and CommonJS modules.\n;;\n;; A CommonJS module can be imported in an ES6 module:\n;;\n;;  - `import foo from \"cjs_module\"` binds `foo` to the value of `module.exports`.\n;;  - `import { foo } from \"cjs_module\"` binds `foo` to the value of `module.exports.foo`.\n;;  - `import(\"cjs_module\")` returns (a promise to) an object with\n;;     - property `default` bound to the value of `module.exports`, and\n;;     - other properties bound to the value of those properties in `module.exports`\n;;       (e.g., `foo` binds `module.exports.foo`).\n;;\n;; A ES6 module can be import in an CommonJS module:\n;;\n;;  - `import(\"es6_module\")` returns (a promise to) an object with\n;;    - property default bound to the value of `export default`, and\n;;    - other properties bound to named exports (e.g., `foo` binds `export { foo }`).\n;;  - `require(\"es6_module\")` is not supported.\n;;\n;; References:\n;;\n;;  - https://nodejs.org/api/esm.html#interoperability-with-commonjs\n;;\n\n\n\n\n\n\n\n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}    \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \n;; \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \n;; \u{2588}\u{2588}   \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588}  \u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \n;; \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}  \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}      \u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}   \u{2588}\u{2588}\u{2588}\u{2588} \u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\u{2588}\n\n;; ## Definiens Rules\n\n;; These rules explain how defined names relate to syntactic definitions\n;; of various forms. Sometimes that\'s declared function names mapping to\n;; the entire function declaration, and sometimes that\'s variables in an\n;; assignment being mapped to the thing it\'s assigned to. The purpose of\n;; these is not to augment stack graphs, per se, but to permit syntax\n;; oriented tools that need to know about approximate call graphs, etc.\n\n;; ### Basic Definiens Rules\n\n;; These rules are all about declarations and terms that have the names\n;; directly in them.\n\n(\n  (class_declaration\n    name:(_)@name\n    body:(class_body\n      member:(method_definition\n        name:(_)@_method_name)@constructor\n    )\n  )\n\n  (#eq? @_method_name \"constructor\")\n) {\n\n  attr (@name.pop) definiens_node = @constructor\n\n}\n\n(function_declaration\n  name:(_)@name\n  parameters:(_)@_call_sig\n  body:(_)@_body)@fun_decl {\n\n  attr (@name.pop) definiens_node = @fun_decl\n\n}\n\n(generator_function_declaration\n  name:(_)@name\n  parameters:(_)@_call_sig\n  body:(_)@_body)@fun_decl {\n\n  attr (@name.pop) definiens_node = @fun_decl\n\n}\n\n(method_definition\n  name:(_)@name\n  parameters:(_)@_call_sig\n  body:(_)@_body)@method_def {\n\n  attr (@name.pop) definiens_node = @method_def\n\n}\n\n(function_expression\n  name:(_)@name\n  parameters:(_)@_call_sig)@fun {\n\n  attr (@name.pop) definiens_node = @fun\n\n}\n\n(generator_function\n  name:(_)@name\n  parameters:(_)@_call_sig)@fun {\n\n  attr (@name.pop) definiens_node = @fun\n\n}\n\n(\n  (class\n    name:(_)@name\n    body:(class_body\n      member:(method_definition\n        name:(_)@_method_name)@constructor\n    )\n  )\n\n  (#eq? @_method_name \"constructor\")\n) {\n\n  attr (@name.pop) definiens_node = @constructor\n\n}\n\n;; ### Assignment-like Rules\n\n;; These rules make up for the fact that JavaScript permits way more\n;; kinds of definitions/declarations than just those that show up in\n;; syntactic declarations of the thing in question.\n\n;; These rules are currently way less precise than we would like but\n;; do provide at least some information about definiens for these\n;; kinds of definitions.\n\n(assignment_expression\n  left: (identifier)@left\n  right: (_))@assignment_expr {\n\n  attr (@left.pop) definiens_node = @assignment_expr\n\n}\n\n(\n  (assignment_expression\n    left: (member_expression\n      object:(identifier)@_object\n      property:(_)@left\n    )\n    right: (_))@assignment_expr\n  (#not-eq? @_object \"module\")\n  (#not-eq? @left \"exports\")\n) {\n\n  node left_definiens_hook\n  node left_ignore_guard\n\n  attr (left_ignore_guard) pop_symbol = \"GUARD:GANDALF\"\n  attr (left_definiens_hook) node_definition = @left\n  attr (left_definiens_hook) definiens_node = @assignment_expr\n  edge @assignment_expr.pkg_pop -> left_ignore_guard\n  edge left_ignore_guard -> left_definiens_hook\n}\n\n(\n  (assignment_expression\n    left: (member_expression\n      object:(identifier)@_object\n      property:(_)@left\n    )\n    right: (_))@assignment_expr\n  (#eq? @_object \"module\")\n  (#eq? @left \"exports\")\n) {\n\n  node left_definiens_hook\n  node left_ignore_guard\n\n  attr (left_ignore_guard) pop_symbol = \"GUARD:GANDALF\"\n  attr (left_definiens_hook) node_definition = @left\n  attr (left_definiens_hook) definiens_node = @assignment_expr\n  edge @assignment_expr.pkg_pop -> left_ignore_guard\n  edge left_ignore_guard -> left_definiens_hook\n\n}\n\n(variable_declaration\n  (variable_declarator\n    name:(identifier)@name))@decl {\n\n  attr (@name.pop) definiens_node = @decl\n\n}\n\n(lexical_declaration\n  (variable_declarator\n    name:(identifier)@name))@decl {\n\n  attr (@name.pop) definiens_node = @decl\n\n}\n\n[\n  (variable_declaration\n    (variable_declarator\n      name:(identifier)@name\n      value: [\n        (function_expression)\n        (generator_function)\n        (arrow_function)\n      ]))\n  (lexical_declaration\n    (variable_declarator\n      name:(identifier)@name\n      value: [\n        (function_expression)\n        (generator_function)\n        (arrow_function)\n      ]))\n  (assignment_expression\n    left: [\n      (identifier)@name\n    ; (member_expression property:(_)@name) ; FIXME member expressions are references and have no .pop\n    ]\n    right: [\n      (function_expression)\n      (generator_function)\n      (arrow_function)\n    ])\n] {\n\n  attr (@name.pop) syntax_type = \"function\"\n\n}\n\n(\n  (assignment_expression\n    left: [\n      ( ; exports.foo = ...\n        (member_expression\n          object:(_)@_exports\n          property:(_)@_property)\n        (#eq? @_exports \"exports\")\n      )\n      ( ; module.exports.foo = ...\n        (member_expression\n          object:(member_expression\n            object:(_)@_module\n            property:(_)@_exports)\n          property:(_)@_property)\n        (#eq? @_module \"module\")\n        (#eq? @_exports \"exports\")\n      )\n    ]\n    right: [\n      (function_expression)\n      (generator_function)\n      (arrow_function)\n    ])@assignment_expr\n\n) {\n\n  attr (@assignment_expr.pop_name) syntax_type = \"function\"\n  attr (@assignment_expr.detour_pop) syntax_type = \"function\"\n  attr (@assignment_expr.default_detour_pop) syntax_type = \"function\"\n\n}\n\n(\n  (assignment_expression\n    left: (member_expression\n      object:(_)@_module\n      property:(_)@_exports)\n    right: [\n      (function_expression)\n      (generator_function)\n      (arrow_function)\n    ])@assignment_expr\n  (#eq? @_module \"module\")\n  (#eq? @_exports \"exports\")\n) {\n\n  attr (@assignment_expr.pop_default_guard) syntax_type = \"function\"\n  attr (@assignment_expr.detour_pop) syntax_type = \"function\"\n  attr (@assignment_expr.default_detour_pop) syntax_type = \"function\"\n\n}\n\n(export_statement \"default\"\n  value:[\n      (function_expression)\n      (generator_function)\n      (arrow_function)\n    ])@export_stmt {\n\n  attr (@export_stmt.pop_guard_default) syntax_type = \"function\"\n  attr (@export_stmt.detour_pop) syntax_type = \"function\"\n  attr (@export_stmt.default_detour_pop) syntax_type = \"function\"\n\n}\n\n(pair\n  key: (_)@name\n  value: [\n    (function_expression)\n    (generator_function)\n    (arrow_function)\n  ]) {\n\n  attr (@name.definiens_hook) syntax_type = \"function\"\n\n}\n\n\n[\n  (variable_declaration\n    (variable_declarator\n      name:(identifier)@name\n      value: (class)))\n  (lexical_declaration\n    (variable_declarator\n      name:(identifier)@name\n      value: (class)))\n  (assignment_expression\n    left: [\n      (identifier)@name\n    ; (member_expression property:(_)@name) ; FIXME member expressions are references and have no .pop\n    ]\n    right: (class))\n] {\n\n  attr (@name.pop) syntax_type = \"class\"\n\n}\n\n(\n  (assignment_expression\n    left: [\n      ( ; exports.foo = ...\n        (member_expression\n          object:(_)@_exports\n          property:(_)@_property)\n        (#eq? @_exports \"exports\")\n      )\n      ( ; module.exports.foo = ...\n        (member_expression\n          object:(member_expression\n            object:(_)@_module\n            property:(_)@_exports)\n          property:(_)@_property)\n        (#eq? @_module \"module\")\n        (#eq? @_exports \"exports\")\n      )\n    ]\n    right: (class))@assignment_expr\n\n) {\n\n  attr (@assignment_expr.pop_name) syntax_type = \"class\"\n  attr (@assignment_expr.detour_pop) syntax_type = \"class\"\n  attr (@assignment_expr.default_detour_pop) syntax_type = \"class\"\n\n}\n\n(\n  (assignment_expression\n    left: (member_expression\n      object:(_)@_module\n      property:(_)@_exports)\n    right: (class))@assignment_expr\n  (#eq? @_module \"module\")\n  (#eq? @_exports \"exports\")\n) {\n\n  attr (@assignment_expr.pop_default_guard) syntax_type = \"class\"\n  attr (@assignment_expr.detour_pop) syntax_type = \"class\"\n  attr (@assignment_expr.default_detour_pop) syntax_type = \"class\"\n\n}\n\n(export_statement \"default\"\n  value:(class))@export_stmt {\n\n  attr (@export_stmt.pop_guard_default) syntax_type = \"class\"\n  attr (@export_stmt.detour_pop) syntax_type = \"class\"\n  attr (@export_stmt.default_detour_pop) syntax_type = \"class\"\n\n}\n\n(pair\n  key: (_)@name\n  value: (class)) {\n\n  attr (@name.definiens_hook) syntax_type = \"class\"\n\n}\n\n(pair\n  key: (_)@name\n  value: (_))@pair_expr {\n\n  node @name.definiens_hook\n  node name_ignore_guard\n\n  attr (name_ignore_guard) pop_symbol = \"GUARD:GANDALF\"\n  attr (@name.definiens_hook) node_definition = @name\n  attr (@name.definiens_hook) definiens_node = @pair_expr\n  edge @pair_expr.pkg_pop -> name_ignore_guard\n  edge name_ignore_guard -> @name.definiens_hook\n\n}\n";
Expand description

The stack graphs tsg source for this language.