============================================
Imports
============================================

import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 } from "module-name";
import defaultMember, { member1, member2 as alias2 } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name";
import { member1 , member2 as alias2, } from "module-name";

----

(program
  (import_statement
    (import_clause (identifier)) (string))
  (import_statement
    (import_clause (namespace_import (identifier))) (string))
  (import_statement
    (import_clause (named_imports (import_specifier (identifier)))) (string))
  (import_statement
    (import_clause (named_imports (import_specifier (identifier)) (import_specifier (identifier)))) (string))
  (import_statement
    (import_clause (named_imports (import_specifier (identifier)) (import_specifier (identifier) (identifier)))) (string))
  (import_statement
    (import_clause (identifier) (named_imports (import_specifier (identifier)) (import_specifier (identifier) (identifier)))) (string))
  (import_statement
    (import_clause (identifier) (namespace_import (identifier))) (string))
  (import_statement
    (string))
  (import_statement
    (import_clause (named_imports (import_specifier (identifier)) (import_specifier (identifier) (identifier)))) (string)))

============================================
Exports
============================================

export { name1, name2, name3, nameN };
export { variable1 as name1, variable2 as name2, nameN };
export let name1, name2, nameN;
export let name1 = value1, name2 = value2, name3, nameN;

export default expression;
export default function () { }
export default function name1() { }
export { name1 as default };

export * from 'foo';
export { name1, name2, nameN } from 'foo';
export { import1 as name1, import2 as name2, nameN } from 'foo';

----

(program
  (export_statement
    (export_clause
      (export_specifier (identifier))
      (export_specifier (identifier))
      (export_specifier (identifier))
      (export_specifier (identifier))))
  (export_statement
    (export_clause
      (export_specifier (identifier) (identifier))
      (export_specifier (identifier) (identifier))
      (export_specifier (identifier))))
  (export_statement
    (lexical_declaration
      (variable_declarator (identifier))
      (variable_declarator (identifier))
      (variable_declarator (identifier))))
  (export_statement
    (lexical_declaration
      (variable_declarator (identifier) (identifier))
      (variable_declarator (identifier) (identifier))
      (variable_declarator (identifier))
      (variable_declarator (identifier))))
  (export_statement
    (identifier))
  (export_statement
    (function (formal_parameters) (statement_block)))
  (export_statement
    (function (identifier) (formal_parameters) (statement_block)))
  (export_statement
    (export_clause (export_specifier (identifier) (identifier))))
  (export_statement
    (string))
  (export_statement
    (export_clause
      (export_specifier (identifier))
      (export_specifier (identifier))
      (export_specifier (identifier)))
    (string))
  (export_statement
    (export_clause
      (export_specifier (identifier) (identifier))
      (export_specifier (identifier) (identifier))
      (export_specifier (identifier)))
    (string)))

============================================
Decorators before exports
============================================

@injectable()
export class Foo {
}

---

(program (export_statement (decorator (call_expression (identifier) (arguments))) (class (identifier) (class_body))))

============================================
If statements
============================================

if (x)
  log(y);

if (a.b) {
  log(c);
  d;
}

----

(program
  (if_statement (parenthesized_expression (identifier))
    (expression_statement (call_expression
      (identifier) (arguments (identifier)))))
  (if_statement (parenthesized_expression (member_expression (identifier) (property_identifier)))
    (statement_block
      (expression_statement (call_expression
        (identifier) (arguments (identifier))))
      (expression_statement (identifier)))))

============================================
If-else statements
============================================

if (x)
  y;
else if (a)
  b;

if (a) {
  c;
  d;
} else {
  e;
}

----

(program
  (if_statement (parenthesized_expression (identifier))
    (expression_statement (identifier))
    (if_statement (parenthesized_expression (identifier))
      (expression_statement (identifier))))
  (if_statement (parenthesized_expression (identifier))
    (statement_block
      (expression_statement (identifier))
      (expression_statement (identifier)))
    (statement_block
      (expression_statement (identifier)))))

============================================
For statements
============================================

for (var a, b; c; d)
  e;

