1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeaudeclare(strict_types=1); 4*37748cd8SNickeau 5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime; 6*37748cd8SNickeau 7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\ATN; 8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ParseTree; 9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ParseTreeVisitor; 10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\RuleNode; 11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\Tree; 12*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\Trees; 13*37748cd8SNickeau 14*37748cd8SNickeau/** 15*37748cd8SNickeau * A rule context is a record of a single rule invocation. 16*37748cd8SNickeau * 17*37748cd8SNickeau * We form a stack of these context objects using the parent pointer. A parent 18*37748cd8SNickeau * pointer of null indicates that the current context is the bottom of the stack. 19*37748cd8SNickeau * The {@see ParserRuleContext} subclass as a children list so that we can turn 20*37748cd8SNickeau * this data structure into a tree. 21*37748cd8SNickeau * 22*37748cd8SNickeau * The root node always has a null pointer and invokingState of -1. 23*37748cd8SNickeau * 24*37748cd8SNickeau * Upon entry to parsing, the first invoked rule function creates a context object 25*37748cd8SNickeau * (a subclass specialized for that rule such as SContext) and makes it the root 26*37748cd8SNickeau * of a parse tree, recorded by field Parser->ctx. 27*37748cd8SNickeau * 28*37748cd8SNickeau * public final s(){ 29*37748cd8SNickeau * SContext _localctx = new SContext(_ctx, getState()); <-- create new node 30*37748cd8SNickeau * enterRule(_localctx, 0, RULE_s); <-- push it 31*37748cd8SNickeau * ... 32*37748cd8SNickeau * exitRule(); <-- pop back to _localctx 33*37748cd8SNickeau * return _localctx; 34*37748cd8SNickeau * } 35*37748cd8SNickeau * 36*37748cd8SNickeau * A subsequent rule invocation of r from the start rule s pushes a new 37*37748cd8SNickeau * context object for r whose parent points at s and use invoking state is 38*37748cd8SNickeau * the state with r emanating as edge label. 39*37748cd8SNickeau * 40*37748cd8SNickeau * The invokingState fields from a context object to the root together 41*37748cd8SNickeau * form a stack of rule indication states where the root (bottom of the stack) 42*37748cd8SNickeau * has a -1 sentinel value. If we invoke start symbol s then call r1, 43*37748cd8SNickeau * which calls r2, the would look like this: 44*37748cd8SNickeau * 45*37748cd8SNickeau * SContext[-1] <- root node (bottom of the stack) 46*37748cd8SNickeau * R1Context[p] <- p in rule s called r1 47*37748cd8SNickeau * R2Context[q] <- q in rule r1 called r2 48*37748cd8SNickeau * 49*37748cd8SNickeau * So the top of the stack, `_ctx`, represents a call to the current rule 50*37748cd8SNickeau * and it holds the return address from another rule that invoke to this rule. 51*37748cd8SNickeau * To invoke a rule, we must always have a current context. 52*37748cd8SNickeau * 53*37748cd8SNickeau * The parent contexts are useful for computing lookahead sets and getting 54*37748cd8SNickeau * error information. 55*37748cd8SNickeau * 56*37748cd8SNickeau * These objects are used during parsing and prediction. For the special case 57*37748cd8SNickeau * of parsers, we use the subclass {@see ParserRuleContext}. 58*37748cd8SNickeau */ 59*37748cd8SNickeauclass RuleContext implements RuleNode 60*37748cd8SNickeau{ 61*37748cd8SNickeau /** 62*37748cd8SNickeau * The context that invoked this rule. 63*37748cd8SNickeau * 64*37748cd8SNickeau * @var RuleContext|null 65*37748cd8SNickeau */ 66*37748cd8SNickeau public $parentCtx; 67*37748cd8SNickeau 68*37748cd8SNickeau /** 69*37748cd8SNickeau * What state invoked the rule associated with this context? 70*37748cd8SNickeau * The "return address" is the followState of invokingState. If parent 71*37748cd8SNickeau * is null, this should be -1 this context object represents the start rule. 72*37748cd8SNickeau * 73*37748cd8SNickeau * @var int 74*37748cd8SNickeau */ 75*37748cd8SNickeau public $invokingState = -1; 76*37748cd8SNickeau 77*37748cd8SNickeau public function __construct(?RuleContext $parent, ?int $invokingState = null) 78*37748cd8SNickeau { 79*37748cd8SNickeau $this->parentCtx = $parent; 80*37748cd8SNickeau $this->invokingState = $invokingState ?? -1; 81*37748cd8SNickeau } 82*37748cd8SNickeau 83*37748cd8SNickeau public static function emptyContext() : ParserRuleContext 84*37748cd8SNickeau { 85*37748cd8SNickeau static $empty; 86*37748cd8SNickeau 87*37748cd8SNickeau return $empty ?? ($empty = new ParserRuleContext(null)); 88*37748cd8SNickeau } 89*37748cd8SNickeau 90*37748cd8SNickeau public function depth() : int 91*37748cd8SNickeau { 92*37748cd8SNickeau $n = 0; 93*37748cd8SNickeau $p = $this; 94*37748cd8SNickeau 95*37748cd8SNickeau while ($p !== null) { 96*37748cd8SNickeau $p = $p->parentCtx; 97*37748cd8SNickeau $n++; 98*37748cd8SNickeau } 99*37748cd8SNickeau 100*37748cd8SNickeau return $n; 101*37748cd8SNickeau } 102*37748cd8SNickeau 103*37748cd8SNickeau /** 104*37748cd8SNickeau * A context is empty if there is no invoking state; meaning nobody call 105*37748cd8SNickeau * current context. 106*37748cd8SNickeau */ 107*37748cd8SNickeau public function isEmpty() : bool 108*37748cd8SNickeau { 109*37748cd8SNickeau return $this->invokingState === -1; 110*37748cd8SNickeau } 111*37748cd8SNickeau 112*37748cd8SNickeau public function getSourceInterval() : Interval 113*37748cd8SNickeau { 114*37748cd8SNickeau return Interval::invalid(); 115*37748cd8SNickeau } 116*37748cd8SNickeau 117*37748cd8SNickeau public function getRuleContext() : RuleContext 118*37748cd8SNickeau { 119*37748cd8SNickeau return $this; 120*37748cd8SNickeau } 121*37748cd8SNickeau 122*37748cd8SNickeau public function getPayload() : RuleContext 123*37748cd8SNickeau { 124*37748cd8SNickeau return $this; 125*37748cd8SNickeau } 126*37748cd8SNickeau 127*37748cd8SNickeau /** 128*37748cd8SNickeau * Return the combined text of all child nodes. This method only considers 129*37748cd8SNickeau * tokens which have been added to the parse tree. 130*37748cd8SNickeau * 131*37748cd8SNickeau * Since tokens on hidden channels (e.g. whitespace or comments) are not 132*37748cd8SNickeau * added to the parse trees, they will not appear in the output 133*37748cd8SNickeau * of this method. 134*37748cd8SNickeau */ 135*37748cd8SNickeau public function getText() : string 136*37748cd8SNickeau { 137*37748cd8SNickeau $text = ''; 138*37748cd8SNickeau 139*37748cd8SNickeau for ($i = 0, $count = $this->getChildCount(); $i < $count; $i++) { 140*37748cd8SNickeau $child = $this->getChild($i); 141*37748cd8SNickeau 142*37748cd8SNickeau if ($child !== null) { 143*37748cd8SNickeau $text .= $child->getText(); 144*37748cd8SNickeau } 145*37748cd8SNickeau } 146*37748cd8SNickeau 147*37748cd8SNickeau return $text; 148*37748cd8SNickeau } 149*37748cd8SNickeau 150*37748cd8SNickeau public function getRuleIndex() : int 151*37748cd8SNickeau { 152*37748cd8SNickeau return -1; 153*37748cd8SNickeau } 154*37748cd8SNickeau 155*37748cd8SNickeau /** 156*37748cd8SNickeau * For rule associated with this parse tree internal node, return the outer 157*37748cd8SNickeau * alternative number used to match the input. Default implementation 158*37748cd8SNickeau * does not compute nor store this alt num. Create a subclass of 159*37748cd8SNickeau * {@see ParserRuleContext} with backing field and set option 160*37748cd8SNickeau * `contextSuperClass` to set it. 161*37748cd8SNickeau */ 162*37748cd8SNickeau public function getAltNumber() : int 163*37748cd8SNickeau { 164*37748cd8SNickeau return ATN::INVALID_ALT_NUMBER; 165*37748cd8SNickeau } 166*37748cd8SNickeau 167*37748cd8SNickeau /** 168*37748cd8SNickeau * Set the outer alternative number for this context node. Default 169*37748cd8SNickeau * implementation does nothing to avoid backing field overhead for trees 170*37748cd8SNickeau * that don't need it. Create a subclass of {@see ParserRuleContext} with backing 171*37748cd8SNickeau * field and set option `contextSuperClass`. 172*37748cd8SNickeau */ 173*37748cd8SNickeau public function setAltNumber(int $altNumber) : void 174*37748cd8SNickeau { 175*37748cd8SNickeau } 176*37748cd8SNickeau 177*37748cd8SNickeau /** 178*37748cd8SNickeau * @return RuleContext|null 179*37748cd8SNickeau */ 180*37748cd8SNickeau public function getParent() : ?Tree 181*37748cd8SNickeau { 182*37748cd8SNickeau return $this->parentCtx; 183*37748cd8SNickeau } 184*37748cd8SNickeau 185*37748cd8SNickeau public function setParent(?RuleContext $ctx) : void 186*37748cd8SNickeau { 187*37748cd8SNickeau $this->parentCtx = $ctx; 188*37748cd8SNickeau } 189*37748cd8SNickeau 190*37748cd8SNickeau /** 191*37748cd8SNickeau * @return ParseTree|null 192*37748cd8SNickeau */ 193*37748cd8SNickeau public function getChild(int $i, ?string $type = null) : ?Tree 194*37748cd8SNickeau { 195*37748cd8SNickeau return null; 196*37748cd8SNickeau } 197*37748cd8SNickeau 198*37748cd8SNickeau public function getChildCount() : int 199*37748cd8SNickeau { 200*37748cd8SNickeau return 0; 201*37748cd8SNickeau } 202*37748cd8SNickeau 203*37748cd8SNickeau public function accept(ParseTreeVisitor $visitor) 204*37748cd8SNickeau { 205*37748cd8SNickeau return $visitor->visitChildren($this); 206*37748cd8SNickeau } 207*37748cd8SNickeau 208*37748cd8SNickeau /** 209*37748cd8SNickeau * Print out a whole tree, not just a node, in LISP format 210*37748cd8SNickeau * (root child1 .. childN). Print just a node if this is a leaf. 211*37748cd8SNickeau * 212*37748cd8SNickeau * @param array<string>|null $ruleNames 213*37748cd8SNickeau */ 214*37748cd8SNickeau public function toStringTree(?array $ruleNames = null) : string 215*37748cd8SNickeau { 216*37748cd8SNickeau return Trees::toStringTree($this, $ruleNames); 217*37748cd8SNickeau } 218*37748cd8SNickeau 219*37748cd8SNickeau public function __toString() : string 220*37748cd8SNickeau { 221*37748cd8SNickeau return $this->toString(); 222*37748cd8SNickeau } 223*37748cd8SNickeau 224*37748cd8SNickeau /** 225*37748cd8SNickeau * @param array<string>|null $ruleNames 226*37748cd8SNickeau */ 227*37748cd8SNickeau public function toString(?array $ruleNames = null, ?RuleContext $stop = null) : string 228*37748cd8SNickeau { 229*37748cd8SNickeau $p = $this; 230*37748cd8SNickeau $string = '['; 231*37748cd8SNickeau 232*37748cd8SNickeau while ($p !== null && $p !== $stop) { 233*37748cd8SNickeau if ($ruleNames === null) { 234*37748cd8SNickeau if (!$p->isEmpty()) { 235*37748cd8SNickeau $string .= $p->invokingState; 236*37748cd8SNickeau } 237*37748cd8SNickeau } else { 238*37748cd8SNickeau $ri = $p->getRuleIndex(); 239*37748cd8SNickeau $ruleName = $ri >= 0 && $ri < \count($ruleNames) ? $ruleNames[$ri] : (string) $ri; 240*37748cd8SNickeau $string .= $ruleName; 241*37748cd8SNickeau } 242*37748cd8SNickeau 243*37748cd8SNickeau if ($p->parentCtx !== null && ($ruleNames !== null || !$p->parentCtx->isEmpty())) { 244*37748cd8SNickeau $string .= ' '; 245*37748cd8SNickeau } 246*37748cd8SNickeau 247*37748cd8SNickeau $p = $p->parentCtx; 248*37748cd8SNickeau } 249*37748cd8SNickeau 250*37748cd8SNickeau return $string . ']'; 251*37748cd8SNickeau } 252*37748cd8SNickeau} 253