File: AFPTreeNode.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (153 lines) | stat: -rw-r--r-- 5,462 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?php

namespace MediaWiki\Extension\AbuseFilter\Parser;

use MediaWiki\Extension\AbuseFilter\Parser\Exception\InternalException;

/**
 * Represents a node of a parser tree.
 */
class AFPTreeNode {
	// Each of the constants below represents a node corresponding to a level
	// of the parser, from the top of the tree to the bottom.

	// ENTRY is always one-element and thus does not have its own node.

	// SEMICOLON is a many-children node, denoting that the nodes have to be
	// evaluated in order and the last value has to be returned.
	public const SEMICOLON = 'SEMICOLON';

	// ASSIGNMENT (formerly known as SET) is a node which is responsible for
	// assigning values to variables.  ASSIGNMENT is a (variable name [string],
	// value [tree node]) tuple, INDEX_ASSIGNMENT (which is used to assign
	// values at array offsets) is a (variable name [string], index [tree node],
	// value [tree node]) tuple, and ARRAY_APPEND has the form of (variable name
	// [string], value [tree node]).
	public const ASSIGNMENT = 'ASSIGNMENT';
	public const INDEX_ASSIGNMENT = 'INDEX_ASSIGNMENT';
	public const ARRAY_APPEND = 'ARRAY_APPEND';

	// CONDITIONAL represents both a ternary operator and an if-then-else-end
	// construct.  The format is (condition, evaluated-if-true, evaluated-in-false).
	// The first two are tree nodes, the last one can be a node, or null if there's no else.
	public const CONDITIONAL = 'CONDITIONAL';

	// LOGIC is a logic operator accepted by AFPData::boolOp.  The format is
	// (operation, left operand, right operand).
	public const LOGIC = 'LOGIC';

	// COMPARE is a comparison operator accepted by AFPData::boolOp.  The format is
	// (operation, left operand, right operand).
	public const COMPARE = 'COMPARE';

	// SUM_REL is either '+' or '-'.  The format is (operation, left operand,
	// right operand).
	public const SUM_REL = 'SUM_REL';

	// MUL_REL is a multiplication-related operation accepted by AFPData::mulRel.
	// The format is (operation, left operand, right operand).
	public const MUL_REL = 'MUL_REL';

	// POW is an exponentiation operator.  The format is (base, exponent).
	public const POW = 'POW';

	// BOOL_INVERT is a boolean inversion operator.  The format is (operand).
	public const BOOL_INVERT = 'BOOL_INVERT';

	// KEYWORD_OPERATOR is one of the binary keyword operators supported by the
	// filter language.  The format is (keyword, left operand, right operand).
	public const KEYWORD_OPERATOR = 'KEYWORD_OPERATOR';

	// UNARY is either unary minus or unary plus.  The format is (operator, operand).
	public const UNARY = 'UNARY';

	// ARRAY_INDEX is an operation of accessing an array by an offset.  The format
	// is (array, offset).
	public const ARRAY_INDEX = 'ARRAY_INDEX';

	// Since parenthesis only manipulate precedence of the operators, they are
	// not explicitly represented in the tree.

	// FUNCTION_CALL is an invocation of built-in function.  The format is a
	// tuple where the first element is a function name, and all subsequent
	// elements are the arguments.
	public const FUNCTION_CALL = 'FUNCTION_CALL';

	// ARRAY_DEFINITION is an array literal.  The $children field contains tree
	// nodes for the values of each of the array element used.
	public const ARRAY_DEFINITION = 'ARRAY_DEFINITION';

	// ATOM is a node representing a literal.  The only element of $children is a
	// token corresponding to the literal.
	public const ATOM = 'ATOM';

	// BINOP is a combination of LOGIC (^), COMPARE (<=, <, etc.),
	// SUM_REL (+, -), MUL_REL (*, /, %), POW (**),
	// KEYWORD_OPERATOR (like, rlike, etc.), and ARRAY_INDEX ([]).
	// The format is (operator, operand, operand).
	// Currently, it's only used in SyntaxChecker
	// & and | which is in LOGIC is not in BINOP because it affects
	// control flow.
	public const BINOP = 'BINOP';

	/** @var string Type of the node, one of the constants above */
	public $type;
	/**
	 * Parameters of the value. Typically it is an array of children nodes,
	 * which might be either strings (for parametrization of the node) or another
	 * node. In case of ATOM it's a parser token.
	 * @var AFPTreeNode[]|string[]|AFPToken
	 */
	public $children;

	/** @var int Position used for error reporting. */
	public $position;

	/**
	 * @param string $type
	 * @param (AFPTreeNode|null)[]|string[]|AFPToken $children
	 * @param int $position
	 */
	public function __construct( $type, $children, $position ) {
		$this->type = $type;
		$this->children = $children;
		$this->position = $position;
	}

	/**
	 * @return string
	 * @codeCoverageIgnore
	 */
	public function toDebugString() {
		return implode( "\n", $this->toDebugStringInner() );
	}

	/**
	 * @return array
	 * @codeCoverageIgnore
	 */
	private function toDebugStringInner() {
		if ( $this->type === self::ATOM ) {
			return [ "ATOM({$this->children->type} {$this->children->value})" ];
		}

		$align = static function ( $line ) {
			return '  ' . $line;
		};

		$lines = [ $this->type ];
		// @phan-suppress-next-line PhanTypeSuspiciousNonTraversableForeach children is array here
		foreach ( $this->children as $subnode ) {
			if ( $subnode instanceof AFPTreeNode ) {
				$sublines = array_map( $align, $subnode->toDebugStringInner() );
			} elseif ( is_string( $subnode ) ) {
				$sublines = [ "  {$subnode}" ];
			} else {
				throw new InternalException( "Each node parameter has to be either a node or a string" );
			}

			$lines = array_merge( $lines, $sublines );
		}
		return $lines;
	}
}