//===------------------ SourceLength.swift - Source Length ----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 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 // //===----------------------------------------------------------------------===// /// The length a syntax node spans in the source code. From any AbsolutePosition /// you reach a node's end location by either adding its UTF-8 length or by /// inserting `lines` newlines and then moving `columns` columns to the right. public final class SourceLength { public let newlines: Int public let columnsAtLastLine: Int public let utf8Length: Int /// Construct the source length of a given text public init(of text: String) { var newlines = 0 var columnsAtLastLine = 0 var utf8Length = 0 for char in text { let charLength = String(char).utf8.count utf8Length += charLength switch char { case "\n", "\r\n", "\r": newlines += 1 columnsAtLastLine = 0 default: columnsAtLastLine += charLength } } self.newlines = newlines self.columnsAtLastLine = columnsAtLastLine self.utf8Length = utf8Length } public init(newlines: Int, columnsAtLastLine: Int, utf8Length: Int) { self.newlines = newlines self.columnsAtLastLine = columnsAtLastLine self.utf8Length = utf8Length } /// A zero-length source length public static let zero: SourceLength = SourceLength(newlines: 0, columnsAtLastLine: 0, utf8Length: 0) /// Combine the length of two source length. Note that the addition is *not* /// commutative (3 columns + 1 line = 1 line but 1 line + 3 columns = 1 line /// and 3 columns) public static func +(lhs: SourceLength, rhs: SourceLength) -> SourceLength { let utf8Length = lhs.utf8Length + rhs.utf8Length let newlines = lhs.newlines + rhs.newlines let columnsAtLastLine: Int if rhs.newlines == 0 { columnsAtLastLine = lhs.columnsAtLastLine + rhs.columnsAtLastLine } else { columnsAtLastLine = rhs.columnsAtLastLine } return SourceLength(newlines: newlines, columnsAtLastLine: columnsAtLastLine, utf8Length: utf8Length) } public static func +=(lhs: inout SourceLength, rhs: SourceLength) { lhs = lhs + rhs } } extension AbsolutePosition { /// Determine the AbsolutePosition by advancing the `lhs` by the given source /// length. public static func +(lhs: AbsolutePosition, rhs: SourceLength) -> AbsolutePosition { let utf8Offset = lhs.utf8Offset + rhs.utf8Length let line = lhs.line + rhs.newlines let column: Int if rhs.newlines == 0 { column = lhs.column + rhs.columnsAtLastLine } else { column = rhs.columnsAtLastLine + 1 // AbsolutePosition has 1-based columns } return AbsolutePosition(line: line, column: column, utf8Offset: utf8Offset) } public static func +=(lhs: inout AbsolutePosition, rhs: SourceLength) { lhs = lhs + rhs } }