From 08ba9379d811e0b111bacfd7461acad9016c8ed0 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 15:58:33 -0700 Subject: [PATCH 1/8] Added tests for RuntimeMetaData.getMajorMinorVersion. --- .../Antlr4Tests/RuntimeMetaDataTests.swift | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 runtime/Swift/Tests/Antlr4Tests/RuntimeMetaDataTests.swift diff --git a/runtime/Swift/Tests/Antlr4Tests/RuntimeMetaDataTests.swift b/runtime/Swift/Tests/Antlr4Tests/RuntimeMetaDataTests.swift new file mode 100644 index 000000000..22ba06db6 --- /dev/null +++ b/runtime/Swift/Tests/Antlr4Tests/RuntimeMetaDataTests.swift @@ -0,0 +1,26 @@ +/// 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 +import Antlr4 + +class RuntimeMetaDataTests: XCTestCase { + + func testGetMajorMinorVersion() { + doGetMajorMinorVersionTest("", "") + doGetMajorMinorVersionTest("4", "4") + doGetMajorMinorVersionTest("4.", "4.") + doGetMajorMinorVersionTest("4.7", "4.7") + doGetMajorMinorVersionTest("4.7.1", "4.7") + doGetMajorMinorVersionTest("4-SNAPSHOT", "4") + doGetMajorMinorVersionTest("4.-SNAPSHOT", "4.") + doGetMajorMinorVersionTest("4.7-SNAPSHOT", "4.7") + doGetMajorMinorVersionTest("4.7.1-SNAPSHOT", "4.7") + } +} + +private func doGetMajorMinorVersionTest(_ input: String, _ expected: String) { + XCTAssertEqual(RuntimeMetaData.getMajorMinorVersion(input), expected) +} From e2b94c783a5a61c27b4f58e6607ebffcb45d59ee Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 23:38:54 -0700 Subject: [PATCH 2/8] Rewrite RuntimeMetaData.getMajorMinorVersion to use standard library String functions and avoid our custom String extensions. --- .../Swift/Sources/Antlr4/RuntimeMetaData.swift | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/runtime/Swift/Sources/Antlr4/RuntimeMetaData.swift b/runtime/Swift/Sources/Antlr4/RuntimeMetaData.swift index 384fa6d11..eeb06d2a4 100644 --- a/runtime/Swift/Sources/Antlr4/RuntimeMetaData.swift +++ b/runtime/Swift/Sources/Antlr4/RuntimeMetaData.swift @@ -163,18 +163,14 @@ public class RuntimeMetaData { /// only the major and minor components of the version string. /// public static func getMajorMinorVersion(_ version: String) -> String { - let firstDot: Int = version.indexOf(".") - let secondDot: Int = firstDot >= 0 ? version.indexOf(".", startIndex: firstDot + 1) : -1 - let firstDash: Int = version.indexOf("-") - var referenceLength: Int = version.length - if secondDot >= 0 { - referenceLength = min(referenceLength, secondDot) + var result = version + + let dotBits = version.split(separator: ".", maxSplits: 2, omittingEmptySubsequences: false) + if dotBits.count >= 2 { + result = dotBits[0..<2].joined(separator: ".") } - if firstDash >= 0 { - referenceLength = min(referenceLength, firstDash) - } - - return version[0 ..< referenceLength] // version.substring(0, referenceLength); + let dashBits = result.split(separator: "-", maxSplits: 1, omittingEmptySubsequences: false) + return String(dashBits[0]) } } From 7933999fa67c053cd34ab457476e756c5750ab1f Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 00:49:56 -0700 Subject: [PATCH 3/8] Remove uses of StringBuilder. Remove the uses of StringBuilder where it is simply accumulating a String for us. In Swift we can use a var String for this; there is no need for a StringBuilder class like in Java. --- .../Sources/Antlr4/BufferedTokenStream.swift | 26 +++--- runtime/Swift/Sources/Antlr4/Lexer.swift | 8 +- .../Swift/Sources/Antlr4/RuleContext.swift | 20 ++-- .../Antlr4/UnbufferedTokenStream.swift | 24 ++--- .../Swift/Sources/Antlr4/atn/ATNConfig.swift | 27 ++---- .../Sources/Antlr4/atn/ATNConfigSet.swift | 18 ++-- .../Antlr4/atn/ArrayPredictionContext.swift | 29 +++--- .../Sources/Antlr4/atn/DecisionInfo.swift | 29 +++--- .../Antlr4/atn/PredictionContext.swift | 56 +++++------ .../atn/SingletonPredictionContext.swift | 4 +- .../Sources/Antlr4/dfa/DFASerializer.swift | 28 ++---- .../Swift/Sources/Antlr4/dfa/DFAState.swift | 14 +-- .../Swift/Sources/Antlr4/misc/BitSet.swift | 11 +-- .../Sources/Antlr4/misc/IntervalSet.swift | 92 +++++++++++-------- runtime/Swift/Sources/Antlr4/misc/Utils.swift | 34 ++++--- runtime/Swift/Sources/Antlr4/tree/Trees.swift | 16 ++-- 16 files changed, 202 insertions(+), 234 deletions(-) diff --git a/runtime/Swift/Sources/Antlr4/BufferedTokenStream.swift b/runtime/Swift/Sources/Antlr4/BufferedTokenStream.swift index 2805f8855..82e0fb05a 100644 --- a/runtime/Swift/Sources/Antlr4/BufferedTokenStream.swift +++ b/runtime/Swift/Sources/Antlr4/BufferedTokenStream.swift @@ -441,14 +441,13 @@ public class BufferedTokenStream: TokenStream { /// Collect all hidden tokens (any off-default channel) to the left of /// the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. /// - public func getHiddenTokensToLeft(_ tokenIndex: Int) throws -> Array? { + public func getHiddenTokensToLeft(_ tokenIndex: Int) throws -> [Token]? { return try getHiddenTokensToLeft(tokenIndex, -1) } - internal func filterForChannel(_ from: Int, _ to: Int, _ channel: Int) -> Array? { - var hidden: Array = Array() - for i in from...to { - let t: Token = tokens[i] + internal func filterForChannel(_ from: Int, _ to: Int, _ channel: Int) -> [Token]? { + var hidden = [Token]() + for t in tokens[from...to] { if channel == -1 { if t.getChannel() != Lexer.DEFAULT_TOKEN_CHANNEL { hidden.append(t) @@ -478,8 +477,8 @@ public class BufferedTokenStream: TokenStream { } public func getText(_ interval: Interval) throws -> String { - let start: Int = interval.a - var stop: Int = interval.b + let start = interval.a + var stop = interval.b if start < 0 || stop < 0 { return "" } @@ -488,15 +487,14 @@ public class BufferedTokenStream: TokenStream { stop = tokens.count - 1 } - let buf: StringBuilder = StringBuilder() - for i in start...stop { - let t: Token = tokens[i] + var buf = "" + for t in tokens[start...stop] { if t.getType() == BufferedTokenStream.EOF { break } - buf.append(t.getText()!) + buf += t.getText()! } - return buf.toString() + return buf } @@ -518,9 +516,9 @@ public class BufferedTokenStream: TokenStream { /// public func fill() throws { try lazyInit() - let blockSize: Int = 1000 + let blockSize = 1000 while true { - let fetched: Int = try fetch(blockSize) + let fetched = try fetch(blockSize) if fetched < blockSize { return } diff --git a/runtime/Swift/Sources/Antlr4/Lexer.swift b/runtime/Swift/Sources/Antlr4/Lexer.swift index 453d92aac..7a538973a 100644 --- a/runtime/Swift/Sources/Antlr4/Lexer.swift +++ b/runtime/Swift/Sources/Antlr4/Lexer.swift @@ -413,11 +413,11 @@ open class Lexer: Recognizer, TokenSource { } open func getErrorDisplay(_ s: String) -> String { - let buf = StringBuilder() - for c in s.characters { - buf.append(getErrorDisplay(c)) + var buf = "" + for c in s { + buf += getErrorDisplay(c) } - return buf.toString() + return buf } open func getErrorDisplay(_ c: Character) -> String { diff --git a/runtime/Swift/Sources/Antlr4/RuleContext.swift b/runtime/Swift/Sources/Antlr4/RuleContext.swift index a44ce5373..4fb8a8d16 100644 --- a/runtime/Swift/Sources/Antlr4/RuleContext.swift +++ b/runtime/Swift/Sources/Antlr4/RuleContext.swift @@ -132,12 +132,12 @@ open class RuleContext: RuleNode { return "" } - let builder = StringBuilder() + var builder = "" for i in 0.. Int { @@ -202,31 +202,31 @@ open class RuleContext: RuleNode { } open func toString(_ ruleNames: [String]?, _ stop: RuleContext?) -> String { - let buf = StringBuilder() + var buf = "" var p: RuleContext? = self - buf.append("[") + buf += "[" while let pWrap = p, pWrap !== stop { if let ruleNames = ruleNames { let ruleIndex = pWrap.getRuleIndex() let ruleIndexInRange = (ruleIndex >= 0 && ruleIndex < ruleNames.count) let ruleName = (ruleIndexInRange ? ruleNames[ruleIndex] : String(ruleIndex)) - buf.append(ruleName) + buf += ruleName } else { if !pWrap.isEmpty() { - buf.append(pWrap.invokingState) + buf += String(pWrap.invokingState) } } if pWrap.parent != nil && (ruleNames != nil || !pWrap.parent!.isEmpty()) { - buf.append(" ") + buf += " " } p = pWrap.parent } - buf.append("]") - return buf.toString() + buf += "]" + return buf } open func castdown(_ subType: T.Type) -> T { diff --git a/runtime/Swift/Sources/Antlr4/UnbufferedTokenStream.swift b/runtime/Swift/Sources/Antlr4/UnbufferedTokenStream.swift index da1c8476a..e69affed7 100644 --- a/runtime/Swift/Sources/Antlr4/UnbufferedTokenStream.swift +++ b/runtime/Swift/Sources/Antlr4/UnbufferedTokenStream.swift @@ -284,27 +284,23 @@ public class UnbufferedTokenStream: TokenStream { public func getText(_ interval: Interval) throws -> String { - let bufferStartIndex: Int = getBufferStartIndex() - let bufferStopIndex: Int = bufferStartIndex + tokens.count - 1 + let bufferStartIndex = getBufferStartIndex() + let bufferStopIndex = bufferStartIndex + tokens.count - 1 - let start: Int = interval.a - let stop: Int = interval.b + let start = interval.a + let stop = interval.b if start < bufferStartIndex || stop > bufferStopIndex { - throw ANTLRError.unsupportedOperation(msg: "interval \(interval) not in token buffer window: \(bufferStartIndex)..bufferStopIndex)") - } - let a: Int = start - bufferStartIndex - let b: Int = stop - bufferStartIndex + let a = start - bufferStartIndex + let b = stop - bufferStartIndex - let buf: StringBuilder = StringBuilder() - for i in a...b { - let t: Token = tokens[i] - buf.append(t.getText()!) + var buf = "" + for t in tokens[a...b] { + buf += t.getText()! } - - return buf.toString() + return buf } internal final func getBufferStartIndex() -> Int { diff --git a/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift b/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift index f91854531..bc8e53439 100644 --- a/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift +++ b/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift @@ -167,29 +167,22 @@ public class ATNConfig: Hashable, CustomStringConvertible { return toString(nil, true) } public func toString(_ recog: Recognizer?, _ showAlt: Bool) -> String { - let buf: StringBuilder = StringBuilder() - buf.append("(") - buf.append(state) + var buf = "(\(state)" if showAlt { - buf.append(",") - buf.append(alt) + buf += ",\(alt)" } - - if context != nil { - buf.append(",[") - buf.append(context!) - buf.append("]") + if let context = context { + buf += ",[\(context)]" } - if semanticContext != SemanticContext.NONE { - buf.append(",") - buf.append(semanticContext) + buf += ",\(semanticContext)" } - if getOuterContextDepth() > 0 { - buf.append(",up=").append(getOuterContextDepth()) + let outerDepth = getOuterContextDepth() + if outerDepth > 0 { + buf += ",up=\(outerDepth)" } - buf.append(")") - return buf.toString() + buf += ")" + return buf } } diff --git a/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift b/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift index 3c52bcd14..630dc4cf2 100644 --- a/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift +++ b/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift @@ -275,25 +275,23 @@ public class ATNConfigSet: Hashable, CustomStringConvertible { } public var description: String { - let buf = StringBuilder() - buf.append(elements().map({ $0.description })) + var buf = "" + buf += String(describing: elements()) if hasSemanticContext { - buf.append(",hasSemanticContext=") - buf.append(hasSemanticContext) + buf += ",hasSemanticContext=true" } if uniqueAlt != ATN.INVALID_ALT_NUMBER { - buf.append(",uniqueAlt=") - buf.append(uniqueAlt) + buf += ",uniqueAlt=\(uniqueAlt)" } if let conflictingAlts = conflictingAlts { - buf.append(",conflictingAlts=") - buf.append(conflictingAlts.description) + buf += ",conflictingAlts=\(conflictingAlts)" } if dipsIntoOuterContext { - buf.append(",dipsIntoOuterContext") + buf += ",dipsIntoOuterContext" } - return buf.toString() + return buf } + public func toString() -> String { return description } diff --git a/runtime/Swift/Sources/Antlr4/atn/ArrayPredictionContext.swift b/runtime/Swift/Sources/Antlr4/atn/ArrayPredictionContext.swift index 9d0168036..fe0d197a9 100644 --- a/runtime/Swift/Sources/Antlr4/atn/ArrayPredictionContext.swift +++ b/runtime/Swift/Sources/Antlr4/atn/ArrayPredictionContext.swift @@ -58,28 +58,25 @@ public class ArrayPredictionContext: PredictionContext { if isEmpty() { return "[]" } - let buf: StringBuilder = StringBuilder() - buf.append("[") - let length = returnStates.count - - for i in 0.. 0 { - buf.append(", ") + buf += ", " } - if returnStates[i] == PredictionContext.EMPTY_RETURN_STATE { - buf.append("$") + if returnState == PredictionContext.EMPTY_RETURN_STATE { + buf += "$" continue } - buf.append(returnStates[i]) - if parents[i] != nil { - buf.append(" ") - buf.append(parents[i].debugDescription) - } else { - buf.append("null") + buf += "\(returnState)" + if let parent = parents[i] { + buf += " \(parent)" + } + else { + buf += "null" } } - buf.append("]") - return buf.toString() + buf += "]" + return buf } internal final func combineCommonParents() { diff --git a/runtime/Swift/Sources/Antlr4/atn/DecisionInfo.swift b/runtime/Swift/Sources/Antlr4/atn/DecisionInfo.swift index ceb939099..cc03cacdc 100644 --- a/runtime/Swift/Sources/Antlr4/atn/DecisionInfo.swift +++ b/runtime/Swift/Sources/Antlr4/atn/DecisionInfo.swift @@ -225,21 +225,22 @@ public class DecisionInfo: CustomStringConvertible { public var description: String { - let desc: StringBuilder = StringBuilder() - desc.append("{") - desc.append("decision=\(decision)") - desc.append(", contextSensitivities=\(contextSensitivities.count)") - desc.append(", errors=\(errors.count)") - desc.append(", ambiguities=\(ambiguities.count)") - desc.append(", SLL_lookahead=\(SLL_TotalLook)") - desc.append(", SLL_ATNTransitions=\(SLL_ATNTransitions)") - desc.append(", SLL_DFATransitions=\(SLL_DFATransitions)") - desc.append(", LL_Fallback=\(LL_Fallback)") - desc.append(", LL_lookahead=\(LL_TotalLook)") - desc.append(", LL_ATNTransitions=\(LL_ATNTransitions)") - desc.append("}") + var desc = "" - return desc.toString() + desc += "{" + desc += "decision=\(decision)" + desc += ", contextSensitivities=\(contextSensitivities.count)" + desc += ", errors=\(errors.count)" + desc += ", ambiguities=\(ambiguities.count)" + desc += ", SLL_lookahead=\(SLL_TotalLook)" + desc += ", SLL_ATNTransitions=\(SLL_ATNTransitions)" + desc += ", SLL_DFATransitions=\(SLL_DFATransitions)" + desc += ", LL_Fallback=\(LL_Fallback)" + desc += ", LL_lookahead=\(LL_TotalLook)" + desc += ", LL_ATNTransitions=\(LL_ATNTransitions)" + desc += "}" + + return desc } } diff --git a/runtime/Swift/Sources/Antlr4/atn/PredictionContext.swift b/runtime/Swift/Sources/Antlr4/atn/PredictionContext.swift index 660528da2..c23cad0c0 100644 --- a/runtime/Swift/Sources/Antlr4/atn/PredictionContext.swift +++ b/runtime/Swift/Sources/Antlr4/atn/PredictionContext.swift @@ -518,47 +518,40 @@ public class PredictionContext: Hashable, CustomStringConvertible { if context == nil { return "" } - let buf = StringBuilder() - buf.append("digraph G {\n") - buf.append("rankdir=LR;\n") + var buf = "" + buf += "digraph G {\n" + buf += "rankdir=LR;\n" var nodes = getAllContextNodes(context!) nodes.sort { $0.id > $1.id } - for current in nodes { if current is SingletonPredictionContext { - let s = String(current.id) - buf.append(" s").append(s) + buf += " s\(current.id)" var returnState = String(current.getReturnState(0)) if current is EmptyPredictionContext { returnState = "$" } - buf.append(" [label=\"") - buf.append(returnState) - buf.append("\"];\n") + buf += " [label=\"\(returnState)\"];\n" continue } let arr = current as! ArrayPredictionContext - buf.append(" s").append(arr.id) - buf.append(" [shape=box, label=\"") - buf.append("[") + buf += " s\(arr.id) [shape=box, label=\"[" var first = true let returnStates = arr.returnStates for inv in returnStates { if !first { - buf.append(", ") + buf += ", " } if inv == EMPTY_RETURN_STATE { - buf.append("$") + buf += "$" } else { - buf.append(inv) + buf += String(inv) } first = false } - buf.append("]") - buf.append("\"];\n") + buf += "]\"];\n" } for current in nodes { @@ -570,21 +563,17 @@ public class PredictionContext: Hashable, CustomStringConvertible { guard let currentParent = current.getParent(i) else { continue } - let s = String(current.id) - buf.append(" s").append(s) - buf.append("->") - buf.append("s") - buf.append(currentParent.id) + buf += " s\(current.id) -> s\(currentParent.id)" if current.size() > 1 { - buf.append(" [label=\"parent[\(i)]\"];\n") + buf += " [label=\"parent[\(i)]\"];\n" } else { - buf.append(";\n") + buf += ";\n" } } } buf.append("}\n") - return buf.toString() + return buf } // From Sam @@ -700,8 +689,7 @@ public class PredictionContext: Hashable, CustomStringConvertible { var last = true var p = self var stateNumber = currentState - let localBuffer = StringBuilder() - localBuffer.append("[") + var localBuffer = "[" while !p.isEmpty() && p !== stop { var index = 0 if p.size() > 0 { @@ -724,9 +712,9 @@ public class PredictionContext: Hashable, CustomStringConvertible { } if let recognizer = recognizer { - if localBuffer.length > 1 { + if localBuffer.count > 1 { // first char is '[', if more than that this isn't the first rule - localBuffer.append(" ") + localBuffer += " " } let atn = recognizer.getATN() @@ -736,19 +724,19 @@ public class PredictionContext: Hashable, CustomStringConvertible { } else if p.getReturnState(index) != PredictionContext.EMPTY_RETURN_STATE { if !p.isEmpty() { - if localBuffer.length > 1 { + if localBuffer.count > 1 { // first char is '[', if more than that this isn't the first rule - localBuffer.append(" ") + localBuffer += " " } - localBuffer.append(p.getReturnState(index)) + localBuffer += String(p.getReturnState(index)) } } stateNumber = p.getReturnState(index) p = p.getParent(index)! } - localBuffer.append("]") - result.append(localBuffer.toString()) + localBuffer += "]" + result.append(localBuffer) if last { break diff --git a/runtime/Swift/Sources/Antlr4/atn/SingletonPredictionContext.swift b/runtime/Swift/Sources/Antlr4/atn/SingletonPredictionContext.swift index 01a49fc7c..460740fee 100644 --- a/runtime/Swift/Sources/Antlr4/atn/SingletonPredictionContext.swift +++ b/runtime/Swift/Sources/Antlr4/atn/SingletonPredictionContext.swift @@ -49,8 +49,8 @@ public class SingletonPredictionContext: PredictionContext { override public var description: String { - let up: String = parent != nil ? parent!.description : "" - if up.length == 0 { + let up = parent?.description ?? "" + if up.isEmpty { if returnState == PredictionContext.EMPTY_RETURN_STATE { return "$" } diff --git a/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift b/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift index 3e19850de..9695cab1f 100644 --- a/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift +++ b/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift @@ -22,33 +22,25 @@ public class DFASerializer: CustomStringConvertible { if dfa.s0 == nil { return "" } - let buf = StringBuilder() + var buf = "" let states = dfa.getStates() for s in states { guard let edges = s.edges else { continue } - let n = edges.count - for i in 0..") - buf.append(getStateString(t)) - buf.append("\n") + for (i, t) in edges.enumerated() { + guard let t = t, t.stateNumber != Int.max else { + continue } + let edgeLabel = getEdgeLabel(i) + buf += getStateString(s) + buf += "-\(edgeLabel)->" + buf += getStateString(t) + buf += "\n" } } - let output = buf.toString() - if output.length == 0 { - return "" - } - //return Utils.sortLinesInString(output); - return output - + return buf } public func toString() -> String { diff --git a/runtime/Swift/Sources/Antlr4/dfa/DFAState.swift b/runtime/Swift/Sources/Antlr4/dfa/DFAState.swift index f0a09c4d4..5d3ac350f 100644 --- a/runtime/Swift/Sources/Antlr4/dfa/DFAState.swift +++ b/runtime/Swift/Sources/Antlr4/dfa/DFAState.swift @@ -136,17 +136,17 @@ public class DFAState: Hashable, CustomStringConvertible { /// _#stateNumber_ is irrelevant. /// public var description: String { - let buf = StringBuilder() - buf.append(stateNumber).append(":").append(configs) + var buf = "\(stateNumber):\(configs)" if isAcceptState { - buf.append("=>") + buf += "=>" if let predicates = predicates { - buf.append(predicates.map({ $0.description })) - } else { - buf.append(prediction) + buf += String(describing: predicates) + } + else { + buf += String(prediction) } } - return buf.toString() + return buf } } diff --git a/runtime/Swift/Sources/Antlr4/misc/BitSet.swift b/runtime/Swift/Sources/Antlr4/misc/BitSet.swift index 4f9c5f899..fa58553ed 100644 --- a/runtime/Swift/Sources/Antlr4/misc/BitSet.swift +++ b/runtime/Swift/Sources/Antlr4/misc/BitSet.swift @@ -1121,23 +1121,22 @@ public class BitSet: Hashable, CustomStringConvertible { //let numBits: Int = (wordsInUse > 128) ? // cardinality() : wordsInUse * BitSet.BITS_PER_WORD - let b = StringBuilder() - b.append("{") + var b = "{" var i = firstSetBit() if i != -1 { - b.append(i) + b += String(i) i = try! nextSetBit(i + 1) while i >= 0 { let endOfRun = try! nextClearBit(i) repeat { - b.append(", ").append(i) + b += ", \(i)" i += 1 } while i < endOfRun i = try! nextSetBit(i + 1) } } - b.append("}") - return b.toString() + b += "}" + return b } public func toString() -> String { diff --git a/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift b/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift index 345f829cc..70071bfbf 100644 --- a/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift +++ b/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift @@ -514,91 +514,103 @@ public class IntervalSet: IntSet, Hashable, CustomStringConvertible { } public func toString(_ elemAreChar: Bool) -> String { - let buf = StringBuilder() - if self.intervals.isEmpty { + if intervals.isEmpty { return "{}" } - if self.size() > 1 { - buf.append("{") + + let selfSize = size() + + var buf = "" + + if selfSize > 1 { + buf += "{" } var first = true for interval in intervals { if !first { - buf.append(", ") + buf += ", " } first = false + let a = interval.a let b = interval.b if a == b { if a == CommonToken.EOF { - buf.append("") - } else { - if elemAreChar { - buf.append("'").append(String(a)).append("'") - } else { - buf.append(a) - } + buf += "" } - } else { - if elemAreChar { - buf.append("'").append(String(a)).append("'..'").append(String(b)).append("'") - } else { - buf.append(a).append("..").append(b) + else if elemAreChar { + buf += "'\(a)'" + } + else { + buf += "\(a)" } } + else if elemAreChar { + buf += "'\(a)'..'\(b)'" + } + else { + buf += "\(a)..\(b)" + } } - if self.size() > 1 { - buf.append("}") + + if selfSize > 1 { + buf += "}" } - return buf.toString() + + return buf } public func toString(_ vocabulary: Vocabulary) -> String { - let buf = StringBuilder() - - if self.intervals.isEmpty { + if intervals.isEmpty { return "{}" } - if self.size() > 1 { - buf.append("{") + + let selfSize = size() + + var buf = "" + + if selfSize > 1 { + buf += "{" } var first = true for interval in intervals { if !first { - buf.append(", ") + buf += ", " } first = false let a = interval.a let b = interval.b if a == b { - buf.append(elementName(vocabulary, a)) - } else { + buf += elementName(vocabulary, a) + } + else { for i in a...b { if i > a { - buf.append(", ") + buf += ", " } - buf.append(elementName(vocabulary, i)) + buf += elementName(vocabulary, i) } } + } + if selfSize > 1 { + buf += "}" } - if self.size() > 1 { - buf.append("}") - } - return buf.toString() + + return buf } internal func elementName(_ vocabulary: Vocabulary, _ a: Int) -> String { if a == CommonToken.EOF { return "" - } else { - if a == CommonToken.EPSILON { - return "" - } else { - return vocabulary.getDisplayName(a) - } + } + else if a == CommonToken.EPSILON { + return "" + } + else { + return vocabulary.getDisplayName(a) } } diff --git a/runtime/Swift/Sources/Antlr4/misc/Utils.swift b/runtime/Swift/Sources/Antlr4/misc/Utils.swift index c025becdc..4233b1c04 100644 --- a/runtime/Swift/Sources/Antlr4/misc/Utils.swift +++ b/runtime/Swift/Sources/Antlr4/misc/Utils.swift @@ -10,27 +10,25 @@ import Foundation public class Utils { public static func escapeWhitespace(_ s: String, _ escapeSpaces: Bool) -> String { - let buf: StringBuilder = StringBuilder() - for c: Character in s.characters { + var buf = "" + for c in s { if c == " " && escapeSpaces { - buf.append("\u{00B7}") - } else { - if c == "\t" { - buf.append("\\t") - } else { - if c == "\n" { - buf.append("\\n") - } else { - if c == "\r" { - buf.append("\\r") - } else { - buf.append(String(c)) - } - } - } + buf += "\u{00B7}" + } + else if c == "\t" { + buf += "\\t" + } + else if c == "\n" { + buf += "\\n" + } + else if c == "\r" { + buf += "\\r" + } + else { + buf.append(c) } } - return buf.toString() + return buf } diff --git a/runtime/Swift/Sources/Antlr4/tree/Trees.swift b/runtime/Swift/Sources/Antlr4/tree/Trees.swift index 09f724e8b..bca323660 100644 --- a/runtime/Swift/Sources/Antlr4/tree/Trees.swift +++ b/runtime/Swift/Sources/Antlr4/tree/Trees.swift @@ -64,24 +64,20 @@ public class Trees { /// parse trees and extract data appropriately. /// public static func toStringTree(_ t: Tree, _ ruleNames: Array?) -> String { - var s: String = Utils.escapeWhitespace(getNodeText(t, ruleNames), false) + let s = Utils.escapeWhitespace(getNodeText(t, ruleNames), false) if t.getChildCount() == 0 { return s } - let buf: StringBuilder = StringBuilder() - buf.append("(") - s = Utils.escapeWhitespace(getNodeText(t, ruleNames), false) - buf.append(s) - buf.append(" ") + var buf = "(\(s) " let length = t.getChildCount() for i in 0.. 0 { - buf.append(" ") + buf += " " } - buf.append(toStringTree(t.getChild(i)!, ruleNames)) + buf += toStringTree(t.getChild(i)!, ruleNames) } - buf.append(")") - return buf.toString() + buf += ")" + return buf } public static func getNodeText(_ t: Tree, _ recog: Parser?) -> String { From 7cfdd9d124e5d19d5ea190e4b4dc5c7681abf243 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 23:53:30 -0700 Subject: [PATCH 4/8] Change TokenStreamRewriter to use an inout String as the execute(buf:) parameter rather than StringBuilder. Tidy up the rest of the class on the way through. This is the last use of StringBuilder, so we can remove that class entirely. --- .../Sources/Antlr4/TokenStreamRewriter.swift | 169 ++++++++---------- .../Antlr4/misc/utils/StringBuilder.swift | 67 ------- 2 files changed, 79 insertions(+), 157 deletions(-) delete mode 100644 runtime/Swift/Sources/Antlr4/misc/utils/StringBuilder.swift diff --git a/runtime/Swift/Sources/Antlr4/TokenStreamRewriter.swift b/runtime/Swift/Sources/Antlr4/TokenStreamRewriter.swift index 2a74c3681..1606e0579 100644 --- a/runtime/Swift/Sources/Antlr4/TokenStreamRewriter.swift +++ b/runtime/Swift/Sources/Antlr4/TokenStreamRewriter.swift @@ -84,19 +84,19 @@ import Foundation public class TokenStreamRewriter { - public let DEFAULT_PROGRAM_NAME: String = "default" - public static let PROGRAM_INIT_SIZE: Int = 100 - public static let MIN_TOKEN_INDEX: Int = 0 + public let DEFAULT_PROGRAM_NAME = "default" + public static let PROGRAM_INIT_SIZE = 100 + public static let MIN_TOKEN_INDEX = 0 // Define the rewrite operation hierarchy public class RewriteOperation: CustomStringConvertible { /// What index into rewrites List are we? - internal var instructionIndex: Int = 0 + internal var instructionIndex = 0 /// Token buffer index. internal var index: Int internal var text: String? - internal var lastIndex: Int = 0 - internal weak var tokens: TokenStream! + internal var lastIndex = 0 + internal weak var tokens: TokenStream! init(_ index: Int, _ tokens: TokenStream) { self.index = index @@ -112,7 +112,7 @@ public class TokenStreamRewriter { /// Execute the rewrite operation by possibly adding to the buffer. /// Return the index of the next token to operate on. /// - public func execute(_ buf: StringBuilder) throws -> Int { + public func execute(_ buf: inout String) throws -> Int { return index } @@ -123,16 +123,13 @@ public class TokenStreamRewriter { } public class InsertBeforeOp: RewriteOperation { - public override init(_ index: Int, _ text: String?, _ tokens: TokenStream) { - super.init(index, text, tokens) - } - - override public func execute(_ buf: StringBuilder) throws -> Int { - if text != nil { - buf.append(text!) + override public func execute(_ buf: inout String) throws -> Int { + if let text = text { + buf.append(text) } - if try tokens.get(index).getType() != CommonToken.EOF { - buf.append(try tokens.get(index).getText()!) + let token = try tokens.get(index) + if token.getType() != CommonToken.EOF { + buf.append(token.getText()!) } return index + 1 } @@ -146,7 +143,7 @@ public class TokenStreamRewriter { /// I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp /// instructions. - /// + /// public class ReplaceOp: RewriteOperation { @@ -156,27 +153,32 @@ public class TokenStreamRewriter { } override - public func execute(_ buf: StringBuilder) -> Int { - if text != nil { - buf.append(text!) + public func execute(_ buf: inout String) -> Int { + if let text = text { + buf += text } return lastIndex + 1 } + override public var description: String { - if text == nil { - return "" + let token = try! tokens.get(index) + let lastToken = try! tokens.get(lastIndex) + if let text = text { + return "" } - return "" + return "" } } public class RewriteOperationArray{ - private final var rewrites: Array = Array() - public init(){ + private final var rewrites = [RewriteOperation?]() + + public init() { rewrites.reserveCapacity(TokenStreamRewriter.PROGRAM_INIT_SIZE) } - final func append(_ op: RewriteOperation){ + + final func append(_ op: RewriteOperation) { op.instructionIndex = rewrites.count rewrites.append(op) } @@ -184,12 +186,15 @@ public class TokenStreamRewriter { final func rollback(_ instructionIndex: Int) { rewrites = Array(rewrites[TokenStreamRewriter.MIN_TOKEN_INDEX ..< instructionIndex]) } - final var count: Int{ + + final var count: Int { return rewrites.count } - final var isEmpty: Bool{ + + final var isEmpty: Bool { return rewrites.isEmpty } + /// We need to combine operations and report invalid operations (like /// overlapping replaces that are not completed nested). Inserts to /// same index need to be combined etc... Here are the cases: @@ -239,37 +244,34 @@ public class TokenStreamRewriter { /// /// Return a map from token index to operation. /// - final func reduceToSingleOperationPerIndex() throws -> Dictionary { + final func reduceToSingleOperationPerIndex() throws -> [Int: RewriteOperation] { let rewritesCount = rewrites.count // WALK REPLACES for i in 0.. rop.index && iop.index <= rop.lastIndex { + } + else if iop.index > rop.index && iop.index <= rop.lastIndex { // delete insert as it's a no-op. rewrites[iop.instructionIndex] = nil } } } // Drop any prior replaces contained within - let prevRopIndexList = getKindOfOps(&rewrites, ReplaceOp.self, i) - for j in prevRopIndexList { + let prevRopIndexList = getKindOfOps(&rewrites, ReplaceOp.self, i) + for j in prevRopIndexList { if let prevRop = rewrites[j] { if prevRop.index >= rop.index && prevRop.lastIndex <= rop.lastIndex { // delete replace as it's a no-op. @@ -285,7 +287,6 @@ public class TokenStreamRewriter { rewrites[prevRop.instructionIndex] = nil // kill first delete rop.index = min(prevRop.index, rop.index) rop.lastIndex = max(prevRop.lastIndex, rop.lastIndex) - print("new rop \(rop)") } else if !disjoint { throw ANTLRError.illegalArgument(msg: "replace op boundaries of \(rop.description) " + "overlap with previous \(prevRop.description)") @@ -341,9 +342,9 @@ public class TokenStreamRewriter { } } - var m: Dictionary = Dictionary() + var m = [Int: RewriteOperation]() for i in 0.. String { - let x: String = a ?? "" - let y: String = b ?? "" - + let x = a ?? "" + let y = b ?? "" return x + y } /// Get all operations before an index of a particular kind - final func getKindOfOps(_ rewrites: inout [RewriteOperation?], _ kind: T.Type, _ before: Int ) -> [Int] { + final func getKindOfOps(_ rewrites: inout [RewriteOperation?], _ kind: T.Type, _ before: Int ) -> [Int] { - let length = min(before,rewrites.count) + let length = min(before, rewrites.count) var op = [Int]() op.reserveCapacity(length) for i in 0.. //Array + internal var programs = [String: RewriteOperationArray]() /// Map String (program name) → Integer index - internal final var lastRewriteTokenIndexes: Dictionary + internal final var lastRewriteTokenIndexes: [String: Int] public init(_ tokens: TokenStream) { self.tokens = tokens - programs = Dictionary() programs[DEFAULT_PROGRAM_NAME] = RewriteOperationArray() lastRewriteTokenIndexes = Dictionary() } @@ -439,7 +437,7 @@ public class TokenStreamRewriter { public func insertAfter(_ programName: String, _ index: Int, _ text: String) { // to insert after, just insert before next index (even if past end) let op = InsertAfterOp(index, text, tokens) - let rewrites = getProgram(programName) + let rewrites = getProgram(programName) rewrites.append(op) } @@ -456,8 +454,8 @@ public class TokenStreamRewriter { } public func insertBefore(_ programName: String, _ index: Int, _ text: String) { - let op: RewriteOperation = InsertBeforeOp(index, text, tokens) - let rewrites: RewriteOperationArray = getProgram(programName) + let op = InsertBeforeOp(index, text, tokens) + let rewrites = getProgram(programName) rewrites.append(op) } @@ -481,10 +479,9 @@ public class TokenStreamRewriter { if from > to || from < 0 || to < 0 || to >= tokens.size() { throw ANTLRError.illegalArgument(msg: "replace: range invalid: \(from)..\(to)(size=\(tokens.size()))") } - let op: RewriteOperation = ReplaceOp(from, to, text, tokens) - let rewritesArray: RewriteOperationArray = getProgram(programName) + let op = ReplaceOp(from, to, text, tokens) + let rewritesArray = getProgram(programName) rewritesArray.append(op) - } public func replace(_ programName: String, _ from: Token, _ to: Token, _ text: String?) throws { @@ -523,30 +520,24 @@ public class TokenStreamRewriter { } internal func getLastRewriteTokenIndex(_ programName: String) -> Int { - let I: Int? = lastRewriteTokenIndexes[programName] - if I == nil { - return -1 - } - return I! + return lastRewriteTokenIndexes[programName] ?? -1 } internal func setLastRewriteTokenIndex(_ programName: String, _ i: Int) { lastRewriteTokenIndexes[programName] = i } - internal func getProgram(_ name: String) -> RewriteOperationArray - { - var program: RewriteOperationArray? = programs[name] - if program == nil { - program = initializeProgram(name) + internal func getProgram(_ name: String) -> RewriteOperationArray { + if let program = programs[name] { + return program + } + else { + return initializeProgram(name) } - return program! } - private func initializeProgram(_ name: String) -> RewriteOperationArray - { - let program: RewriteOperationArray = RewriteOperationArray() - + private func initializeProgram(_ name: String) -> RewriteOperationArray { + let program = RewriteOperationArray() programs[name] = program return program } @@ -579,8 +570,8 @@ public class TokenStreamRewriter { } public func getText(_ programName: String, _ interval: Interval) throws -> String { - var start: Int = interval.a - var stop: Int = interval.b + var start = interval.a + var stop = interval.b // ensure start/end are in range if stop > tokens.size() - 1 { @@ -589,32 +580,31 @@ public class TokenStreamRewriter { if start < 0 { start = 0 } - guard let rewrites = programs[programName] , !rewrites.isEmpty else { + guard let rewrites = programs[programName], !rewrites.isEmpty else { return try tokens.getText(interval) // no instructions to execute } - let buf: StringBuilder = StringBuilder() + var buf = "" // First, optimize instruction stream - var indexToOp: Dictionary = try rewrites.reduceToSingleOperationPerIndex() + var indexToOp = try rewrites.reduceToSingleOperationPerIndex() // Walk buffer, executing instructions and emitting tokens - var i: Int = start + var i = start while i <= stop && i < tokens.size() { - let op: RewriteOperation? = indexToOp[i] - indexToOp.removeValue(forKey: i) - //indexToOp.remove(i); // remove so any left have index size-1 - let t: Token = try tokens.get(i) - if op == nil { + let op = indexToOp[i] + indexToOp.removeValue(forKey: i) // remove so any left have index size-1 + let t = try tokens.get(i) + if let op = op { + i = try op.execute(&buf) // execute operation and skip + } + else { // no operation at that index, just dump token if t.getType() != CommonToken.EOF { buf.append(t.getText()!) } i += 1 // move to next token - } else { - i = try op!.execute(buf) // execute operation and skip } - } // include stuff after end if it's last index in buffer @@ -623,14 +613,13 @@ public class TokenStreamRewriter { if stop == tokens.size() - 1 { // Scan any remaining operations after last token // should be included (they will be inserts). - for op: RewriteOperation in indexToOp.values { + for op in indexToOp.values { if op.index >= tokens.size() - 1 { - buf.append(op.text!) + buf += op.text! } } } - return buf.toString() + return buf } - } diff --git a/runtime/Swift/Sources/Antlr4/misc/utils/StringBuilder.swift b/runtime/Swift/Sources/Antlr4/misc/utils/StringBuilder.swift deleted file mode 100644 index ccfb32237..000000000 --- a/runtime/Swift/Sources/Antlr4/misc/utils/StringBuilder.swift +++ /dev/null @@ -1,67 +0,0 @@ -/* 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. - */ - -// -// StringBuilder.swift -// antlr.swift -// -// Created by janyou on 15/9/4. -// - -import Foundation - -public class StringBuilder { - private var stringValue: String - - public init(string: String = "") { - self.stringValue = string - } - - public func toString() -> String { - return stringValue - } - - public var length: Int { - return stringValue.length - } - @discardableResult - public func append(_ string: String) -> StringBuilder { - stringValue += string - return self - } - @discardableResult - public func append(_ value: T) -> StringBuilder { - stringValue += value.description - return self - } - @discardableResult - public func appendLine(_ string: String) -> StringBuilder { - stringValue += string + "\n" - return self - } - @discardableResult - public func appendLine(_ value: T) -> StringBuilder { - stringValue += value.description + "\n" - return self - } - @discardableResult - public func clear() -> StringBuilder { - stringValue = "" - return self - } -} - -public func +=(lhs: StringBuilder, rhs: String) { - lhs.append(rhs) -} - -public func +=(lhs: StringBuilder, rhs: T) { - lhs.append(rhs.description) -} - -public func +(lhs: StringBuilder, rhs: StringBuilder) -> StringBuilder { - return StringBuilder(string: lhs.toString() + rhs.toString()) -} - From 775040e1866d9447b27722a5b726d1bb4114a179 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 15:41:59 -0700 Subject: [PATCH 5/8] Remove the toString implementations. In Swift, we use description for the same thing. All these just stubbed-over or replicated the description implementation, except for PredicateTransition which now implements CustomStringConvertible. --- .../Swift/Sources/Antlr4/atn/ATNConfig.swift | 3 --- .../Sources/Antlr4/atn/ATNConfigSet.swift | 4 ---- .../Swift/Sources/Antlr4/atn/ATNState.swift | 3 --- .../Antlr4/atn/ParserATNSimulator.swift | 2 +- .../atn/PrecedencePredicateTransition.swift | 5 ----- .../Antlr4/atn/PredicateTransition.swift | 6 ++---- .../Sources/Antlr4/atn/RangeTransition.swift | 5 ----- .../Sources/Antlr4/atn/SemanticContext.swift | 9 --------- runtime/Swift/Sources/Antlr4/dfa/DFA.swift | 9 ++------- .../Sources/Antlr4/dfa/DFASerializer.swift | 4 ---- runtime/Swift/Sources/Antlr4/misc/BitSet.swift | 18 +++++++----------- runtime/Swift/Sources/Antlr4/misc/IntSet.swift | 2 -- .../Swift/Sources/Antlr4/misc/Interval.swift | 6 ------ .../Sources/Antlr4/misc/IntervalSet.swift | 4 ---- .../Antlr4/tree/pattern/ParseTreeMatch.swift | 3 --- 15 files changed, 12 insertions(+), 71 deletions(-) diff --git a/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift b/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift index bc8e53439..a8a721bab 100644 --- a/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift +++ b/runtime/Swift/Sources/Antlr4/atn/ATNConfig.swift @@ -159,9 +159,6 @@ public class ATNConfig: Hashable, CustomStringConvertible { } - public func toString() -> String { - return description - } public var description: String { //return "MyClass \(string)" return toString(nil, true) diff --git a/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift b/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift index 630dc4cf2..b1c682533 100644 --- a/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift +++ b/runtime/Swift/Sources/Antlr4/atn/ATNConfigSet.swift @@ -292,10 +292,6 @@ public class ATNConfigSet: Hashable, CustomStringConvertible { return buf } - public func toString() -> String { - return description - } - /// /// override /// public func toArray(a : [T]) -> [T] { diff --git a/runtime/Swift/Sources/Antlr4/atn/ATNState.swift b/runtime/Swift/Sources/Antlr4/atn/ATNState.swift index 88cf1a183..8ad626abc 100644 --- a/runtime/Swift/Sources/Antlr4/atn/ATNState.swift +++ b/runtime/Swift/Sources/Antlr4/atn/ATNState.swift @@ -136,9 +136,6 @@ public class ATNState: Hashable, CustomStringConvertible { } - public func toString() -> String { - return description - } public var description: String { //return "MyClass \(string)" return String(stateNumber) diff --git a/runtime/Swift/Sources/Antlr4/atn/ParserATNSimulator.swift b/runtime/Swift/Sources/Antlr4/atn/ParserATNSimulator.swift index 530738b22..ac1b95e63 100644 --- a/runtime/Swift/Sources/Antlr4/atn/ParserATNSimulator.swift +++ b/runtime/Swift/Sources/Antlr4/atn/ParserATNSimulator.swift @@ -1907,7 +1907,7 @@ open class ParserATNSimulator: ATNSimulator { } else if let st = t as? SetTransition { let not = st is NotSetTransition - trans = (not ? "~" : "") + "Set " + st.set.toString() + trans = (not ? "~" : "") + "Set " + st.set.description } } errPrint("\(c.toString(parser, true)):\(trans)") diff --git a/runtime/Swift/Sources/Antlr4/atn/PrecedencePredicateTransition.swift b/runtime/Swift/Sources/Antlr4/atn/PrecedencePredicateTransition.swift index 5a8565faf..712dfe67d 100644 --- a/runtime/Swift/Sources/Antlr4/atn/PrecedencePredicateTransition.swift +++ b/runtime/Swift/Sources/Antlr4/atn/PrecedencePredicateTransition.swift @@ -42,9 +42,4 @@ public final class PrecedencePredicateTransition: AbstractPredicateTransition, C public var description: String { return "\(precedence) >= _p" } - - public func toString() -> String { - return description - } - } diff --git a/runtime/Swift/Sources/Antlr4/atn/PredicateTransition.swift b/runtime/Swift/Sources/Antlr4/atn/PredicateTransition.swift index aa608857c..9efd66fb5 100644 --- a/runtime/Swift/Sources/Antlr4/atn/PredicateTransition.swift +++ b/runtime/Swift/Sources/Antlr4/atn/PredicateTransition.swift @@ -14,7 +14,7 @@ /// multiple ATN configurations into a single DFA state. /// -public final class PredicateTransition: AbstractPredicateTransition { +public final class PredicateTransition: AbstractPredicateTransition, CustomStringConvertible { public let ruleIndex: Int public let predIndex: Int public let isCtxDependent: Bool @@ -47,9 +47,7 @@ public final class PredicateTransition: AbstractPredicateTransition { return SemanticContext.Predicate(ruleIndex, predIndex, isCtxDependent) } - - public func toString() -> String { + public var description: String { return "pred_\(ruleIndex):\(predIndex)" } - } diff --git a/runtime/Swift/Sources/Antlr4/atn/RangeTransition.swift b/runtime/Swift/Sources/Antlr4/atn/RangeTransition.swift index ddb2c4e75..69dd39d82 100644 --- a/runtime/Swift/Sources/Antlr4/atn/RangeTransition.swift +++ b/runtime/Swift/Sources/Antlr4/atn/RangeTransition.swift @@ -31,11 +31,6 @@ public final class RangeTransition: Transition, CustomStringConvertible { return symbol >= from && symbol <= to } - - public func toString() -> String { - return description - } - public var description: String { return "'" + String(from) + "'..'" + String(to) + "'" diff --git a/runtime/Swift/Sources/Antlr4/atn/SemanticContext.swift b/runtime/Swift/Sources/Antlr4/atn/SemanticContext.swift index 261a3734e..bf9be2924 100644 --- a/runtime/Swift/Sources/Antlr4/atn/SemanticContext.swift +++ b/runtime/Swift/Sources/Antlr4/atn/SemanticContext.swift @@ -277,10 +277,6 @@ public class SemanticContext: Hashable, CustomStringConvertible { return result } - public func toString() -> String { - return description - } - override public var description: String { return opnds.map({ $0.description }).joined(separator: "&&") @@ -386,11 +382,6 @@ public class SemanticContext: Hashable, CustomStringConvertible { return result } - - public func toString() -> String { - return description - } - override public var description: String { return opnds.map({ $0.description }).joined(separator: "||") diff --git a/runtime/Swift/Sources/Antlr4/dfa/DFA.swift b/runtime/Swift/Sources/Antlr4/dfa/DFA.swift index 3f8096ca1..a54aa2aa8 100644 --- a/runtime/Swift/Sources/Antlr4/dfa/DFA.swift +++ b/runtime/Swift/Sources/Antlr4/dfa/DFA.swift @@ -165,18 +165,13 @@ public class DFA: CustomStringConvertible { return toString(Vocabulary.EMPTY_VOCABULARY) } - - public func toString() -> String { - return description - } - public func toString(_ vocabulary: Vocabulary) -> String { if s0 == nil { return "" } let serializer = DFASerializer(self, vocabulary) - return serializer.toString() + return serializer.description } public func toLexerString() -> String { @@ -184,7 +179,7 @@ public class DFA: CustomStringConvertible { return "" } let serializer = LexerDFASerializer(self) - return serializer.toString() + return serializer.description } } diff --git a/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift b/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift index 9695cab1f..d49fc705a 100644 --- a/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift +++ b/runtime/Swift/Sources/Antlr4/dfa/DFASerializer.swift @@ -43,10 +43,6 @@ public class DFASerializer: CustomStringConvertible { return buf } - public func toString() -> String { - return description - } - internal func getEdgeLabel(_ i: Int) -> String { return vocabulary.getDisplayName(i - 1) } diff --git a/runtime/Swift/Sources/Antlr4/misc/BitSet.swift b/runtime/Swift/Sources/Antlr4/misc/BitSet.swift index fa58553ed..ef03b8aa7 100644 --- a/runtime/Swift/Sources/Antlr4/misc/BitSet.swift +++ b/runtime/Swift/Sources/Antlr4/misc/BitSet.swift @@ -1104,15 +1104,15 @@ public class BitSet: Hashable, CustomStringConvertible { /// /// Example: /// - /// BitSet drPepper = new BitSet(); - /// Now `drPepper.toString()` returns "`{`}". + /// `BitSet drPepper = new BitSet();` + /// Now `drPepper.description` returns `"{}"`. /// - /// drPepper.set(2); - /// Now `drPepper.toString()` returns "`{2`}". + /// `drPepper.set(2);` + /// Now `drPepper.description` returns `"{2}"`. /// - /// drPepper.set(4); - /// drPepper.set(10); - /// Now `drPepper.toString()` returns "`{2, 4, 10`}". + /// `drPepper.set(4);` + /// `drPepper.set(10);` + /// Now `drPepper.description` returns `"{2, 4, 10}"`. /// /// - returns: a string representation of this bit set /// @@ -1139,10 +1139,6 @@ public class BitSet: Hashable, CustomStringConvertible { return b } - public func toString() -> String { - return description - } - } public func ==(lhs: BitSet, rhs: BitSet) -> Bool { diff --git a/runtime/Swift/Sources/Antlr4/misc/IntSet.swift b/runtime/Swift/Sources/Antlr4/misc/IntSet.swift index cc448593f..20faf88e7 100644 --- a/runtime/Swift/Sources/Antlr4/misc/IntSet.swift +++ b/runtime/Swift/Sources/Antlr4/misc/IntSet.swift @@ -146,6 +146,4 @@ public protocol IntSet { /// in ascending numerical order. /// func toList() -> [Int] - - func toString() -> String } diff --git a/runtime/Swift/Sources/Antlr4/misc/Interval.swift b/runtime/Swift/Sources/Antlr4/misc/Interval.swift index 8e926a6ee..e3b4ad49f 100644 --- a/runtime/Swift/Sources/Antlr4/misc/Interval.swift +++ b/runtime/Swift/Sources/Antlr4/misc/Interval.swift @@ -159,12 +159,6 @@ public class Interval: Hashable { } - public func toString() -> String { - return "\(a)..\(b)" - - } - - public var description: String { return "\(a)..\(b)" } diff --git a/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift b/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift index 70071bfbf..99fcc8278 100644 --- a/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift +++ b/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift @@ -105,7 +105,6 @@ public class IntervalSet: IntSet, Hashable, CustomStringConvertible { if readonly { throw ANTLRError.illegalState(msg: "can't alter readonly IntervalSet") } - //System.out.println("add "+addition+" to "+intervals.toString()); if addition.b < addition.a { return } @@ -509,9 +508,6 @@ public class IntervalSet: IntSet, Hashable, CustomStringConvertible { public var description: String { return toString(false) } - public func toString() -> String { - return description - } public func toString(_ elemAreChar: Bool) -> String { if intervals.isEmpty { diff --git a/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreeMatch.swift b/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreeMatch.swift index 55b362a3c..cae72e481 100644 --- a/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreeMatch.swift +++ b/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreeMatch.swift @@ -160,9 +160,6 @@ public class ParseTreeMatch: CustomStringConvertible { return tree } - public func toString() -> String { - return description - } public var description: String { let info = succeeded() ? "succeeded" : "failed" return "Match \(info); found \(getLabels().size()) labels" From 73d90ec18b26937aee5c75f1f7e81618d5c99821 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 15:38:25 -0700 Subject: [PATCH 6/8] Tidy up some uses of String.characters and integer indexing into Strings. In Swift 4, Strings have a set of sequence operations that we can use, so that we don't need our String extensions. Tidy up a bunch of places where the code has been converted from Java through Swift 3 and Swift 4, and become a mess. --- .../Sources/Antlr4/ANTLRInputStream.swift | 4 +-- runtime/Swift/Sources/Antlr4/Lexer.swift | 14 ++++---- .../Sources/Antlr4/ListTokenSource.swift | 5 ++- runtime/Swift/Sources/Antlr4/Parser.swift | 2 +- .../Sources/Antlr4/VocabularySingle.swift | 33 ++++++++----------- .../Sources/Antlr4/misc/IntervalSet.swift | 8 +---- .../pattern/ParseTreePatternMatcher.swift | 2 +- 7 files changed, 27 insertions(+), 41 deletions(-) diff --git a/runtime/Swift/Sources/Antlr4/ANTLRInputStream.swift b/runtime/Swift/Sources/Antlr4/ANTLRInputStream.swift index 17bbd8096..4267ce132 100644 --- a/runtime/Swift/Sources/Antlr4/ANTLRInputStream.swift +++ b/runtime/Swift/Sources/Antlr4/ANTLRInputStream.swift @@ -42,8 +42,8 @@ public class ANTLRInputStream: CharStream { /// Copy data in string to a local char array /// public init(_ input: String) { - self.data = Array(input.characters) // input.toCharArray(); - self.n = input.length + self.data = Array(input) + self.n = data.count } /// diff --git a/runtime/Swift/Sources/Antlr4/Lexer.swift b/runtime/Swift/Sources/Antlr4/Lexer.swift index 7a538973a..e6c26296b 100644 --- a/runtime/Swift/Sources/Antlr4/Lexer.swift +++ b/runtime/Swift/Sources/Antlr4/Lexer.swift @@ -421,21 +421,19 @@ open class Lexer: Recognizer, TokenSource { } open func getErrorDisplay(_ c: Character) -> String { - var s = String(c) if c.integerValue == CommonToken.EOF { - s = "" + return "" } - switch s { + switch c { case "\n": - s = "\\n" + return "\\n" case "\t": - s = "\\t" + return "\\t" case "\r": - s = "\\r" + return "\\r" default: - break + return String(c) } - return s } open func getCharErrorDisplay(_ c: Character) -> String { diff --git a/runtime/Swift/Sources/Antlr4/ListTokenSource.swift b/runtime/Swift/Sources/Antlr4/ListTokenSource.swift index 0863e16ee..943e603c4 100644 --- a/runtime/Swift/Sources/Antlr4/ListTokenSource.swift +++ b/runtime/Swift/Sources/Antlr4/ListTokenSource.swift @@ -142,9 +142,8 @@ public class ListTokenSource: TokenSource { var line = lastToken.getLine() if let tokenText = lastToken.getText() { - let length = tokenText.length - for j in 0.. { if result == nil { let deserializationOptions = ATNDeserializationOptions() try! deserializationOptions.setGenerateRuleBypassTransitions(true) - result = try! ATNDeserializer(deserializationOptions).deserialize(Array(serializedAtn.characters)) + result = try! ATNDeserializer(deserializationOptions).deserialize(Array(serializedAtn)) self.bypassAltsAtnCache[serializedAtn] = result! } } diff --git a/runtime/Swift/Sources/Antlr4/VocabularySingle.swift b/runtime/Swift/Sources/Antlr4/VocabularySingle.swift index 5b63ff4d4..1aff04892 100644 --- a/runtime/Swift/Sources/Antlr4/VocabularySingle.swift +++ b/runtime/Swift/Sources/Antlr4/VocabularySingle.swift @@ -85,27 +85,25 @@ public class Vocabulary: Hashable { /// the display names of tokens. /// public static func fromTokenNames(_ tokenNames: [String?]?) -> Vocabulary { - guard let tokenNames = tokenNames , tokenNames.count > 0 else { + guard let tokenNames = tokenNames, tokenNames.count > 0 else { return EMPTY_VOCABULARY } - var literalNames: [String?] = tokenNames// Arrays.copyOf(tokenNames, tokenNames.length); - var symbolicNames: [String?] = tokenNames + var literalNames = tokenNames + var symbolicNames = tokenNames let length = tokenNames.count for i in 0.. String { if tokenType >= 0 && tokenType < displayNames.count { - let displayName: String? = displayNames[tokenType] - if displayName != nil { - return displayName! + if let displayName = displayNames[tokenType] { + return displayName } } - let literalName: String? = getLiteralName(tokenType) - if literalName != nil { - return literalName! + if let literalName = getLiteralName(tokenType) { + return literalName } - let symbolicName: String? = getSymbolicName(tokenType) - if symbolicName != nil { - return symbolicName! + if let symbolicName = getSymbolicName(tokenType) { + return symbolicName } return String(tokenType) diff --git a/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift b/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift index 99fcc8278..68c3facbd 100644 --- a/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift +++ b/runtime/Swift/Sources/Antlr4/misc/IntervalSet.swift @@ -613,13 +613,7 @@ public class IntervalSet: IntSet, Hashable, CustomStringConvertible { public func size() -> Int { var n = 0 - let numIntervals = intervals.count - if numIntervals == 1 { - let firstInterval = intervals[0] - return firstInterval.b - firstInterval.a + 1 - } - for i in 0.. Date: Wed, 1 Nov 2017 23:51:31 -0700 Subject: [PATCH 7/8] Rewrite ParseTreePatternMatcher to use standard library String functions and avoid our custom String extensions. --- .../pattern/ParseTreePatternMatcher.swift | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreePatternMatcher.swift b/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreePatternMatcher.swift index 81ea3fa6f..ff47116e5 100644 --- a/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreePatternMatcher.swift +++ b/runtime/Swift/Sources/Antlr4/tree/pattern/ParseTreePatternMatcher.swift @@ -311,7 +311,7 @@ public class ParseTreePatternMatcher { for chunk in chunks { if let tagChunk = chunk as? TagChunk { // add special rule token or conjure up new token from name - let firstStr = String(tagChunk.getTag()[0]) + let firstStr = String(tagChunk.getTag().first!) if firstStr.lowercased() != firstStr { let ttype = parser.getTokenType(tagChunk.getTag()) if ttype == CommonToken.INVALID_TYPE { @@ -351,29 +351,34 @@ public class ParseTreePatternMatcher { /// Split ` = ;` into 4 chunks for tokenizing by _#tokenize_. /// public func split(_ pattern: String) throws -> [Chunk] { - var p = 0 - let n = pattern.length + var p = pattern.startIndex + let n = pattern.endIndex var chunks = [Chunk]() // find all start and stop indexes first, then collect - var starts = [Int]() - var stops = [Int]() + var starts = [Range]() + var stops = [Range]() + let escapedStart = escape + start + let escapedStop = escape + stop while p < n { - if p == pattern.indexOf(escape + start, startIndex: p) { - p += escape.length + start.length + let slice = pattern[p...] + if slice.hasPrefix(escapedStart) { + p = pattern.index(p, offsetBy: escapedStart.count) } - else if p == pattern.indexOf(escape + stop, startIndex: p) { - p += escape.length + stop.length + else if slice.hasPrefix(escapedStop) { + p = pattern.index(p, offsetBy: escapedStop.count) } - else if p == pattern.indexOf(start, startIndex: p) { - starts.append(p) - p += start.length + else if slice.hasPrefix(start) { + let upperBound = pattern.index(p, offsetBy: start.count) + starts.append(p ..< upperBound) + p = upperBound } - else if p == pattern.indexOf(stop, startIndex: p) { - stops.append(p) - p += stop.length + else if slice.hasPrefix(stop) { + let upperBound = pattern.index(p, offsetBy: stop.count) + stops.append(p ..< upperBound) + p = upperBound } else { - p += 1 + p = pattern.index(after: p) } } @@ -387,46 +392,50 @@ public class ParseTreePatternMatcher { let ntags = starts.count for i in 0..= stops[i] { + if starts[i].lowerBound >= stops[i].lowerBound { throw ANTLRError.illegalArgument(msg: "tag delimiters out of order in pattern: " + pattern) } } // collect into chunks now if ntags == 0 { - let text = pattern[0 ..< n] + let text = String(pattern[.. 0 && starts[0] > 0 { + if ntags > 0 && starts[0].lowerBound > pattern.startIndex { // copy text up to first tag into chunks - let text = pattern[0 ..< starts[0]] - chunks.append(TextChunk(text)) + let text = pattern[pattern.startIndex ..< starts[0].lowerBound] + chunks.append(TextChunk(String(text))) } for i in 0 ..< ntags { // copy inside of - let tag = pattern[starts[i] + start.length ..< stops[i]] - var ruleOrToken = tag - var label: String? - let colon = tag.indexOf(":") - if colon >= 0 { - label = tag[0 ..< colon] - ruleOrToken = tag[colon + 1 ..< tag.length] + let tag = pattern[starts[i].upperBound ..< stops[i].lowerBound] + let ruleOrToken: String + let label: String? + let bits = tag.split(separator: ":", maxSplits: 1) + if bits.count == 2 { + label = String(bits[0]) + ruleOrToken = String(bits[1]) + } + else { + label = nil + ruleOrToken = String(tag) } chunks.append(try TagChunk(label, ruleOrToken)) if i + 1 < ntags { // copy from end of to start of next - let text = pattern[stops[i] + stop.length ..< starts[i + 1]] - chunks.append(TextChunk(text)) + let text = pattern[stops[i].upperBound ..< starts[i + 1].lowerBound] + chunks.append(TextChunk(String(text))) } } if ntags > 0 { - let afterLastTag = stops[ntags - 1] + stop.length + let afterLastTag = stops[ntags - 1].upperBound if afterLastTag < n { // copy text from end of last tag to end let text = pattern[afterLastTag ..< n] - chunks.append(TextChunk(text)) + chunks.append(TextChunk(String(text))) } } From ba392be1afb2eb15c2ca65554afdac96050a6938 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 1 Nov 2017 23:55:56 -0700 Subject: [PATCH 8/8] 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) +}