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.