@@ -50,7 +50,9 @@ CallableParameter
50
50
: MaybeDefaultCallableParameter()
51
51
;
52
52
53
- // Parses "<param>" or "<param> =" expression
53
+ // Expects expression:
54
+ // - "<param>"
55
+ // - "<param> ="
54
56
MaybeDefaultCallableParameter -> {
55
57
if (\count($children) === 1) {
56
58
return $children[0];
@@ -63,62 +65,133 @@ MaybeDefaultCallableParameter -> {
63
65
$children[0]->optional = true;
64
66
return $children[0];
65
67
}
66
- : MaybeNamedCallableParameter() <T_ASSIGN>?
68
+ : ( MaybePrefixedVariadicTypedNamedCallableParameter()
69
+ | MaybeModifiersNamedCallableParameter() )
70
+ <T_ASSIGN>?
67
71
;
68
72
69
- // Parses "$variable" or "<param> $variable", or "<param>" expression
70
- MaybeNamedCallableParameter -> {
71
- if ($children instanceof Node\Stmt\Callable\CallableParameterNode) {
73
+ // Expects expression:
74
+ // - "&...<var_param>"
75
+ // - "...&<var_param>"
76
+ // - "...<var_param>"
77
+ // - "&<var_param>"
78
+ // - "<var_param>"
79
+ MaybeModifiersNamedCallableParameter -> {
80
+ if (!\is_array($children)) {
72
81
return $children;
73
82
}
74
83
75
- if (\count($children) === 1) {
76
- return $children[0];
84
+ $result = \end($children);
85
+
86
+ foreach ($children as $modifier) {
87
+ if ($modifier instanceof \Phplrt\Contracts\Lexer\TokenInterface) {
88
+ switch ($modifier->getName()) {
89
+ case 'T_AMP':
90
+ $result->output = true;
91
+ break;
92
+ case 'T_ELLIPSIS':
93
+ if ($result->variadic) {
94
+ throw SemanticException::fromVariadicRedefinition($offset);
95
+ }
96
+ $result->variadic = true;
97
+ break;
98
+ }
99
+ }
77
100
}
78
101
79
- $children[0]->name = $children[1];
80
- return $children[0];
102
+ return $result;
81
103
}
82
- : MaybeVariableCallableParameter()
83
- | MaybeVariadicCallableParameter() VariableLiteral()?
104
+ : <T_AMP> <T_ELLIPSIS> MaybeSuffixedVariadicNamedCallableParameter()
105
+ | <T_ELLIPSIS> <T_AMP> MaybeSuffixedVariadicNamedCallableParameter()
106
+ | <T_ELLIPSIS> MaybeSuffixedVariadicNamedCallableParameter()
107
+ | <T_AMP> MaybeSuffixedVariadicNamedCallableParameter()
108
+ | MaybeSuffixedVariadicNamedCallableParameter()
84
109
;
85
110
86
- // Parses "$variable" expression
87
- MaybeVariableCallableParameter -> {
88
- return new Node\Stmt\Callable\CallableParameterNode(null, $children[0]);
111
+ // Expects expression:
112
+ // - "$<var>..."
113
+ // - "$<var>"
114
+ MaybeSuffixedVariadicNamedCallableParameter -> {
115
+ $result = new Node\Stmt\Callable\CallableParameterNode(null, $children[0]);
116
+
117
+ if (\count($children) !== 1) {
118
+ $result->variadic = true;
119
+ }
120
+
121
+ return $result;
89
122
}
90
123
: VariableLiteral()
124
+ <T_ELLIPSIS>?
91
125
;
92
126
93
- // Parses "...<param>" or "<param>...", or "<param>" expression
94
- MaybeVariadicCallableParameter -> {
95
- if (count($children) === 1) {
127
+ MaybePrefixedVariadicTypedNamedCallableParameter -> {
128
+ if (\count($children) === 1) {
96
129
return $children[0];
97
130
}
98
131
99
- if ($children[0] instanceof Node\Stmt\Callable\ParameterNode) {
100
- $children[0]->variadic = true;
101
- return $children[0];
132
+ if ($children[1]->variadic) {
133
+ throw SemanticException::fromVariadicRedefinition($offset);
102
134
}
103
135
104
136
$children[1]->variadic = true;
105
137
return $children[1];
106
138
}
107
- : <T_ELLIPSIS> MaybeOutputCallableParameter() // Prefixed variadic argument (Psalm format)
108
- | MaybeOutputCallableParameter() <T_ELLIPSIS>? // Suffixed variadic argument (PhpStan + Psalm)
139
+ : <T_ELLIPSIS>? MaybeTypedNamedCallableParameter()
109
140
;
110
141
111
- // Parses "<param>&" or "<param>" expression
112
- MaybeOutputCallableParameter -> {
113
- $argument = new Node\Stmt\Callable\CallableParameterNode($children[0]);
142
+ // Expects expression:
143
+ // - "<typed_param> $<var>"
144
+ // - "<typed_param>"
145
+ MaybeTypedNamedCallableParameter -> {
146
+ if (\count($children) === 1) {
147
+ return $children[0];
148
+ }
114
149
115
- if (\count($children) !== 1) {
116
- $argument->output = true;
150
+ $children[0]->name = $children[1];
151
+ return $children[0];
152
+ }
153
+ : MaybeModifiersTypedCallableParameter()
154
+ VariableLiteral()?
155
+ ;
156
+
157
+ // Expects expression:
158
+ // - "<type>...&"
159
+ // - "<type>&..."
160
+ // - "<type>&"
161
+ // - "<type>..."
162
+ // - "<type>"
163
+ MaybeModifiersTypedCallableParameter -> {
164
+ $result = \reset($children);
165
+
166
+ foreach ($children as $modifier) {
167
+ if ($modifier instanceof \Phplrt\Contracts\Lexer\TokenInterface) {
168
+ switch ($modifier->getName()) {
169
+ case 'T_AMP':
170
+ $result->output = true;
171
+ break;
172
+ case 'T_ELLIPSIS':
173
+ if ($result->variadic) {
174
+ throw SemanticException::fromVariadicRedefinition($offset);
175
+ }
176
+ $result->variadic = true;
177
+ break;
178
+ }
179
+ }
117
180
}
118
181
119
- return $argument;
182
+ return $result;
183
+ }
184
+ : TypedCallableParameter()
185
+ ( <T_AMP> <T_ELLIPSIS>?
186
+ | <T_ELLIPSIS> <T_AMP>? )?
187
+ ;
188
+
189
+ // Expects expression:
190
+ // - "<type>"
191
+ TypedCallableParameter -> {
192
+ return new Node\Stmt\Callable\CallableParameterNode($children[0]);
120
193
}
121
- : Type() <T_AMP>?
194
+ : Type()
122
195
;
123
196
124
197
CallableReturnType
0 commit comments