mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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.
93 lines
3.2 KiB
Swift
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
|
|
}
|
|
} |