;;;;;;;;;;;;;;;;;;;
;; Global Variables
global FILE_PATH ; project relative path of this file
global PROJECT_NAME = "" ; project name, used to isolate different projects in the same stack graph
global JUMP_TO_SCOPE_NODE
global ROOT_NODE
;;;;;;;;;;;;;;;;;;;;;;;
;; Attribute Shorthands
attribute node_definition = node => type = "pop_symbol", node_symbol = node, is_definition
attribute node_reference = node => type = "push_symbol", node_symbol = node, is_reference
attribute pop_node = node => type = "pop_symbol", node_symbol = node
attribute pop_scoped_node = node => type = "pop_scoped_symbol", node_symbol = node
attribute pop_scoped_symbol = symbol => type = "pop_scoped_symbol", symbol = symbol
attribute pop_symbol = symbol => type = "pop_symbol", symbol = symbol
attribute push_node = node => type = "push_symbol", node_symbol = node
attribute push_scoped_node = node => type = "push_scoped_symbol", node_symbol = node
attribute push_scoped_symbol = symbol => type = "push_scoped_symbol", symbol = symbol
attribute push_symbol = symbol => type = "push_symbol", symbol = symbol
attribute scoped_node_definition = node => type = "pop_scoped_symbol", node_symbol = node, is_definition
attribute scoped_node_reference = node => type = "push_scoped_symbol", node_symbol = node, is_reference
attribute symbol_definition = symbol => type = "pop_symbol", symbol = symbol, is_definition
attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, is_reference
attribute node_symbol = node => symbol = (source-text node), source_node = node
; ######
; # # ##### #### #### ##### ## # # ####
; # # # # # # # # # # # # ## ## #
; ###### # # # # # # # # # # ## # ####
; # ##### # # # ### ##### ###### # # #
; # # # # # # # # # # # # # # #
; # # # #### #### # # # # # # ####
;
; ########################################################
(program)@prog {
node @prog.defs
node @prog.lexical_scope
edge @prog.lexical_scope -> ROOT_NODE
edge @prog.lexical_scope -> @prog.defs
}
(program (_)@declaration)@prog {
edge @prog.defs -> @declaration.defs
edge @declaration.lexical_scope -> @prog.lexical_scope
}
;; =======================
;; Top level declarations
;; =======================
[
(module_declaration)
(package_declaration)
(import_declaration)
] @decl
{
node @decl.defs
node @decl.lexical_scope
}
(program
(package_declaration
(identifier)@pkg_name)? @package) @prog {
if none @package {
edge ROOT_NODE -> @prog.defs
} else {
node pkg_def
attr (pkg_def) node_definition = @pkg_name
edge pkg_def -> @prog.defs
edge ROOT_NODE -> pkg_def
}
}
(import_declaration (_) @ref) @import {
edge @ref.lexical_scope -> @import.lexical_scope
}
;; X
(identifier) @name {
node @name.lexical_scope
node @name.type
node @name.ref
attr (@name.ref) node_reference = @name
edge @name.ref -> @name.lexical_scope
}
;; _.X
(scoped_identifier scope: (_) @scope name: (_) @name) @scoped_name {
node @scoped_name.lexical_scope
edge @scope.lexical_scope -> @scoped_name.lexical_scope
edge @name.lexical_scope -> @scope.ref
node @scoped_name.ref
edge @scoped_name.ref -> @name.ref
}
[
(import_declaration (identifier) @_scope @name)
(import_declaration (scoped_identifier scope: (_) @_scope name: (identifier) @name))
] @import {
node def
attr (def) node_definition = @name
edge def -> @name.ref
edge @import.defs -> def
}
;;;;;;;;;;;;;;;;;;;;
;; Class Expressions
; Classes (and other declarations with members, e.g. records, enums, interfaces) define a name in their enclosing scope as well as names belonging to the class itself (i.e. statics) and instances of the class.
;
; They additionally implicitly define `this` available in the bodies of instance methods, and subclasses further define `super`. The nodes defining these point at the types of the class and superclass, respectively.
(class_declaration
name: (identifier) @name
body: (class_body) @class_body) @class {
node def
attr (def) node_definition = @name
node ref
attr (ref) node_reference = @name
edge ref -> @class.lexical_scope
edge @class_body.lexical_scope -> ref
edge @class_body.lexical_scope -> @class.lexical_scope
edge @class_body.lexical_scope -> @class_body.defs
attr (@class_body.lexical_scope -> @class_body.defs) precedence = 1
edge @class.defs -> def
edge def -> @class_body.defs
edge def -> @class_body.static_defs
node this__expr_def
node @class.type
edge @class.lexical_scope -> this__expr_def
attr (this__expr_def) pop_symbol = "this", source_node = @name, empty_source_span
edge this__expr_def -> @class.type
attr (@class.type) pop_symbol = ":"
node def__typeof
attr (def__typeof) pop_symbol = ":"
edge def -> def__typeof
edge def__typeof -> @class_body.static_defs
edge @class.type -> ref
attr (@class.type -> ref) precedence = 1
}
(class_declaration
superclass: (superclass
(_) @superclass_name)
body: (class_body) @class_body) @class {
node ref
attr (ref) node_reference = @superclass_name
edge @superclass_name.lexical_scope -> @class.lexical_scope
edge ref -> @class.lexical_scope
edge @class_body.lexical_scope -> ref
node super__expr_def
node super__expr_def__typeof
edge @class.lexical_scope -> super__expr_def
attr (super__expr_def) pop_symbol = "super", source_node = @superclass_name, empty_source_span
edge super__expr_def -> super__expr_def__typeof
attr (super__expr_def__typeof) pop_symbol = ":"
edge super__expr_def__typeof -> ref
edge @class.type -> ref
}
(class_declaration (type_parameters)) @class {
node @class.type_parameters
edge @class.lexical_scope -> @class.type_parameters
}
(class_declaration (type_parameters (type_parameter) @param)) @class {
edge @class.type_parameters -> @param.def
edge @param.lexical_scope -> @class.lexical_scope
}
(type_parameter (type_identifier) @name) @this {
node @this.def
node @this.lexical_scope
edge @name.lexical_scope -> @this.lexical_scope
attr (@this.def) node_definition = @name
}
(spread_parameter) @spread_param {
node @spread_param.lexical_scope
node @spread_param.def
}
(class_declaration interfaces: (super_interfaces (type_list (_) @type))) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(class_body) @class_body {
node @class_body.lexical_scope
node @class_body.defs
node @class_body.static_defs
}
(class_body (_)@declaration)@class_body {
edge @class_body.defs -> @declaration.defs
edge @class_body.static_defs -> @declaration.static_defs
edge @declaration.lexical_scope -> @class_body.lexical_scope
}
(class_body (block) @block) {
node @block.defs
node @block.static_defs
node @block.lexical_scope
edge @block.lexical_scope -> @block.before_scope
}
;; =====================
;; Member Declarations
;; =====================
; Member declarations can occur as members of classes, enums, etc. They propagate lexical scope and usually define one or more names, available in `defs`.
[
(class_declaration)
(enum_declaration)
(field_declaration)
(interface_declaration)
(method_declaration)
(constructor_declaration)
(annotation_type_declaration)
(constant_declaration)
(record_declaration)
] @decl
{
; FIXME: can we get away with defining one and only one thing for each of these, and therefore having a `.def` node instead of `.defs`?
node @decl.defs
node @decl.lexical_scope
node @decl.static_defs
}
(annotation_type_declaration
name: (identifier) @name) @annotation {
node def
attr (def) node_definition = @name
edge def -> @annotation.lexical_scope
edge @annotation.defs -> def
}
(constructor_declaration body: (constructor_body) @body) @this {
edge @body.lexical_scope -> @this.lexical_scope
}
(constructor_body) @this {
node @this.lexical_scope
}
(constructor_body . (_) @first) @this {
edge @first.before_scope -> @this.lexical_scope
}
(constructor_body (_) @a . (_) @b) {
edge @b.before_scope -> @a.after_scope
}
(explicit_constructor_invocation) @this {
node @this.before_scope
node @this.after_scope
}
(explicit_constructor_invocation constructor: (_) @constructor) @this {
edge @constructor.lexical_scope -> @this.before_scope
}
(explicit_constructor_invocation object: (_) @object) @this {
edge @object.lexical_scope -> @this.before_scope
}
(explicit_constructor_invocation arguments: (argument_list (_) @arg)) @this {
edge @arg.lexical_scope -> @this.before_scope
}
(enum_declaration name: (_) @name) @this {
node def
attr (def) node_definition = @name
edge @this.defs -> def
node @this.constants
attr (@this.constants) pop_symbol = "."
edge def -> @this.constants
; allow A.X field accesses to resolve constants
node def__typeof
attr (def__typeof) pop_symbol = ":"
edge def -> def__typeof
edge def__typeof -> @this.constants
}
(enum_declaration (enum_body (enum_constant name: (_) @name))) @this {
node def
attr (def) node_definition = @name
edge @this.constants -> def
}
(field_declaration
type: (_) @type
declarator: (variable_declarator
name: (_) @name
)
) @field_decl
{
edge @type.lexical_scope -> @field_decl.lexical_scope
node member
edge @field_decl.defs -> member
attr (member) pop_symbol = "."
node def
attr (def) node_definition = @name
edge member -> def
node def__typeof
attr (def__typeof) pop_symbol = ":"
edge def__typeof -> @type.type
edge def -> def__typeof
}
(modifiers) @this {
node @this.lexical_scope
}
(modifiers (_) @annotation) @this {
edge @annotation.ref -> @this.lexical_scope
}
(marker_annotation name: (_) @name) @this {
node @this.ref
attr (@this.ref) node_reference = @name
}
(annotation name: (_) @name) @this {
node @this.ref
node @this.lexical_scope
attr (@this.ref) node_reference = @name
}
(modifiers (annotation arguments: (annotation_argument_list (_) @value))) @this {
edge @value.lexical_scope -> @this.lexical_scope
}
(element_value_array_initializer) @this {
node @this.def
node @this.lexical_scope
}
(element_value_pair value: (_) @value) @this {
node @this.lexical_scope
edge @value.lexical_scope -> @this.lexical_scope
}
(field_declaration (modifiers) @modifiers) @decl {
edge @modifiers.lexical_scope -> @decl.lexical_scope
}
(interface_declaration name: (_) @name body: (_) @body) @this {
node def
attr (def) node_definition = @name
edge @this.defs -> def
edge def -> @body.defs
edge @body.lexical_scope -> @this.lexical_scope
}
(interface_declaration (extends_interfaces (type_list (_) @type))) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(interface_declaration
type_parameters: (type_parameters
(type_parameter
(type_identifier) @type_identifier))
body: (_) @body) @_this {
node type_ident
attr (type_ident) node_definition = @type_identifier
edge @body.lexical_scope -> type_ident
}
(interface_body) @this {
node @this.defs
node @this.lexical_scope
}
(interface_body (_) @child) @this {
edge @this.defs -> @child.defs
edge @child.lexical_scope -> @this.lexical_scope
}
(method_declaration
(modifiers "static"?@is_static)?
type: (_) @type
name: (identifier) @name
body: (block) @_block) @method
{
edge @type.lexical_scope -> @method.lexical_scope
node member
if none @is_static {
edge @method.defs -> member
} else {
edge @method.static_defs -> member
}
attr (member) pop_symbol = "."
node def
attr (def) node_definition = @name
edge member -> def
}
(method_declaration (formal_parameters (_) @param)) @method
{
edge @param.lexical_scope -> @method.lexical_scope
edge @method.lexical_scope -> @param.def
edge @method.defs -> @param.def
}
(formal_parameter type: (_) @type (_) @name) @param
{
node @param.def
node @param.lexical_scope
node def__typeof
edge @type.lexical_scope -> @param.lexical_scope
attr (@param.def) node_definition = @name
attr (def__typeof) pop_symbol = ":"
edge def__typeof -> @type.type
edge @param.def -> def__typeof
}
(formal_parameter (modifiers) @modifiers) @this {
edge @modifiers.lexical_scope -> @this.lexical_scope
}
(method_declaration
(modifiers) @modifiers) @this {
edge @modifiers.lexical_scope -> @this.lexical_scope
}
(method_declaration
body: (_) @stmt) @method
{
edge @stmt.before_scope -> @method.lexical_scope
}
(record_declaration name: (_) @name body: (_) @body) @this {
node def
attr (def) node_definition = @name
edge @this.defs -> def
edge @body.lexical_scope -> @this.lexical_scope
}
(record_declaration parameters: (formal_parameters (_) @param)) @this {
edge @param.lexical_scope -> @this.lexical_scope
edge @this.lexical_scope -> @param.def
edge @this.defs -> @param.def
}
;; ============
;; Statements
;; ============
; Statements are sequenced one after the next, and some (local variable declarations) bring names into scope/shadow existing names for subsequent statements. Thus, instead of having a lexical scope, they have before and after scopes; the before scope points to the previous statement, or the parent scope for the first statement in a sequence, while the after scope points either at the before scope (if no variable is bound) or at a node referencing any variables the statement binds.
[
(assert_statement)
(block)
(break_statement)
(continue_statement)
(declaration)
(do_statement)
(expression_statement)
(enhanced_for_statement)
(for_statement)
(if_statement)
(labeled_statement)
(local_variable_declaration)
(return_statement)
(switch_expression)
(synchronized_statement)
(throw_statement)
(try_statement)
(try_with_resources_statement)
(while_statement)
(yield_statement)
] @stmt
{
node @stmt.before_scope
node @stmt.after_scope
}
(assert_statement) @stmt {
edge @stmt.after_scope -> @stmt.before_scope
}
(assert_statement (expression) @expr) @stmt {
edge @expr.lexical_scope -> @stmt.before_scope
}
(block
(_) @left
.
(_) @right
)
{
edge @right.before_scope -> @left.after_scope
}
(block
.
(_) @first) @block {
edge @first.before_scope -> @block.before_scope
}
(block
(_) @last
. ) @block {
edge @block.after_scope -> @last.after_scope
}
(break_statement (identifier) @_name) @this {
edge @this.after_scope -> @this.before_scope
}
(break_statement (identifier) @name) @stmt {
node ref
node ns
attr (ref) node_reference = @name
edge ref -> ns
attr (ns) push_symbol = "%Label"
edge ns -> @stmt.before_scope
}
(continue_statement) @this {
edge @this.after_scope -> @this.before_scope
}
(continue_statement (identifier) @name) @this {
node ref
node ns
attr (ref) node_reference = @name
edge ref -> ns
attr (ns) push_symbol = "%Label"
edge ns -> @this.before_scope
}
(declaration) @_decl {}
(do_statement body: (_) @body condition: (_) @cond) @stmt {
edge @body.before_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
edge @cond.lexical_scope -> @stmt.before_scope
}
(expression_statement (_) @expr) @expr_stmt
{
edge @expr.lexical_scope -> @expr_stmt.before_scope
edge @expr_stmt.after_scope -> @expr_stmt.before_scope
}
(enhanced_for_statement type: (_) @type (_) @name value: (_) @value body: (_) @body) @stmt {
edge @type.lexical_scope -> @stmt.before_scope
edge @value.lexical_scope -> @stmt.before_scope
node def
node defs
attr (def) node_definition = @name
edge defs -> @stmt.before_scope
edge defs -> def
edge @body.before_scope -> defs
edge @stmt.after_scope -> @stmt.before_scope
}
(for_statement) @this {
edge @this.after_scope -> @this.before_scope
}
(for_statement !init !condition !update body: (_) @body) @this {
edge @body.before_scope -> @this.before_scope
}
(for_statement init: (expression) @init condition: (_) @condition update: (_) @update body: (_) @body) @stmt {
edge @init.lexical_scope -> @stmt.before_scope
edge @condition.lexical_scope -> @stmt.before_scope
edge @update.lexical_scope -> @stmt.before_scope
edge @body.before_scope -> @stmt.before_scope
}
(for_statement init: (local_variable_declaration) @init condition: (_) @condition update: (_) @update body: (_) @body) @stmt {
edge @init.before_scope -> @stmt.before_scope
edge @condition.lexical_scope -> @init.after_scope
edge @update.lexical_scope -> @init.after_scope
edge @body.before_scope -> @init.after_scope
}
(if_statement condition: (_) @condition consequence: (_) @consequence) @stmt {
edge @condition.lexical_scope -> @stmt.before_scope
edge @consequence.before_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
}
(if_statement alternative: (_) @alternative) @stmt {
edge @alternative.before_scope -> @stmt.before_scope
}
(labeled_statement (identifier) @name (statement) @child) @stmt {
edge @child.before_scope -> @stmt.before_scope
edge @stmt.after_scope -> @child.after_scope
node def
attr (def) node_definition = @name
node ns
attr (ns) pop_symbol = "%Label"
edge ns -> def
edge @stmt.before_scope -> ns
}
(local_variable_declaration
type: (_) @type
declarator: (variable_declarator) @var_decl
) @_local_var
{
edge @var_decl.def__typeof -> @type.type
}
(local_variable_declaration
type: (_) @type) @local_var {
edge @type.lexical_scope -> @local_var.before_scope
}
(variable_declarator value: (_) @value) @this {
edge @value.lexical_scope -> @this.before_scope
}
(local_variable_declaration
declarator: (_) @last
. ) @local_var {
edge @local_var.after_scope -> @last.after_scope
attr (@local_var.after_scope -> @last.after_scope) precedence = 1
}
(local_variable_declaration
type: (_)
.
declarator: (_) @first) @local_var {
edge @first.before_scope -> @local_var.before_scope
}
(local_variable_declaration
declarator: (_) @left
.
declarator: (_) @right
) @_local_var {
edge @right.before_scope -> @left.after_scope
}
(variable_declarator
name: (_) @name) @var_decl {
node @var_decl.before_scope
node @var_decl.after_scope
node @var_decl.def__typeof
attr (@var_decl.def__typeof) pop_symbol = ":"
node def
attr (def) node_definition = @name
edge @var_decl.after_scope -> def
edge @var_decl.after_scope -> @var_decl.before_scope
edge def -> @var_decl.def__typeof
}
(return_statement (_) @expr) @stmt
{
edge @expr.lexical_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
}
(switch_expression condition: (_) @condition body: (_) @body) @stmt {
edge @condition.lexical_scope -> @stmt.before_scope
edge @body.lexical_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
}
(method_declaration
parameters:
(formal_parameters
(formal_parameter
type: (generic_type
(type_arguments
(type_identifier) @type))))
body:
(block
(switch_expression
condition: (_)
body: (switch_block
(switch_block_statement_group
(switch_label
(identifier))
@label))
)) @stmt) {
node ident
attr (ident) node_reference = @type
node ref__typeof
attr(ref__typeof) push_symbol = "."
node implicit_this__typeof
attr(implicit_this__typeof) push_symbol = ":"
edge implicit_this__typeof -> @label.lexical_scope
edge @label.lexical_scope -> ref__typeof
edge ref__typeof -> implicit_this__typeof
edge implicit_this__typeof -> ident
edge ident -> @stmt.after_scope
}
(switch_block) @this {
node @this.lexical_scope
}
(switch_block (switch_block_statement_group (switch_label) @label)) @this {
edge @label.lexical_scope -> @this.lexical_scope
}
(switch_block (switch_block_statement_group (switch_label)+ . (statement) @first)) @this {
edge @first.before_scope -> @this.lexical_scope
}
(switch_block (switch_block_statement_group (switch_label)+ (statement) @a . (statement) @b)) @_this {
edge @b.before_scope -> @a.after_scope
}
(switch_block (switch_rule (switch_label) @label (_) @body)) @this {
edge @label.lexical_scope -> @this.lexical_scope
edge @body.before_scope -> @this.lexical_scope
}
(switch_label) @label {
node @label.lexical_scope
}
(switch_label (expression) @expr) @label {
edge @expr.lexical_scope -> @label.lexical_scope
}
(synchronized_statement (_) @expr body: (_) @body) @stmt {
edge @expr.lexical_scope -> @stmt.before_scope
edge @body.before_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
}
(try_statement body: (_) @body) @stmt {
edge @body.before_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
}
(try_statement (catch_clause (catch_formal_parameter (catch_type) @type (_) @name) body: (_) @body)) @stmt {
node def
node defs
attr (def) node_definition = @name
edge defs -> def
edge @body.before_scope -> defs
edge defs -> @stmt.before_scope
edge @type.lexical_scope -> @stmt.before_scope
node def__typeof
attr (def__typeof) pop_symbol = ":"
edge def -> def__typeof
edge def__typeof -> @type.type
}
(catch_type) @catch_type {
node @catch_type.type
node @catch_type.lexical_scope
}
(catch_type (_) @type) @catch_type {
edge @catch_type.type -> @type.type
edge @type.lexical_scope -> @catch_type.lexical_scope
}
(try_statement (finally_clause (_) @finally)) @stmt {
edge @finally.before_scope -> @stmt.before_scope
}
(try_with_resources_statement) @stmt {
edge @stmt.after_scope -> @stmt.before_scope
}
(try_with_resources_statement resources: (resource_specification . (resource) @first)) @stmt {
edge @first.before_scope -> @stmt.before_scope
}
(try_with_resources_statement resources: (resource_specification (resource) @a . (resource) @b)) @_stmt {
edge @b.before_scope -> @a.after_scope
}
(try_with_resources_statement resources: (resource_specification (resource) @last .) body: (_) @body) @_stmt {
edge @body.before_scope -> @last.after_scope
}
(resource) @this {
node @this.before_scope
node @this.after_scope
}
(resource type: (_) @type (_) @name value: (_) @value) @this {
edge @type.lexical_scope -> @this.before_scope
edge @value.lexical_scope -> @this.before_scope
node def
attr (def) node_definition = @name
node def__typeof
attr (def__typeof) pop_symbol = ":"
edge def -> def__typeof
edge def__typeof -> @type.type
edge @this.after_scope -> def
edge @this.after_scope -> @this.before_scope
}
(resource . (identifier) @name .) @this {
node ref
node ref__typeof
attr (ref) node_reference = @name
edge ref -> @name.lexical_scope
edge @name.lexical_scope -> @this.before_scope
edge @name.type -> ref__typeof
attr (ref__typeof) push_symbol = ":"
edge ref__typeof -> ref
edge @this.after_scope -> @this.before_scope
}
(resource (field_access) @field_access) @this {
edge @field_access.lexical_scope -> @this.before_scope
edge @this.after_scope -> @this.before_scope
}
(try_with_resources_statement (catch_clause (catch_formal_parameter (catch_type) @type (_) @name) body: (_) @body)) @stmt {
node def
node defs
attr (def) node_definition = @name
edge defs -> def
edge @body.before_scope -> defs
edge defs -> @stmt.before_scope
edge @type.lexical_scope -> @stmt.before_scope
node def__typeof
attr (def__typeof) pop_symbol = ":"
edge def -> def__typeof
edge def__typeof -> @type.type
}
(try_with_resources_statement (finally_clause (_) @finally)) @stmt {
edge @finally.before_scope -> @stmt.before_scope
}
(while_statement condition: (_) @condition body: (_) @body) @stmt {
edge @condition.lexical_scope -> @stmt.before_scope
edge @body.before_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
}
(yield_statement (_) @expr) @stmt {
edge @expr.lexical_scope -> @stmt.before_scope
edge @stmt.after_scope -> @stmt.before_scope
}
;; =====================
;; Primary Expressions
;; =====================
(array_access (primary_expression) @array (expression) @index) @this {
edge @array.lexical_scope -> @this.lexical_scope
edge @index.lexical_scope -> @this.lexical_scope
}
(array_creation_expression type: (_) @type) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(array_creation_expression (dimensions_expr (_) @expr)) @this {
edge @expr.lexical_scope -> @this.lexical_scope
}
(array_initializer (_) @expr) @this {
edge @expr.lexical_scope -> @this.lexical_scope
}
(class_literal (_) @type) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(primary_expression/identifier) @name
{
node member
node implicit_this
node implicit_this__typeof
node object__typeof
attr (implicit_this) symbol_reference = "this", empty_source_span
edge implicit_this__typeof -> implicit_this
attr (implicit_this__typeof) push_symbol = ":"
edge implicit_this -> @name.lexical_scope
node ref
attr (ref) node_reference = @name
edge ref -> @name.lexical_scope
attr (ref -> @name.lexical_scope) precedence = 1
edge ref -> member
attr (member) push_symbol = "."
edge member -> object__typeof
edge object__typeof -> implicit_this__typeof
node ref__typeof
edge @name.type -> ref__typeof
attr (ref__typeof) push_symbol = ":"
edge ref__typeof -> ref
}
(field_access
object: (_) @object
field: (identifier) @name) @field_access {
node member
edge @object.lexical_scope -> @field_access.lexical_scope
node ref
attr (ref) node_reference = @name
edge ref -> member
attr (member) push_symbol = "."
edge member -> @object.type
node ref__typeof
edge @field_access.type -> ref__typeof
attr (ref__typeof) push_symbol = ":"
edge ref__typeof -> ref
}
(method_invocation) @method_invocation
{
node @method_invocation.before_scope
node @method_invocation.after_scope
}
(method_invocation arguments: (argument_list (expression) @expr)) @method_invocation {
edge @expr.lexical_scope -> @method_invocation.lexical_scope
}
; method calls with implicit receiver
(method_invocation
!object
name: (identifier) @method_name) @method_invocation {
node member
node implicit_this
node implicit_this__typeof
node object__typeof
; attr (implicit_this) node_reference = @method_invocation
attr (implicit_this) symbol_reference = "this", empty_source_span
; receiver is implicitly "this"
edge implicit_this__typeof -> implicit_this
attr (implicit_this__typeof) push_symbol = ":"
edge implicit_this -> @method_invocation.lexical_scope
node expr_ref
attr (expr_ref) node_reference = @method_name
edge expr_ref -> member
attr (member) push_symbol = "."
edge member -> object__typeof
edge object__typeof -> implicit_this__typeof
node expr_ref__typeof
edge @method_invocation.type -> expr_ref__typeof
attr (expr_ref__typeof) push_symbol = ":"
edge expr_ref__typeof -> expr_ref
}
(method_reference . (_) @lhs) @this {
edge @lhs.lexical_scope -> @this.lexical_scope
}
(method_reference . (_) @lhs (identifier) @name) @this {
node @this.member
node expr_ref
attr (expr_ref) node_reference = @name
edge expr_ref -> @this.member
attr (@this.member) push_symbol = "."
edge @this.member -> @lhs.type
node expr_ref__typeof
; edge @this.type -> expr_ref__typeof ; FIXME: function types
attr (expr_ref__typeof) push_symbol = ":"
edge expr_ref__typeof -> expr_ref
}
(method_reference . (identifier) @lhs (identifier) @_name) @this {
; @lhs could be a type name
node ref
attr (ref) node_reference = @lhs
edge @this.member -> ref
edge ref -> @this.lexical_scope
}
(parenthesized_expression (_) @child) @expr {
edge @child.lexical_scope -> @expr.lexical_scope
}
;; =============
;; Expressions
;; =============
; Expressions have a lexical scope (propagated to child expressions) and a type. The lexical scope is used for lexical name lookup, while types enable type-based name lookup (for field accesses, method lookup, and so forth).
[
(array_initializer)
(assignment_expression)
(binary_expression)
(instanceof_expression)
(lambda_expression)
(ternary_expression)
(update_expression)
(decimal_integer_literal)
(hex_integer_literal)
(octal_integer_literal)
(binary_integer_literal)
(decimal_floating_point_literal)
(hex_floating_point_literal)
(true)
(false)
(character_literal)
(string_literal)
(null_literal)
(class_literal)
(this)
; (identifier)
(parenthesized_expression)
(object_creation_expression)
(field_access)
(array_access)
(method_invocation)
(method_reference)
(array_creation_expression)
(unary_expression)
(cast_expression)
(switch_expression)
(super)
] @expr
{
node @expr.type
node @expr.lexical_scope
}
(assignment_expression left: (identifier) @name) @this {
node member
node implicit_this
node implicit_this__typeof
node object__typeof
attr (implicit_this) symbol_reference = "this", empty_source_span
edge implicit_this__typeof -> implicit_this
attr (implicit_this__typeof) push_symbol = ":"
edge implicit_this -> @name.lexical_scope
node ref
attr (ref) node_reference = @name
edge ref -> @name.lexical_scope
attr (ref -> @name.lexical_scope) precedence = 1
edge ref -> member
attr (member) push_symbol = "."
edge member -> object__typeof
edge object__typeof -> implicit_this__typeof
node ref__typeof
edge @name.type -> ref__typeof
attr (ref__typeof) push_symbol = ":"
edge ref__typeof -> ref
edge @name.lexical_scope -> @this.lexical_scope
}
(assignment_expression left: (field_access) @access) @this {
edge @access.lexical_scope -> @this.lexical_scope
}
(assignment_expression right: (_) @right) @this {
edge @right.lexical_scope -> @this.lexical_scope
}
(binary_expression left: (_) @lhs right: (_) @rhs) @this {
edge @lhs.lexical_scope -> @this.lexical_scope
edge @rhs.lexical_scope -> @this.lexical_scope
}
(cast_expression type: (_) @type) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(cast_expression value: (_) @expr) @this {
edge @expr.lexical_scope -> @this.lexical_scope
}
(instanceof_expression left: (_) @expr right: (_) @type) @this {
edge @expr.lexical_scope -> @this.lexical_scope
edge @type.lexical_scope -> @this.lexical_scope
}
(lambda_expression) @this {
node @this.params
}
(lambda_expression body: (expression) @body) @this {
edge @body.lexical_scope -> @this.lexical_scope
edge @body.lexical_scope -> @this.params
}
(lambda_expression body: (block) @body) @this {
edge @body.before_scope -> @this.lexical_scope
edge @body.before_scope -> @this.params
}
(lambda_expression parameters: (_) @param) @this {
node param
attr (param) node_definition = @param
edge @this.params -> param
}
[
(super)
(this)
] @expr
{
node expr_ref
node expr_ref__typeof
attr (expr_ref) node_reference = @expr
edge expr_ref -> @expr.lexical_scope
edge @expr.type -> expr_ref__typeof
attr (expr_ref__typeof) push_symbol = ":"
edge expr_ref__typeof -> expr_ref
}
(method_invocation
object: (_) @object
name: (identifier) @method_name) @method_invocation {
node member
edge @object.lexical_scope -> @method_invocation.lexical_scope
node expr_ref
attr (expr_ref) node_reference = @method_name
edge expr_ref -> member
attr (member) push_symbol = "."
edge member -> @object.type
node expr_ref__typeof
edge @method_invocation.type -> expr_ref__typeof
attr (expr_ref__typeof) push_symbol = ":"
edge expr_ref__typeof -> expr_ref
}
(object_creation_expression (primary_expression) @child) @this {
edge @child.lexical_scope -> @this.lexical_scope
}
(object_creation_expression type_arguments: (type_arguments (_) @type)) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(object_creation_expression type: (_) @type) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(object_creation_expression arguments: (argument_list (expression) @expr)) @this {
edge @expr.lexical_scope -> @this.lexical_scope
}
(ternary_expression (expression) @expr) @this {
edge @expr.lexical_scope -> @this.lexical_scope
}
(unary_expression (expression) @expr) @this {
edge @expr.lexical_scope -> @this.lexical_scope
}
(update_expression (expression) @expr) @this {
edge @expr.lexical_scope -> @this.lexical_scope
}
;; ==========
;; Types
;; ==========
; Types have a lexical scope for type name lookup.
[
(annotated_type)
(array_type)
(boolean_type)
(floating_point_type)
(generic_type)
(integral_type)
(scoped_type_identifier)
(type_identifier)
(void_type)
] @type
{
node @type.lexical_scope
node @type.type ; FIXME: is this actually needed?
}
[
(boolean_type)
(floating_point_type)
(integral_type)
(type_identifier)
(void_type)
] @type
{
attr (@type.type) node_reference = @type
}
(array_type element: (_) @child) @this {
edge @child.lexical_scope -> @this.lexical_scope
; FIXME: use some sort of subscripting relation for .type
}
(generic_type . (_) @name) @this {
edge @name.lexical_scope -> @this.lexical_scope
}
(generic_type (type_arguments (_) @type)) @this {
edge @type.lexical_scope -> @this.lexical_scope
}
(scoped_type_identifier . (_) @name) @this {
edge @name.lexical_scope -> @this.lexical_scope
}
(wildcard) @this
{
node @this.lexical_scope
}
(type_identifier) @this
{
edge @this.type -> @this.lexical_scope
}
(scoped_type_identifier
(type_identifier) @imported_class_name (type_identifier) @method_name) {
node member
attr (member) push_symbol = "."
edge @method_name.type -> member
edge member -> @imported_class_name.type
}
;; ==========
;; Comments
;; ==========
(line_comment)@line_comment {
node @line_comment.before_scope
node @line_comment.after_scope
node @line_comment.lexical_defs
node @line_comment.lexical_scope
node @line_comment.defs
node @line_comment.ref
node @line_comment.static_defs
edge @line_comment.after_scope -> @line_comment.before_scope
}
(block_comment)@block_comment {
node @block_comment.before_scope
node @block_comment.after_scope
node @block_comment.defs
node @block_comment.ref
node @block_comment.static_defs
node @block_comment.lexical_scope
edge @block_comment.after_scope -> @block_comment.before_scope
}