Files
swift-mirror/tools/SwiftSyntax/SourceLength.swift
Alex Hoppen 56bf9a3469 [SwiftSyntax] Refactor AbsolutePosition
AbsolutePosition being a mutable reference type easily leads to bugs
where an AbsolutePosition is modified. Making it immutable eliminates
this issue. Furthermore, the introduction of SourceLength should allow
easier manipulation of AbsolutePositions on the client side.

We still cannot make AbsolutePosition a value type since it is used
inside AtomicCache, but the immutability gives the same safety.
2018-08-01 11:55:35 -07:00

93 lines
3.2 KiB
Swift

//===------------------ 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
}
}