Add ability to set parse tree internal node super class with option contextSuperClass. Provide impl in Java target that has altNum backing field. Add test across targets to set/get alt num. Fixes #1152.

This commit is contained in:
parrt 2016-03-30 11:00:47 -07:00
parent 7d16438a19
commit 9e98714a1d
41 changed files with 587 additions and 63 deletions

View File

@ -327,6 +327,19 @@ ParseTreeWalker walker = new ParseTreeWalker();
walker.Walk(new LeafListener(), <s>);
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::members {
public class MyRuleNode : ParserRuleContext {
public int altNum;
public MyRuleNode(ParserRuleContext parent, int invokingStateNumber): base(parent, invokingStateNumber)
{
}
public override int getAltNumber() { return altNum; }
public override void setAltNumber(int altNum) { this.altNum = altNum; }
}
}
>>
TokenGetterListener(X) ::= <<
public class LeafListener : TBaseListener {
public override void ExitA(TParser.AContext ctx) {

View File

@ -335,6 +335,19 @@ ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new LeafListener(), <s>);
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::members {
public static class MyRuleNode extends ParserRuleContext {
public int altNum;
public MyRuleNode(ParserRuleContext parent, int invokingStateNumber) {
super(parent, invokingStateNumber);
}
@Override public int getAltNumber() { return altNum; }
@Override public void setAltNumber(int altNum) { this.altNum = altNum; }
}
}
>>
TokenGetterListener(X) ::= <<
public static class LeafListener extends TBaseListener {
public void exitA(TParser.AContext ctx) {

View File

@ -322,6 +322,20 @@ var walker = new antlr4.tree.ParseTreeWalker();
walker.walk(new this.LeafListener(), <s>);
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::header {
MyRuleNode = function(parent, invokingState) {
antlr4.ParserRuleContext.call(this, parent, invokingState);
this.altNum = 0;
return this;
};
MyRuleNode.prototype = Object.create(antlr4.ParserRuleContext.prototype);
MyRuleNode.prototype.constructor = MyRuleNode;
}
>>
TokenGetterListener(X) ::= <<
this.LeafListener = function() {
this.exitA = function(ctx) {

View File

@ -322,6 +322,20 @@ var walker = new antlr4.tree.ParseTreeWalker();
walker.walk(new this.LeafListener(), <s>);
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::header {
MyRuleNode = function(parent, invokingState) {
antlr4.ParserRuleContext.call(this, parent, invokingState);
this.altNum = 0;
return this;
};
MyRuleNode.prototype = Object.create(antlr4.ParserRuleContext.prototype);
MyRuleNode.prototype.constructor = MyRuleNode;
}
>>
TokenGetterListener(X) ::= <<
this.LeafListener = function() {
this.exitA = function(ctx) {

View File

@ -324,6 +324,20 @@ var walker = new antlr4.tree.ParseTreeWalker();
walker.walk(new this.LeafListener(), <s>);
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::header {
MyRuleNode = function(parent, invokingState) {
antlr4.ParserRuleContext.call(this, parent, invokingState);
this.altNum = 0;
return this;
};
MyRuleNode.prototype = Object.create(antlr4.ParserRuleContext.prototype);
MyRuleNode.prototype.constructor = MyRuleNode;
}
>>
TokenGetterListener(X) ::= <<
this.LeafListener = function() {
this.exitA = function(ctx) {

View File

@ -322,6 +322,24 @@ var walker = new antlr4.tree.ParseTreeWalker();
walker.walk(new this.LeafListener(), <s>);
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::header {
MyRuleNode = function(parent, invokingState) {
antlr4.ParserRuleContext.call(this, parent, invokingState);
this.altNum = 0;
return this;
};
MyRuleNode.prototype = Object.create(antlr4.ParserRuleContext.prototype);
MyRuleNode.prototype.constructor = MyRuleNode;
MyRuleNode.prototype.getAltNumber = function() { return this.altNum; }
MyRuleNode.prototype.setAltNumber = function(altNumber) { this.altNum = altNumber; }
}
>>
TokenGetterListener(X) ::= <<
this.LeafListener = function() {
this.exitA = function(ctx) {

View File

@ -322,6 +322,21 @@ var walker = new antlr4.tree.ParseTreeWalker();
walker.walk(new this.LeafListener(), <s>);
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::header {
MyRuleNode = function(parent, invokingState) {
antlr4.ParserRuleContext.call(this, parent, invokingState);
this.altNum = 0;
return this;
};
MyRuleNode.prototype = Object.create(antlr4.ParserRuleContext.prototype);
MyRuleNode.prototype.constructor = MyRuleNode;
}
>>
TokenGetterListener(X) ::= <<
this.LeafListener = function() {
this.exitA = function(ctx) {

View File

@ -312,6 +312,19 @@ walker = ParseTreeWalker()
walker.walk(TParser.LeafListener(), <s>)
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::members {
class MyRuleNode(ParserRuleContext):
def __init__(self, parent = None, invokingStateNumber = None ):
super(<X>Parser.MyRuleNode, self).__init__(parent, invokingStateNumber)
self.altNum = 0;
def getAltNumber(self):
return self.altNum
def setAltNumber(self, altNum):
self.altNum = altNum
}
>>
TokenGetterListener(X) ::= <<
if __name__ is not None and "." in __name__:
from .<X>Listener import <X>Listener

View File

@ -314,6 +314,19 @@ walker = ParseTreeWalker()
walker.walk(TParser.LeafListener(), <s>)
>>
TreeNodeWithAltNumField(X) ::= <<
@parser::members {
class MyRuleNode(ParserRuleContext):
def __init__(self, parent:ParserRuleContext = None, invokingStateNumber:int = None ):
super(<X>Parser.MyRuleNode, self).__init__(parent, invokingStateNumber)
self.altNum = 0;
def getAltNumber(self):
return self.altNum
def setAltNumber(self, altNum):
self.altNum = altNum
}
>>
TokenGetterListener(X) ::= <<
class LeafListener(MockListener):
def exitA(self, ctx):

View File

@ -0,0 +1,40 @@
TestType() ::= "Parser"
Grammar ::= [
"T": {<grammar("T")>}
]
Input() ::= "xyz"
Rule() ::= "s"
Output() ::= <<
(a:3 x (b:2 y) z)<\n>
>>
Errors() ::= ""
grammar(grammarName) ::= <<
grammar <grammarName>;
options { contextSuperClass=MyRuleNode; }
<TreeNodeWithAltNumField(X=grammarName)>
s
@init {
<BuildParseTrees()>
}
@after {
<ToStringTree("$r.ctx"):writeln()>
}
: r=a ;
a : 'f'
| 'g'
| 'x' b 'z'
;
b : 'e' {} | 'y'
;
>>

View File

@ -6,5 +6,6 @@ TestTemplates ::= [
"RuleRef": [],
"ExtraToken": [],
"NoViableAlt": [],
"Sync": []
"Sync": [],
"AltNum": []
]

View File

@ -2,7 +2,6 @@
package org.antlr.v4.test.runtime.csharp;
import org.junit.Test;
import org.junit.Ignore;
@SuppressWarnings("unused")
public class TestParseTrees extends BaseTest {
@ -52,6 +51,49 @@ public class TestParseTrees extends BaseTest {
assertEquals("(a y)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testAltNum() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(547);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("\n");
grammarBuilder.append("options { contextSuperClass=MyRuleNode; }\n");
grammarBuilder.append("\n");
grammarBuilder.append("@parser::members {\n");
grammarBuilder.append("public class MyRuleNode : ParserRuleContext {\n");
grammarBuilder.append(" public int altNum;\n");
grammarBuilder.append(" public MyRuleNode(ParserRuleContext parent, int invokingStateNumber): base(parent, invokingStateNumber)\n");
grammarBuilder.append(" {\n");
grammarBuilder.append(" }\n");
grammarBuilder.append(" public override int getAltNumber() { return altNum; }\n");
grammarBuilder.append(" public override void setAltNumber(int altNum) { this.altNum = altNum; }\n");
grammarBuilder.append("}\n");
grammarBuilder.append("}\n");
grammarBuilder.append("\n");
grammarBuilder.append("\n");
grammarBuilder.append("s\n");
grammarBuilder.append("@init {\n");
grammarBuilder.append("this.BuildParseTree = true;\n");
grammarBuilder.append("}\n");
grammarBuilder.append("@after {\n");
grammarBuilder.append("Console.WriteLine($r.ctx.ToStringTree(this));\n");
grammarBuilder.append("}\n");
grammarBuilder.append(" : r=a ;\n");
grammarBuilder.append("\n");
grammarBuilder.append("a : 'f'\n");
grammarBuilder.append(" | 'g'\n");
grammarBuilder.append(" | 'x' b 'z'\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("b : 'e' {} | 'y'\n");
grammarBuilder.append(" ;");
String grammar = grammarBuilder.toString();
String input ="xyz";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
assertEquals("(a:3 x (b:2 y) z)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test

View File

@ -1,10 +1,10 @@
/* This file is generated by TestGenerator, any edits will be overwritten by the next generation. */
package org.antlr.v4.test.runtime.java;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class TestParseTrees extends BaseTest {
@ -62,6 +62,53 @@ public class TestParseTrees extends BaseTest {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testAltNum() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(562);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("\n");
grammarBuilder.append("options { contextSuperClass=MyRuleNode; }\n");
grammarBuilder.append("\n");
grammarBuilder.append("@parser::members {\n");
grammarBuilder.append("public static class MyRuleNode extends ParserRuleContext {\n");
grammarBuilder.append(" public int altNum;\n");
grammarBuilder.append(" public MyRuleNode(ParserRuleContext parent, int invokingStateNumber) {\n");
grammarBuilder.append(" super(parent, invokingStateNumber);\n");
grammarBuilder.append(" }\n");
grammarBuilder.append(" @Override public int getAltNumber() { return altNum; }\n");
grammarBuilder.append(" @Override public void setAltNumber(int altNum) { this.altNum = altNum; }\n");
grammarBuilder.append("}\n");
grammarBuilder.append("}\n");
grammarBuilder.append("\n");
grammarBuilder.append("\n");
grammarBuilder.append("s\n");
grammarBuilder.append("@init {\n");
grammarBuilder.append("setBuildParseTree(true);\n");
grammarBuilder.append("}\n");
grammarBuilder.append("@after {\n");
grammarBuilder.append("System.out.println($r.ctx.toStringTree(this));\n");
grammarBuilder.append("}\n");
grammarBuilder.append(" : r=a ;\n");
grammarBuilder.append("\n");
grammarBuilder.append("a : 'f'\n");
grammarBuilder.append(" | 'g'\n");
grammarBuilder.append(" | 'x' b 'z'\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("b : 'e' {} | 'y'\n");
grammarBuilder.append(" ;");
String grammar = grammarBuilder.toString();
String input ="xyz";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
assertEquals("(a:3 x (b:2 y) z)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testExtraToken() throws Exception {

View File

@ -1,10 +1,10 @@
/* This file is generated by TestGenerator, any edits will be overwritten by the next generation. */
package org.antlr.v4.test.runtime.javascript.node;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@SuppressWarnings("unused")
public class TestParseTrees extends BaseTest {
@ -58,6 +58,55 @@ public class TestParseTrees extends BaseTest {
assertEquals("(a y)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testAltNum() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(663);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("\n");
grammarBuilder.append("options { contextSuperClass=MyRuleNode; }\n");
grammarBuilder.append("\n");
grammarBuilder.append("@parser::header {\n");
grammarBuilder.append("MyRuleNode = function(parent, invokingState) {\n");
grammarBuilder.append(" antlr4.ParserRuleContext.call(this, parent, invokingState);\n");
grammarBuilder.append("\n");
grammarBuilder.append(" this.altNum = 0;\n");
grammarBuilder.append(" return this;\n");
grammarBuilder.append("};\n");
grammarBuilder.append("\n");
grammarBuilder.append("MyRuleNode.prototype = Object.create(antlr4.ParserRuleContext.prototype);\n");
grammarBuilder.append("MyRuleNode.prototype.constructor = MyRuleNode;\n");
grammarBuilder.append("MyRuleNode.prototype.getAltNumber = function() { return this.altNum; }\n");
grammarBuilder.append("MyRuleNode.prototype.setAltNumber = function(altNumber) { this.altNum = altNumber; }\n");
grammarBuilder.append("\n");
grammarBuilder.append("}\n");
grammarBuilder.append("\n");
grammarBuilder.append("\n");
grammarBuilder.append("s\n");
grammarBuilder.append("@init {\n");
grammarBuilder.append("this.buildParseTrees = true;\n");
grammarBuilder.append("}\n");
grammarBuilder.append("@after {\n");
grammarBuilder.append("console.log($r.ctx.toStringTree(null, this));\n");
grammarBuilder.append("}\n");
grammarBuilder.append(" : r=a ;\n");
grammarBuilder.append("\n");
grammarBuilder.append("a : 'f'\n");
grammarBuilder.append(" | 'g'\n");
grammarBuilder.append(" | 'x' b 'z'\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("b : 'e' {} | 'y'\n");
grammarBuilder.append(" ;");
String grammar = grammarBuilder.toString();
String input ="xyz";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"TListener", "TVisitor",
"s", input, false);
assertEquals("(a:3 x (b:2 y) z)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test

View File

@ -1,9 +1,10 @@
/* This file is generated by TestGenerator, any edits will be overwritten by the next generation. */
package org.antlr.v4.test.runtime.python2;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@SuppressWarnings("unused")
public class TestParseTrees extends BasePython2Test {
@ -64,6 +65,54 @@ public class TestParseTrees extends BasePython2Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testAltNum() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(562);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("\n");
grammarBuilder.append("options { contextSuperClass=MyRuleNode; }\n");
grammarBuilder.append("\n");
grammarBuilder.append("@parser::members {\n");
grammarBuilder.append("class MyRuleNode(ParserRuleContext):\n");
grammarBuilder.append(" def __init__(self, parent = None, invokingStateNumber = None ):\n");
grammarBuilder.append(" super(TParser.MyRuleNode, self).__init__(parent, invokingStateNumber)\n");
grammarBuilder.append(" self.altNum = 0;\n");
grammarBuilder.append(" def getAltNumber(self):\n");
grammarBuilder.append(" return self.altNum\n");
grammarBuilder.append(" def setAltNumber(self, altNum):\n");
grammarBuilder.append(" self.altNum = altNum\n");
grammarBuilder.append("}\n");
grammarBuilder.append("\n");
grammarBuilder.append("\n");
grammarBuilder.append("s\n");
grammarBuilder.append("@init {\n");
grammarBuilder.append("self._buildParseTrees = True\n");
grammarBuilder.append("}\n");
grammarBuilder.append("@after {\n");
grammarBuilder.append("print($r.ctx.toStringTree(recog=self))\n");
grammarBuilder.append("}\n");
grammarBuilder.append(" : r=a ;\n");
grammarBuilder.append("\n");
grammarBuilder.append("a : 'f'\n");
grammarBuilder.append(" | 'g'\n");
grammarBuilder.append(" | 'x' b 'z'\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("b : 'e' {} | 'y'\n");
grammarBuilder.append(" ;");
String grammar = grammarBuilder.toString();
String input ="xyz";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "s", input, false);
assertEquals("(a:3 x (b:2 y) z)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testExtraToken() throws Exception {

View File

@ -41,7 +41,7 @@ public abstract class BasePython3Test extends BasePythonTest {
@Override
protected String getPythonExecutable() {
return "python3.5";
return "python3";
}
@Override

View File

@ -1,9 +1,10 @@
/* This file is generated by TestGenerator, any edits will be overwritten by the next generation. */
package org.antlr.v4.test.runtime.python3;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@SuppressWarnings("unused")
public class TestParseTrees extends BasePython3Test {
@ -64,6 +65,54 @@ public class TestParseTrees extends BasePython3Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testAltNum() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(584);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("\n");
grammarBuilder.append("options { contextSuperClass=MyRuleNode; }\n");
grammarBuilder.append("\n");
grammarBuilder.append("@parser::members {\n");
grammarBuilder.append("class MyRuleNode(ParserRuleContext):\n");
grammarBuilder.append(" def __init__(self, parent:ParserRuleContext = None, invokingStateNumber:int = None ):\n");
grammarBuilder.append(" super(TParser.MyRuleNode, self).__init__(parent, invokingStateNumber)\n");
grammarBuilder.append(" self.altNum = 0;\n");
grammarBuilder.append(" def getAltNumber(self):\n");
grammarBuilder.append(" return self.altNum\n");
grammarBuilder.append(" def setAltNumber(self, altNum):\n");
grammarBuilder.append(" self.altNum = altNum\n");
grammarBuilder.append("}\n");
grammarBuilder.append("\n");
grammarBuilder.append("\n");
grammarBuilder.append("s\n");
grammarBuilder.append("@init {\n");
grammarBuilder.append("self._buildParseTrees = True\n");
grammarBuilder.append("}\n");
grammarBuilder.append("@after {\n");
grammarBuilder.append("print($r.ctx.toStringTree(recog=self))\n");
grammarBuilder.append("}\n");
grammarBuilder.append(" : r=a ;\n");
grammarBuilder.append("\n");
grammarBuilder.append("a : 'f'\n");
grammarBuilder.append(" | 'g'\n");
grammarBuilder.append(" | 'x' b 'z'\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("b : 'e' {} | 'y'\n");
grammarBuilder.append(" ;");
String grammar = grammarBuilder.toString();
String input ="xyz";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "s", input, false);
assertEquals("(a:3 x (b:2 y) z)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testExtraToken() throws Exception {

View File

@ -352,7 +352,7 @@ namespace Antlr4.Runtime
/// for a newly constructed parser.
/// </remarks>
/// <returns>
///
///
/// <see langword="true"/>
/// if a complete parse tree will be constructed while
/// parsing, otherwise
@ -378,14 +378,14 @@ namespace Antlr4.Runtime
/// by default for a newly constructed parser.
/// </remarks>
/// <value>
///
///
/// <see langword="true"/>
/// to trim the capacity of the
/// <see cref="ParserRuleContext.children"/>
/// list to its size after a rule is parsed.
/// </value>
/// <returns>
///
///
/// <see langword="true"/>
/// if the
/// <see cref="ParserRuleContext.children"/>
@ -649,9 +649,9 @@ namespace Antlr4.Runtime
}
}
public override IIntStream InputStream
public override IIntStream InputStream
{
get
get
{
return _input;
}
@ -659,11 +659,11 @@ namespace Antlr4.Runtime
public ITokenStream TokenStream
{
get
get
{
return _input;
}
set
set
{
this._input = null;
Reset ();
@ -842,6 +842,7 @@ namespace Antlr4.Runtime
public virtual void EnterOuterAlt(ParserRuleContext localctx, int altNum)
{
localctx.setAltNumber(altNum);
// if we have new localctx, make sure we replace existing ctx
// that is previous child of parse tree
if (_buildParseTrees && _ctx != localctx)
@ -1004,7 +1005,7 @@ namespace Antlr4.Runtime
/// </summary>
/// <param name="symbol">the symbol type to check</param>
/// <returns>
///
///
/// <see langword="true"/>
/// if
/// <paramref name="symbol"/>

View File

@ -30,6 +30,7 @@
using System.Collections.Generic;
using System.Text;
using Antlr4.Runtime;
using Antlr4.Runtime.Atn;
using Antlr4.Runtime.Misc;
using Antlr4.Runtime.Sharpen;
using Antlr4.Runtime.Tree;
@ -139,7 +140,7 @@ namespace Antlr4.Runtime
{
return _parent;
}
set
set
{
_parent = value;
}
@ -216,6 +217,23 @@ namespace Antlr4.Runtime
}
}
/* For rule associated with this parse tree internal node, return
* the outer alternative number used to match the input. Default
* implementation does not compute nor store this alt num. Create
* a subclass of ParserRuleContext with backing field and set
* option contextSuperClass.
* to set it.
*/
public virtual int getAltNumber() { return Atn.ATN.InvalidAltNumber; }
/* Set the outer alternative number for this context node. Default
* implementation does nothing to avoid backing field overhead for
* trees that don't need it. Create
* a subclass of ParserRuleContext with backing field and set
* option contextSuperClass.
*/
public virtual void setAltNumber(int altNumber) { }
public virtual IParseTree GetChild(int i)
{
return null;

View File

@ -30,6 +30,7 @@
using System.Collections.Generic;
using System.Text;
using Antlr4.Runtime;
using Antlr4.Runtime.Atn;
using Antlr4.Runtime.Misc;
using Antlr4.Runtime.Sharpen;
using Antlr4.Runtime.Tree;
@ -111,10 +112,14 @@ namespace Antlr4.Runtime.Tree
{
if (ruleNames != null)
{
if (t is IRuleNode)
if (t is RuleContext)
{
int ruleIndex = ((IRuleNode)t).RuleContext.RuleIndex;
int ruleIndex = ((RuleContext)t).RuleIndex;
string ruleName = ruleNames[ruleIndex];
int altNumber = ((RuleContext)t).getAltNumber();
if ( altNumber!=Atn.ATN.InvalidAltNumber ) {
return ruleName+":"+altNumber;
}
return ruleName;
}
else

View File

@ -0,0 +1,20 @@
package org.antlr.v4.runtime;
/** A handy class for use with
*
* options {contextSuperClass=org.antlr.v4.runtime.RuleContextWithAltNum;}
*
* that provides a backing field / impl for the outer alternative number
* matched for an internal parse tree node.
*
* I'm only putting into Java runtime as I'm certain I'm the only one that
* will really every use this.
*/
public class RuleContextWithAltNum extends ParserRuleContext {
public int altNum;
public RuleContextWithAltNum(ParserRuleContext parent, int invokingStateNumber) {
super(parent, invokingStateNumber);
}
@Override public int getAltNumber() { return altNum; }
@Override public void setAltNumber(int altNum) { this.altNum = altNum; }
}

View File

@ -33,7 +33,9 @@ package org.antlr.v4.runtime.tree;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.misc.Predicate;
import org.antlr.v4.runtime.misc.Utils;
@ -91,9 +93,13 @@ public class Trees {
public static String getNodeText(Tree t, List<String> ruleNames) {
if ( ruleNames!=null ) {
if ( t instanceof RuleNode ) {
int ruleIndex = ((RuleNode)t).getRuleContext().getRuleIndex();
if ( t instanceof RuleContext ) {
int ruleIndex = ((RuleContext)t).getRuleContext().getRuleIndex();
String ruleName = ruleNames.get(ruleIndex);
int altNumber = ((RuleContext) t).getAltNumber();
if ( altNumber!=ATN.INVALID_ALT_NUMBER ) {
return ruleName+":"+altNumber;
}
return ruleName;
}
else if ( t instanceof ErrorNode) {

View File

@ -451,6 +451,7 @@ Parser.prototype.exitRule = function() {
};
Parser.prototype.enterOuterAlt = function(localctx, altNum) {
localctx.setAltNumber(altNum);
// if we have new localctx, make sure we replace existing ctx
// that is previous child of parse tree
if (this.buildParseTrees && this._ctx !== localctx) {

View File

@ -51,6 +51,7 @@
var RuleNode = require('./tree/Tree').RuleNode;
var INVALID_INTERVAL = require('./tree/Tree').INVALID_INTERVAL;
var INVALID_ALT_NUMBER = require('./atn/ATN').INVALID_ALT_NUMBER;
function RuleContext(parent, invokingState) {
RuleNode.call(this);
@ -113,6 +114,21 @@ RuleContext.prototype.getText = function() {
}
};
// For rule associated with this parse tree internal node, return
// the outer alternative number used to match the input. Default
// implementation does not compute nor store this alt num. Create
// a subclass of ParserRuleContext with backing field and set
// option contextSuperClass.
// to set it.
RuleContext.prototype.getAltNumber = function() { return INVALID_ALT_NUMBER; }
// Set the outer alternative number for this context node. Default
// implementation does nothing to avoid backing field overhead for
// trees that don't need it. Create
// a subclass of ParserRuleContext with backing field and set
// option contextSuperClass.
RuleContext.prototype.setAltNumber = function(altNumber) { }
RuleContext.prototype.getChild = function(i) {
return null;
};

View File

@ -34,6 +34,8 @@ var RuleNode = require('./Tree').RuleNode;
var ErrorNode = require('./Tree').ErrorNode;
var TerminalNode = require('./Tree').TerminalNode;
var ParserRuleContext = require('./../ParserRuleContext').ParserRuleContext;
var RuleContext = require('./../RuleContext').RuleContext;
var INVALID_ALT_NUMBER = require('./../atn/ATN').INVALID_ALT_NUMBER;
/** A set of utility routines useful for all kinds of ANTLR trees. */
@ -75,8 +77,12 @@ Trees.getNodeText = function(t, ruleNames, recog) {
ruleNames = recog.ruleNames;
}
if(ruleNames!==null) {
if (t instanceof RuleNode) {
return ruleNames[t.getRuleContext().ruleIndex];
if (t instanceof RuleContext) {
var altNumber = t.getAltNumber();
if ( altNumber!=INVALID_ALT_NUMBER ) {
return ruleNames[t.ruleIndex]+":"+altNumber;
}
return ruleNames[t.ruleIndex];
} else if ( t instanceof ErrorNode) {
return t.toString();
} else if(t instanceof TerminalNode) {
@ -115,7 +121,7 @@ Trees.getAncestors = function(t) {
}
return ancestors;
};
Trees.findAllTokenNodes = function(t, ttype) {
return Trees.findAllNodes(t, ttype, true);
};

View File

@ -2,12 +2,12 @@ from distutils.core import setup
setup(
name='antlr4-python2-runtime',
version='4.5.2.1',
version='4.5.3',
packages=['antlr4', 'antlr4.atn', 'antlr4.dfa', 'antlr4.tree', 'antlr4.error', 'antlr4.xpath'],
package_dir={'': 'src'},
url='http://www.antlr.org',
license='BSD',
author='Eric Vergnaud, Terence Parr, Sam Harwell',
author_email='eric.vergnaud@wanadoo.fr',
description='ANTLR 4.5.2.1 runtime for Python 2.7.6'
description='ANTLR 4.5.3 runtime for Python 2.7.6'
)

View File

@ -38,7 +38,7 @@ from antlr4.tree.ParseTreePatternMatcher import ParseTreePatternMatcher
from antlr4.tree.Tree import ParseTreeListener
class TraceListener(ParseTreeListener):
def __init__(self, parser):
self._parser = parser
@ -152,7 +152,7 @@ class Parser (Recognizer):
# @throws RecognitionException if the current input symbol did not match
# a wildcard and the error strategy could not recover from the mismatched
# symbol
def matchWildcard(self):
t = self.getCurrentToken()
if t.type > 0:
@ -382,6 +382,7 @@ class Parser (Recognizer):
self._ctx = self._ctx.parentCtx
def enterOuterAlt(self, localctx, altNum):
localctx.setAltNumber(altNum)
# if we have new localctx, make sure we replace existing ctx
# that is previous child of parse tree
if self.buildParseTrees and self._ctx != localctx:

View File

@ -52,6 +52,7 @@
from io import StringIO
from antlr4.tree.Tree import RuleNode, INVALID_INTERVAL
from antlr4.tree.Trees import Trees
from antlr4.atn.ATN import ATN
class RuleContext(RuleNode):
@ -109,6 +110,23 @@ class RuleContext(RuleNode):
def getRuleIndex(self):
return -1
# For rule associated with this parse tree internal node, return
# the outer alternative number used to match the input. Default
# implementation does not compute nor store this alt num. Create
# a subclass of ParserRuleContext with backing field and set
# option contextSuperClass.
# to set it.
def getAltNumber(self):
return ATN.INVALID_ALT_NUMBER
# Set the outer alternative number for this context node. Default
# implementation does nothing to avoid backing field overhead for
# trees that don't need it. Create
# a subclass of ParserRuleContext with backing field and set
# option contextSuperClass.
def setAltNumber(self, altNumber):
pass
def getChild(self, i):
return None

View File

@ -32,6 +32,8 @@
# A set of utility routines useful for all kinds of ANTLR trees.#
from io import StringIO
import antlr4
from antlr4.atn.ATN import ATN
from antlr4.Token import Token
from antlr4.Utils import escapeWhitespace
from antlr4.tree.Tree import RuleNode, ErrorNode, TerminalNode
@ -65,7 +67,9 @@ class Trees(object):
ruleNames = recog.ruleNames
if ruleNames is not None:
if isinstance(t, RuleNode):
return ruleNames[t.getRuleContext().getRuleIndex()]
if t.getAltNumber()!=ATN.INVALID_ALT_NUMBER:
return ruleNames[t.getRuleIndex()]+":"+str(t.getAltNumber())
return ruleNames[t.getRuleIndex()]
elif isinstance( t, ErrorNode):
return unicode(t)
elif isinstance(t, TerminalNode):

View File

@ -2,12 +2,12 @@ from distutils.core import setup
setup(
name='antlr4-python3-runtime',
version='4.5.2.1',
version='4.5.3',
packages=['antlr4', 'antlr4.atn', 'antlr4.dfa', 'antlr4.tree', 'antlr4.error', 'antlr4.xpath'],
package_dir={'': 'src'},
url='http://www.antlr.org',
license='BSD',
author='Eric Vergnaud, Terence Parr, Sam Harwell',
author_email='eric.vergnaud@wanadoo.fr',
description='ANTLR 4.5.2.1 runtime for Python 3.4.0'
description='ANTLR 4.5.3 runtime for Python 3.4.0'
)

View File

@ -159,7 +159,7 @@ class Parser (Recognizer):
# @throws RecognitionException if the current input symbol did not match
# a wildcard and the error strategy could not recover from the mismatched
# symbol
def matchWildcard(self):
t = self.getCurrentToken()
if t.type > 0:
@ -389,6 +389,7 @@ class Parser (Recognizer):
self._ctx = self._ctx.parentCtx
def enterOuterAlt(self, localctx:ParserRuleContext, altNum:int):
localctx.setAltNumber(altNum)
# if we have new localctx, make sure we replace existing ctx
# that is previous child of parse tree
if self.buildParseTrees and self._ctx != localctx:

View File

@ -113,6 +113,23 @@ class RuleContext(RuleNode):
def getRuleIndex(self):
return -1
# For rule associated with this parse tree internal node, return
# the outer alternative number used to match the input. Default
# implementation does not compute nor store this alt num. Create
# a subclass of ParserRuleContext with backing field and set
# option contextSuperClass.
# to set it.
def getAltNumber(self):
return 0 # should use ATN.INVALID_ALT_NUMBER but won't compile
# Set the outer alternative number for this context node. Default
# implementation does nothing to avoid backing field overhead for
# trees that don't need it. Create
# a subclass of ParserRuleContext with backing field and set
# option contextSuperClass.
def setAltNumber(self, altNumber:int):
pass
def getChild(self, i:int):
return None

View File

@ -68,7 +68,9 @@ class Trees(object):
ruleNames = recog.ruleNames
if ruleNames is not None:
if isinstance(t, RuleNode):
return ruleNames[t.getRuleContext().getRuleIndex()]
if t.getAltNumber()!=0: # should use ATN.INVALID_ALT_NUMBER but won't compile
return ruleNames[t.getRuleIndex()]+":"+str(t.getAltNumber())
return ruleNames[t.getRuleIndex()]
elif isinstance( t, ErrorNode):
return str(t)
elif isinstance(t, TerminalNode):

View File

@ -1,10 +1,9 @@
package org.antlr.v4.test.tool;
import org.antlr.v4.gui.TreeTextProvider;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.Tree;
import org.antlr.v4.runtime.tree.Trees;
import org.antlr.v4.gui.TreeTextProvider;
import org.antlr.v4.tool.GrammarInterpreterRuleContext;
import java.util.Arrays;
import java.util.List;
@ -17,10 +16,6 @@ public class InterpreterTreeTextProvider implements TreeTextProvider {
public String getText(Tree node) {
if ( node==null ) return "null";
String nodeText = Trees.getNodeText(node, ruleNames);
if ( node instanceof GrammarInterpreterRuleContext) {
GrammarInterpreterRuleContext ctx = (GrammarInterpreterRuleContext) node;
return nodeText+":"+ctx.getOuterAltNum();
}
if ( node instanceof ErrorNode) {
return "<error "+nodeText+">";
}

View File

@ -30,7 +30,7 @@
// args must be <object-model-object>, <fields-resulting-in-STs>
ParserFile(file, parser, namedActions) ::= <<
ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
<if(file.genPackage)>
namespace <file.genPackage> {
@ -839,7 +839,7 @@ CaptureNextTokenType(d) ::= "<d.varName> = TokenStream.La(1);"
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers,
superClass={ParserRuleContext}) ::= <<
public partial class <struct.name> : <superClass><if(interfaces)>, <interfaces; separator=", "><endif> {
public partial class <struct.name> : <if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif><if(interfaces)>, <interfaces; separator=", "><endif> {
<attrs:{a | public <a>;}; separator="\n">
<getters:{g | <g>}; separator="\n">
<if(ctorAttrs)>public <struct.name>(ParserRuleContext parent, int invokingState) : base(parent, invokingState) { }<endif>

View File

@ -42,7 +42,7 @@ javaTypeInitMap ::= [
// args must be <object-model-object>, <fields-resulting-in-STs>
ParserFile(file, parser, namedActions) ::= <<
ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
<if(file.genPackage)>
package <file.genPackage>;
@ -765,8 +765,9 @@ ListLabelName(label) ::= "<label>"
CaptureNextToken(d) ::= "<d.varName> = _input.LT(1);"
CaptureNextTokenType(d) ::= "<d.varName> = _input.LA(1);"
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= <<
public static class <struct.name> extends ParserRuleContext <if(interfaces)> implements <interfaces; separator=", "><endif> {
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers)
::= <<
public static class <struct.name> extends <if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif><if(interfaces)> implements <interfaces; separator=", "><endif> {
<attrs:{a | public <a>;}; separator="\n">
<getters:{g | <g>}; separator="\n">
<if(ctorAttrs)>public <struct.name>(ParserRuleContext parent, int invokingState) { super(parent, invokingState); }<endif>

View File

@ -46,7 +46,7 @@ pythonTypeInitMap ::= [
// args must be <object-model-object>, <fields-resulting-in-STs>
ParserFile(file, parser, namedActions) ::= <<
ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
var antlr4 = require('antlr4/index');
<if(file.genListener)>
@ -671,8 +671,7 @@ ListLabelName(label) ::= "<label>"
CaptureNextToken(d) ::= "<d.varName> = self._input.LT(1)"
CaptureNextTokenType(d) ::= "<d.varName> = this._input.LA(1);"
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers,
superClass={antlr4.ParserRuleContext}) ::= <<
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= <<
function <struct.name>(parser, parent, invokingState<struct.ctorAttrs:{a | , <a.name>}>) {
if(parent===undefined) {
parent = null;
@ -680,7 +679,7 @@ function <struct.name>(parser, parent, invokingState<struct.ctorAttrs:{a | , <a.
if(invokingState===undefined || invokingState===null) {
invokingState = -1;
}
<superClass>.call(this, parent, invokingState);
<if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif>.call(this, parent, invokingState);
this.parser = parser;
this.ruleIndex = <parser.name>.RULE_<struct.derivedFromName>;
<attrs:{a | <a>}; separator="\n">
@ -688,14 +687,14 @@ function <struct.name>(parser, parent, invokingState<struct.ctorAttrs:{a | , <a.
return this;
}
<struct.name>.prototype = Object.create(<superClass>.prototype);
<struct.name>.prototype = Object.create(<if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif>.prototype);
<struct.name>.prototype.constructor = <struct.name>;
<getters:{g | <struct.name>.prototype.<g>}; separator="\n\n">
<if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !>
<struct.name>.prototype.copyFrom = function(ctx) {
<superClass>.prototype.copyFrom.call(this, ctx);
<if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif>.prototype.copyFrom.call(this, ctx);
<struct.attrs:{a | this.<a.name> = ctx.<a.name>;}; separator="\n">
};
<endif>

View File

@ -46,7 +46,7 @@ pythonTypeInitMap ::= [
// args must be <object-model-object>, <fields-resulting-in-STs>
ParserFile(file, parser, namedActions) ::= <<
ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
# encoding: utf-8
from __future__ import print_function
@ -630,9 +630,8 @@ ListLabelName(label) ::= "<label>"
CaptureNextToken(d) ::= "<d.varName> = self._input.LT(1)"
CaptureNextTokenType(d) ::= "<d.varName> = self._input.LA(1)"
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers,
superClass={ParserRuleContext}) ::= <<
class <struct.name>(<superClass>):
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= <<
class <struct.name>(<if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif>):
def __init__(self, parser, parent=None, invokingState=-1<struct.ctorAttrs:{a | , <a.name>=None}>):
super(<parser.name>.<struct.name>, self).__init__(parent, invokingState)

View File

@ -46,7 +46,7 @@ pythonTypeInitMap ::= [
// args must be <object-model-object>, <fields-resulting-in-STs>
ParserFile(file, parser, namedActions) ::= <<
ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
# encoding: utf-8
from antlr4 import *
@ -638,9 +638,8 @@ ListLabelName(label) ::= "<label>"
CaptureNextToken(d) ::= "<d.varName> = self._input.LT(1)"
CaptureNextTokenType(d) ::= "<d.varName> = self._input.LA(1)"
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers,
superClass={ParserRuleContext}) ::= <<
class <struct.name>(<superClass>):
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= <<
class <struct.name>(<if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif>):
def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1<struct.ctorAttrs:{a | , <a.name><if(a.type)>:<a.type><endif>=None}>):
super().__init__(parent, invokingState)

View File

@ -63,8 +63,8 @@ public class ParserFile extends OutputFile {
genVisitor = g.tool.gen_visitor;
grammarName = g.name;
if (g.getOptionString("superClass") != null) {
contextSuperClass = new ActionText(null, g.getOptionString("superClass"));
if (g.getOptionString("contextSuperClass") != null) {
contextSuperClass = new ActionText(null, g.getOptionString("contextSuperClass"));
}
}
}

View File

@ -54,4 +54,15 @@ public class GrammarInterpreterRuleContext extends InterpreterRuleContext {
public void setOuterAltNum(int outerAltNum) {
this.outerAltNum = outerAltNum;
}
@Override
public int getAltNumber() {
// override here and called old functionality; makes it backward compatible vs changing names
return getOuterAltNum();
}
@Override
public void setAltNumber(int altNumber) {
setOuterAltNum(altNumber);
}
}