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