mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
287 lines
8.2 KiB
Swift
287 lines
8.2 KiB
Swift
%{
|
|
# -*- mode: Swift -*-
|
|
from gyb_syntax_support.Trivia import TRIVIAS
|
|
# Ignore the following admonition it applies to the resulting .swift file only
|
|
}%
|
|
//// Automatically Generated From Trivia.swift.gyb.
|
|
//// Do Not Edit Directly!
|
|
//===------------------- Trivia.swift - Source Trivia Enum ----------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Foundation
|
|
|
|
/// A contiguous stretch of a single kind of trivia. The constituent part of
|
|
/// a `Trivia` collection.
|
|
///
|
|
/// For example, four spaces would be represented by
|
|
/// `.spaces(4)`
|
|
///
|
|
/// In general, you should deal with the actual Trivia collection instead
|
|
/// of individual pieces whenever possible.
|
|
public enum TriviaPiece: Codable {
|
|
enum CodingKeys: CodingKey {
|
|
case kind, value
|
|
}
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
let kind = try container.decode(String.self, forKey: .kind)
|
|
switch kind {
|
|
% for trivia in TRIVIAS:
|
|
case "${trivia.name}":
|
|
% if trivia.is_collection():
|
|
let value = try container.decode(Int.self, forKey: .value)
|
|
self = .${trivia.lower_name}s(value)
|
|
% else:
|
|
let value = try container.decode(String.self, forKey: .value)
|
|
self = .${trivia.lower_name}(value)
|
|
% end
|
|
% end
|
|
default:
|
|
let context =
|
|
DecodingError.Context(codingPath: [CodingKeys.kind],
|
|
debugDescription: "invalid TriviaPiece kind \(kind)")
|
|
throw DecodingError.valueNotFound(String.self, context)
|
|
}
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
switch self {
|
|
% for trivia in TRIVIAS:
|
|
% if trivia.is_collection():
|
|
case .${trivia.lower_name}s(let count):
|
|
try container.encode("${trivia.name}", forKey: .kind)
|
|
try container.encode(count, forKey: .value)
|
|
% else:
|
|
case .${trivia.lower_name}(let text):
|
|
try container.encode("${trivia.name}", forKey: .kind)
|
|
try container.encode(text, forKey: .value)
|
|
% end
|
|
% end
|
|
}
|
|
}
|
|
|
|
% for trivia in TRIVIAS:
|
|
/// ${trivia.comment}
|
|
% if trivia.is_collection():
|
|
case ${trivia.lower_name}s(Int)
|
|
% else:
|
|
case ${trivia.lower_name}(String)
|
|
% end
|
|
% end
|
|
}
|
|
|
|
extension TriviaPiece: TextOutputStreamable {
|
|
/// Prints the provided trivia as they would be written in a source file.
|
|
///
|
|
/// - Parameter stream: The stream to which to print the trivia.
|
|
public func write<Target>(to target: inout Target)
|
|
where Target: TextOutputStream {
|
|
func printRepeated(_ character: String, count: Int) {
|
|
for _ in 0..<count { target.write(character) }
|
|
}
|
|
switch self {
|
|
% for trivia in TRIVIAS:
|
|
% if trivia.is_collection():
|
|
% joined = ''.join(trivia.swift_characters)
|
|
case let .${trivia.lower_name}s(count):
|
|
printRepeated("${joined}", count: count)
|
|
% else:
|
|
case let .${trivia.lower_name}(text):
|
|
target.write(text)
|
|
% end
|
|
% end
|
|
}
|
|
}
|
|
|
|
/// Computes the information from this trivia to inform the source locations
|
|
/// of the associated tokens.
|
|
/// Specifically, walks through the trivia and keeps track of every newline
|
|
/// to give a number of how many newlines and UTF8 characters appear in the
|
|
/// trivia, along with the UTF8 offset of the last column.
|
|
func characterSizes() -> (lines: Int, lastColumn: Int, utf8Length: Int) {
|
|
func calculateTextSizes(_ text: String) ->
|
|
(lines: Int, lastColumn: Int, utf8Length: Int) {
|
|
var lines = 0
|
|
var col = 0
|
|
var total = 0
|
|
var prevChar: UInt8? = nil
|
|
// TODO: CR + LF should be regarded as one newline
|
|
for char in text.utf8 {
|
|
total += 1
|
|
switch char {
|
|
case 0x0a:
|
|
if prevChar == 0x0d {
|
|
/* ASCII CR LF */
|
|
assert(col == 0)
|
|
} else {
|
|
/* ASCII newline */
|
|
col = 0
|
|
lines += 1
|
|
}
|
|
/* ASCII carriage-return */
|
|
case 0x0d:
|
|
col = 0
|
|
lines += 1
|
|
|
|
default:
|
|
col += 1
|
|
}
|
|
prevChar = char
|
|
}
|
|
return (lines: lines, lastColumn: col, utf8Length: total)
|
|
}
|
|
switch self {
|
|
% for trivia in TRIVIAS:
|
|
% if trivia.is_new_line:
|
|
case let .${trivia.lower_name}s(n):
|
|
return (lines: n, lastColumn: 0, utf8Length: n * ${trivia.characters_len()})
|
|
% elif trivia.is_collection():
|
|
case let .${trivia.lower_name}s(n):
|
|
return (lines: 0, lastColumn: n, utf8Length: n * ${trivia.characters_len()})
|
|
% else:
|
|
case let .${trivia.lower_name}(text):
|
|
return calculateTextSizes(text)
|
|
% end
|
|
% end
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A collection of leading or trailing trivia. This is the main data structure
|
|
/// for thinking about trivia.
|
|
public struct Trivia: Codable {
|
|
let pieces: [TriviaPiece]
|
|
|
|
/// Creates Trivia with the provided underlying pieces.
|
|
public init(pieces: [TriviaPiece]) {
|
|
self.pieces = pieces
|
|
}
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
var container = try decoder.unkeyedContainer()
|
|
var pieces = [TriviaPiece]()
|
|
while let piece = try container.decodeIfPresent(TriviaPiece.self) {
|
|
pieces.append(piece)
|
|
}
|
|
self.pieces = pieces
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.unkeyedContainer()
|
|
for piece in pieces {
|
|
try container.encode(piece)
|
|
}
|
|
}
|
|
|
|
/// Creates Trivia with no pieces.
|
|
public static var zero: Trivia {
|
|
return Trivia(pieces: [])
|
|
}
|
|
|
|
/// Creates a new `Trivia` by appending the provided `TriviaPiece` to the end.
|
|
public func appending(_ piece: TriviaPiece) -> Trivia {
|
|
var copy = pieces
|
|
copy.append(piece)
|
|
return Trivia(pieces: copy)
|
|
}
|
|
|
|
% for trivia in TRIVIAS:
|
|
% if trivia.is_collection():
|
|
% joined = ''.join(trivia.swift_characters)
|
|
/// Return a piece of trivia for some number of '${joined}' characters.
|
|
public static func ${trivia.lower_name}s(_ count: Int) -> Trivia {
|
|
return [.${trivia.lower_name}s(count)]
|
|
}
|
|
% else:
|
|
/// Return a piece of trivia for ${trivia.name}.
|
|
public static func ${trivia.lower_name}(_ text: String) -> Trivia {
|
|
return [.${trivia.lower_name}(text)]
|
|
}
|
|
% end
|
|
% end
|
|
|
|
/// Computes the total sizes and offsets of all pieces in this Trivia.
|
|
func characterSizes() -> (lines: Int, lastColumn: Int, utf8Length: Int) {
|
|
var lines = 0
|
|
var lastColumn = 0
|
|
var length = 0
|
|
for piece in pieces {
|
|
let (ln, col, len) = piece.characterSizes()
|
|
lines += ln
|
|
lastColumn = col
|
|
length += len
|
|
}
|
|
return (lines: lines, lastColumn: lastColumn, utf8Length: length)
|
|
}
|
|
}
|
|
|
|
/// Conformance for Trivia to the Collection protocol.
|
|
extension Trivia: Collection {
|
|
public var startIndex: Int {
|
|
return pieces.startIndex
|
|
}
|
|
|
|
public var endIndex: Int {
|
|
return pieces.endIndex
|
|
}
|
|
|
|
public func index(after i: Int) -> Int {
|
|
return pieces.index(after: i)
|
|
}
|
|
|
|
public subscript(_ index: Int) -> TriviaPiece {
|
|
return pieces[index]
|
|
}
|
|
|
|
/// Get the byteSize of this trivia
|
|
public var byteSize: Int {
|
|
let pos = UTF8Position()
|
|
for piece in pieces {
|
|
piece.accumulateAbsolutePosition(pos)
|
|
}
|
|
return pos.byteOffset
|
|
}
|
|
}
|
|
|
|
|
|
extension Trivia: ExpressibleByArrayLiteral {
|
|
/// Creates Trivia from the provided pieces.
|
|
public init(arrayLiteral elements: TriviaPiece...) {
|
|
self.pieces = elements
|
|
}
|
|
}
|
|
|
|
/// Concatenates two collections of `Trivia` into one collection.
|
|
public func +(lhs: Trivia, rhs: Trivia) -> Trivia {
|
|
return Trivia(pieces: lhs.pieces + rhs.pieces)
|
|
}
|
|
|
|
extension TriviaPiece {
|
|
func accumulateAbsolutePosition(_ pos: AbsolutePosition) {
|
|
switch self {
|
|
% for trivia in TRIVIAS:
|
|
% if trivia.is_new_line:
|
|
case let .${trivia.lower_name}s(count):
|
|
pos.add(lines: count, size: ${trivia.characters_len()})
|
|
% elif trivia.is_collection():
|
|
case let .${trivia.lower_name}s(count):
|
|
pos.add(columns: count)
|
|
% else:
|
|
case let .${trivia.lower_name}(text):
|
|
pos.add(text: text)
|
|
% end
|
|
% end
|
|
}
|
|
}
|
|
}
|