# Appendix A. Syntax Tree Format

Esprima syntax tree format is derived from the original version of [Mozilla Parser API](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API), which is then formalized and expanded as the [ESTree specification](https://github.com/estree/estree).

**Note**: In the following sections, interfaces are described using the syntax of [TypeScript interface](https://www.typescriptlang.org/docs/handbook/interfaces.html).

Each node is represented as a regular JavaScript object that implements the interface:

```js
interface Node {
  type: string;
}
```

The `type` property is a string that contains the variant type of the node. Each subtype of _Node_ is explained in the subsequent sections.

When the node is annotated with [its location](syntactic-analysis.html#node-location), the interface becomes:

```js
interface Node {
  type: string;
  range?: [number, number];
  loc?: SourceLocation;
}
```

with the source location defined as:

```js
interface Position {
    line: number;
    column: number;
}

interface SourceLocation {
    start: Position;
    end: Position;
    source?: string | null;
}
```

## Expressions and Patterns

A binding pattern can be one of the following:

```js
type BindingPattern = ArrayPattern | ObjectPattern;
```

An expression can be one of the following:

```js
type Expression = ThisExpression | Identifier | Literal |
    ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | ClassExpression |
    TaggedTemplateExpression | MemberExpression | Super | MetaProperty |
    NewExpression | CallExpression | UpdateExpression | AwaitExpression | UnaryExpression |
    BinaryExpression | LogicalExpression | ConditionalExpression |
    YieldExpression | AssignmentExpression | SequenceExpression;
```

### Array Pattern

```js
interface ArrayPattern {
    type: 'ArrayPattern';
    elements: ArrayPatternElement[];
}
```

with

```js
type ArrayPatternElement = AssignmentPattern | Identifier | BindingPattern | RestElement | null;

interface RestElement {
    type: 'RestElement';
    argument: Identifier | BindingPattern;
}
```

### Assignment Pattern

```js
interface AssignmentPattern {
    type: 'AssignmentPattern';
    left: Identifier | BindingPattern;
    right: Expression;
}
```

### Object Pattern

```js
interface ObjectPattern {
    type: 'ObjectPattern';
    properties: Property[];
}
```

### This Expression

```js
interface ThisExpression {
    type: 'ThisExpression';
}
```

### Identifier

```js
interface Identifier {
    type: 'Identifier';
    name: string;
}
```

### Literal

```js
interface Literal {
    type: 'Literal';
    value: boolean | number | string | RegExp | null;
    raw: string;
    regex?: { pattern: string, flags: string };
}
```

The `regex` property only applies to regular expression literals.

### Array Expression

```js
interface ArrayExpression {
    type: 'ArrayExpression';
    elements: ArrayExpressionElement[];
}
```

where

```js
type ArrayExpressionElement = Expression | SpreadElement;
```

### Object Expression

```js
interface ObjectExpression {
    type: 'ObjectExpression';
    properties: Property[];
}
```

where

```js
interface Property {
    type: 'Property';
    key: Expression;
    computed: boolean;
    value: Expression | null;
    kind: 'get' | 'set' | 'init';
    method: false;
    shorthand: boolean;
}
```

### Function Expression

```js
interface FunctionExpression {
    type: 'FunctionExpression';
    id: Identifier | null;
    params: FunctionParameter[];
    body: BlockStatement;
    generator: boolean;
    async: boolean;
    expression: boolean;
}
```

with

```js
type FunctionParameter = AssignmentPattern | Identifier | BindingPattern;
```

The value of `generator` is true for a generator expression.

### Arrow Function Expression

```js
interface ArrowFunctionExpression {
    type: 'ArrowFunctionExpression';
    id: Identifier | null;
    params: FunctionParameter[];
    body: BlockStatement | Expression;
    generator: boolean;
    async: boolean;
    expression: false;
}
```

### Class Expression

```js
interface ClassExpression {
    type: 'ClassExpression';
    id: Identifier | null;
    superClass: Identifier | null;
    body: ClassBody;
}
```

with

```js
interface ClassBody {
    type: 'ClassBody';
    body: MethodDefinition[];
}

interface MethodDefinition {
    type: 'MethodDefinition';
    key: Expression | null;
    computed: boolean;
    value: FunctionExpression | null;
    kind: 'method' | 'constructor';
    static: boolean;
}
```

### Tagged Template Expression

```js
interface TaggedTemplateExpression {
    type: 'TaggedTemplateExpression';
    readonly tag: Expression;
    readonly quasi: TemplateLiteral;
}
```

with

```js
interface TemplateElement {
    type: 'TemplateElement';
    value: { cooked: string; raw: string };
    tail: boolean;
}

interface TemplateLiteral {
    type: 'TemplateLiteral';
    quasis: TemplateElement[];
    expressions: Expression[];
}
```

### Member Expression

```js
interface MemberExpression {
    type: 'MemberExpression';
    computed: boolean;
    object: Expression;
    property: Expression;
}
```

### Super

```js
interface Super {
    type: 'Super';
}
```

### MetaProperty

```js
interface MetaProperty {
    type: 'MetaProperty';
    meta: Identifier;
    property: Identifier;
}
```

### Call and New Expressions

```js
interface CallExpression {
    type: 'CallExpression';
    callee: Expression;
    arguments: ArgumentListElement[];
}

interface NewExpression {
    type: 'NewExpression';
    callee: Expression;
    arguments: ArgumentListElement[];
}
```

with

```js
type ArgumentListElement = Expression | SpreadElement;

interface SpreadElement {
    type: 'SpreadElement';
    argument: Expression;
}
```

### Update Expression

```js
interface UpdateExpression {
    type: 'UpdateExpression';
    operator: '++' | '--';
    argument: Expression;
    prefix: boolean;
}
```

### Await Expression

```js
interface AwaitExpression {
    type: 'AwaitExpression';
    argument: Expression;
}
```

### Unary Expression

```js
interface UnaryExpression {
    type: 'UnaryExpression';
    operator: '+' | '-' | '~' | '!' | 'delete' | 'void' | 'typeof';
    argument: Expression;
    prefix: true;
}
```

### Binary Expression

```js
interface BinaryExpression {
    type: 'BinaryExpression';
    operator: 'instanceof' | 'in' | '+' | '-' | '*' | '/' | '%' | '**' |
        '|' | '^' | '&' | '==' | '!=' | '===' | '!==' |
        '<' | '>' | '<=' | '<<' | '>>' | '>>>';
    left: Expression;
    right: Expression;
}
```

### Logical Expression

```js
interface LogicalExpression {
    type: 'LogicalExpression';
    operator: '||' | '&&';
    left: Expression;
    right: Expression;
}
```

### Conditional Expression

```js
interface ConditionalExpression {
    type: 'ConditionalExpression';
    test: Expression;
    consequent: Expression;
    alternate: Expression;
}
```

### Yield Expression

```js
interface YieldExpression {
    type: 'YieldExpression';
    argument: Expression | null;
    delegate: boolean;
}
```

### Assignment Expression

```js
interface AssignmentExpression {
    type: 'AssignmentExpression';
    operator: '=' | '*=' | '**=' | '/=' | '%=' | '+=' | '-=' |
        '<<=' | '>>=' | '>>>=' | '&=' | '^=' | '|=';
    left: Expression;
    right: Expression;
}
```

### Sequence Expression

```js
interface SequenceExpression {
    type: 'SequenceExpression';
    expressions: Expression[];
}
```

## Statements and Declarations

A statement can be one of the following:

```js
type Statement = BlockStatement | BreakStatement | ContinueStatement |
    DebuggerStatement | DoWhileStatement | EmptyStatement |
    ExpressionStatement | ForStatement | ForInStatement |
    ForOfStatement | FunctionDeclaration | IfStatement |
    LabeledStatement | ReturnStatement | SwitchStatement |
    ThrowStatement | TryStatement | VariableDeclaration |
    WhileStatement | WithStatement;
```

A declaration can be one of the following:

```js
type Declaration = ClassDeclaration | FunctionDeclaration |  VariableDeclaration;
```

A statement list item is either a statement or a declaration:

```js
type StatementListItem = Declaration | Statement;
```

### Block Statement

A series of statements enclosed by a pair of curly braces form a block statement:

```js
interface BlockStatement {
    type: 'BlockStatement';
    body: StatementListItem[];
}
```

### Break Statement

```js
interface BreakStatement {
    type: 'BreakStatement';
    label: Identifier | null;
}
```

### Class Declaration

```js
interface ClassDeclaration {
    type: 'ClassDeclaration';
    id: Identifier | null;
    superClass: Identifier | null;
    body: ClassBody;
}
```

### Continue Statement

```js
interface ContinueStatement {
    type: 'ContinueStatement';
    label: Identifier | null;
}
```

### Debugger Statement

```js
interface DebuggerStatement {
    type: 'DebuggerStatement';
}
```

### Do-While Statement

```js
interface DoWhileStatement {
    type: 'DoWhileStatement';
    body: Statement;
    test: Expression;
}
```

### Empty Statement

```js
interface EmptyStatement {
    type: 'EmptyStatement';
}
```

### Expression Statement

```js
interface ExpressionStatement {
    type: 'ExpressionStatement';
    expression: Expression;
    directive?: string;
}
```

When the expression statement represents a directive (such as `"use strict"`), then the `directive` property will contain the directive string.

### For Statement

```js
interface ForStatement {
    type: 'ForStatement';
    init: Expression | VariableDeclaration | null;
    test: Expression | null;
    update: Expression | null;
    body: Statement;
}
```

### For-In Statement

```js
interface ForInStatement {
    type: 'ForInStatement';
    left: Expression;
    right: Expression;
    body: Statement;
    each: false;
}
```

### For-Of Statement

```js
interface ForOfStatement {
    type: 'ForOfStatement';
    left: Expression;
    right: Expression;
    body: Statement;
}
```

### Function Declaration

```js
interface FunctionDeclaration {
    type: 'FunctionDeclaration';
    id: Identifier | null;
    params: FunctionParameter[];
    body: BlockStatement;
    generator: boolean;
    async: boolean;
    expression: false;
}
```

with

```js
type FunctionParameter = AssignmentPattern | Identifier | BindingPattern;
```

### If Statement

```js
interface IfStatement {
    type: 'IfStatement';
    test: Expression;
    consequent: Statement;
    alternate?: Statement;
}
```

### Labelled Statement

A statement prefixed by a label becomes a labelled statement:

```js
interface LabeledStatement {
    type: 'LabeledStatement';
    label: Identifier;
    body: Statement;
}
```

### Return Statement

```js
interface ReturnStatement {
    type: 'ReturnStatement';
    argument: Expression | null;
}
```

### Switch Statement

```js
interface SwitchStatement {
    type: 'SwitchStatement';
    discriminant: Expression;
    cases: SwitchCase[];
}
```

with

```js
interface SwitchCase {
    type: 'SwitchCase';
    test: Expression | null;
    consequent: Statement[];
}
```

### Throw Statement

```js
interface ThrowStatement {
    type: 'ThrowStatement';
    argument: Expression;
}
```

### Try Statement

```js
interface TryStatement {
    type: 'TryStatement';
    block: BlockStatement;
    handler: CatchClause | null;
    finalizer: BlockStatement | null;
}
```

with

```js
interface CatchClause {
    type: 'CatchClause';
    param: Identifier | BindingPattern;
    body: BlockStatement;
}
```

### Variable Declaration

```js
interface VariableDeclaration {
    type: 'VariableDeclaration';
    declarations: VariableDeclarator[];
    kind: 'var' | 'const' | 'let';
}
```

with

```js
interface VariableDeclarator {
    type: 'VariableDeclarator';
    id: Identifier | BindingPattern;
    init: Expression | null;
}
```

### While Statement

```js
interface WhileStatement {
    type: 'WhileStatement';
    test: Expression;
    body: Statement;
}
```

### With Statement

```js
interface WithStatement {
    type: 'WithStatement';
    object: Expression;
    body: Statement;
}
```

## Scripts and Modules

A program can be either a script or a module.

```js
interface Program {
  type: 'Program';
  sourceType: 'script';
  body: StatementListItem[];
}

interface Program {
  type: 'Program';
  sourceType: 'module';
  body: ModuleItem[];
}
```

with

```js
type StatementListItem = Declaration | Statement;
type ModuleItem = ImportDeclaration | ExportDeclaration | StatementListItem;
```

### Import Declaration

```js
type ImportDeclaration {
    type: 'ImportDeclaration';
    specifiers: ImportSpecifier[];
    source: Literal;
}
```

with

```js
interface ImportSpecifier {
    type: 'ImportSpecifier' | 'ImportDefaultSpecifier' | 'ImportNamespaceSpecifier';
    local: Identifier;
    imported?: Identifier;
}
```

### Export Declaration

An export declaration can be in the form of a batch, a default, or a named declaration.

```js
type ExportDeclaration = ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration;
```

Each possible export declaration is described as follows:

```js
interface ExportAllDeclaration {
    type: 'ExportAllDeclaration';
    source: Literal;
}

interface ExportDefaultDeclaration {
    type: 'ExportDefaultDeclaration';
    declaration: Identifier | BindingPattern | ClassDeclaration | Expression | FunctionDeclaration;
}

interface ExportNamedDeclaration {
    type: 'ExportNamedDeclaration';
    declaration: ClassDeclaration | FunctionDeclaration | VariableDeclaration;
    specifiers: ExportSpecifier[];
    source: Literal;
}
```

with

```js
interface ExportSpecifier {
    type: 'ExportSpecifier';
    exported: Identifier;
    local: Identifier;
};
```
