Merge pull request #1697 from hanjoes/master

Swift imple of #1665, #1674.
This commit is contained in:
Terence Parr 2017-03-01 14:50:50 -08:00 committed by GitHub
commit e04e7a40cc
5 changed files with 142 additions and 65 deletions

View File

@ -72,11 +72,12 @@ public protocol ANTLRErrorStrategy {
/// the parsing process
func sync(_ recognizer: Parser) throws // RecognitionException;
/// Tests whether or not {@code recognizer} is in the process of recovering
/// Tests whether or not recognizer} is in the process of recovering
/// from an error. In error recovery mode, {@link org.antlr.v4.runtime.Parser#consume} adds
/// symbols to the parse tree by calling
/// {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode(org.antlr.v4.runtime.Token)} instead of
/// {@link org.antlr.v4.runtime.ParserRuleContext#addChild(org.antlr.v4.runtime.Token)}.
/// {@link Parser#createErrorNode(ParserRuleContext, Token)} then
/// {@link ParserRuleContext#addErrorNode(ErrorNode)} instead of
/// {@link Parser#createTerminalNode(ParserRuleContext, Token)}.
///
/// - parameter recognizer: the parser instance
/// - returns: {@code true} if the parser is currently recovering from a parse

View File

@ -1,18 +1,15 @@
/* Copyright (c) 2012-2016 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.
*/
/** This is all the parsing support code essentially; most of it is error recovery stuff. */
//public abstract class Parser : Recognizer<Token, ParserATNSimulator> {
///
/// Copyright (c) 2012-2016 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
/// This is all the parsing support code essentially; most of it is error recovery stuff.
open class Parser: Recognizer<ParserATNSimulator> {
public static let EOF: Int = -1
public static var ConsoleError = true
//false
public class TraceListener: ParseTreeListener {
var host: Parser
@ -62,10 +59,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
public func exitEveryRule(_ ctx: ParserRuleContext) {
//TODO: check necessary
// if (ctx.children is ArrayList) {
// (ctx.children as ArrayList<?>).trimToSize();
// }
// TODO: Print exit info.
}
}
@ -75,10 +69,8 @@ open class Parser: Recognizer<ParserATNSimulator> {
*
* @see org.antlr.v4.runtime.atn.ATNDeserializationOptions#isGenerateRuleBypassTransitions()
*/
//private let bypassAltsAtnCache : Dictionary<String, ATN> =
// WeakHashMap<String, ATN>(); MapTable<NSString, ATN>
private let bypassAltsAtnCache: HashMap<String, ATN> = HashMap<String, ATN>()
/**
* The error handling strategy for the parser. The default value is a new
* instance of {@link org.antlr.v4.runtime.DefaultErrorStrategy}.
@ -86,7 +78,6 @@ open class Parser: Recognizer<ParserATNSimulator> {
* @see #getErrorHandler
* @see #setErrorHandler
*/
public var _errHandler: ANTLRErrorStrategy = DefaultErrorStrategy()
/**
@ -177,14 +168,15 @@ open class Parser: Recognizer<ParserATNSimulator> {
* strategy to attempt recovery. If {@link #getBuildParseTree} is
* {@code true} and the token index of the symbol returned by
* {@link org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
* the parse tree by calling {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode}.</p>
* the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.</p>
*
* @param ttype the token type to match
* @return the matched symbol
* @throws org.antlr.v4.runtime.RecognitionException if the current input symbol did not match
* {@code ttype} and the error strategy could not recover from the
* mismatched symbol
*///; RecognitionException
*/
@discardableResult
public func match(_ ttype: Int) throws -> Token {
var t: Token = try getCurrentToken()
@ -196,7 +188,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
if _buildParseTrees && t.getTokenIndex() == -1 {
// we must have conjured up a new token during single token insertion
// if it's not the current symbol
_ctx!.addErrorNode(t)
_ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t))
}
}
return t
@ -212,7 +204,8 @@ open class Parser: Recognizer<ParserATNSimulator> {
* strategy to attempt recovery. If {@link #getBuildParseTree} is
* {@code true} and the token index of the symbol returned by
* {@link org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
* the parse tree by calling {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode}.</p>
* the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.</p>
*
* @return the matched symbol
* @throws org.antlr.v4.runtime.RecognitionException if the current input symbol did not match
@ -230,7 +223,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
if _buildParseTrees && t.getTokenIndex() == -1 {
// we must have conjured up a new token during single token insertion
// if it's not the current symbol
_ctx!.addErrorNode(t)
_ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t))
}
}
@ -562,11 +555,11 @@ open class Parser: Recognizer<ParserATNSimulator> {
* </pre>
*
* If the parser is not in error recovery mode, the consumed symbol is added
* to the parse tree using {@link org.antlr.v4.runtime.ParserRuleContext#addChild(org.antlr.v4.runtime.Token)}, and
* to the parse tree using {@link ParserRuleContext#addChild(TerminalNode)}, and
* {@link org.antlr.v4.runtime.tree.ParseTreeListener#visitTerminal} is called on any parse listeners.
* If the parser <em>is</em> in error recovery mode, the consumed symbol is
* added to the parse tree using
* {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode(org.antlr.v4.runtime.Token)}, and
* added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then
* {@link ParserRuleContext#addErrorNode(ErrorNode)} and
* {@link org.antlr.v4.runtime.tree.ParseTreeListener#visitErrorNode} is called on any parse
* listeners.
*/
@ -583,14 +576,14 @@ open class Parser: Recognizer<ParserATNSimulator> {
if _buildParseTrees || hasListener {
if _errHandler.inErrorRecoveryMode(self) {
let node: ErrorNode = _ctx.addErrorNode(o)
let node: ErrorNode = _ctx.addErrorNode(createErrorNode(parent: _ctx, t: o))
if let _parseListeners = _parseListeners {
for listener: ParseTreeListener in _parseListeners {
listener.visitErrorNode(node)
}
}
} else {
let node: TerminalNode = _ctx.addChild(o)
let node: TerminalNode = _ctx.addChild(createTerminalNode(parent: _ctx, t: o))
if let _parseListeners = _parseListeners {
for listener: ParseTreeListener in _parseListeners {
listener.visitTerminal(node)
@ -600,6 +593,24 @@ open class Parser: Recognizer<ParserATNSimulator> {
}
return o
}
/** How to create a token leaf node associated with a parent.
* Typically, the terminal node to create is not a function of the parent.
*
* @since 4.6.1
*/
public func createTerminalNode(parent: ParserRuleContext, t: Token) -> TerminalNode {
return TerminalNodeImpl(t);
}
/** How to create an error node, given a token, associated with a parent.
* Typically, the error node to create is not a function of the parent.
*
* @since 4.6.1
*/
public func createErrorNode(parent: ParserRuleContext, t: Token) -> ErrorNode {
return ErrorNode(t);
}
internal func addContextToParseTree() {

View File

@ -72,6 +72,14 @@ open class ParserRuleContext: RuleContext {
/** COPY a ctx (I'm deliberately not using copy constructor) to avoid
* confusion with creating node with parent. Does not copy children.
*
* This is used in the generated parser code to flip a generic XContext
* node for rule X to a YContext for alt label Y. In that sense, it is
* not really a generic copy function.
*
* If we do an error sync() at start of a rule, we might add error nodes
* to the generic XContext so this function must copy those nodes to
* the YContext as well else they are lost!
*/
open func copyFrom(_ ctx: ParserRuleContext) {
self.parent = ctx.parent
@ -81,13 +89,12 @@ open class ParserRuleContext: RuleContext {
self.stop = ctx.stop
// copy any error nodes to alt label node
if ctx.children != nil{
if ctx.children != nil {
self.children = Array<ParseTree>()
// reset parent pointer for any error nodes
for child: ParseTree in ctx.children! {
if child is ErrorNode{
self.children?.append(child)
( (child as! ErrorNode)).parent = self
for child: ParseTree in ctx.children! {
if child is ErrorNode {
addChild(child as! ErrorNode)
}
}
}
@ -105,51 +112,90 @@ open class ParserRuleContext: RuleContext {
open func exitRule(_ listener: ParseTreeListener) {
}
/** Does not set parent link; other add methods do that */
/** Add a parse tree node to this as a child. Works for
* internal and leaf nodes. Does not set parent link;
* other add methods must do that. Other addChild methods
* call this.
*
* We cannot set the parent pointer of the incoming node
* because the existing interfaces do not have a setParent()
* method and I don't want to break backward compatibility for this.
*
* @since 4.6.1
*/
@discardableResult
open func addChild(_ t: TerminalNode) -> TerminalNode {
open func addAnyChild<T: ParseTree>(_ t: T) -> T {
if children == nil {
children = Array<ParseTree>()
children = [T]()
}
children!.append(t)
return t
}
@discardableResult
open func addChild(_ ruleInvocation: RuleContext) -> RuleContext {
if children == nil {
children = Array<ParseTree>()
}
children!.append(ruleInvocation)
return ruleInvocation
return addAnyChild(ruleInvocation)
}
/** Add a token leaf node child and force its parent to be this node. */
@discardableResult
open func addChild(_ t: TerminalNode) -> TerminalNode {
t.setParent(self)
return addAnyChild(t)
}
/** Add an error node child and force its parent to be this node.
*
* @since 4.6.1
*/
@discardableResult
open func addErrorNode(_ errorNode: ErrorNode) -> ErrorNode {
errorNode.setParent(self)
return addAnyChild(errorNode)
}
/** Add a child to this node based upon matchedToken. It
* creates a TerminalNodeImpl rather than using
* {@link Parser#createTerminalNode(ParserRuleContext, Token)}. I'm leaving this
* in for compatibility but the parser doesn't use this anymore.
*/
@available(*, deprecated)
open func addChild(_ matchedToken: Token) -> TerminalNode {
let t: TerminalNodeImpl = TerminalNodeImpl(matchedToken)
addAnyChild(t)
t.setParent(self)
return t
}
/** Add a child to this node based upon badToken. It
* creates a ErrorNodeImpl rather than using
* {@link Parser#createErrorNode(ParserRuleContext, Token)}. I'm leaving this
* in for compatibility but the parser doesn't use this anymore.
*/
@discardableResult
@available(*, deprecated)
open func addErrorNode(_ badToken: Token) -> ErrorNode {
let t: ErrorNode = ErrorNode(badToken)
addAnyChild(t)
t.setParent(self)
return t
}
// public void trace(int s) {
// if ( states==null ) states = new ArrayList<Integer>();
// states.add(s);
// }
/** Used by enterOuterAlt to toss out a RuleContext previously added as
* we entered a rule. If we have # label, we will need to remove
* generic ruleContext object.
*/
*/
open func removeLastChild() {
children?.removeLast()
//children.remove(children.size()-1);
}
// public void trace(int s) {
// if ( states==null ) states = new ArrayList<Integer>();
// states.add(s);
// }
open func addChild(_ matchedToken: Token) -> TerminalNode {
let t: TerminalNodeImpl = TerminalNodeImpl(matchedToken)
addChild(t)
t.parent = self
return t
}
@discardableResult
open func addErrorNode(_ badToken: Token) -> ErrorNode {
let t: ErrorNode = ErrorNode(badToken)
addChild(t)
t.parent = self
return t
if children != nil {
children!.remove(at: children!.count-1)
}
}
override
/** Override to make type more specific */

View File

@ -9,4 +9,18 @@ public class TerminalNode: ParseTree {
fatalError()
}
/** Set the parent for this leaf node.
*
* Technically, this is not backward compatible as it changes
* the interface but no one was able to create custom
* TerminalNodes anyway so I'm adding as it improves internal
* code quality.
*
* @since 4.6.1
*/
public func setParent(_ parent: RuleContext) {
RuntimeException(" must overriden !")
fatalError()
}
}

View File

@ -27,6 +27,11 @@ public class TerminalNodeImpl: TerminalNode {
return parent
}
override
public func setParent(_ parent: RuleContext) {
self.parent = parent
}
override
public func getPayload() -> AnyObject {
return symbol