diff --git a/src/main/java/org/antlr/v4/runtime/RuleContext.java b/src/main/java/org/antlr/v4/runtime/RuleContext.java index 903e5c6..26f41ec 100644 --- a/src/main/java/org/antlr/v4/runtime/RuleContext.java +++ b/src/main/java/org/antlr/v4/runtime/RuleContext.java @@ -30,7 +30,7 @@ * current context is the bottom of the stack. The ParserRuleContext subclass as a children list so that we can turn * this data structure into a tree. *

- * The root node always has a null pointer and invokingState of -1. + * The root node of an actual parse tree always has a null parent pointer and invokingState of -1. *

* Upon entry to parsing, the first invoked rule function creates a context object (a subclass specialized for that rule * such as SContext) and makes it the root of a parse tree, recorded by field Parser._ctx. @@ -67,11 +67,9 @@ public class RuleContext implements RuleNode { public @Nullable RuleContext parent; /** - * What state invoked the rule associated with this context? The "return address" is the followState of invokingState - * If parent is null, this should be -1 this context object represents the start rule. + * What state invoked the rule associated with this context? The "return address" is the followState of invokingState. + * For the root node of an actual parse tree, where parent is null, this should be -1. */ - // todo на самом деле все не совсем так, есть варианты, когда - // todo parent == null, а стейт отличен от -1 public int invokingState = -1; public RuleContext(@Nullable RuleContext parent, int invokingState) { diff --git a/src/test/java/org/antlr/v4/runtime/tree/TreesTest.java b/src/test/java/org/antlr/v4/runtime/tree/TreesTest.java index 435981a..ef31ebf 100644 --- a/src/test/java/org/antlr/v4/runtime/tree/TreesTest.java +++ b/src/test/java/org/antlr/v4/runtime/tree/TreesTest.java @@ -52,7 +52,7 @@ void setUp() { terminal1 = new TerminalNodeImpl(token1); terminal2 = new TerminalNodeImpl(token2); - root = new TestParserRuleContext(null, 0, 0); + root = new TestParserRuleContext(null, -1, 0); child1 = new TestParserRuleContext(root, -1, 1); child2 = new TestParserRuleContext(root, -1, 1); grandChild = new TestParserRuleContext(child1, -1, 2); @@ -167,7 +167,7 @@ void testGetTokensFromParseTree() { @Test void testGetTokensFromParseTreeEmpty() { - ParserRuleContext emptyContext = new TestParserRuleContext(null, 0, 0); + ParserRuleContext emptyContext = new TestParserRuleContext(null, -1, 0); List tokens = Trees.getTokensFromParseTree(emptyContext); assertThat(tokens).isEmpty(); } diff --git a/src/test/java/org/antlr/v4/test/tool/ExpectedTokensTest.java b/src/test/java/org/antlr/v4/test/tool/ExpectedTokensTest.java index 1257796..ad4ed49 100644 --- a/src/test/java/org/antlr/v4/test/tool/ExpectedTokensTest.java +++ b/src/test/java/org/antlr/v4/test/tool/ExpectedTokensTest.java @@ -160,14 +160,15 @@ void testFollowIncludedInLeftRecursiveRule() throws Exception { ATN atn = g.getATN(); // Simulate call stack after input '(x' from rule s - ParserRuleContext callStackFrom_s = new ParserRuleContext(null, 4); + ParserRuleContext root = ParserRuleContext.emptyContext(); + ParserRuleContext callStackFrom_s = new ParserRuleContext(root, 4); ParserRuleContext callStackFrom_expr = new ParserRuleContext(callStackFrom_s, 9); int afterID = 14; IntervalSet tokens = atn.getExpectedTokens(afterID, callStackFrom_expr); assertThat(tokens.toString(g.getVocabulary())).isEqualTo("{R, PLUS}"); // Simulate call stack after input '(x' from within rule expr - callStackFrom_expr = new ParserRuleContext(null, 9); + callStackFrom_expr = new ParserRuleContext(ParserRuleContext.emptyContext(), 9); tokens = atn.getExpectedTokens(afterID, callStackFrom_expr); assertThat(tokens.toString(g.getVocabulary())).isEqualTo("{R, PLUS}"); }