================================================================================
Let statements
================================================================================

let singleVariable = 1
let (tuple1, tuple2) = (2, 3)
let `default` = 0

--------------------------------------------------------------------------------

(source_file
  (property_declaration
    (pattern
      (simple_identifier))
    (integer_literal))
  (property_declaration
    (pattern
      (pattern
        (simple_identifier))
      (pattern
        (simple_identifier)))
    (tuple_expression
      (integer_literal)
      (integer_literal)))
  (property_declaration
    (pattern
      (simple_identifier))
    (integer_literal)))

================================================================================
C-style compound declaration
================================================================================

var one = 1, two = 2, four = 4, eight = 8

--------------------------------------------------------------------------------

(source_file
  (property_declaration
    (pattern
      (simple_identifier))
    (integer_literal)
    (pattern
      (simple_identifier))
    (integer_literal)
    (pattern
      (simple_identifier))
    (integer_literal)
    (pattern
      (simple_identifier))
    (integer_literal)))

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

for value: MyType in values {
    print(value)
}

for case .some(value) in valuesMaybe { }

for case .some((.some(0), .some(1))) in crazyValues {
}

for var value in values where value.isExcellent() {
}

--------------------------------------------------------------------------------

(source_file
  (for_statement
    (pattern
      (simple_identifier))
    (type_annotation
      (user_type
        (type_identifier)))
    (simple_identifier)
    (statements
      (call_expression
        (simple_identifier)
        (call_suffix
          (value_arguments
            (value_argument
              (simple_identifier)))))))
  (for_statement
    (pattern
      (simple_identifier)
      (pattern
        (simple_identifier)))
    (simple_identifier))
  (for_statement
    (pattern
      (simple_identifier)
      (pattern
        (pattern
          (simple_identifier)
          (pattern
            (integer_literal)))
        (pattern
          (simple_identifier)
          (pattern
            (integer_literal)))))
    (simple_identifier))
  (for_statement
    (pattern
      (simple_identifier))
    (simple_identifier)
    (where_clause
      (where_keyword)
      (call_expression
        (navigation_expression
          (simple_identifier)
          (navigation_suffix
            (simple_identifier)))
        (call_suffix
          (value_arguments))))))

================================================================================
Weird for statements
================================================================================

for case let fileUrl as URL in directory {
}

for case let (a, b?) in tuples {
}

outerLoop: for outerObject in dataArray {
    for innerObject in comparisonArray {
        if outerObject == innerObject {
            isValid = true
            break outerLoop
        }
    }
}

--------------------------------------------------------------------------------

(source_file
  (for_statement
    (pattern
      (pattern
        (simple_identifier))
      (user_type
        (type_identifier)))
    (simple_identifier))
  (for_statement
    (pattern
      (pattern
        (simple_identifier))
      (pattern
        (simple_identifier)))
    (simple_identifier))
  (statement_label)
  (for_statement
    (pattern
      (simple_identifier))
    (simple_identifier)
    (statements
      (for_statement
        (pattern
          (simple_identifier))
        (simple_identifier)
        (statements
          (if_statement
            (equality_expression
              (simple_identifier)
              (simple_identifier))
            (statements
              (assignment
                (directly_assignable_expression
                  (simple_identifier))
                (boolean_literal))
              (control_transfer_statement
                (simple_identifier)))))))))

================================================================================
While and friends
================================================================================

while idx > 0, input.count > 0 {
    // ...
}

while let .ok(data) = doWork() {
    // ...
}

repeat {
    // ...
} while something()

--------------------------------------------------------------------------------

(source_file
  (while_statement
    (comparison_expression
      (simple_identifier)
      (integer_literal))
    (comparison_expression
      (navigation_expression
        (simple_identifier)
        (navigation_suffix
          (simple_identifier)))
      (integer_literal))
    (comment))
  (while_statement
    (simple_identifier)
    (pattern
      (simple_identifier))
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (comment))
  (repeat_while_statement
    (comment)
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))))

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

switch something {
    case .pattern: return "Hello"
    case expression: return "and"
    case "Literal": return "Goodbye"
    default: return ":)"
}

--------------------------------------------------------------------------------

