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
50namespace WebCore {
51
52namespace WHLSL {
53
54NameResolver::NameResolver(NameContext& nameContext)
55 : m_nameContext(nameContext)
56{
57}
58
59void 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
86void 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
97void 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
105void 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
120void 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
129void 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
138void 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
146void NameResolver::visit(AST::VariableDeclaration& variableDeclaration)
147{
148 if (!m_nameContext.add(variableDeclaration)) {
149 setError();
150 return;
151 }
152 Visitor::visit(variableDeclaration);
153}
154
155void 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
168void NameResolver::visit(AST::Return& returnStatement)
169{
170 ASSERT(m_currentFunction);
171 returnStatement.setFunction(m_currentFunction);
172 Visitor::visit(returnStatement);
173}
174
175void 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
186void 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
214void 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
237void 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
259bool 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
284bool 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