| %{ |
| # -*- mode: Swift -*- |
| from gyb_syntax_support import * |
| from gyb_syntax_support.Traits import TRAITS |
| NODE_MAP = create_node_map() |
| # Ignore the following admonition it applies to the resulting .swift file only |
| }% |
| //// Automatically Generated From SyntaxNodes.swift.gyb. |
| //// Do Not Edit Directly! |
| //===------------ SyntaxNodes.swift - Syntax Node definitions -------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| %{ |
| """ |
| Each Syntax node implements the protocol of a more generic node. For example, |
| StructDeclSyntax implements DeclSyntax and can be used in contexts |
| where DeclSyntax is expected. |
| |
| Each node will have: |
| - An accessor for each child that will lazily instantiate it. |
| - A `withX(_ x: XSyntax)` method for each child that will return a new Syntax |
| node with the existing X child replaced with the passed-in version. This is a |
| way to incrementally transform nodes in the tree. |
| - An `addX(_ x: XSyntax)` method for children that are collections. This will |
| append the provided node to the collection and return a new node with that |
| collection replaced. |
| - (in DEBUG mode) a `validate()` method that's called in the initializer. This |
| only validates that all the children are the right kind/token, and does not |
| raise an error if, say, a non-optional child is missing. |
| """ |
| }% |
| |
| /// A wrapper around a raw Syntax layout. |
| public struct UnknownSyntax: _SyntaxBase { |
| let _root: SyntaxData |
| unowned let _data: SyntaxData |
| |
| /// Creates an `UnknownSyntax` node from the provided root and data. |
| internal init(root: SyntaxData, data: SyntaxData) { |
| self._root = root |
| self._data = data |
| #if DEBUG |
| validate() |
| #endif |
| } |
| } |
| |
| % for node in SYNTAX_NODES: |
| % base_type = node.base_type |
| % if node.is_base(): |
| % for line in dedented_lines(node.description): |
| /// ${line} |
| % end |
| public protocol ${node.name}: Syntax {} |
| |
| % elif node.collection_element: |
| % pass |
| % else: |
| |
| % for line in dedented_lines(node.description): |
| /// ${line} |
| % end |
| public struct ${node.name}: ${base_type}, _SyntaxBase, Hashable { |
| % if node.children: |
| enum Cursor: Int { |
| % for child in node.children: |
| case ${child.swift_name} |
| % end |
| } |
| % end |
| |
| let _root: SyntaxData |
| unowned let _data: SyntaxData |
| |
| /// Creates a `${node.name}` node from the provided root and data. |
| internal init(root: SyntaxData, data: SyntaxData) { |
| self._root = root |
| self._data = data |
| #if DEBUG |
| validate() |
| #endif |
| } |
| |
| % if node.requires_validation(): |
| #if DEBUG |
| func validate() { |
| if isMissing { return } |
| precondition(raw.layout.count == ${len(node.children)}) |
| % for child in node.children: |
| % child_var = '_' + child.swift_name |
| let ${child_var} = raw[Cursor.${child.swift_syntax_kind}] |
| % if child.token_choices: |
| % choices = ["." + choice.swift_kind() for choice in child.token_choices] |
| % choice_array = "[%s]" % ', '.join(choices) |
| guard let ${child_var}TokenKind = ${child_var}.tokenKind else { |
| fatalError("expected token child, got \(${child_var}.kind)") |
| } |
| precondition(${choice_array}.contains(${child_var}TokenKind), |
| "expected one of ${choice_array} for '${child.swift_name}' " + |
| "in node of kind ${node.swift_syntax_kind}") |
| % elif child.text_choices: |
| % choices = ", ".join("\"%s\"" % choice |
| % for choice in child.text_choices) |
| guard let ${child_var}TokenKind = ${child_var}.tokenKind else { |
| fatalError("expected token child, got \(${child_var}.kind)") |
| } |
| precondition([${choices}].contains(${child_var}TokenKind.text), |
| "expected one of '[${', '.join(child.text_choices)}]', got " + |
| "'\(${child_var}TokenKind.text)'") |
| % else: |
| precondition(${child_var}.kind == .${child.swift_syntax_kind}, |
| "expected child of kind .${child.swift_syntax_kind}, " + |
| "got \(${child_var}.kind)") |
| % end |
| % end |
| } |
| #endif |
| % end |
| % for child in node.children: |
| % ret_type = child.type_name |
| % cast_symbol = 'as!' |
| % if child.is_optional: |
| % ret_type += '?' |
| % cast_symbol = 'as?' |
| % end |
| % cast = '' if child.type_name == 'Syntax' \ |
| % else '%s %s' % (cast_symbol, child.type_name) |
| % for line in dedented_lines(child.description): |
| /// ${line} |
| % end |
| public var ${child.swift_name}: ${ret_type} { |
| let child = data.cachedChild(at: Cursor.${child.swift_name}) |
| % if child.is_optional: |
| if child == nil { return nil } |
| % end |
| return makeSyntax(root: _root, data: child!) ${cast} |
| } |
| % child_node = NODE_MAP.get(child.syntax_kind) |
| % if child_node and child_node.is_syntax_collection(): |
| % child_elt = child_node.collection_element_name |
| % child_elt_type = child_node.collection_element_type |
| |
| /// Adds the provided `${child_elt}` to the node's `${child.swift_name}` |
| /// collection. |
| /// - param element: The new `${child_elt}` to add to the node's |
| /// `${child.swift_name}` collection. |
| /// - returns: A copy of the receiver with the provided `${child_elt}` |
| /// appended to its `${child.swift_name}` collection. |
| public func add${child_elt}(_ element: ${child_elt_type}) -> ${node.name} { |
| var collection: RawSyntax |
| if let col = raw[Cursor.${child.swift_name}] { |
| collection = col.appending(element.raw) |
| } else { |
| collection = RawSyntax.node(SyntaxKind.${child_node.swift_syntax_kind}, |
| [element.raw], .present) |
| } |
| let (root, newData) = data.replacingChild(collection, |
| at: Cursor.${child.swift_name}) |
| return ${node.name}(root: root, data: newData) |
| } |
| % end |
| |
| /// Returns a copy of the receiver with its `${child.swift_name}` replaced. |
| /// - param newChild: The new `${child.swift_name}` to replace the node's |
| /// current `${child.swift_name}`, if present. |
| public func with${child.name}( |
| _ newChild: ${child.type_name}?) -> ${node.name} { |
| let raw = newChild?.raw ?? ${make_missing_swift_child(child)} |
| let (root, newData) = data.replacingChild(raw, |
| at: Cursor.${child.swift_name}) |
| return ${node.name}(root: root, data: newData) |
| } |
| % end |
| |
| /// Determines if two `${node.name}` nodes are equal to each other. |
| public static func ==(lhs: ${node.name}, rhs: ${node.name}) -> Bool { |
| return lhs._data === rhs._data |
| } |
| |
| /// A unique hash value for this node. |
| public var hashValue: Int { |
| return ObjectIdentifier(_data).hashValue |
| } |
| } |
| |
| % end |
| % end |
| |
| % for trait in TRAITS: |
| public protocol ${trait.trait_name}Syntax: Syntax { |
| % for child in trait.children: |
| % ret_type = child.type_name |
| % if child.is_optional: |
| % ret_type += '?' |
| % end |
| var ${child.swift_name}: ${ret_type} { get } |
| func with${child.name}(_ newChild: ${child.type_name}?) -> Self |
| % end |
| } |
| % end |
| |
| % for node in SYNTAX_NODES: |
| % base_type = node.base_type |
| % if node.is_base(): |
| % pass |
| % elif node.collection_element: |
| % pass |
| % elif node.traits: |
| % traits_list = ", ".join(trait + 'Syntax' for trait in node.traits) |
| extension ${node.name}: ${traits_list} {} |
| % end |
| % end |
| |
| /// MARK: Convenience methods |
| |
| extension StructDeclSyntax { |
| /// Creates a new StructDeclSyntax with the provided name as its identifier. |
| /// - param name: The new struct's name. |
| /// - returns: A new StructDeclSyntax with the same fields as the receiver, |
| /// but with the provided identifier. |
| func withIdentifier(_ name: String) -> StructDeclSyntax { |
| let newToken = SyntaxFactory.makeIdentifier(name, |
| leadingTrivia: identifier.leadingTrivia, |
| trailingTrivia: identifier.trailingTrivia) |
| return withIdentifier(newToken) |
| } |
| } |