(source_file
  (switch_statement
    (simple_identifier)
    (switch_entry
      (switch_pattern
        (pattern
          (simple_identifier)))
      (statements
        (control_transfer_statement
          (line_string_literal
            (line_str_text)))))
    (switch_entry
      (switch_pattern
        (pattern
          (simple_identifier)))
      (statements
        (control_transfer_statement
          (line_string_literal
            (line_str_text)))))
    (switch_entry
      (switch_pattern
        (pattern
          (line_string_literal
            (line_str_text))))
      (statements
        (control_transfer_statement
          (line_string_literal
            (line_str_text)))))
    (switch_entry
      (default_keyword)
      (statements
        (control_transfer_statement
          (line_string_literal
            (line_str_text)))))))

================================================================================
Weird switch statements
================================================================================

switch something {
    case let .pattern2(_, bound): fallthrough
    case .ident where someCondition, ident2: fallthrough
    @unknown default: return "Goodbye"
}

switch self {
case .notExecutable(let path?):
    return "File not executable: \(path)"
case let .isExecutable(path?):
    return "File is executable: \(path)"
}

--------------------------------------------------------------------------------

(source_file
  (switch_statement
    (simple_identifier)
    (switch_entry
      (switch_pattern
        (pattern
          (simple_identifier)
          (pattern
            (wildcard_pattern))
          (pattern
            (simple_identifier))))
      (statements
        (simple_identifier)))
    (switch_entry
      (switch_pattern
        (pattern
          (simple_identifier)))
      (where_keyword)
      (simple_identifier)
      (switch_pattern
        (pattern
          (simple_identifier)))
      (statements
        (simple_identifier)))
    (switch_entry
      (modifiers
        (attribute
          (user_type
            (type_identifier))))
      (default_keyword)
      (statements
        (control_transfer_statement
          (line_string_literal
            (line_str_text))))))
  (switch_statement
    (self_expression)
    (switch_entry
      (switch_pattern
        (pattern
          (simple_identifier)
          (pattern
            (simple_identifier))))
      (statements
        (control_transfer_statement
          (line_string_literal
            (line_str_text)
            (interpolated_expression
              (simple_identifier))))))
    (switch_entry
      (switch_pattern
        (pattern
          (simple_identifier)
          (pattern
            (simple_identifier))))
      (statements
        (control_transfer_statement
          (line_string_literal
            (line_str_text)
            (interpolated_expression
              (simple_identifier))))))))

================================================================================
Switch with extra parentheses
================================================================================

switch result {
case let .success((successfulResult)):
    return successfulResult
}

--------------------------------------------------------------------------------

(source_file
  (switch_statement
    (simple_identifier)
    (switch_entry
      (switch_pattern
        (pattern
          (simple_identifier)
          (pattern
            (pattern
              (simple_identifier)))))
      (statements
        (control_transfer_statement
          (simple_identifier))))))

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

import Foundation
import class SomeModule.SomeClass

class Foo { }

import SomethingElse

--------------------------------------------------------------------------------

(source_file
  (import_declaration
    (identifier
      (simple_identifier)))
  (import_declaration
    (identifier
      (simple_identifier)
      (simple_identifier)))
  (class_declaration
    (type_identifier)
    (class_body))
  (import_declaration
    (identifier
      (simple_identifier))))

================================================================================
Do-catch
================================================================================

do {
    let b = 1
} catch let error as MyError {
} catch SomeError.specificError {
} catch let error as MyOtherError where error.code == 2 {
} catch let MyEnumError.missingField(fieldName) { 
} catch MyEnumError.missingField(fieldName: let fieldName) { 
} catch {
}

do {
    let c = 1
}

--------------------------------------------------------------------------------

(source_file
  (do_statement
    (statements
      (property_declaration
        (pattern
          (simple_identifier))
        (integer_literal)))
    (catch_block
      (catch_keyword)
      (pattern
        (pattern
          (simple_identifier))
        (user_type
          (type_identifier))))
    (catch_block
      (catch_keyword)
      (pattern
        (user_type
          (type_identifier))
        (simple_identifier)))
    (catch_block
      (catch_keyword)
      (pattern
        (pattern
          (simple_identifier))
        (user_type
          (type_identifier)))
      (where_clause
        (where_keyword)
        (equality_expression
          (navigation_expression
            (simple_identifier)
            (navigation_suffix
              (simple_identifier)))
          (integer_literal))))
    (catch_block
      (catch_keyword)
      (pattern
        (user_type
          (type_identifier))
        (simple_identifier)
        (pattern
          (simple_identifier))))
    (catch_block
      (catch_keyword)
      (pattern
        (user_type
          (type_identifier))
        (simple_identifier)
        (simple_identifier)
        (pattern
          (simple_identifier))))
    (catch_block
      (catch_keyword)))
  (do_statement
    (statements
      (property_declaration
        (pattern
          (simple_identifier))
        (integer_literal)))))

