1 | /* |
2 | * Copyright (C) 2019 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "WHLSLNameResolver.h" |
28 | |
29 | #if ENABLE(WEBGPU) |
30 | |
31 | #include "WHLSLCallExpression.h" |
32 | #include "WHLSLDoWhileLoop.h" |
33 | #include "WHLSLDotExpression.h" |
34 | #include "WHLSLEnumerationDefinition.h" |
35 | #include "WHLSLEnumerationMemberLiteral.h" |
36 | #include "WHLSLForLoop.h" |
37 | #include "WHLSLFunctionDefinition.h" |
38 | #include "WHLSLIfStatement.h" |
39 | #include "WHLSLNameContext.h" |
40 | #include "WHLSLProgram.h" |
41 | #include "WHLSLPropertyAccessExpression.h" |
42 | #include "WHLSLResolveOverloadImpl.h" |
43 | #include "WHLSLReturn.h" |
44 | #include "WHLSLScopedSetAdder.h" |
45 | #include "WHLSLTypeReference.h" |
46 | #include "WHLSLVariableDeclaration.h" |
47 | #include "WHLSLVariableReference.h" |
48 | #include "WHLSLWhileLoop.h" |
49 | |
50 | namespace WebCore { |
51 | |
52 | namespace WHLSL { |
53 | |
54 | NameResolver::NameResolver(NameContext& nameContext) |
55 | : m_nameContext(nameContext) |
56 | { |
57 | } |
58 | |
59 | void NameResolver::visit(AST::TypeReference& typeReference) |
60 | { |
61 | ScopedSetAdder<AST::TypeReference*> adder(m_typeReferences, &typeReference); |
62 | if (!adder.isNewEntry()) { |
63 | setError(); |
64 | return; |
65 | } |
66 | |
67 | Visitor::visit(typeReference); |
68 | if (typeReference.resolvedType()) |
69 | return; |
70 | |
71 | auto* candidates = m_nameContext.getTypes(typeReference.name()); |
72 | if (candidates == nullptr) { |
73 | setError(); |
74 | return; |
75 | } |
76 | for (auto& candidate : *candidates) |
77 | Visitor::visit(candidate); |
78 | if (auto result = resolveTypeOverloadImpl(*candidates, typeReference.typeArguments())) |
79 | typeReference.setResolvedType(*result); |
80 | else { |
81 | setError(); |
82 | return; |
83 | } |
84 | } |
85 | |
86 | void NameResolver::visit(AST::FunctionDefinition& functionDefinition) |
87 | { |
88 | NameContext newNameContext(&m_nameContext); |
89 | NameResolver newNameResolver(newNameContext); |
90 | newNameResolver.setCurrentFunctionDefinition(m_currentFunction); |
91 | checkErrorAndVisit(functionDefinition.type()); |
92 | for (auto& parameter : functionDefinition.parameters()) |
93 | newNameResolver.checkErrorAndVisit(parameter); |
94 | newNameResolver.checkErrorAndVisit(functionDefinition.block()); |
95 | } |
96 | |
97 | void NameResolver::visit(AST::Block& block) |
98 | { |
99 | NameContext nameContext(&m_nameContext); |
100 | NameResolver newNameResolver(nameContext); |
101 | newNameResolver.setCurrentFunctionDefinition(m_currentFunction); |
102 | newNameResolver.Visitor::visit(block); |
103 | } |
104 | |
105 | void NameResolver::visit(AST::IfStatement& ifStatement) |
106 | { |
107 | checkErrorAndVisit(ifStatement.conditional()); |
108 | NameContext nameContext(&m_nameContext); |
109 | NameResolver newNameResolver(nameContext); |
110 | newNameResolver.setCurrentFunctionDefinition(m_currentFunction); |
111 | newNameResolver.checkErrorAndVisit(ifStatement.body()); |
112 | if (ifStatement.elseBody()) { |
113 | NameContext nameContext(&m_nameContext); |
114 | NameResolver newNameResolver(nameContext); |
115 | newNameResolver.setCurrentFunctionDefinition(m_currentFunction); |
116 | newNameResolver.checkErrorAndVisit(*ifStatement.elseBody()); |
117 | } |
118 | } |
119 | |
120 | void NameResolver::visit(AST::WhileLoop& whileLoop) |
121 | { |
122 | checkErrorAndVisit(whileLoop.conditional()); |
123 | NameContext nameContext(&m_nameContext); |
124 | NameResolver newNameResolver(nameContext); |
125 | newNameResolver.setCurrentFunctionDefinition(m_currentFunction); |
126 | newNameResolver.checkErrorAndVisit(whileLoop.body()); |
127 | } |
128 | |
129 | void NameResolver::visit(AST::DoWhileLoop& whileLoop) |
130 | { |
131 | NameContext nameContext(&m_nameContext); |
132 | NameResolver newNameResolver(nameContext); |
133 | newNameResolver.setCurrentFunctionDefinition(m_currentFunction); |
134 | newNameResolver.checkErrorAndVisit(whileLoop.body()); |
135 | checkErrorAndVisit(whileLoop.conditional()); |
136 | } |
137 | |
138 | void NameResolver::visit(AST::ForLoop& forLoop) |
139 | { |
140 | NameContext nameContext(&m_nameContext); |
141 | NameResolver newNameResolver(nameContext); |
142 | newNameResolver.setCurrentFunctionDefinition(m_currentFunction); |
143 | newNameResolver.Visitor::visit(forLoop); |
144 | } |
145 | |
146 | void NameResolver::visit(AST::VariableDeclaration& variableDeclaration) |
147 | { |
148 | if (!m_nameContext.add(variableDeclaration)) { |
149 | setError(); |
150 | return; |
151 | } |
152 | Visitor::visit(variableDeclaration); |
153 | } |
154 | |
155 | void NameResolver::visit(AST::VariableReference& variableReference) |
156 | { |
157 | if (variableReference.variable()) |
158 | return; |
159 | |
160 | if (auto* variable = m_nameContext.getVariable(variableReference.name())) |
161 | variableReference.setVariable(*variable); |
162 | else { |
163 | setError(); |
164 | return; |
165 | } |
166 | } |
167 | |
168 | void NameResolver::visit(AST::Return& returnStatement) |
169 | { |
170 | ASSERT(m_currentFunction); |
171 | returnStatement.setFunction(m_currentFunction); |
172 | Visitor::visit(returnStatement); |
173 | } |
174 | |
175 | void NameResolver::visit(AST::PropertyAccessExpression& propertyAccessExpression) |
176 | { |
177 | if (auto* getFunctions = m_nameContext.getFunctions(propertyAccessExpression.getFunctionName())) |
178 | propertyAccessExpression.setPossibleGetOverloads(*getFunctions); |
179 | if (auto* setFunctions = m_nameContext.getFunctions(propertyAccessExpression.setFunctionName())) |
180 | propertyAccessExpression.setPossibleSetOverloads(*setFunctions); |
181 | if (auto* andFunctions = m_nameContext.getFunctions(propertyAccessExpression.andFunctionName())) |
182 | propertyAccessExpression.setPossibleAndOverloads(*andFunctions); |
183 | Visitor::visit(propertyAccessExpression); |
184 | } |
185 | |
186 | void NameResolver::visit(AST::DotExpression& dotExpression) |
187 | { |
188 | if (is<AST::VariableReference>(dotExpression.base())) { |
189 | auto baseName = downcast<AST::VariableReference>(dotExpression.base()).name(); |
190 | if (auto enumerationTypes = m_nameContext.getTypes(baseName)) { |
191 | ASSERT(enumerationTypes->size() == 1); |
192 | AST::NamedType& type = (*enumerationTypes)[0]; |
193 | if (is<AST::EnumerationDefinition>(type)) { |
194 | AST::EnumerationDefinition& enumerationDefinition = downcast<AST::EnumerationDefinition>(type); |
195 | auto memberName = dotExpression.fieldName(); |
196 | if (auto* member = enumerationDefinition.memberByName(memberName)) { |
197 | static_assert(sizeof(AST::EnumerationMemberLiteral) <= sizeof(AST::DotExpression), "Dot expressions need to be able to become EnumerationMemberLiterals without updating backreferences" ); |
198 | Lexer::Token origin = dotExpression.origin(); |
199 | // FIXME: Perhaps do this with variants or a Rewriter instead. |
200 | dotExpression.~DotExpression(); |
201 | auto enumerationMemberLiteral = AST::EnumerationMemberLiteral::wrap(WTFMove(origin), WTFMove(baseName), WTFMove(memberName), enumerationDefinition, *member); |
202 | new (&dotExpression) AST::EnumerationMemberLiteral(WTFMove(enumerationMemberLiteral)); |
203 | return; |
204 | } |
205 | setError(); |
206 | return; |
207 | } |
208 | } |
209 | } |
210 | |
211 | Visitor::visit(dotExpression); |
212 | } |
213 | |
214 | void NameResolver::visit(AST::CallExpression& callExpression) |
215 | { |
216 | if (!callExpression.hasOverloads()) { |
217 | if (auto* functions = m_nameContext.getFunctions(callExpression.name())) |
218 | callExpression.setOverloads(*functions); |
219 | else { |
220 | if (auto* types = m_nameContext.getTypes(callExpression.name())) { |
221 | if (types->size() == 1) { |
222 | if (auto* functions = m_nameContext.getFunctions("operator cast"_str )) { |
223 | callExpression.setCastData((*types)[0].get()); |
224 | callExpression.setOverloads(*functions); |
225 | } |
226 | } |
227 | } |
228 | } |
229 | } |
230 | if (!callExpression.hasOverloads()) { |
231 | setError(); |
232 | return; |
233 | } |
234 | Visitor::visit(callExpression); |
235 | } |
236 | |
237 | void NameResolver::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral) |
238 | { |
239 | if (enumerationMemberLiteral.enumerationMember()) |
240 | return; |
241 | |
242 | if (auto enumerationTypes = m_nameContext.getTypes(enumerationMemberLiteral.left())) { |
243 | ASSERT(enumerationTypes->size() == 1); |
244 | AST::NamedType& type = (*enumerationTypes)[0]; |
245 | if (is<AST::EnumerationDefinition>(type)) { |
246 | AST::EnumerationDefinition& enumerationDefinition = downcast<AST::EnumerationDefinition>(type); |
247 | if (auto* member = enumerationDefinition.memberByName(enumerationMemberLiteral.right())) { |
248 | enumerationMemberLiteral.setEnumerationMember(enumerationDefinition, *member); |
249 | return; |
250 | } |
251 | } |
252 | } |
253 | |
254 | setError(); |
255 | } |
256 | |
257 | // FIXME: Make sure all the names have been resolved. |
258 | |
259 | bool resolveNamesInTypes(Program& program, NameResolver& nameResolver) |
260 | { |
261 | for (auto& typeDefinition : program.typeDefinitions()) { |
262 | nameResolver.checkErrorAndVisit(typeDefinition); |
263 | if (nameResolver.error()) |
264 | return false; |
265 | } |
266 | for (auto& structureDefinition : program.structureDefinitions()) { |
267 | nameResolver.checkErrorAndVisit(structureDefinition); |
268 | if (nameResolver.error()) |
269 | return false; |
270 | } |
271 | for (auto& enumerationDefinition : program.enumerationDefinitions()) { |
272 | nameResolver.checkErrorAndVisit(enumerationDefinition); |
273 | if (nameResolver.error()) |
274 | return false; |
275 | } |
276 | for (auto& nativeTypeDeclaration : program.nativeTypeDeclarations()) { |
277 | nameResolver.checkErrorAndVisit(nativeTypeDeclaration); |
278 | if (nameResolver.error()) |
279 | return false; |
280 | } |
281 | return true; |
282 | } |
283 | |
284 | bool resolveNamesInFunctions(Program& program, NameResolver& nameResolver) |
285 | { |
286 | for (auto& functionDefinition : program.functionDefinitions()) { |
287 | nameResolver.setCurrentFunctionDefinition(&functionDefinition); |
288 | nameResolver.checkErrorAndVisit(functionDefinition); |
289 | if (nameResolver.error()) |
290 | return false; |
291 | } |
292 | nameResolver.setCurrentFunctionDefinition(nullptr); |
293 | for (auto& nativeFunctionDeclaration : program.nativeFunctionDeclarations()) { |
294 | nameResolver.checkErrorAndVisit(nativeFunctionDeclaration); |
295 | if (nameResolver.error()) |
296 | return false; |
297 | } |
298 | return true; |
299 | } |
300 | |
301 | } // namespace WHLSL |
302 | |
303 | } // namespace WebCore |
304 | |
305 | #endif // ENABLE(WEBGPU) |
306 | |