blob: 009788c5c85ced0baa84b17768ada693326737a2 [file] [log] [blame]
//===------------------ 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
}
}