================================================================================
If let statements
================================================================================

if let something = doThing() {
    anotherThing()
}

if case .someCase(_) = otherThing() {
}

if let something: MyType = doThing() {
}

someLabel: if a.isEmpty, let b = getB() {
}

--------------------------------------------------------------------------------

(source_file
  (if_statement
    (simple_identifier)
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (statements
      (call_expression
        (simple_identifier)
        (call_suffix
          (value_arguments)))))
  (if_statement
    (simple_identifier)
    (pattern
      (wildcard_pattern))
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments))))
  (if_statement
    (simple_identifier)
    (type_annotation
      (user_type
        (type_identifier)))
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments))))
  (statement_label)
  (if_statement
    (navigation_expression
      (simple_identifier)
      (navigation_suffix
        (simple_identifier)))
    (simple_identifier)
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))))

================================================================================
If let with function call
================================================================================

func doSomething() {
    if let a = try? Foo.getValue("key") {
        return a
    }
    return defaultValue
}

--------------------------------------------------------------------------------

(source_file
  (function_declaration
    (simple_identifier)
    (function_body
      (statements
        (if_statement
          (simple_identifier)
          (try_expression
            (call_expression
              (navigation_expression
                (simple_identifier)
                (navigation_suffix
                  (simple_identifier)))
              (call_suffix
                (value_arguments
                  (value_argument
                    (line_string_literal
                      (line_str_text)))))))
          (statements
            (control_transfer_statement
              (simple_identifier))))
        (control_transfer_statement
          (simple_identifier))))))

================================================================================
Compound if let
================================================================================

if let something = doThing(), something.isSpecial() {
    anotherThing()
}

if let something = doThing(), let somethingElse = something.somethingElse() {
    // Nothing
}

--------------------------------------------------------------------------------

(source_file
  (if_statement
    (simple_identifier)
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (call_expression
      (navigation_expression
        (simple_identifier)
        (navigation_suffix
          (simple_identifier)))
      (call_suffix
        (value_arguments)))
    (statements
      (call_expression
        (simple_identifier)
        (call_suffix
          (value_arguments)))))
  (if_statement
    (simple_identifier)
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (simple_identifier)
    (call_expression
      (navigation_expression
        (simple_identifier)
        (navigation_suffix
          (simple_identifier)))
      (call_suffix
        (value_arguments)))
    (comment)))

================================================================================
Else if...
================================================================================

if let aPrime = a {
} else if let bPrime = b {
}

if a == b {
}
else if let cPrime = c {
}

--------------------------------------------------------------------------------

(source_file
  (if_statement
    (simple_identifier)
    (simple_identifier)
    (else)
    (if_statement
      (simple_identifier)
      (simple_identifier)))
  (if_statement
    (equality_expression
      (simple_identifier)
      (simple_identifier))
    (else)
    (if_statement
      (simple_identifier)
      (simple_identifier))))

================================================================================
Else interacts with comments
================================================================================

if foo {
  fooVal = 0; // A comment
}
// Another comment
else if bar {
}

--------------------------------------------------------------------------------

(source_file
  (if_statement
    (simple_identifier)
    (statements
      (assignment
        (directly_assignable_expression
          (simple_identifier))
        (integer_literal)))
    (comment)
    (comment)
    (else)
    (if_statement
      (simple_identifier))))

================================================================================
If try
================================================================================

    if try limit == nil && singleResult && !expectsSingleResult {
        return a
    }

--------------------------------------------------------------------------------

(source_file
  (if_statement
    (try_expression
      (equality_expression
        (simple_identifier)
        (conjunction_expression
          (conjunction_expression
            (simple_identifier)
            (prefix_expression
              (bang)
              (simple_identifier))))))
    (statements
      (control_transfer_statement
        (simple_identifier)))))

================================================================================
Guard statements
================================================================================

guard let something = doThing() else {
    anotherThing()
}

guard someGuard() else {
    anotherThing()
}

guard case .someCase(ident: let foo)? = otherThing() else {
}

