Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SwiftSyntax: for Good and Evil

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

SwiftSyntax: for Good and Evil

Avatar for Nick Lockwood

Nick Lockwood

April 14, 2025

More Decks by Nick Lockwood

Other Decks in Technology

Transcript

  1. A. A SET OF SWIFT LIBRARIES FOR PARSING, INSPECTING, GENERATING, AND

    TRANSFORMING SWIFT SOURCE CODE1 1 https://github.com/swiftlang/swift-syntax
  2. SWIFTSYNTAX MODULES // From swift-syntax Package.swift .library(name: "SwiftBasicFormat", targets: ["SwiftBasicFormat"]),

    .library(name: "SwiftCompilerPlugin", targets: ["SwiftCompilerPlugin"]), .library(name: "SwiftDiagnostics", targets: ["SwiftDiagnostics"]), .library(name: "SwiftIDEUtils", targets: ["SwiftIDEUtils"]), .library(name: "SwiftOperators", targets: ["SwiftOperators"]), .library(name: "SwiftParser", targets: ["SwiftParser"]), .library(name: "SwiftParserDiagnostics", targets: ["SwiftParserDiagnostics"]), .library(name: "SwiftRefactor", targets: ["SwiftRefactor"]), .library(name: "SwiftSyntax", targets: ["SwiftSyntax"]), .library(name: "SwiftSyntaxBuilder", targets: ["SwiftSyntaxBuilder"]), .library(name: "SwiftSyntaxMacros", targets: ["SwiftSyntaxMacros"]), .library(name: "SwiftSyntaxMacroExpansion", targets: ["SwiftSyntaxMacroExpansion"]), .library(name: "SwiftSyntaxMacrosTestSupport", targets: ["SwiftSyntaxMacrosTestSupport"]), .library(name: "SwiftSyntaxMacrosGenericTestSupport", targets: ["SwiftSyntaxMacrosGenericTestSupport"]), .library(name: "_SwiftCompilerPluginMessageHandling", targets: ["SwiftCompilerPluginMessageHandling"]), .library(name: "_SwiftLibraryPluginProvider", targets: ["SwiftLibraryPluginProvider"]),
  3. SWIFTSYNTAX MODULES // From swift-syntax Package.swift .library(name: "SwiftBasicFormat", targets: ["SwiftBasicFormat"]),

    .library(name: "SwiftCompilerPlugin", targets: ["SwiftCompilerPlugin"]), .library(name: "SwiftDiagnostics", targets: ["SwiftDiagnostics"]), .library(name: "SwiftIDEUtils", targets: ["SwiftIDEUtils"]), .library(name: "SwiftOperators", targets: ["SwiftOperators"]), .library(name: "SwiftParser", targets: ["SwiftParser"]), .library(name: "SwiftParserDiagnostics", targets: ["SwiftParserDiagnostics"]), .library(name: "SwiftRefactor", targets: ["SwiftRefactor"]), .library(name: "SwiftSyntax", targets: ["SwiftSyntax"]), .library(name: "SwiftSyntaxBuilder", targets: ["SwiftSyntaxBuilder"]), .library(name: "SwiftSyntaxMacros", targets: ["SwiftSyntaxMacros"]), .library(name: "SwiftSyntaxMacroExpansion", targets: ["SwiftSyntaxMacroExpansion"]), .library(name: "SwiftSyntaxMacrosTestSupport", targets: ["SwiftSyntaxMacrosTestSupport"]), .library(name: "SwiftSyntaxMacrosGenericTestSupport", targets: ["SwiftSyntaxMacrosGenericTestSupport"]), .library(name: "_SwiftCompilerPluginMessageHandling", targets: ["SwiftCompilerPluginMessageHandling"]), .library(name: "_SwiftLibraryPluginProvider", targets: ["SwiftLibraryPluginProvider"]),
  4. SYNTAX PROTOCOL struct TokenSyntax: SyntaxProtocol struct FunctionDeclSyntax: DeclSyntaxProtocol struct TupleExprSyntax:

    ExprSyntaxProtocol struct ForStmtSyntax: StmtSyntaxProtcol struct SourceFileSyntax: SyntaxProtocol
  5. USE CASES ‣Language Features → Conditional compilation, macros ‣IDE Tools

    → Swift migration tool, refactoring, fixits and formatting
  6. USE CASES ‣Language Features → Conditional compilation, macros ‣IDE Tools

    → Swift migration tool, refactoring, fixits and formatting ‣Linting → Detecting style violations and enforcing best practices
  7. USE CASES ‣Language Features → Conditional compilation, macros ‣IDE Tools

    → Swift migration tool, refactoring, fixits and formatting ‣Linting → Detecting style violations and enforcing best practices ‣Static Analysis → Detecting dead code, deprecated APIs, etc.
  8. USE CASES ‣Language Features → Conditional compilation, macros ‣IDE Tools

    → Swift migration tool, refactoring, fixits and formatting ‣Linting → Detecting style violations and enforcing best practices ‣Static Analysis → Detecting dead code, deprecated APIs, etc. ‣Code generation → Creating and modifying source code safely
  9. EVALUATING EXPRESSIONS import SwiftParser let source = "1 + 2

    * 3" let sourceSyntax = Parser.parse(source: source) debugPrint(sourceSyntax)
  10. EVALUATING EXPRESSIONS import SwiftParser let source = "1 + 2

    * 3" let sourceSyntax = Parser.parse(source: source) debugPrint(sourceSyntax) SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: SequenceExprSyntax │ ╰─elements: ExprListSyntax │ ├─[0]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─[1]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ├─[2]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─[3]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─[4]: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  11. EVALUATING EXPRESSIONS import SwiftParser let source = "1 + 2

    * 3" let sourceSyntax = Parser.parse(source: source) debugPrint(sourceSyntax) SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: SequenceExprSyntax │ ╰─elements: ExprListSyntax │ ├─[0]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─[1]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ├─[2]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─[3]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─[4]: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  12. CUSTOM OPERATORS // Percentage operator postfix operator % postfix func

    % (value: Double) -> Double { return value / 100 }
  13. CUSTOM OPERATORS // Exponent operator infix operator ^ : MultiplicationPrecedence

    func ^ (base: Double, exponent: Double) -> Double { return pow(base, exponent) }
  14. SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: SequenceExprSyntax │

    ╰─elements: ExprListSyntax │ ├─[0]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─[1]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ├─[2]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─[3]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─[4]: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  15. SWIFTOPERATORS import SwiftParser import SwiftOperators let source = "1 +

    2 * 3" let sourceSyntax = Parser.parse(source: source) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) debugPrint(sourceSyntax)
  16. SWIFTOPERATORS import SwiftParser import SwiftOperators let source = "1 +

    2 * 3" let sourceSyntax = Parser.parse(source: source) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) debugPrint(sourceSyntax)
  17. SWIFTOPERATORS import SwiftParser import SwiftOperators let source = "1 +

    2 * 3" let sourceSyntax = Parser.parse(source: source) let operatorTable = OperatorTable let foldedSyntax = try operatorTable.foldAll(sourceSyntax) debugPrint(sourceSyntax)
  18. SWIFTOPERATORS import SwiftParser import SwiftOperators let source = "1 +

    2 * 3" let sourceSyntax = Parser.parse(source: source) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) debugPrint(sourceSyntax)
  19. SWIFTOPERATORS import SwiftParser import SwiftOperators let source = "1 +

    2 * 3" let sourceSyntax = Parser.parse(source: source) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) debugPrint(foldedSyntax)
  20. SWIFTOPERATORS import SwiftSyntax import SwiftParser import SwiftOperators let source =

    "1 + 2 * 3" let sourceSyntax = Parser.parse(source: source) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) debugPrint(foldedSyntax) SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ╰─rightOperand: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─rightOperand: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  21. SWIFTOPERATORS SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: SequenceExprSyntax

    → │ ╰─elements: ExprListSyntax │ ├─[0]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─[1]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ├─[2]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─[3]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─[4]: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ╰─rightOperand: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─rightOperand: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  22. SWIFTOPERATORS SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: SequenceExprSyntax

    → │ ╰─elements: ExprListSyntax │ ├─[0]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─[1]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ├─[2]: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─[3]: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─[4]: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ╰─rightOperand: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─rightOperand: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  23. INTERPRETER class Interpreter { private var result: Double = .nan

    func evaluate( _ syntax: SyntaxProtocol) -> Double { result = .nan // TODO return result } }
  24. INTERPRETER class Interpreter { private var result: Double = .nan

    func evaluate( _ syntax: SyntaxProtocol) -> Double { result = .nan // TODO return result } }
  25. INTERPRETER class Interpreter { private var result: Double = .nan

    func evaluate( _ syntax: SyntaxProtocol ) -> Double { result = .nan // TODO return result } } SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ╰─rightOperand: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─rightOperand: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  26. INTERPRETER class Interpreter { private var result: Double = .nan

    func evaluate( _ syntax: SyntaxProtocol ) -> Double { result = .nan // TODO return result } } SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ╰─rightOperand: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─rightOperand: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  27. SYNTAX VISITOR open class SyntaxVisitor { public func walk(_ node:

    some SyntaxProtocol) } // Usage let syntaxTree = Parser.parse(source: source) let visitor = MySyntaxVisitor(viewMode: .fixedUp) visitor.walk(syntaxTree)
  28. SYNTAX VISITOR open class SyntaxVisitor { public func walk(_ node:

    some SyntaxProtocol) open func visit(_ node: AccessorBlockSyntax) open func visit(_ node: AccessorDeclListSyntax) open func visit(_ node: AccessorEffectSpeci...) open func visit(_ node: AccessorParametersSyntax) open func visit(_ node: ActorDeclSyntax) ...
  29. INTERPRETER import SwiftSyntax class Interpreter { private var result: Double

    = .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan // TODO return result } }
  30. INTERPRETER import SwiftSyntax class Interpreter: SyntaxVisitor { private var result:

    Double = .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan // TODO return result } }
  31. INTERPRETER import SwiftSyntax class Interpreter: SyntaxVisitor { private var result:

    Double = .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } }
  32. import SwiftSyntax class Interpreter: SyntaxVisitor { private var result: Double

    = .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } }
  33. import SwiftSyntax class Interpreter: SyntaxVisitor { private var result: Double

    = .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } }
  34. import SwiftSyntax class Interpreter: SyntaxVisitor { ... override func visit(_

    node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) switch node.operator.trimmedDescription { case "+": result = lhs + rhs case "-": result = lhs - rhs case "*": result = lhs * rhs case "/": result = lhs / rhs default: break } return .skipChildren } }
  35. import SwiftParser import SwiftOperators print("Type expressions to see the result.

    Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  36. import SwiftParser import SwiftOperators print("Type expressions to see the result.

    Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  37. import SwiftParser import SwiftOperators print("Type expressions to see the result.

    Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  38. import SwiftParser import SwiftOperators print("Type expressions to see the result.

    Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  39. private class ExpressionEvaluator: SyntaxVisitor { var result: Double = .nan

    ... override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) switch node.operator.trimmedDescription { case "+": result = lhs + rhs case "-": result = lhs - rhs case "*": result = lhs * rhs case "/": result = lhs / rhs default: break } return .skipChildren } } Type expressions to see the result. Type 'exit' to quit. > 1 + 2 = 3.0 > 2 + 3 * 4 = 14.0 > 1 / 2 = 0.5 > 1 / 0 = inf > 1 + 2.5 = nan > 3 + * 4 = nan > 3 ++ 4 Swift/ErrorType.swift:253: Fatal error: Error raised at top level: SwiftOperators.OperatorError.missingOperator( "++", referencedFrom: binaryOperator("++"))
  40. private class ExpressionEvaluator: SyntaxVisitor { var result: Double = .nan

    ... override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) switch node.operator.trimmedDescription { case "+": result = lhs + rhs case "-": result = lhs - rhs case "*": result = lhs * rhs case "/": result = lhs / rhs default: break } return .skipChildren } } Type expressions to see the result. Type 'exit' to quit. > 1 + 2 = 3.0 > 2 + 3 * 4 = 14.0 > 1 / 2 = 0.5 > 1 / 0 = inf > 1 + 2.5 = nan > 3 + * 4 = nan > 3 ++ 4 Swift/ErrorType.swift:253: Fatal error: Error raised at top level: SwiftOperators.OperatorError.missingOperator( "++", referencedFrom: binaryOperator("++"))
  41. private class ExpressionEvaluator: SyntaxVisitor { var result: Double = .nan

    ... override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) switch node.operator.trimmedDescription { case "+": result = lhs + rhs case "-": result = lhs - rhs case "*": result = lhs * rhs case "/": result = lhs / rhs default: break } return .skipChildren } } Type expressions to see the result. Type 'exit' to quit. > 1 + 2 = 3.0 > 2 + 3 * 4 = 14.0 > 1 / 2 = 0.5 > 1 / 0 = inf > 1 + 2.5 = nan > 3 + * 4 = nan > 3 ++ 4 Swift/ErrorType.swift:253: Fatal error: Error raised at top level: SwiftOperators.OperatorError.missingOperator( "++", referencedFrom: binaryOperator("++"))
  42. private class ExpressionEvaluator: SyntaxVisitor { var result: Double = .nan

    ... override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) ... return .skipChildren } } Type expressions to see the result. Type 'exit' to quit. > 1 + 2 = 3.0 > 2 + 3 * 4 = 14.0 > 1 / 2 = 0.5 > 1 / 0 = inf > 1 + 2.5 = nan > 3 + * 4 = nan > 3 ++ 4 Swift/ErrorType.swift:253: Fatal error: Error raised at top level: SwiftOperators.OperatorError.missingOperator( "++", referencedFrom: binaryOperator("++"))
  43. private class ExpressionEvaluator: SyntaxVisitor { var result: Double = .nan

    ... override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) ... return .skipChildren } } Type expressions to see the result. Type 'exit' to quit. > 1 + 2 = 3.0 > 2 + 3 * 4 = 14.0 > 1 / 2 = 0.5 > 1 / 0 = inf > 1 + 2.5 = nan > 3 + * 4 = nan > 3 ++ 4 Swift/ErrorType.swift:253: Fatal error: Error raised at top level: SwiftOperators.OperatorError.missingOperator( "++", referencedFrom: binaryOperator("++"))
  44. import SwiftSyntax import SwiftParser import SwiftOperators print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  45. import SwiftSyntax import SwiftParser import SwiftOperators print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  46. ERROR RECOVERY UnexpectedNodesSyntax // For input that couldn't be parsed

    MissingSyntax // For missing nodes MissingStmtSyntax MissingDeclSyntax MissingTypeSyntax MissingExprSyntax etc... extension TokenSyntax { var presence: SourcePresence // present or missing }
  47. ERROR RECOVERY UnexpectedNodesSyntax // For input that couldn't be parsed

    MissingSyntax // For missing nodes MissingStmtSyntax MissingDeclSyntax MissingTypeSyntax MissingExprSyntax etc... extension TokenSyntax { var presence: SourcePresence // present or missing }
  48. ERROR RECOVERY UnexpectedNodesSyntax // For input that couldn't be parsed

    MissingSyntax // For missing nodes MissingStmtSyntax MissingDeclSyntax MissingTypeSyntax MissingExprSyntax etc... extension TokenSyntax { var presence: SourcePresence // present or missing }
  49. ERROR RECOVERY UnexpectedNodesSyntax // For input that couldn't be parsed

    MissingSyntax // For missing nodes MissingStmtSyntax MissingDeclSyntax MissingTypeSyntax MissingExprSyntax etc... extension TokenSyntax { var presence: SourcePresence // present or missing }
  50. VIEWMODE open class SyntaxVisitor { public init(viewMode: SyntaxTreeViewMode) { ...

    } } public enum SyntaxTreeViewMode: Sendable { /// Visit only the nodes present in the original source code case sourceAccurate /// Missing nodes will be visited, unexpected nodes will be skipped case fixedUp /// Both missing and unexpected nodes will be traversed case all }
  51. VIEWMODE open class SyntaxVisitor { public init(viewMode: SyntaxTreeViewMode) { ...

    } } public enum SyntaxTreeViewMode: Sendable { /// Visit only the nodes present in the original source code case sourceAccurate /// Missing nodes will be visited, unexpected nodes will be skipped case fixedUp /// Both missing and unexpected nodes will be traversed case all }
  52. VIEWMODE open class SyntaxVisitor { public init(viewMode: SyntaxTreeViewMode) { ...

    } } public enum SyntaxTreeViewMode: Sendable { /// Visit only the nodes present in the original source code case sourceAccurate /// Missing nodes will be visited, unexpected nodes will be skipped case fixedUp /// Both missing and unexpected nodes will be traversed case all }
  53. import SwiftParser import SwiftOperators print("Type expressions to see the result.

    Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  54. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  55. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParserDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  56. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParserDiagnosticsGenerator.diagnostics(for: sourceSyntax) for diagnostic in diagnostics { print(diagnostic) } let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  57. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParserDiagnosticsGenerator.diagnostics(for: sourceSyntax) for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  58. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParserDiagnosticsGenerator.diagnostics(for: sourceSyntax) for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  59. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParserDiagnosticsGenerator.diagnostics(for: sourceSyntax) for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  60. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParserDiagnosticsGenerator.diagnostics(for: sourceSyntax) for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  61. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParserDiagnosticsGenerator.diagnostics(for: sourceSyntax) for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  62. OPERATOR ERROR extension OperatorTable { public func foldAll( _ node:

    some SyntaxProtocol, errorHandler: OperatorErrorHandler = { throw $0 } ) rethrows -> Syntax } extension OperatorError { /// Produce a diagnostic for a given operator-precedence error. public var asDiagnostic: Diagnostic }
  63. OPERATOR ERROR extension OperatorTable { public func foldAll( _ node:

    some SyntaxProtocol, errorHandler: OperatorErrorHandler = { throw $0 } ) rethrows -> Syntax } extension OperatorError { /// Produce a diagnostic for a given operator-precedence error. public var asDiagnostic: Diagnostic }
  64. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) let diagnostics = ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = try operatorTable.foldAll(sourceSyntax) for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  65. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  66. SYNTAX ANY VISITOR /// A SyntaxVisitor that can visit the

    nodes as generic Syntax values. /// /// This subclass of SyntaxVisitor is slower than the type-specific visitation /// of SyntaxVisitor. Use SyntaxAnyVisitor if the visitAny(_) function /// would be useful to have, otherwise inherit from SyntaxVisitor. /// open class SyntaxAnyVisitor: SyntaxVisitor { open func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { return .visitChildren } ... }
  67. INTERPRETER class Interpreter: SyntaxVisitor { private var result: Double =

    .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } ... }
  68. INTERPRETER class Interpreter: SyntaxAnyVisitor { private var result: Double =

    .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } ... }
  69. INTERPRETER class Interpreter: SyntaxAnyVisitor { private var result: Double =

    .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } ... }
  70. INTERPRETER class Interpreter: SyntaxAnyVisitor { private var result: Double =

    .nan func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { result = .nan return .visitChildren } }
  71. DIAGNOSTIC public struct Diagnostic: CustomDebugStringConvertible, Sendable { public init( node:

    some SyntaxProtocol, position: AbsolutePosition? = nil, message: DiagnosticMessage, highlights: [Syntax]? = nil, notes: [Note] = [], fixIts: [FixIt] = [] ) }
  72. DIAGNOSTIC public struct Diagnostic: CustomDebugStringConvertible, Sendable { public init( node:

    some SyntaxProtocol, position: AbsolutePosition? = nil, message: DiagnosticMessage, highlights: [Syntax]? = nil, notes: [Note] = [], fixIts: [FixIt] = [] ) }
  73. DIAGNOSTIC public struct Diagnostic: CustomDebugStringConvertible, Sendable { public init( node:

    some SyntaxProtocol, position: AbsolutePosition? = nil, message: DiagnosticMessage, highlights: [Syntax]? = nil, notes: [Note] = [], fixIts: [FixIt] = [] ) }
  74. DIAGNOSTIC public protocol DiagnosticMessage: Sendable { /// The diagnostic message

    that should be displayed in the client. var message: String { get } var diagnosticID: MessageID { get } var severity: DiagnosticSeverity { get } }
  75. import SwiftDiagnostics class Interpreter: SyntaxAnyVisitor { private var result: Double

    = .nan ... override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { result = .nan return .visitChildren } }
  76. import SwiftDiagnostics struct Message: DiagnosticMessage { var message: String var

    severity: DiagnosticSeverity = .error var diagnosticID: MessageID { .init(domain: "Interpreter", id: message) } } class Interpreter: SyntaxAnyVisitor { private var result: Double = .nan ... override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { result = .nan return .visitChildren } }
  77. import SwiftDiagnostics struct Message: DiagnosticMessage { var message: String var

    severity: DiagnosticSeverity = .error var diagnosticID: MessageID { .init(domain: "Interpreter", id: message) } } extension SyntaxProtocol { func error(_ message: String) -> Diagnostic { .init(node: self, message: Message(message: message)) } } class Interpreter: SyntaxAnyVisitor { private var result: Double = .nan ... override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { result = .nan return .visitChildren } }
  78. import SwiftDiagnostics struct Message: DiagnosticMessage { var message: String var

    severity: DiagnosticSeverity = .error var diagnosticID: MessageID { .init(domain: "Interpreter", id: message) } } extension SyntaxProtocol { func error(_ message: String) -> Diagnostic { .init(node: self, message: Message(message: message)) } } class Interpreter: SyntaxAnyVisitor { private var result: Double = .nan var diagnostics: [Diagnostic] = [] ... override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { result = .nan return .visitChildren } }
  79. import SwiftDiagnostics struct Message: DiagnosticMessage { var message: String var

    severity: DiagnosticSeverity = .error var diagnosticID: MessageID { .init(domain: "Interpreter", id: message) } } extension SyntaxProtocol { func error(_ message: String) -> Diagnostic { .init(node: self, message: Message(message: message)) } } class Interpreter: SyntaxAnyVisitor { private var result: Double = .nan var diagnostics: [Diagnostic] = [] ... override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax: '\(node.kind)'")) return .visitChildren } }
  80. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } let result = interpreter.evaluate(foldedSyntax) print("= \(result)") }
  81. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } print("= \(result)") }
  82. import SwiftParser import SwiftOperators import SwiftParserDiagnostics print("Type expressions to see

    the result. Type 'exit' to quit.") let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) diagnostics += result.diagnostics result.diagnostics.removeAll() for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } print("= \(result)") }
  83. SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: InfixOperatorExprSyntax │

    ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ╰─rightOperand: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─rightOperand: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  84. SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: InfixOperatorExprSyntax │

    ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("1") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("+") │ ╰─rightOperand: InfixOperatorExprSyntax │ ├─leftOperand: IntegerLiteralExprSyntax │ │ ╰─literal: integerLiteral("2") │ ├─operator: BinaryOperatorExprSyntax │ │ ╰─operator: binaryOperator("*") │ ╰─rightOperand: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("3") ╰─endOfFileToken: endOfFile
  85. class Interpreter: SyntaxAnyVisitor { ... override func visit(_ node: IntegerLiteralExprSyntax)

    -> SyntaxVisitorContinueKind { ... } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax: '\(node.kind)'")) return .visitChildren } }
  86. class Interpreter: SyntaxAnyVisitor { ... override func visit(_ node: IntegerLiteralExprSyntax)

    -> SyntaxVisitorContinueKind { ... } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { ... } override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax: '\(node.kind)'")) return .visitChildren } // MARK: Ignored override open func visit(_ token: SourceFileSyntax) -> SyntaxVisitorContinueKind { return .visitChildren } override open func visit(_ token: CodeBlockItemListSyntax) -> SyntaxVisitorContinueKind { return .visitChildren } override open func visit(_ token: CodeBlockItemSyntax) -> SyntaxVisitorContinueKind { return .visitChildren } override open func visit(_ token: TokenSyntax) -> SyntaxVisitorContinueKind { return .visitChildren } }
  87. enum Variant: Equatable { case undefined case number(Double) case boolean(Bool)

    case string(String) } extension Variant: CustomStringConvertible { var description: String { switch self { case .undefined: "undefined" case let .number(value): "\(value)" case let .boolean(value): "\(value)" case let .string(value): value } } } class Interpreter: SyntaxAnyVisitor { private var result: Double = .nan var diagnostics: [Diagnostic] = [] func evaluate(_ syntax: SyntaxProtocol) -> Double { result = .nan walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = Double(node.literal.text) ?? .nan return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) switch node.operator.trimmedDescription { case "+": result = lhs + rhs case "-": result = lhs - rhs case "*": result = lhs * rhs case "/": result = lhs / rhs default: break } return .skipChildren } ... }
  88. enum Variant: Equatable { case undefined case number(Double) case boolean(Bool)

    case string(String) } extension Variant: CustomStringConvertible { var description: String { switch self { case .undefined: "undefined" case let .number(value): "\(value)" case let .boolean(value): "\(value)" case let .string(value): value } } } class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined var diagnostics: [Diagnostic] = [] func evaluate(_ syntax: SyntaxProtocol) -> Variant { result = .undefined walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = .number(Double(node.literal.text) ?? .nan) return .skipChildren } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = .number(Double(node.literal.text) ?? .nan) return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) switch (lhs, rhs, node.operator.trimmedDescription) { case let (.number(l), .number(r), "+"): result = .number(l + r) case let (.number(l), .number(r), "-"): result = .number(l - r) case let (.number(l), .number(r), "*"): result = .number(l * r) case let (.number(l), .number(r), "/"): result = .number(l / r) default: diagnostics.append(node.error("invalid expression: \(node.trimmed)")) } return .skipChildren } ... }
  89. enum Variant: Equatable { case undefined case number(Double) case boolean(Bool)

    case string(String) } extension Variant: CustomStringConvertible { var description: String { switch self { case .undefined: "undefined" case let .number(value): "\(value)" case let .boolean(value): "\(value)" case let .string(value): value } } } class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined private var variables: [String: Variant] = [:] var diagnostics: [Diagnostic] = [] func evaluate(_ syntax: SyntaxProtocol) -> Variant { result = .undefined walk(syntax) return result } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = .number(Double(node.literal.text) ?? .nan) return .skipChildren } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = .number(Double(node.literal.text) ?? .nan) return .skipChildren } override func visit(_ node: InfixOperatorExprSyntax) -> SyntaxVisitorContinueKind { let lhs = evaluate(node.leftOperand) let rhs = evaluate(node.rightOperand) switch (lhs, rhs, node.operator.trimmedDescription) { case let (.number(l), .number(r), "+"): result = .number(l + r) case let (.number(l), .number(r), "-"): result = .number(l - r) case let (.number(l), .number(r), "*"): result = .number(l * r) case let (.number(l), .number(r), "/"): result = .number(l / r) default: diagnostics.append(node.error("invalid expression: \(node.trimmed)")) } return .skipChildren } ... }
  90. enum Variant: Equatable { case undefined case number(Double) case boolean(Bool)

    case string(String) } extension Variant: CustomStringConvertible { var description: String { switch self { case .undefined: "undefined" case let .number(value): "\(value)" case let .boolean(value): "\(value)" case let .string(value): value } } } class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined private var variables: [String: Variant] = [:] var diagnostics: [Diagnostic] = [] func evaluate(_ syntax: SyntaxProtocol) -> Variant { ... } override func visit(_ node: DeclReferenceExprSyntax) -> SyntaxVisitorContinueKind { if let value = variables[node.baseName.text] { result = value } else { result = .undefined diagnostics.append(node.error("undefined variable '\(node.trimmed)'")) } return .skipChildren } override func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = .number(Double(node.literal.text) ?? .nan) return .skipChildren } override func visit(_ node: FloatLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = .number(Double(node.literal.text) ?? .nan) return .skipChildren } override func visit(_ node: BooleanLiteralExprSyntax) -> SyntaxVisitorContinueKind { result = .boolean(node.literal.tokenKind == .keyword(.true)) return .skipChildren } ... }
  91. enum Variant: Equatable { case undefined case number(Double) case boolean(Bool)

    case string(String) } extension Variant: CustomStringConvertible { var description: String { switch self { case .undefined: "undefined" case let .number(value): "\(value)" case let .boolean(value): "\(value)" case let .string(value): value } } } class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined private var variables: [String: Variant] = [:] var diagnostics: [Diagnostic] = [] func evaluate(_ syntax: SyntaxProtocol) -> Variant { ... } override func visit(_ node: DeclReferenceExprSyntax) -> SyntaxVisitorContinueKind { if let value = variables[node.baseName.text] { result = value } else { result = .undefined diagnostics.append(node.error("undefined variable '\(node.trimmed)'")) } return .skipChildren } override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { for binding in node.bindings { switch binding.pattern.as(PatternSyntaxEnum.self) { case let .identifierPattern(identifier): let value = binding.initializer.map { evaluate($0.value) } variables[identifier.identifier.text] = value ?? .undefined default: diagnostics.append( node.error("unsupported syntax '\(binding.pattern.trimmed)'") ) } } return .skipChildren } ... }
  92. class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined

    private var variables: [String: Variant] = [:] var diagnostics: [Diagnostic] = [] ... override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { for binding in node.bindings { switch binding.pattern.as(PatternSyntaxEnum.self) { case let .identifierPattern(identifier): let value = binding.initializer.map { evaluate($0.value) } variables[identifier.identifier.text] = value ?? .undefined default: diagnostics.append(node.error("unsupported syntax '\(binding.pattern.kind)'")) } } return .skipChildren } override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { variables[node.name.text] = .function(node) return .skipChildren } override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.kind)'")) return .visitChildren } ... }
  93. class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined

    private var variables: [String: Variant] = [:] var diagnostics: [Diagnostic] = [] ... override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { for binding in node.bindings { switch binding.pattern.as(PatternSyntaxEnum.self) { case let .identifierPattern(identifier): let value = binding.initializer.map { evaluate($0.value) } variables[identifier.identifier.text] = value ?? .undefined default: diagnostics.append(node.error("unsupported syntax '\(binding.pattern.kind)'")) } } return .skipChildren } override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { variables[node.name.text] = .function(node) return .skipChildren } override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.kind)'")) return .visitChildren } ... }
  94. class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined

    private var variables: [String: Variant] = [:] var diagnostics: [Diagnostic] = [] ... override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { for binding in node.bindings { switch binding.pattern.as(PatternSyntaxEnum.self) { case let .identifierPattern(identifier): let value = binding.initializer.map { evaluate($0.value) } variables[identifier.identifier.text] = value ?? .undefined default: diagnostics.append(node.error("unsupported syntax '\(binding.pattern.kind)'")) } } return .skipChildren } override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { variables[node.name.text] = .function(node) return .skipChildren } override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.kind)'")) return .visitChildren } ... }
  95. class Interpreter: SyntaxAnyVisitor { private var result: Variant = .undefined

    private var variables: [String: Variant] = [:] var diagnostics: [Diagnostic] = [] ... override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { for binding in node.bindings { switch binding.pattern.as(PatternSyntaxEnum.self) { case let .identifierPattern(identifier): let value = binding.initializer.map { evaluate($0.value) } variables[identifier.identifier.text] = value ?? .undefined default: diagnostics.append(node.error("unsupported syntax '\(binding.pattern.kind)'")) } } return .skipChildren } override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { variables[node.name.text] = .function(node) return .skipChildren } override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.kind)'")) return .visitChildren } ... }
  96. class Preprocessor: SyntaxVisitor { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  97. class Preprocessor: SyntaxVisitor { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  98. class Preprocessor: SyntaxVisitor { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  99. class Preprocessor: SyntaxVisitor { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  100. class Preprocessor: SyntaxVisitor { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  101. class Preprocessor: SyntaxVisitor { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  102. print("Type expressions to see the result. Type 'exit' to quit.")

    let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) diagnostics += interpreter.diagnostics interpreter.diagnostics.removeAll() for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } if result != .undefined { print("= \(result)") } }
  103. print("Type expressions to see the result. Type 'exit' to quit.")

    let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) diagnostics += interpreter.diagnostics interpreter.diagnostics.removeAll() for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } if result != .undefined { print("= \(result)") } }
  104. print("Type expressions to see the result. Type 'exit' to quit.")

    let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = Preprocessor.diagnostics(for: sourceSyntax) diagnostics += ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) diagnostics += interpreter.diagnostics interpreter.diagnostics.removeAll() for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } if result != .undefined { print("= \(result)") } }
  105. class Preprocessor: SyntaxVisitor { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  106. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  107. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return .skipChildren } override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return .skipChildren } }
  108. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> TypeAnnotationSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: ReturnClauseSyntax) -> ReturnClauseSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: FunctionParameterSyntax) -> FunctionParameterSyntax { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return node } }
  109. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> TypeAnnotationSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: ReturnClauseSyntax) -> ReturnClauseSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: FunctionParameterSyntax) -> FunctionParameterSyntax { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return node } }
  110. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> TypeAnnotationSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: ReturnClauseSyntax) -> ReturnClauseSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: FunctionParameterSyntax) -> FunctionParameterSyntax { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return node .with(\.colon.presence, .present) } }
  111. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> TypeAnnotationSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: ReturnClauseSyntax) -> ReturnClauseSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: FunctionParameterSyntax) -> FunctionParameterSyntax { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return node .with(\.colon.presence, .present) .with(\.type, TypeSyntax( IdentifierTypeSyntax(name: .identifier("Any"), trailingTrivia: .space) )) } }
  112. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func diagnostics(for syntax: SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor(viewMode: .sourceAccurate) processor.walk(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> TypeAnnotationSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: ReturnClauseSyntax) -> ReturnClauseSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: FunctionParameterSyntax) -> FunctionParameterSyntax { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return node .with(\.colon.presence, .present) .with(\.type, TypeSyntax( IdentifierTypeSyntax(name: .identifier("Any"), trailingTrivia: .space) )) } }
  113. class Preprocessor: SyntaxRewriter { private var diagnostics: [Diagnostic] = []

    static func process(_ syntax: inout SourceFileSyntax) -> [Diagnostic] { let processor = Preprocessor() syntax = processor.visit(syntax) return processor.diagnostics } override func visit(_ node: TypeAnnotationSyntax) -> TypeAnnotationSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: ReturnClauseSyntax) -> ReturnClauseSyntax { diagnostics.append(node.error("unsupported syntax '\(node.trimmed)'")) return node } override func visit(_ node: FunctionParameterSyntax) -> FunctionParameterSyntax { if node.colon.presence == .present { diagnostics.append(node.error("unsupported syntax ': \(node.type.trimmed)'")) } return node .with(\.colon.presence, .present) .with(\.type, TypeSyntax( IdentifierTypeSyntax(name: .identifier("Any"), trailingTrivia: .space) )) } }
  114. print("Type expressions to see the result. Type 'exit' to quit.")

    let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = Preprocessor.diagnostics(for: sourceSyntax) diagnostics += ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) diagnostics += interpreter.diagnostics interpreter.diagnostics.removeAll() for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } if result != .undefined { print("= \(result)") } }
  115. print("Type expressions to see the result. Type 'exit' to quit.")

    let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } let sourceSyntax = Parser.parse(source: input) var diagnostics = Preprocessor.diagnostics(for: sourceSyntax) diagnostics += ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) diagnostics += interpreter.diagnostics interpreter.diagnostics.removeAll() for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } if result != .undefined { print("= \(result)") } }
  116. print("Type expressions to see the result. Type 'exit' to quit.")

    let interpreter = Interpreter(viewMode: .fixedUp) while true { print("> ", terminator: "") guard let input = readLine(), input.lowercased() != "exit" else { break } var sourceSyntax = Parser.parse(source: input) var diagnostics = Preprocessor.process(&sourceSyntax) diagnostics += ParseDiagnosticsGenerator.diagnostics(for: sourceSyntax) let operatorTable = OperatorTable.standardOperators let foldedSyntax = operatorTable.foldAll(sourceSyntax) { error in diagnostics.append(error.asDiagnostic) } let result = interpreter.evaluate(foldedSyntax) diagnostics += interpreter.diagnostics interpreter.diagnostics.removeAll() for diagnostic in diagnostics { print(diagnostic) } if diagnostics.contains(where: { $0.diagMessage.severity == .error }) { continue } if result != .undefined { print("= \(result)") } }