mirror of
https://github.com/github/codeql.git
synced 2026-06-25 14:47:04 +02:00
Rewrite AST
This commit is contained in:
@@ -2,36 +2,103 @@ supertypes:
|
||||
expr:
|
||||
- name_expr
|
||||
- int_literal
|
||||
- float_literal
|
||||
- boolean_literal
|
||||
- string_literal
|
||||
- regex_literal
|
||||
- builtin_expr
|
||||
- binary_expr
|
||||
- unary_expr
|
||||
- call_expr
|
||||
- member_access_expr
|
||||
- lambda_expr
|
||||
- unsupported_node
|
||||
stmt:
|
||||
- empty_stmt
|
||||
- block_stmt
|
||||
- expr_stmt
|
||||
- if_stmt
|
||||
- variable_declaration_stmt
|
||||
- guard_if_stmt
|
||||
- unsupported_node
|
||||
condition:
|
||||
- expr_condition
|
||||
- let_pattern_condition
|
||||
- sequence_condition
|
||||
- super_expr
|
||||
- function_expr
|
||||
- array_literal
|
||||
- map_literal
|
||||
- key_value_pair
|
||||
- tuple_expr
|
||||
- type_cast_expr
|
||||
- type_test_expr
|
||||
- if_expr
|
||||
- assign_expr
|
||||
- compound_assign_expr
|
||||
- pattern_guard_expr
|
||||
- empty_expr
|
||||
- block
|
||||
- break_expr
|
||||
- continue_expr
|
||||
- return_expr
|
||||
- throw_expr
|
||||
- try_expr
|
||||
- switch_expr
|
||||
- unsupported_node
|
||||
expr_or_pattern:
|
||||
- expr
|
||||
- pattern
|
||||
expr_or_type:
|
||||
- expr
|
||||
- type_expr
|
||||
pattern:
|
||||
- var_pattern
|
||||
- apply_pattern
|
||||
- name_pattern
|
||||
- tuple_pattern
|
||||
- constructor_pattern
|
||||
- ignore_pattern
|
||||
- expr_equality_pattern
|
||||
- bulk_importing_pattern
|
||||
- unsupported_node
|
||||
# A statement is anything that can appear in a block.
|
||||
# This type contains all of 'expr' and has partial overlap with 'member'.
|
||||
# For example, type_alias_declaration can appear either as a stmt or member.
|
||||
# constructor_declaration and destructor_declaration appear here because
|
||||
# tree-sitter-swift's error recovery for #if/#endif in class bodies can place
|
||||
# init/deinit declarations at the wrong (statement) level.
|
||||
stmt:
|
||||
- expr
|
||||
- variable_declaration
|
||||
- type_alias_declaration
|
||||
- function_declaration
|
||||
- import_declaration
|
||||
- operator_syntax_declaration
|
||||
- class_like_declaration
|
||||
- accessor_declaration
|
||||
- constructor_declaration
|
||||
- destructor_declaration
|
||||
- guard_if_stmt
|
||||
- for_each_stmt
|
||||
- while_stmt
|
||||
- do_while_stmt
|
||||
- labeled_stmt
|
||||
# A member is anything that can appear in the body of a class-like declaration
|
||||
member:
|
||||
- constructor_declaration
|
||||
- destructor_declaration
|
||||
- function_declaration
|
||||
- variable_declaration
|
||||
- accessor_declaration
|
||||
- initializer_declaration
|
||||
- class_like_declaration
|
||||
- type_alias_declaration
|
||||
- associated_type_declaration
|
||||
- unsupported_node
|
||||
type_expr:
|
||||
- named_type_expr
|
||||
- generic_type_expr
|
||||
- tuple_type_expr
|
||||
- function_type_expr
|
||||
- inferred_type_expr
|
||||
- unsupported_node
|
||||
type_constraint:
|
||||
- equality_type_constraint
|
||||
- bound_type_constraint
|
||||
operator:
|
||||
- infix_operator
|
||||
- prefix_operator
|
||||
- postfix_operator
|
||||
named:
|
||||
# Top-level is the root node, currently containing a list of expressions
|
||||
# Top-level is the root node, containing a single block of statements
|
||||
# (which are themselves expressions or declarations).
|
||||
top_level:
|
||||
body*: [expr, stmt]
|
||||
body: block
|
||||
|
||||
# An identifier used in the context of an expression
|
||||
name_expr:
|
||||
@@ -40,13 +107,28 @@ named:
|
||||
# An integer literal
|
||||
int_literal:
|
||||
|
||||
# A floating-point literal
|
||||
float_literal:
|
||||
|
||||
# A boolean literal
|
||||
boolean_literal:
|
||||
|
||||
# A literal backed by a keyword such as `nil`, `null`, or `nullptr`.
|
||||
#
|
||||
# Altough nil/null are keyword literals in many languages there should be
|
||||
# no attempt to normalize "null-like" named entities, like Python's `None`.
|
||||
builtin_expr:
|
||||
|
||||
# A string literal
|
||||
string_literal:
|
||||
|
||||
# A regex literal
|
||||
regex_literal:
|
||||
|
||||
# Application of a binary operator, such as `a + b`
|
||||
binary_expr:
|
||||
left: expr
|
||||
operator: operator
|
||||
operator: infix_operator
|
||||
right: expr
|
||||
|
||||
# Application of a unary operator, such as `!x`
|
||||
@@ -54,86 +136,310 @@ named:
|
||||
operand: expr
|
||||
operator: operator
|
||||
|
||||
# A function or method call, such as `f(x)` or `obj.m(x)`. Method calls
|
||||
# are represented as a call whose `function` is a `member_access_expr`.
|
||||
# Plain assignment
|
||||
assign_expr:
|
||||
target: expr_or_pattern
|
||||
value: expr
|
||||
|
||||
# Compound assignment
|
||||
compound_assign_expr:
|
||||
target: expr
|
||||
operator: infix_operator
|
||||
value: expr
|
||||
|
||||
# A function or method call, such as `f(x)` or `obj.m(x)`.
|
||||
#
|
||||
# Method calls are represented as a call whose `function` is a `member_access_expr`.
|
||||
#
|
||||
# Constructor calls are marked by a language-specific modifier, and the target may be
|
||||
# a `type_expr` if the parser can deduce that the target is a type.
|
||||
call_expr:
|
||||
function: expr
|
||||
argument*: expr
|
||||
modifier*: modifier
|
||||
callee: expr_or_type
|
||||
argument*: argument
|
||||
|
||||
argument:
|
||||
modifier*: modifier
|
||||
name?: identifier
|
||||
value: expr
|
||||
|
||||
# Member access, such as `obj.member`.
|
||||
#
|
||||
# The base may be a type expression when it is a static member access like `Array<Int>.method`.
|
||||
# In ambiguous cases where the parser cannot distinguish static and instance member access, the base
|
||||
# will be typically be an expression.
|
||||
#
|
||||
# For `super.x` the base will be an instance of `super_expr`.
|
||||
member_access_expr:
|
||||
target: expr
|
||||
base: expr_or_type
|
||||
member: identifier
|
||||
|
||||
lambda_expr:
|
||||
# A type expression that refers to a type inferred from the contextual type.
|
||||
# This is used to translate Swift's leading-dot syntax, `.foo`, which means `T.foo` where
|
||||
# `T` is the contextual type of some enclosing expression. This is translated to a member_access
|
||||
# with an inferred_type_expr as the base.
|
||||
inferred_type_expr:
|
||||
|
||||
# A `super` token, which can usually only appear as the base of member access.
|
||||
super_expr:
|
||||
|
||||
function_expr:
|
||||
modifier*: modifier
|
||||
capture_declaration*: variable_declaration
|
||||
parameter*: parameter
|
||||
body: [expr, stmt]
|
||||
return_type?: type_expr
|
||||
body: block
|
||||
|
||||
# A parameter
|
||||
array_literal:
|
||||
element*: expr
|
||||
|
||||
map_literal:
|
||||
element*: expr
|
||||
|
||||
# A key-value pair, usually appearing as a named argument or as part of a map literal.
|
||||
#
|
||||
# For some languages, the key-value pair is a first class value and this type of expression
|
||||
# may thus appear anywhere in the general case.
|
||||
key_value_pair:
|
||||
key: expr
|
||||
value: expr
|
||||
|
||||
# A tuple expression, such as `(a, b, c)`.
|
||||
tuple_expr:
|
||||
element*: expr
|
||||
|
||||
# A parameter.
|
||||
#
|
||||
# `type` is its declared type annotation (if any)
|
||||
#
|
||||
# `pattern` binds the parameter's internal name(s). For a simple parameter this is a
|
||||
# `name_pattern`, but may be an arbitrary pattern for languages where patterns may appear
|
||||
# in the parameter list.
|
||||
#
|
||||
# `external_name` is the name by which to call sites refer to the parameter, if the parameter
|
||||
# can be passed as a named parameter. For example, the Swift function `func greet(person id: String)`
|
||||
# would have `person` as the external name and a `name_pattern` wrapping `id` is the parameter's pattern.
|
||||
parameter:
|
||||
modifier*: modifier
|
||||
external_name?: identifier
|
||||
type?: type_expr
|
||||
pattern?: pattern
|
||||
default?: expr
|
||||
|
||||
# An expression that does nothing. Used where the grammar permits an
|
||||
# empty statement (e.g. a stray `;`).
|
||||
empty_expr:
|
||||
|
||||
# A brace-delimited sequence of statements (`{ ... }`). Blocks are the
|
||||
# only nodes that can directly contain statements; every other body-like
|
||||
# field holds a single `block`.
|
||||
block:
|
||||
stmt*: stmt
|
||||
|
||||
if_expr:
|
||||
condition: expr
|
||||
then?: expr
|
||||
else?: expr
|
||||
|
||||
# A variable declaration or destructuring assignment that introduces new variables.
|
||||
#
|
||||
# Any occurrence of `var_patterns` in 'pattern' result in fresh bindings that are
|
||||
# in scope for the rest of the enclosing block.
|
||||
#
|
||||
# The initializer is optional (but typically cannot be omitted if combined with a non-trivial pattern).
|
||||
#
|
||||
# Modifiers should include 'var', 'let', 'const', etc, if they are significant.
|
||||
# A grouped declaration like `let x = 1, y = 2` is emitted as a sequence of
|
||||
# `variable_declaration`s directly into the enclosing stmt/member slot; every
|
||||
# declaration after the first in such a group is tagged with a synthetic
|
||||
# `chained_declaration` modifier so the grouping can be recovered downstream.
|
||||
variable_declaration:
|
||||
modifier*: modifier
|
||||
pattern: pattern
|
||||
|
||||
empty_stmt:
|
||||
|
||||
block_stmt:
|
||||
body*: stmt
|
||||
|
||||
expr_stmt:
|
||||
expr: expr
|
||||
|
||||
if_stmt:
|
||||
condition: condition
|
||||
then?: stmt
|
||||
else?: stmt
|
||||
|
||||
variable_declaration_stmt:
|
||||
variable_declarator+: variable_declarator
|
||||
|
||||
# A variable declaration, or assignment to a pattern.
|
||||
# The initializer is optional (but typically only possible in combination with a simple variable pattern).
|
||||
variable_declarator:
|
||||
pattern: pattern
|
||||
type?: type_expr
|
||||
value?: expr
|
||||
|
||||
# Evaluate 'condition', and if false, execute 'else' which must break from the enclosing block scope (return, break, etc).
|
||||
# Any variables bound by 'condition' will be in scope for the remainder of the enclosing block scope
|
||||
# (which differs from how if_stmt works).
|
||||
# (which differs from how if_expr works).
|
||||
guard_if_stmt:
|
||||
condition: condition
|
||||
else: stmt
|
||||
condition: expr
|
||||
else: block
|
||||
|
||||
# Evaluates the given condition and interprets it as a boolean (by language conventions)
|
||||
expr_condition:
|
||||
expr: expr
|
||||
# `break` (with optional label)
|
||||
break_expr:
|
||||
label?: identifier
|
||||
|
||||
# A series of statements that are executed before evaluating the trailing condition.
|
||||
# Useful for languages where a conditional clause may be preceded by side-effecting
|
||||
# syntactic elements (e.g. binding clauses) that don't themselves form a condition.
|
||||
sequence_condition:
|
||||
stmt*: stmt
|
||||
condition: condition
|
||||
# `continue` (with optional label)
|
||||
continue_expr:
|
||||
label?: identifier
|
||||
|
||||
# A labeled statement, such as `outer: for ... { ... }`. The labeled
|
||||
# statement appears as the `stmt` field; `break`/`continue` may target
|
||||
# the label.
|
||||
labeled_stmt:
|
||||
label: identifier
|
||||
stmt: stmt
|
||||
|
||||
# `return value` or bare `return`
|
||||
return_expr:
|
||||
value?: expr
|
||||
|
||||
# `throw value`
|
||||
throw_expr:
|
||||
value?: expr
|
||||
|
||||
# An import declaration.
|
||||
#
|
||||
# The semantics of an import are generally:
|
||||
# - Evaluate the 'imported_expr' to a value (possibly a compile-time value, such as namespace)
|
||||
# - Filter away possible values based on modifiers (e.g. type-only imports only accept types)
|
||||
# - Assign the value to the pattern, binding variables and/or type names in scope
|
||||
#
|
||||
import_declaration:
|
||||
modifier*: modifier
|
||||
imported_expr: expr # Qualified names are encoded as a chain of member_access_expr ending with a name_expr
|
||||
pattern?: pattern # Binds local names in scope (possibly via bulk_importing_pattern)
|
||||
|
||||
# `typealias Name = Type`
|
||||
type_alias_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
type_parameter*: type_parameter
|
||||
type_constraint*: type_constraint
|
||||
type: type_expr
|
||||
|
||||
# A top-level function declaration.
|
||||
function_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
type_parameter*: type_parameter
|
||||
type_constraint*: type_constraint
|
||||
parameter*: parameter
|
||||
return_type?: type_expr
|
||||
body?: block
|
||||
|
||||
# `for pattern in iterable [where guard] { body }`.
|
||||
for_each_stmt:
|
||||
modifier*: modifier
|
||||
pattern: pattern
|
||||
iterable: expr
|
||||
guard?: expr
|
||||
body?: block
|
||||
|
||||
# `while condition { body }`.
|
||||
while_stmt:
|
||||
modifier*: modifier
|
||||
condition: expr
|
||||
body?: block
|
||||
|
||||
# `repeat { body } while condition`.
|
||||
do_while_stmt:
|
||||
modifier*: modifier
|
||||
body?: block
|
||||
condition: expr
|
||||
|
||||
# `do { body } catch pattern { ... } catch ...`. Swift uses `do`/`catch`
|
||||
# for error handling; for languages with `try`/`catch`, this is the same shape.
|
||||
try_expr:
|
||||
modifier*: modifier
|
||||
body: block
|
||||
catch_clause*: catch_clause
|
||||
|
||||
catch_clause:
|
||||
modifier*: modifier
|
||||
pattern?: pattern
|
||||
guard?: expr
|
||||
body: block
|
||||
|
||||
# `switch value { case pattern: body case ...: default: body }`
|
||||
switch_expr:
|
||||
modifier*: modifier
|
||||
value: expr
|
||||
case*: switch_case
|
||||
|
||||
# A single `case ...:` (or `default:`) entry in a switch.
|
||||
# An entry with multiple `case p1, p2:` patterns has multiple `pattern`s.
|
||||
# A `default:` entry has no patterns.
|
||||
# An optional `guard` corresponds to a `where`-clause on the case.
|
||||
switch_case:
|
||||
modifier*: modifier
|
||||
pattern*: pattern
|
||||
guard?: expr
|
||||
body: block
|
||||
|
||||
# Evaluate 'expr' and match its result against 'pattern', and return true if it matches.
|
||||
# Variables bound by the pattern will be in scope within the 'true' branch controlled by this condition.
|
||||
let_pattern_condition:
|
||||
# Variables bound by the pattern will be in scope within the 'true' branch controlled by this expression.
|
||||
#
|
||||
# In Swift, `if case let PATTERN = EXPR` maps to this node
|
||||
#
|
||||
# Java: 'if (x instanceof Foo y && w ...) { ... }'
|
||||
pattern_guard_expr:
|
||||
pattern: pattern
|
||||
value: expr
|
||||
|
||||
# A pattern matching anything, binding its value to the given variable
|
||||
var_pattern:
|
||||
# A type cast expression, such as `x as T`, `x as? T`, or `x as! T`. The
|
||||
# operator distinguishes between the variants.
|
||||
type_cast_expr:
|
||||
expr: expr
|
||||
operator: infix_operator
|
||||
type: type_expr
|
||||
|
||||
# A type-test expression, such as `x is T`. Yields a boolean indicating
|
||||
# whether `expr` is an instance of `type`.
|
||||
type_test_expr:
|
||||
expr: expr
|
||||
operator: infix_operator
|
||||
type: type_expr
|
||||
|
||||
# An identifier that introduces a variable.
|
||||
#
|
||||
# When used as a pattern, the pattern matches anything and binds its incoming value to the variable
|
||||
name_pattern:
|
||||
modifier*: modifier
|
||||
identifier: identifier
|
||||
|
||||
# A pattern matching anything, binding no variables, usually using the syntax "_"
|
||||
ignore_pattern:
|
||||
|
||||
# A pattern such as `Some(x)` where `Some` is the constructor and `x` is an argument
|
||||
apply_pattern:
|
||||
constructor: expr
|
||||
argument*: pattern
|
||||
# A pattern that matches if the incoming value is equal to the value of the given expression.
|
||||
# Used for literal patterns in switch (e.g. `case 1:`).
|
||||
expr_equality_pattern:
|
||||
expr: expr
|
||||
|
||||
# A tuple pattern such as `(a, b)` in `let (a, b) = pair`.
|
||||
#
|
||||
# Elements of the tuple pattern can have names, such as Swift's `let (foo: x, bar: y) = tuple`.
|
||||
tuple_pattern:
|
||||
element*: pattern
|
||||
modifier*: modifier
|
||||
element*: pattern_element
|
||||
|
||||
# A pattern such as `Some(x)` where `Some` is the constructor and `x` is an element.
|
||||
# The element names are interpreted as argument labels and/or field names.
|
||||
constructor_pattern:
|
||||
modifier*: modifier
|
||||
constructor: expr_or_type
|
||||
element*: pattern_element
|
||||
|
||||
# A pattern with an optional associated name.
|
||||
pattern_element:
|
||||
modifier*: modifier
|
||||
key?: identifier
|
||||
pattern: pattern
|
||||
|
||||
# A pattern that checks if the incoming value has the given type, and if so, the
|
||||
# value is matched against the given nested pattern (and succeeds iff the nested match succeeds).
|
||||
#
|
||||
# In Swift: `if let y = x as? Foo` is a pattern_guard_expr containing a type_test_pattern
|
||||
# In Java: `x instanceof Foo y` is a type_test_pattern wrapping a name_pattern
|
||||
type_test_pattern:
|
||||
pattern: pattern
|
||||
type: type_expr
|
||||
|
||||
# A '*' pattern that imports all members of the incoming value into the local scope
|
||||
# Currently this can only appear in import declarations.
|
||||
bulk_importing_pattern:
|
||||
modifier*: modifier
|
||||
|
||||
# An simple unqualified identifier token
|
||||
identifier:
|
||||
@@ -141,4 +447,129 @@ named:
|
||||
# A node that we don't yet translate
|
||||
unsupported_node:
|
||||
|
||||
operator:
|
||||
infix_operator:
|
||||
|
||||
prefix_operator:
|
||||
|
||||
postfix_operator:
|
||||
|
||||
# The fixity of a custom operator declaration (e.g. "prefix", "infix",
|
||||
# "postfix"). The value is the keyword string.
|
||||
fixity:
|
||||
|
||||
type_parameter:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
bound?: type_expr
|
||||
|
||||
# A generic constraint of the form `T == U`, requiring two types to be
|
||||
# equal. Appears in `where` clauses on generic declarations
|
||||
# (e.g. Swift `func foo<T, U>() where T == U`).
|
||||
equality_type_constraint:
|
||||
left: type_expr
|
||||
right: type_expr
|
||||
|
||||
# A generic constraint of the form `T: Bound`, requiring a type parameter
|
||||
# to conform to (or inherit from) some other type. Appears in `where`
|
||||
# clauses on generic declarations (e.g. Swift `where T: Equatable`).
|
||||
bound_type_constraint:
|
||||
type: type_expr
|
||||
bound: type_expr
|
||||
|
||||
# `infix operator +++` (and the like) — a declaration of a custom operator.
|
||||
operator_syntax_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
# The fixity specifier (`prefix`, `infix`, `postfix`), when applicable.
|
||||
fixity?: fixity
|
||||
# The declared precedence level, when present (e.g. Swift's
|
||||
# `infix operator +++ : AdditionPrecedence`).
|
||||
precedence?: expr
|
||||
|
||||
# A class-like declaration: class, struct, interface (protocol), enum (or actor).
|
||||
# The syntactic kind is carried as a `modifier` (e.g. "class", "struct",
|
||||
# "interface", "enum", "extension"). The `"enum_case"` modifier additionally
|
||||
# marks a declaration as an enum case with associated values. Extensions are
|
||||
# represented as a class-like declaration with the `"extension"` modifier and
|
||||
# no `name`; the extended type appears as a `base_type`.
|
||||
class_like_declaration:
|
||||
modifier*: modifier
|
||||
name?: identifier
|
||||
type_parameter*: type_parameter
|
||||
type_constraint*: type_constraint
|
||||
base_type*: base_type
|
||||
member*: member
|
||||
|
||||
# One of the base types of a class declaration.
|
||||
#
|
||||
# If the language has multiple kinds of base classes (e.g. extends/implements) the
|
||||
# kind should be included as a modifier on this node.
|
||||
base_type:
|
||||
modifier*: modifier
|
||||
type: type_expr
|
||||
|
||||
constructor_declaration:
|
||||
modifier*: modifier
|
||||
name?: identifier
|
||||
parameter*: parameter
|
||||
body: block
|
||||
|
||||
# A destructor / finalizer (Swift `deinit`, C++ `~T()`, etc.).
|
||||
destructor_declaration:
|
||||
modifier*: modifier
|
||||
body: block
|
||||
|
||||
# Declaration of a single accessor for a property (such as a getter, setter,
|
||||
# or observer like Swift's `willSet`/`didSet`).
|
||||
#
|
||||
# Multiple accessors for the same property are emitted as a sequence of
|
||||
# accessor_declaration nodes; every accessor after the first is tagged with
|
||||
# a synthetic `chained_declaration` modifier so the grouping can be recovered
|
||||
# downstream. Stored properties with observers are emitted as a
|
||||
# variable_declaration followed by one accessor_declaration per observer
|
||||
# (each observer also tagged with `chained_declaration`).
|
||||
accessor_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
accessor_kind: accessor_kind
|
||||
parameter*: parameter
|
||||
type?: type_expr
|
||||
body?: block
|
||||
|
||||
# "get", "set", or a language-specific kind like "didSet"
|
||||
accessor_kind:
|
||||
|
||||
# Static or instance initializer block. That is, code that runs at initialization time of either the class or an instance.
|
||||
initializer_declaration:
|
||||
modifier*: modifier
|
||||
body: block
|
||||
|
||||
associated_type_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
bound?: type_expr
|
||||
|
||||
named_type_expr:
|
||||
qualifier?: type_expr
|
||||
name: identifier
|
||||
|
||||
generic_type_expr:
|
||||
base: type_expr
|
||||
type_argument*: type_expr
|
||||
|
||||
# A tuple type such as `(Int, String)` or `(a: A, b: B)`.
|
||||
tuple_type_expr:
|
||||
element*: tuple_type_element
|
||||
|
||||
# An element of a `tuple_type_expr`, optionally carrying a label.
|
||||
tuple_type_element:
|
||||
name?: identifier
|
||||
type: type_expr
|
||||
|
||||
# A function type such as `(Int, String) -> Bool` or `(x: Int) -> Bool`.
|
||||
function_type_expr:
|
||||
parameter*: parameter
|
||||
return_type: type_expr
|
||||
|
||||
# A modifier such as 'static', 'public', or 'async'. For now this is just a leaf node with a string value.
|
||||
modifier:
|
||||
|
||||
Reference in New Issue
Block a user