Skip to content

Commit

Permalink
[Swift] reduce Optionals in APIs (#3621)
Browse files Browse the repository at this point in the history
* ParserRuleContext.children

see comment in removeLastChild

* TokenStream.getText

* Parser._parseListeners

this might require changes to the code templates?

* ATN {various}

* make computeReachSet return empty, not nil

* overrides refine optionality

* BufferedTokenStream getHiddenTokensTo{Left, Right} return empty not nil

* Update Swift.stg

* avoid breakage by adding overload of `getText` in extension
  • Loading branch information
Dante-Broggi committed Apr 10, 2022
1 parent 37496e2 commit b5ccba0
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 115 deletions.
21 changes: 7 additions & 14 deletions runtime/Swift/Sources/Antlr4/BufferedTokenStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ public class BufferedTokenStream: TokenStream {
/// the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or
/// EOF. If channel is -1, find any non default channel token.
///
public func getHiddenTokensToRight(_ tokenIndex: Int, _ channel: Int = -1) throws -> [Token]? {
public func getHiddenTokensToRight(_ tokenIndex: Int, _ channel: Int = -1) throws -> [Token] {
try lazyInit()
guard tokens.indices.contains(tokenIndex) else {
throw ANTLRError.indexOutOfBounds(msg: "\(tokenIndex) not in 0 ..< \(tokens.count)")
Expand All @@ -397,28 +397,28 @@ public class BufferedTokenStream: TokenStream {
/// the current token up until we see a token on DEFAULT_TOKEN_CHANNEL.
/// If channel is -1, find any non default channel token.
///
public func getHiddenTokensToLeft(_ tokenIndex: Int, _ channel: Int = -1) throws -> [Token]? {
public func getHiddenTokensToLeft(_ tokenIndex: Int, _ channel: Int = -1) throws -> [Token] {
try lazyInit()
guard tokens.indices.contains(tokenIndex) else {
throw ANTLRError.indexOutOfBounds(msg: "\(tokenIndex) not in 0 ..< \(tokens.count)")
}

if tokenIndex == 0 {
// obviously no tokens can appear before the first token
return nil
return []
}

let prevOnChannel = try previousTokenOnChannel(tokenIndex - 1, Lexer.DEFAULT_TOKEN_CHANNEL)
if prevOnChannel == tokenIndex - 1 {
return nil
return []
}
// if none onchannel to left, prevOnChannel=-1 then from=0
let from = prevOnChannel + 1
let to = tokenIndex - 1
return filterForChannel(from, to, channel)
}

internal func filterForChannel(_ from: Int, _ to: Int, _ channel: Int) -> [Token]? {
internal func filterForChannel(_ from: Int, _ to: Int, _ channel: Int) -> [Token] {
var hidden = [Token]()
for t in tokens[from...to] {
if channel == -1 {
Expand All @@ -431,9 +431,6 @@ public class BufferedTokenStream: TokenStream {
}
}
}
if hidden.isEmpty {
return nil
}
return hidden
}

Expand Down Expand Up @@ -472,12 +469,8 @@ public class BufferedTokenStream: TokenStream {
}


public func getText(_ start: Token?, _ stop: Token?) throws -> String {
if let start = start, let stop = stop {
return try getText(Interval.of(start.getTokenIndex(), stop.getTokenIndex()))
}

return ""
public func getText(_ start: Token, _ stop: Token) throws -> String {
return try getText(Interval.of(start.getTokenIndex(), stop.getTokenIndex()))
}

///
Expand Down
51 changes: 17 additions & 34 deletions runtime/Swift/Sources/Antlr4/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
///
/// - SeeAlso: #addParseListener
///
public var _parseListeners: Array<ParseTreeListener>?
public var _parseListeners: Array<ParseTreeListener> = []

///
/// The number of syntax errors reported during parsing. This value is
Expand Down Expand Up @@ -285,7 +285,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
}

public func getParseListeners() -> [ParseTreeListener] {
return _parseListeners ?? [ParseTreeListener]()
return _parseListeners
}

///
Expand Down Expand Up @@ -314,11 +314,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
/// - Parameter listener: the listener to add
///
public func addParseListener(_ listener: ParseTreeListener) {
if _parseListeners == nil {
_parseListeners = [ParseTreeListener]()
}

_parseListeners!.append(listener)
_parseListeners.append(listener)
}

///
Expand All @@ -333,16 +329,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
///

public func removeParseListener(_ listener: ParseTreeListener?) {
if _parseListeners != nil {
if !_parseListeners!.filter({ $0 === listener }).isEmpty {
_parseListeners = _parseListeners!.filter({
$0 !== listener
})
if _parseListeners!.isEmpty {
_parseListeners = nil
}
}
}
_parseListeners.removeAll(where: { $0 === listener })
}

///
Expand All @@ -351,7 +338,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
/// - SeeAlso: #addParseListener
///
public func removeParseListeners() {
_parseListeners = nil
_parseListeners = []
}

///
Expand All @@ -360,7 +347,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
/// - SeeAlso: #addParseListener
///
public func triggerEnterRuleEvent() throws {
if let _parseListeners = _parseListeners, let _ctx = _ctx {
if let _ctx = _ctx {
for listener: ParseTreeListener in _parseListeners {
try listener.enterEveryRule(_ctx)
_ctx.enterRule(listener)
Expand All @@ -375,7 +362,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
///
public func triggerExitRuleEvent() throws {
// reverse order walk of listeners
if let _parseListeners = _parseListeners, let _ctx = _ctx {
if let _ctx = _ctx {
for listener in _parseListeners.reversed() {
_ctx.exitRule(listener)
try listener.exitEveryRule(_ctx)
Expand Down Expand Up @@ -542,24 +529,20 @@ open class Parser: Recognizer<ParserATNSimulator> {
guard let _ctx = _ctx else {
return o
}
let hasListener = _parseListeners != nil && !_parseListeners!.isEmpty
let hasListener = !_parseListeners.isEmpty

if _buildParseTrees || hasListener {
if _errHandler.inErrorRecoveryMode(self) {
let node = createErrorNode(parent: _ctx, t: o)
_ctx.addErrorNode(node)
if let _parseListeners = _parseListeners {
for listener in _parseListeners {
listener.visitErrorNode(node)
}
for listener in _parseListeners {
listener.visitErrorNode(node)
}
} else {
let node = createTerminalNode(parent: _ctx, t: o)
_ctx.addChild(node)
if let _parseListeners = _parseListeners {
for listener in _parseListeners {
listener.visitTerminal(node)
}
for listener in _parseListeners {
listener.visitTerminal(node)
}
}
}
Expand Down Expand Up @@ -611,7 +594,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
}
ctx.stop = try _input.LT(-1)
// trigger event on _ctx, before it reverts to parent
if _parseListeners != nil {
if !_parseListeners.isEmpty {
try triggerExitRuleEvent()
}
setState(ctx.invokingState)
Expand All @@ -629,7 +612,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
}
}
_ctx = localctx
if _parseListeners != nil {
if !_parseListeners.isEmpty {
try triggerEnterRuleEvent()
}
}
Expand Down Expand Up @@ -664,7 +647,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
_precedenceStack.push(precedence)
_ctx = localctx
_ctx!.start = try _input.LT(1)
if _parseListeners != nil {
if !_parseListeners.isEmpty {
try triggerEnterRuleEvent() // simulates rule entry for left-recursive rules
}
}
Expand All @@ -684,7 +667,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
_ctx!.addChild(previous)
}

if _parseListeners != nil {
if !_parseListeners.isEmpty {
try triggerEnterRuleEvent() // simulates rule entry for left-recursive rules
}
}
Expand All @@ -695,7 +678,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
let retctx = _ctx! // save current ctx (return value)

// unroll so _ctx is as it was before call to recursive method
if _parseListeners != nil {
if !_parseListeners.isEmpty {
while let ctxWrap = _ctx, ctxWrap !== _parentctx {
try triggerExitRuleEvent()
_ctx = ctxWrap.parent as? ParserRuleContext
Expand Down
41 changes: 16 additions & 25 deletions runtime/Swift/Sources/Antlr4/ParserRuleContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ open class ParserRuleContext: RuleContext {
/// operation because we don't the need to track the details about
/// how we parse this rule.
///
public var children: [ParseTree]?
public var children: [ParseTree] = []

/// For debugging/tracing purposes, we want to track all of the nodes in
/// the ATN traversed by the parser for a particular rule.
Expand Down Expand Up @@ -89,13 +89,12 @@ open class ParserRuleContext: RuleContext {
self.stop = ctx.stop

// copy any error nodes to alt label node
if let ctxChildren = ctx.children {
self.children = [ParseTree]()
// reset parent pointer for any error nodes
for child in ctxChildren {
if let errNode = child as? ErrorNode {
addChild(errNode)
}
let ctxChildren = ctx.children
self.children = [ParseTree]()
// reset parent pointer for any error nodes
for child in ctxChildren {
if let errNode = child as? ErrorNode {
addChild(errNode)
}
}
}
Expand All @@ -120,10 +119,7 @@ open class ParserRuleContext: RuleContext {
/// - Since: 4.7
///
open func addAnyChild(_ t: ParseTree) {
if children == nil {
children = [ParseTree]()
}
children!.append(t)
children.append(t)
}

open func addChild(_ ruleInvocation: RuleContext) {
Expand All @@ -148,20 +144,22 @@ open class ParserRuleContext: RuleContext {
/// generic ruleContext object.
///
open func removeLastChild() {
children?.removeLast()
// removeLast asserts if called when empty, popLast does not,
// this preserves edge case behavior, perhaps unnecessarily.
_ = children.popLast()
}


override
open func getChild(_ i: Int) -> Tree? {
guard let children = children, i >= 0 && i < children.count else {
guard i >= 0 && i < children.count else {
return nil
}
return children[i]
}

open func getChild<T: ParseTree>(_ ctxType: T.Type, i: Int) -> T? {
guard let children = children, i >= 0 && i < children.count else {
guard i >= 0 && i < children.count else {
return nil
}
var j = -1 // what element have we found with ctxType?
Expand All @@ -178,7 +176,7 @@ open class ParserRuleContext: RuleContext {
}

open func getToken(_ ttype: Int, _ i: Int) -> TerminalNode? {
guard let children = children, i >= 0 && i < children.count else {
guard i >= 0 && i < children.count else {
return nil
}
var j = -1 // what token with ttype have we found?
Expand All @@ -198,10 +196,6 @@ open class ParserRuleContext: RuleContext {
}

open func getTokens(_ ttype: Int) -> [TerminalNode] {
guard let children = children else {
return [TerminalNode]()
}

return children.compactMap {
if let tnode = $0 as? TerminalNode, let symbol = tnode.getSymbol(), symbol.getType() == ttype {
return tnode
Expand All @@ -217,20 +211,17 @@ open class ParserRuleContext: RuleContext {
}

open func getRuleContexts<T: ParserRuleContext>(_ ctxType: T.Type) -> [T] {
guard let children = children else {
return [T]()
}
return children.compactMap { $0 as? T }
}

override
open func getChildCount() -> Int {
return children?.count ?? 0
return children.count
}

override
open subscript(index: Int) -> ParseTree {
return children![index]
return children[index]
}

override
Expand Down
38 changes: 37 additions & 1 deletion runtime/Swift/Sources/Antlr4/TokenStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,41 @@ public protocol TokenStream: IntStream {
/// and `stop` tokens.
///
///
func getText(_ start: Token?, _ stop: Token?) throws -> String
func getText(_ start: Token, _ stop: Token) throws -> String
}

extension TokenStream {
///
/// Return the text of all tokens in this stream between `start` and
/// `stop` (inclusive).
///
/// If the specified `start` or `stop` token was not provided by
/// this stream, or if the `stop` occurred before the `start`
/// token, the behavior is unspecified.
///
/// For streams which ensure that the _org.antlr.v4.runtime.Token#getTokenIndex_ method is
/// accurate for all of its provided tokens, this method behaves like the
/// following code. Other streams may implement this method in other ways
/// provided the behavior is consistent with this at a high level.
///
///
/// TokenStream stream = ...;
/// String text = "";
/// for (int i = start.getTokenIndex(); i &lt;= stop.getTokenIndex(); i++) {
/// text += stream.get(i).getText();
/// }
///
///
/// - Parameter start: The first token in the interval to get text for.
/// - Parameter stop: The last token in the interval to get text for (inclusive).
/// - Throws: ANTLRError.unsupportedOperation if this stream does not support
/// this method for the specified tokens
/// - Returns: The text of all tokens lying between the specified `start`
/// and `stop` tokens.
///
///
func getText(_ start: Token?, _ stop: Token?) throws -> String {
guard let start = start, let stop = stop else { return "" }
return try getText(start, stop)
}
}
4 changes: 2 additions & 2 deletions runtime/Swift/Sources/Antlr4/UnbufferedTokenStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ public class UnbufferedTokenStream: TokenStream {
}


public func getText(_ start: Token?, _ stop: Token?) throws -> String {
return try getText(Interval.of(start!.getTokenIndex(), stop!.getTokenIndex()))
public func getText(_ start: Token, _ stop: Token) throws -> String {
return try getText(Interval.of(start.getTokenIndex(), stop.getTokenIndex()))
}


Expand Down
Loading

0 comments on commit b5ccba0

Please sign in to comment.