Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
85.87% |
79 / 92 |
|
66.67% |
6 / 9 |
CRAP | |
0.00% |
0 / 1 |
ZFunction | |
85.87% |
79 / 92 |
|
66.67% |
6 / 9 |
36.07 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getDefinition | |
100.00% |
28 / 28 |
|
100.00% |
1 / 1 |
1 | |||
isValid | |
100.00% |
25 / 25 |
|
100.00% |
1 / 1 |
15 | |||
getReturnType | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
3.07 | |||
getIdentity | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getArgumentDeclarations | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getTesterZids | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getImplementationZids | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAssociatedZids | |
55.00% |
11 / 20 |
|
0.00% |
0 / 1 |
11.47 |
1 | <?php |
2 | /** |
3 | * WikiLambda ZFunction |
4 | * |
5 | * @file |
6 | * @ingroup Extensions |
7 | * @copyright 2020– WikiLambda team; see AUTHORS.txt |
8 | * @license MIT |
9 | */ |
10 | |
11 | namespace MediaWiki\Extension\WikiLambda\ZObjects; |
12 | |
13 | use FormatJson; |
14 | use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry; |
15 | use MediaWiki\Extension\WikiLambda\ZErrorException; |
16 | use MediaWiki\Extension\WikiLambda\ZObjectFactory; |
17 | |
18 | class ZFunction extends ZObject { |
19 | |
20 | /** |
21 | * Construct a ZFunction instance |
22 | * |
23 | * @param ZTypedList $arguments |
24 | * @param ZObject $returnType |
25 | * @param ZTypedList $testers |
26 | * @param ZTypedList $implementations |
27 | * @param ZReference $identity |
28 | */ |
29 | public function __construct( $arguments, $returnType, $testers, $implementations, $identity ) { |
30 | $this->data[ ZTypeRegistry::Z_FUNCTION_ARGUMENTS ] = $arguments; |
31 | $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ] = $returnType; |
32 | $this->data[ ZTypeRegistry::Z_FUNCTION_TESTERS ] = $testers; |
33 | $this->data[ ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS ] = $implementations; |
34 | $this->data[ ZTypeRegistry::Z_FUNCTION_IDENTITY ] = $identity; |
35 | } |
36 | |
37 | /** |
38 | * @inheritDoc |
39 | */ |
40 | public static function getDefinition(): array { |
41 | return [ |
42 | 'type' => [ |
43 | 'type' => ZTypeRegistry::Z_REFERENCE, |
44 | 'value' => ZTypeRegistry::Z_FUNCTION, |
45 | ], |
46 | 'keys' => [ |
47 | ZTypeRegistry::Z_FUNCTION_ARGUMENTS => [ |
48 | 'type' => ZTypeRegistry::Z_FUNCTION_TYPED_LIST, |
49 | 'required' => true |
50 | ], |
51 | ZTypeRegistry::Z_FUNCTION_RETURN_TYPE => [ |
52 | 'type' => ZTypeRegistry::Z_REFERENCE, |
53 | 'required' => true |
54 | ], |
55 | ZTypeRegistry::Z_FUNCTION_TESTERS => [ |
56 | 'type' => ZTypeRegistry::Z_FUNCTION_TYPED_LIST, |
57 | 'required' => true |
58 | ], |
59 | ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS => [ |
60 | 'type' => ZTypeRegistry::Z_FUNCTION_TYPED_LIST, |
61 | 'required' => true |
62 | ], |
63 | ZTypeRegistry::Z_FUNCTION_IDENTITY => [ |
64 | 'type' => ZTypeRegistry::Z_REFERENCE, |
65 | 'required' => true |
66 | ], |
67 | ] |
68 | ]; |
69 | } |
70 | |
71 | /** |
72 | * @inheritDoc |
73 | */ |
74 | public function isValid(): bool { |
75 | // Check Z8K1 is a list of argument declarations |
76 | if ( !( $this->data[ ZTypeRegistry::Z_FUNCTION_ARGUMENTS ] instanceof ZTypedList ) ) { |
77 | return false; |
78 | } |
79 | $list = $this->data[ ZTypeRegistry::Z_FUNCTION_ARGUMENTS ]; |
80 | if ( !$list->isEmpty() && ( $list->getElementType()->getZValue() !== ZTypeRegistry::Z_ARGUMENTDECLARATION ) ) { |
81 | return false; |
82 | } |
83 | |
84 | // Check Z8K2 is either a valid reference or a valid function call |
85 | if ( |
86 | !( $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ] instanceof ZReference ) && |
87 | !( $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ] instanceof ZFunctionCall ) ) { |
88 | return false; |
89 | } |
90 | if ( !( $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ]->isValid() ) ) { |
91 | return false; |
92 | } |
93 | |
94 | // Check Z8K3 is a list of testers |
95 | if ( !( $this->data[ ZTypeRegistry::Z_FUNCTION_TESTERS ] instanceof ZTypedList ) ) { |
96 | return false; |
97 | } |
98 | $list = $this->data[ ZTypeRegistry::Z_FUNCTION_TESTERS ]; |
99 | if ( !$list->isEmpty() && ( $list->getElementType()->getZValue() !== ZTypeRegistry::Z_TESTER ) ) { |
100 | return false; |
101 | } |
102 | |
103 | // Check Z8K4 is a list of implementations |
104 | if ( !( $this->data[ ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS ] instanceof ZTypedList ) ) { |
105 | return false; |
106 | } |
107 | $list = $this->data[ ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS ]; |
108 | if ( !$list->isEmpty() && ( $list->getElementType()->getZValue() !== ZTypeRegistry::Z_IMPLEMENTATION ) ) { |
109 | return false; |
110 | } |
111 | |
112 | // Check Z8K5 is a reference |
113 | if ( !( $this->data[ ZTypeRegistry::Z_FUNCTION_IDENTITY ] instanceof ZReference ) ) { |
114 | return false; |
115 | } |
116 | if ( !( $this->data[ ZTypeRegistry::Z_FUNCTION_IDENTITY ]->isValid() ) ) { |
117 | return false; |
118 | } |
119 | |
120 | return true; |
121 | } |
122 | |
123 | /** |
124 | * Expected return type of this ZFunction. |
125 | * |
126 | * @return string|null |
127 | */ |
128 | public function getReturnType() { |
129 | if ( $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ] instanceof ZReference ) { |
130 | return $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ]->getZValue(); |
131 | } |
132 | |
133 | if ( $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ] instanceof ZFunctionCall ) { |
134 | return $this->data[ ZTypeRegistry::Z_FUNCTION_RETURN_TYPE ]->getReturnType(); |
135 | } |
136 | |
137 | return null; |
138 | } |
139 | |
140 | /** |
141 | * Return the string value of its identity. |
142 | * |
143 | * @return string|null |
144 | */ |
145 | public function getIdentity() { |
146 | $functionId = $this->data[ ZTypeRegistry::Z_FUNCTION_IDENTITY ]; |
147 | return ( $functionId instanceof ZReference ) |
148 | ? $functionId->getZValue() |
149 | : null; |
150 | } |
151 | |
152 | /** |
153 | * Return an array with the argument declarations, or empty array if undefined |
154 | * |
155 | * @return array |
156 | */ |
157 | public function getArgumentDeclarations(): array { |
158 | if ( !( $this->data[ ZTypeRegistry::Z_FUNCTION_ARGUMENTS ] instanceof ZTypedList ) ) { |
159 | return []; |
160 | } |
161 | return $this->data[ ZTypeRegistry::Z_FUNCTION_ARGUMENTS ]->getAsArray(); |
162 | } |
163 | |
164 | /** |
165 | * Get the Z8K3/Testers and return a list of ZIDs for them. |
166 | * |
167 | * @return string[] |
168 | * @throws ZErrorException from ZObjectFactory::create |
169 | */ |
170 | public function getTesterZids() { |
171 | return $this->getAssociatedZids( ZTypeRegistry::Z_FUNCTION_TESTERS ); |
172 | } |
173 | |
174 | /** |
175 | * Get the Z8K4/Implementations and return a list of ZIDs for them. |
176 | * |
177 | * @return string[] |
178 | * @throws ZErrorException from ZObjectFactory::create |
179 | */ |
180 | public function getImplementationZids() { |
181 | return $this->getAssociatedZids( ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS ); |
182 | } |
183 | |
184 | /** |
185 | * @param string $key One of ZTypeRegistry::Z_FUNCTION_IMPLEMENTATIONS or ZTypeRegistry::Z_FUNCTION_TESTERS |
186 | * @return string[] |
187 | * @throws ZErrorException from ZObjectFactory::create |
188 | */ |
189 | private function getAssociatedZids( $key ) { |
190 | $zids = []; |
191 | $associatedList = $this->getValueByKey( $key ); |
192 | |
193 | if ( !$associatedList ) { |
194 | return []; |
195 | } |
196 | |
197 | '@phan-var \MediaWiki\Extension\WikiLambda\ZObjects\ZTypedList $associatedList'; |
198 | $associatedArray = $associatedList->getAsArray(); |
199 | |
200 | foreach ( $associatedArray as $item ) { |
201 | if ( is_string( $item ) ) { |
202 | $decodedJson = FormatJson::decode( $item ); |
203 | // If not JSON, assume we have received a ZID. |
204 | if ( $decodedJson ) { |
205 | $item = ZObjectFactory::create( $decodedJson ); |
206 | } else { |
207 | $item = new ZReference( $item ); |
208 | } |
209 | } |
210 | |
211 | $zids[] = ( $item->getZType() === ZTypeRegistry::Z_REFERENCE ) ? |
212 | $item->getValueByKey( ZTypeRegistry::Z_REFERENCE_VALUE ) : |
213 | ( |
214 | ( $item->getZType() === ZTypeRegistry::Z_PERSISTENTOBJECT_ID ) ? |
215 | $item->getValueByKey( ZTypeRegistry::Z_PERSISTENTOBJECT_ID )-> |
216 | getValueByKey( ZTypeRegistry::Z_STRING_VALUE ) : |
217 | ZTypeRegistry::Z_NULL_REFERENCE |
218 | ); |
219 | } |
220 | return $zids; |
221 | } |
222 | |
223 | } |