for (i = 0, init(); i < 10; i++)
  log(y);

for (;;) {
  z;
  continue;
}

for (var i = 0
  ; i < l
  ; i++) {
}

---

(program
  (for_statement
    (variable_declaration
      (variable_declarator (identifier))
      (variable_declarator (identifier)))
    (expression_statement (identifier))
    (identifier)
    (expression_statement (identifier)))

  (for_statement
    (expression_statement (sequence_expression
      (assignment_expression (identifier) (number))
      (call_expression (identifier) (arguments))))
    (expression_statement (binary_expression (identifier) (number)))
    (update_expression (identifier))
    (expression_statement (call_expression (identifier) (arguments (identifier)))))

  (for_statement
    (empty_statement)
    (empty_statement)
    (statement_block
      (expression_statement (identifier))
      (continue_statement)))

  (for_statement
    (variable_declaration (variable_declarator (identifier) (number)))
    (expression_statement (binary_expression (identifier) (identifier)))
    (update_expression (identifier))
    (expression_statement (object))))

============================================
For-in statements
============================================

for (item in items)
  item();

for (var item in items || {})
  item();

for (const {thing} in things)
  thing();

---

(program
  (for_in_statement (identifier) (identifier)
    (expression_statement (call_expression (identifier) (arguments))))
  (for_in_statement (identifier) (binary_expression (identifier) (object))
    (expression_statement (call_expression (identifier) (arguments))))
  (for_in_statement
    (object_pattern (shorthand_property_identifier))
    (identifier)
    (expression_statement (call_expression (identifier) (arguments)))))

==========================================
For loops beginning with an in-expression
==========================================

for (key in something && i = 0; i < n; i++) {
  doSomething();
}

---

(program (for_statement
  (expression_statement
    (binary_expression
      (binary_expression (identifier) (identifier))
      (assignment_expression (identifier) (number))))
  (expression_statement (binary_expression (identifier) (identifier)))
  (update_expression (identifier))
  (statement_block
    (expression_statement (call_expression (identifier) (arguments))))))

============================================
For-of statements
============================================

for (a of b)
  process(a);

for (let {a, b} of items || [])
  process(a, b);

---

(program
  (for_of_statement
    (identifier)
    (identifier)
    (expression_statement (call_expression (identifier) (arguments (identifier)))))
  (for_of_statement
    (object_pattern (shorthand_property_identifier) (shorthand_property_identifier))
    (binary_expression (identifier) (array))
    (expression_statement (call_expression (identifier) (arguments (identifier) (identifier))))))

============================================
While statements
============================================

while (a)
  b();

---

(program
  (while_statement (parenthesized_expression (identifier))
    (expression_statement (call_expression (identifier) (arguments)))))

============================================
Do statements
============================================

do {
  a;
} while (b)

do a; while (b)
---

(program
  (do_statement
    (statement_block (expression_statement (identifier)))
    (parenthesized_expression (identifier)))
  (do_statement (expression_statement (identifier)) (parenthesized_expression (identifier))))

============================================
Return statements
============================================

return;
return 5;
return 1,2;
return async;
return a;

---

(program
  (return_statement)
  (return_statement (number))
  (return_statement (sequence_expression (number) (number)))
  (return_statement (identifier))
  (return_statement (identifier)))

============================================
Variable declarations
============================================

var x = 1;
var x, y = {}, z;

---

(program
  (variable_declaration
    (variable_declarator (identifier) (number)))
  (variable_declaration
    (variable_declarator (identifier))
    (variable_declarator (identifier) (object))
    (variable_declarator (identifier))))

============================================
Comments
============================================

{

  // This is a property
  aProperty: 1,

  /*
   * This is a method
   */
  aMethod: function() {}
};

---

(program
  (expression_statement (object
    (comment)
    (pair (property_identifier) (number))
    (comment)
    (pair (property_identifier) (function (formal_parameters) (statement_block))))))

==========================================
Comments between statements
==========================================

// this is the beginning of the script.
// here we go.
var thing = {

  // this is a property.
  // its value is a function.
  key: function(x /* this is a parameter */) {
    // this is one statement
    one();
    // this is another statement
    two();
  }
};