guard case justIdentifier = bound else { }

--------------------------------------------------------------------------------

(source_file
  (guard_statement
    (simple_identifier)
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (else)
    (statements
      (call_expression
        (simple_identifier)
        (call_suffix
          (value_arguments)))))
  (guard_statement
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (else)
    (statements
      (call_expression
        (simple_identifier)
        (call_suffix
          (value_arguments)))))
  (guard_statement
    (simple_identifier)
    (simple_identifier)
    (pattern
      (simple_identifier))
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (else))
  (guard_statement
    (simple_identifier)
    (simple_identifier)
    (else)))

================================================================================
Compound guard
================================================================================

guard let something = doThing(), something.isSpecial() else {
    anotherThing()
}

--------------------------------------------------------------------------------

(source_file
  (guard_statement
    (simple_identifier)
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))
    (call_expression
      (navigation_expression
        (simple_identifier)
        (navigation_suffix
          (simple_identifier)))
      (call_suffix
        (value_arguments)))
    (else)
    (statements
      (call_expression
        (simple_identifier)
        (call_suffix
          (value_arguments))))))

================================================================================
Type annotation on `guard case let`
================================================================================

guard case let size: Int = variable.size else {
    return nil
}

--------------------------------------------------------------------------------

(source_file
  (guard_statement
    (simple_identifier)
    (type_annotation
      (user_type
        (type_identifier)))
    (navigation_expression
      (simple_identifier)
      (navigation_suffix
        (simple_identifier)))
    (else)
    (statements
      (control_transfer_statement))))

================================================================================
Availability conditions
================================================================================

if #available(iOS 14.0, *) {
    doSomething()
}

if #available(macOS 10.12.0, *) {
    return 3
} else {
    return 0
}

--------------------------------------------------------------------------------

(source_file
  (if_statement
    (availability_condition
      (identifier
        (simple_identifier))
      (integer_literal)
      (integer_literal))
    (statements
      (call_expression
        (simple_identifier)
        (call_suffix
          (value_arguments)))))
  (if_statement
    (availability_condition
      (identifier
        (simple_identifier))
      (integer_literal)
      (integer_literal)
      (integer_literal))
    (statements
      (control_transfer_statement
        (integer_literal)))
    (else)
    (statements
      (control_transfer_statement
        (integer_literal)))))

================================================================================
Unicode identifiers
================================================================================

let ø = unicode()

--------------------------------------------------------------------------------

(source_file
  (property_declaration
    (pattern
      (simple_identifier))
    (call_expression
      (simple_identifier)
      (call_suffix
        (value_arguments)))))

================================================================================
Contextual keywords are usable as identifiers
================================================================================

public init() {
    // `prefix` doesn't work as a function modifier here, so it's legal as an identifier
    prefix = prefixToJSON

    // But some modifiers are legal!
    weak var weakPrefix = prefix
    final class LocalClass { }

    // Annotations are legal too!
    @someAnnotation
    func innerFunc() { }
}

--------------------------------------------------------------------------------

(source_file
  (function_declaration
    (modifiers
      (visibility_modifier))
    (function_body
      (comment)
      (statements
        (assignment
          (directly_assignable_expression
            (simple_identifier))
          (simple_identifier))
        (comment)
        (property_declaration
          (ownership_modifier)
          (pattern
            (simple_identifier))
          (simple_identifier))
        (class_declaration
          (inheritance_modifier)
          (type_identifier)
          (class_body))
        (comment)
        (function_declaration
          (attribute
            (user_type
              (type_identifier)))
          (simple_identifier)
          (function_body))))))

================================================================================
Compiler diagnostics
================================================================================

#if SOME_FLAG
#error("SOME_FLAG must not be enabled!")
#elseif OTHER_FLAG
#warning("OTHER_FLAG is deprecated!")
#else
#sourceLocation(file: "SomeFile.swift", line: 99)
#endif

--------------------------------------------------------------------------------

(source_file
  (directive)
  (diagnostic)
  (directive)
  (diagnostic)
  (directive)
  (directive)
  (directive))

================================================================================
Async let
================================================================================

async let foo = 64
async let bar = 66

--------------------------------------------------------------------------------

(source_file
  (property_declaration
    (pattern
      (simple_identifier))
    (integer_literal))
  (property_declaration
    (pattern
      (simple_identifier))
    (integer_literal)))
