     case nodeLookupFailed(SyntaxNodeId)
   }
 
+  /// Creates a RawSyntax node that's marked missing in the source with the
+  /// provided kind and layout.
+  /// - Parameters:
+  ///   - kind: The syntax kind underlying this node.
+  ///   - layout: The children of this node.
+  /// - Returns: A new RawSyntax `.node` with the provided kind and layout, with
+  ///            `.missing` source presence.
+  static func missing(_ kind: SyntaxKind) -> RawSyntax {
+    return RawSyntax(kind: kind, layout: [], presence: .missing)
+  }
+
+  /// Creates a RawSyntax token that's marked missing in the source with the
+  /// provided kind and no leading/trailing trivia.
+  /// - Parameter kind: The token kind.
+  /// - Returns: A new RawSyntax `.token` with the provided kind, no
+  ///            leading/trailing trivia, and `.missing` source presence.
+  static func missingToken(_ kind: TokenKind) -> RawSyntax {
+    return RawSyntax(kind: kind, leadingTrivia: [], trailingTrivia: [], presence: .missing)
+  }
+
+  /// Returns a new RawSyntax node with the provided layout instead of the
+  /// existing layout.
+  /// - Note: This function does nothing with `.token` nodes --- the same token
+  ///         is returned.
+  /// - Parameter newLayout: The children of the new node you're creating.
+  func replacingLayout(_ newLayout: [RawSyntax?]) -> RawSyntax {
+    switch data {
+    case let .node(kind, _):
+      return RawSyntax(kind: kind, layout: newLayout, presence: presence)
+    case .token(_, _, _): return self
+    }
+  }
+
+  /// Creates a new RawSyntax with the provided child appended to its layout.
+  /// - Parameter child: The child to append
+  /// - Note: This function does nothing with `.token` nodes --- the same token
+  ///         is returned.
+  /// - Return: A new RawSyntax node with the provided child at the end.
+  func appending(_ child: RawSyntax) -> RawSyntax {
+    var newLayout = layout
+    newLayout.append(child)
+    return replacingLayout(newLayout)
+  }
+
+  /// Returns the child at the provided cursor in the layout.
+  /// - Parameter index: The index of the child you're accessing.
+  /// - Returns: The child at the provided index.
+  subscript<CursorType: RawRepresentable>(_ index: CursorType) -> RawSyntax?
+    where CursorType.RawValue == Int {
+      return layout[index.rawValue]
+  }
+
+  /// Replaces the child at the provided index in this node with the provided
+  /// child.
+  /// - Parameters:
+  ///   - index: The index of the child to replace.
+  ///   - newChild: The new child that should occupy that index in the node.
+  func replacingChild(_ index: Int,
+                      with newChild: RawSyntax) -> RawSyntax {
+    precondition(index < layout.count, "Cursor \(index) reached past layout")
+    var newLayout = layout
+    newLayout[index] = newChild
+    return replacingLayout(newLayout)
+  }
+}
+
+extension RawSyntax: TextOutputStreamable {
+  /// Prints the RawSyntax node, and all of its children, to the provided
+  /// stream. This implementation must be source-accurate.
+  /// - Parameter stream: The stream on which to output this node.
+  func write<Target>(to target: inout Target)
+    where Target: TextOutputStream {
+    switch data {
+    case .node(_, let layout):
+      for child in layout {
+        guard let child = child else { continue }
+        child.write(to: &target)
+      }
+    case let .token(kind, leadingTrivia, trailingTrivia):
+      guard isPresent else { return }
+      for piece in leadingTrivia {
+        piece.write(to: &target)
+      }
+      target.write(kind.text)
+      for piece in trailingTrivia {
+        piece.write(to: &target)
+      }
+    }
+  }
+}
+
+extension RawSyntax {
+  var leadingTrivia: Trivia? {
+    switch data {
+    case .node(_, let layout):
+      for child in layout {
+        guard let child = child else { continue }
+        guard let result = child.leadingTrivia else { continue }
+        return result
+      }
+      return nil
+    case let .token(_, leadingTrivia, _):
+      return leadingTrivia
+    }
+  }
+
+  var trailingTrivia: Trivia? {
+    switch data {
+    case .node(_, let layout):
+      for child in layout.reversed() {
+        guard let child = child else { continue }
+        guard let result = child.trailingTrivia else { continue }
+        return result
+      }
+      return nil
+    case let .token(_, _, trailingTrivia):
+      return trailingTrivia
+    }
+  }
+}
+
+extension RawSyntax {
+  var leadingTriviaLength: SourceLength {
+    return leadingTrivia?.sourceLength ?? .zero
+  }
+
+  var trailingTriviaLength: SourceLength {
+    return trailingTrivia?.sourceLength ?? .zero
+  }
+
+  /// The length of this node including all of its trivia
+  var totalLength: SourceLength {
+    return leadingTriviaLength + contentLength + trailingTriviaLength
+  }
+}
+
+extension RawSyntax: Codable {
   /// Creates a RawSyntax from the provided Foundation Decoder.
   init(from decoder: Decoder) throws {
     let container = try decoder.container(keyedBy: CodingKeys.self)

/// Represents the raw tree structure underlying the syntax tree. These nodes
/// have no notion of identity and only provide structure to the tree. They
/// are immutable and can be freely shared between syntax nodes.
struct RawSyntax: Codable {
  fileprivate let data: RawSyntaxData
  let presence: SourcePresence


      try container.encode(trailingTrivia, forKey: .trailingTrivia)
    }
    try container.encode(presence, forKey: .presence)
  }
}