---

(program
  (comment)
  (comment)
  (variable_declaration (variable_declarator
    (identifier)
    (object
      (comment)
      (comment)
      (pair (property_identifier) (function
        (formal_parameters (identifier) (comment))
        (statement_block
          (comment)
          (expression_statement
            (call_expression (identifier) (arguments)))
          (comment)
          (expression_statement
            (call_expression (identifier) (arguments))))))))))

============================================
Comments with asterisks
============================================

/* a */
const a = 1;

/* b **/
const b = 1;

/* c ***/
const c = 1;

/* d

***/
const d = 1;

---

(program
  (comment)
  (lexical_declaration (variable_declarator (identifier) (number)))
  (comment)
  (lexical_declaration (variable_declarator (identifier) (number)))
  (comment)
  (lexical_declaration (variable_declarator (identifier) (number)))
  (comment)
  (lexical_declaration (variable_declarator (identifier) (number))))

==========================================
Comments within expressions
==========================================

y // comment
  * z;

---

(program (expression_statement
  (binary_expression (identifier) (comment) (identifier))))

============================================
Switch statements
============================================

switch (x) {
  case 1:
  case 2:
    something();
    break;
  case "three":
    somethingElse();
    break;
  default:
    return 4;
}

---

(program
  (switch_statement (parenthesized_expression (identifier)) (switch_body
    (switch_case (number))
    (switch_case (number)
      (expression_statement (call_expression (identifier) (arguments)))
      (break_statement))
    (switch_case (string)
      (expression_statement (call_expression (identifier) (arguments)))
      (break_statement))
    (switch_default
      (return_statement (number))))))

============================================
Throw statements
============================================

throw new Error("uh oh");

---

(program
  (throw_statement
    (new_expression (call_expression (identifier) (arguments (string))))))

============================================
Throw statements with sequence expressions
============================================

throw f = 1, f;
throw g = 2, g
---

(program
  (throw_statement
    (sequence_expression (assignment_expression (identifier) (number)) (identifier)))
  (throw_statement
    (sequence_expression (assignment_expression (identifier) (number)) (identifier))))

============================================
Try catch finally statements
============================================

try { a; } catch (b) { c; }
try { d; } finally { e; }
try { f; } catch { g; } finally { h; }

---

(program
  (try_statement
    (statement_block (expression_statement (identifier)))
    (catch_clause (identifier)
      (statement_block (expression_statement (identifier)))))
  (try_statement
    (statement_block (expression_statement (identifier)))
    (finally_clause
      (statement_block (expression_statement (identifier)))))
  (try_statement
    (statement_block (expression_statement (identifier)))
    (catch_clause
      (statement_block (expression_statement (identifier))))
    (finally_clause
      (statement_block (expression_statement (identifier))))))

============================================
Empty statements
============================================

if (true) { ; };;;

---

(program
  (if_statement (parenthesized_expression (true)) (statement_block
    (empty_statement)))
  (empty_statement)
  (empty_statement)
  (empty_statement))

============================================
Labeled statements
============================================

theLoop:
for (;;) {
  if (a) {
    break theLoop;
  } else {
    continue theLoop;
  }
}

---

(program
  (labeled_statement (statement_identifier)
    (for_statement
      (empty_statement)
      (empty_statement)
      (statement_block
        (if_statement (parenthesized_expression (identifier))
          (statement_block (break_statement (statement_identifier)))
          (statement_block (continue_statement (statement_identifier))))))))

============================================
Debugger statements
============================================

debugger;
debugger

---

(program (debugger_statement) (debugger_statement))

============================================
With statements
============================================

with (x) { i; }

---

(program (with_statement (parenthesized_expression (identifier)) (statement_block (expression_statement (identifier)))))

==========================================
Hash bang lines
==========================================

#!/usr/bin/env node

console.log("HI")

---

(program
  (hash_bang_line)
  (expression_statement
    (call_expression
      (member_expression
        (identifier)
        (property_identifier))
      (arguments
        (string)))))
