1<?php 2 3declare(strict_types=1); 4 5namespace Antlr\Antlr4\Runtime\Atn\SemanticContexts; 6 7use Antlr\Antlr4\Runtime\Comparison\Hashable; 8use Antlr\Antlr4\Runtime\Recognizer; 9use Antlr\Antlr4\Runtime\RuleContext; 10use Antlr\Antlr4\Runtime\Utils\Set; 11 12/** 13 * A tree structure used to record the semantic context in which 14 * an ATN configuration is valid. It's either a single predicate, 15 * a conjunction `p1&&p2`, or a sum of products `p1 || p2`. 16 * 17 * I have scoped the {@see AndOperator}, {@see OrOperator}, and 18 * {@see PrecedencePredicate} subclasses of {@see SemanticContext} within 19 * the scope of this outer class. 20 */ 21abstract class SemanticContext implements Hashable 22{ 23 /** 24 * The default {@see SemanticContext}, which is semantically equivalent to 25 * a predicate of the form `{true}?`. 26 */ 27 public static function none() : Predicate 28 { 29 static $none; 30 31 return $none = $none ?? new Predicate(); 32 } 33 34 public static function andContext(?self $a, ?self $b) : ?self 35 { 36 if ($a === null || $a === self::none()) { 37 return $b; 38 } 39 40 if ($b === null || $b === self::none()) { 41 return $a; 42 } 43 44 $result = new AndOperator($a, $b); 45 46 return \count($result->operands) === 1 ? $result->operands[0] : $result; 47 } 48 49 public static function orContext(?self $a, ?self $b) : ?self 50 { 51 if ($a === null) { 52 return $b; 53 } 54 55 if ($b === null) { 56 return $a; 57 } 58 59 if ($a === self::none() || $b === self::none()) { 60 return self::none(); 61 } 62 63 $result = new OrOperator($a, $b); 64 65 return \count($result->operand) === 1 ? $result->operand[0] : $result; 66 } 67 68 /** 69 * For context independent predicates, we evaluate them without a local 70 * context (i.e., null context). That way, we can evaluate them without 71 * having to create proper rule-specific context during prediction (as 72 * opposed to the parser, which creates them naturally). In a practical 73 * sense, this avoids a cast exception from RuleContext to myruleContext. 74 * 75 * For context dependent predicates, we must pass in a local context so that 76 * references such as $arg evaluate properly as _localctx.arg. We only 77 * capture context dependent predicates in the context in which we begin 78 * prediction, so we passed in the outer context here in case of context 79 * dependent predicate evaluation. 80 */ 81 abstract public function eval(Recognizer $parser, RuleContext $parserCallStack); 82 83 /** 84 * Evaluate the precedence predicates for the context and reduce the result. 85 * 86 * @param Recognizer $parser The parser instance. 87 * 88 * @return self|null The simplified semantic context after precedence predicates 89 * are evaluated, which will be one of the following values. 90 * 91 * - {@see self::NONE()}: if the predicate simplifies to 92 * `true` after precedence predicates are evaluated. 93 * - `null`: if the predicate simplifies to `false` after 94 * precedence predicates are evaluated. 95 * - `this`: if the semantic context is not changed 96 * as a result of precedence predicate evaluation. 97 * - A non-`null` {@see SemanticContext}: if the new simplified 98 * semantic context after precedence predicates are evaluated. 99 */ 100 public function evalPrecedence(Recognizer $parser, RuleContext $parserCallStack) : ?self 101 { 102 return $this; 103 } 104 105 /** 106 * @return array<PrecedencePredicate> 107 */ 108 public static function filterPrecedencePredicates(Set $set) : array 109 { 110 $result = []; 111 foreach ($set->getValues() as $context) { 112 if ($context instanceof PrecedencePredicate) { 113 $result[] = $context; 114 } 115 } 116 117 return $result; 118 } 119 120 abstract public function __toString() : string; 121} 122