From ba392be1afb2eb15c2ca65554afdac96050a6938 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 23:55:56 -0700 Subject: [PATCH] Remove use of deprecated String functions in StringExtension. Remove some functions that are no longer used, and update the rest to Swift 4's String API. lastIndexOf changes to lastIndex(of: ), matching the standard library naming conventions, and returns a String.Index? instead of an Int. Add an implementation of Substring.hasPrefix for Linux; this is in the Apple standard library but not the Linux one. https://bugs.swift.org/browse/SR-5627 Add unit tests for StringExtension. Bump the Swift download for the Travis Linux tests from 4.0 to 4.0.2. There is a bug in Substring.range(of:) in 4.0.0 (https://bugs.swift.org/browse/SR-5663) that we need to avoid. --- .travis/run-tests-swift.sh | 2 +- .../Sources/Antlr4/ListTokenSource.swift | 5 +- .../misc/extension/StringExtension.swift | 70 ++++++------------- .../Antlr4Tests/StringExtensionTests.swift | 31 ++++++++ 4 files changed, 57 insertions(+), 51 deletions(-) create mode 100644 runtime/Swift/Tests/Antlr4Tests/StringExtensionTests.swift diff --git a/.travis/run-tests-swift.sh b/.travis/run-tests-swift.sh index b78a1bb42..a50f7213f 100755 --- a/.travis/run-tests-swift.sh +++ b/.travis/run-tests-swift.sh @@ -6,7 +6,7 @@ set -euo pipefail # here since environment variables doesn't pass # across scripts if [ $TRAVIS_OS_NAME == "linux" ]; then - export SWIFT_VERSION=swift-4.0 + export SWIFT_VERSION=swift-4.0.2 export SWIFT_HOME=$(pwd)/swift/$SWIFT_VERSION-RELEASE-ubuntu14.04/usr/bin/ export PATH=$SWIFT_HOME:$PATH diff --git a/runtime/Swift/Sources/Antlr4/ListTokenSource.swift b/runtime/Swift/Sources/Antlr4/ListTokenSource.swift index 943e603c4..681e7aa9d 100644 --- a/runtime/Swift/Sources/Antlr4/ListTokenSource.swift +++ b/runtime/Swift/Sources/Antlr4/ListTokenSource.swift @@ -85,9 +85,8 @@ public class ListTokenSource: TokenSource { let lastToken = tokens[tokens.count - 1] if let tokenText = lastToken.getText() { - let lastNewLine = tokenText.lastIndexOf("\n") - if lastNewLine >= 0 { - return tokenText.length - lastNewLine - 1 + if let lastNewLine = tokenText.lastIndex(of: "\n") { + return tokenText.distance(from: lastNewLine, to: tokenText.endIndex) - 1 } } return (lastToken.getCharPositionInLine() + diff --git a/runtime/Swift/Sources/Antlr4/misc/extension/StringExtension.swift b/runtime/Swift/Sources/Antlr4/misc/extension/StringExtension.swift index 1928be7f9..47c4cb1e5 100644 --- a/runtime/Swift/Sources/Antlr4/misc/extension/StringExtension.swift +++ b/runtime/Swift/Sources/Antlr4/misc/extension/StringExtension.swift @@ -6,62 +6,38 @@ import Foundation -//http://stackoverflow.com/questions/28182441/swift-how-to-get-substring-from-start-to-last-index-of-character -//https://github.com/williamFalcon/Bolt_Swift/blob/master/Bolt/BoltLibrary/String/String.swift - extension String { - - var length: Int { - return self.characters.count - } - - func indexOf(_ target: String) -> Int { - let range = self.range(of: target) - if let range = range { - return self.characters.distance(from: self.startIndex, to: range.lowerBound) - - } else { - return -1 + func lastIndex(of target: String) -> String.Index? { + if target.isEmpty { + return nil } - } - - func indexOf(_ target: String, startIndex: Int) -> Int { - - let startRange = self.characters.index(self.startIndex, offsetBy: startIndex) - let range = self.range(of: target, options: .literal, range: startRange.. Int { - var index = -1 - var stepIndex = self.indexOf(target) - while stepIndex > -1 { - index = stepIndex - if stepIndex + target.length < self.length { - stepIndex = indexOf(target, startIndex: stepIndex + target.length) - } else { - stepIndex = -1 + var result: String.Index? = nil + var substring = self[...] + while true { + guard let targetRange = substring.range(of: target) else { + return result } + result = targetRange.lowerBound + let nextChar = substring.index(after: targetRange.lowerBound) + substring = self[nextChar...] } - return index - } - - subscript(integerIndex: Int) -> Character { - let index = characters.index(startIndex, offsetBy: integerIndex) - return self[index] } subscript(integerRange: Range) -> String { - let start = characters.index(startIndex, offsetBy: integerRange.lowerBound) - let end = characters.index(startIndex, offsetBy: integerRange.upperBound) + let start = index(startIndex, offsetBy: integerRange.lowerBound) + let end = index(startIndex, offsetBy: integerRange.upperBound) let range = start ..< end return String(self[range]) } } + +// Implement Substring.hasPrefix, which is not currently in the Linux stdlib. +// https://bugs.swift.org/browse/SR-5627 +#if os(Linux) +extension Substring { + func hasPrefix(_ prefix: String) -> Bool { + return String(self).hasPrefix(prefix) + } +} +#endif diff --git a/runtime/Swift/Tests/Antlr4Tests/StringExtensionTests.swift b/runtime/Swift/Tests/Antlr4Tests/StringExtensionTests.swift new file mode 100644 index 000000000..6dddd669e --- /dev/null +++ b/runtime/Swift/Tests/Antlr4Tests/StringExtensionTests.swift @@ -0,0 +1,31 @@ +/// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +/// Use of this file is governed by the BSD 3-clause license that +/// can be found in the LICENSE.txt file in the project root. + +import Foundation +import XCTest +@testable import Antlr4 + +class StringExtensionTests: XCTestCase { + + func testLastIndex() { + doLastIndexTest("", "", nil) + doLastIndexTest("a", "", nil) + doLastIndexTest("a", "a", 0) + doLastIndexTest("aba", "a", 2) + doLastIndexTest("aba", "b", 1) + doLastIndexTest("abc", "d", nil) + } + +} + +private func doLastIndexTest(_ str: String, _ target: String, _ expectedOffset: Int?) { + let expectedIdx: String.Index? + if let expectedOffset = expectedOffset { + expectedIdx = str.index(str.startIndex, offsetBy: expectedOffset) + } + else { + expectedIdx = nil + } + XCTAssertEqual(str.lastIndex(of: target), expectedIdx) +}