cbf07ee1b91d14c5323d13f04229308f8c07f017
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / NameResolver.js
1 /*
2  * Copyright (C) 2017 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 "use strict";
26
27 // This only resolves names. After this phase runs, all names will be resolved. This means that all
28 // XYZRef objects now know who they resolve to. This does not yet allow type analysis, because there
29 // are still TypeDefs. This throws type errors for failed name resolutions and for things that are
30 // more convenient to check here than in the Checker. This usually involves things that need to be
31 // checked before TypeRefToTypeDefSkipper.
32 class NameResolver extends Visitor {
33     // It's totally OK to instantiate this with zero arguments (i.e. passing undefined for both of
34     // them) if you're creating a NameResolver to visit a Program.
35     constructor(nameContext)
36     {
37         super();
38         this._nameContext = nameContext;
39     }
40     
41     visitProgram(node)
42     {
43         let nameContext = new NameContext(this._nameContext);
44         nameContext.program = node;
45         nameContext.recognizeIntrinsics();
46         nameContext.handleDefining();
47         node.intrinsics = nameContext.intrinsics;
48         for (let statement of node.topLevelStatements)
49             nameContext.add(statement);
50         let checker = new NameResolver(nameContext);
51         for (let statement of node.topLevelStatements)
52             nameContext.doStatement(statement, () => statement.visit(checker));
53         node.globalNameContext = nameContext;
54     }
55     
56     _visitTypeParametersAndBuildNameContext(node)
57     {
58         let nameContext = new NameContext(this._nameContext);
59         for (let typeParameter of node.typeParameters) {
60             nameContext.add(typeParameter);
61             typeParameter.visit(this);
62         }
63         return nameContext;
64     }
65     
66     visitFunc(node)
67     {
68         let checker = new NameResolver(this._visitTypeParametersAndBuildNameContext(node));
69         node.returnType.visit(checker);
70         for (let parameter of node.parameters)
71             parameter.visit(checker);
72     }
73     
74     visitFuncDef(node)
75     {
76         let contextWithTypeParameters = this._visitTypeParametersAndBuildNameContext(node);
77         let checkerWithTypeParameters = new NameResolver(contextWithTypeParameters);
78         node.returnType.visit(checkerWithTypeParameters);
79         let contextWithParameters = new NameContext(contextWithTypeParameters);
80         for (let parameter of node.parameters) {
81             parameter.visit(checkerWithTypeParameters);
82             contextWithParameters.add(parameter);
83         }
84         let checkerWithParameters = new NameResolver(contextWithParameters);
85         node.body.visit(checkerWithParameters);
86     }
87     
88     visitBlock(node)
89     {
90         let checker = new NameResolver(new NameContext(this._nameContext));
91         for (let statement of node.statements)
92             statement.visit(checker);
93     }
94
95     visitIfStatement(node)
96     {
97         node.conditional.visit(this);
98         // The bodies might not be Blocks, so we need to explicitly give them a new context.
99         node.body.visit(new NameResolver(new NameContext(this._nameContext)));
100         if (node.elseBody)
101             node.elseBody.visit(new NameResolver(new NameContext(this._nameContext)));
102     }
103
104     visitWhileLoop(node)
105     {
106         node.conditional.visit(this);
107         // The bodies might not be Blocks, so we need to explicitly give them a new context.
108         node.body.visit(new NameResolver(new NameContext(this._nameContext)));
109     }
110
111     visitDoWhileLoop(node)
112     {
113         // The bodies might not be Blocks, so we need to explicitly give them a new context.
114         node.body.visit(new NameResolver(new NameContext(this._nameContext)));
115         node.conditional.visit(this);
116     }
117
118     visitForLoop(node)
119     {
120         let newResolver = new NameResolver(new NameContext(this._nameContext))
121         if (node.initialization)
122             node.initialization.visit(newResolver);
123         if (node.condition)
124             node.condition.visit(newResolver);
125         if (node.increment)
126             node.increment.visit(newResolver);
127         node.body.visit(newResolver);
128     }
129     
130     visitProtocolDecl(node)
131     {
132         let nameContext = new NameContext(this._nameContext);
133         nameContext.add(node.typeVariable);
134         let checker = new NameResolver(nameContext);
135         for (let signature of node.signatures)
136             signature.visit(checker);
137     }
138     
139     visitProtocolRef(node)
140     {
141         let result = this._nameContext.get(Protocol, node.name);
142         if (!result)
143             throw new WTypeError(node.origin.originString, "Could not find protocol named " + node.name);
144         node.protocolDecl = result;
145     }
146     
147     visitProtocolFuncDecl(node)
148     {
149         this.visitFunc(node);
150         let funcs = this._nameContext.get(Func, node.name);
151         if (!funcs)
152             throw new WTypeError(node.origin.originString, "Cannot find any functions named " + node.na,e);
153         node.possibleOverloads = funcs;
154     }
155     
156     visitTypeDef(node)
157     {
158         let nameContext = new NameContext(this._nameContext);
159         for (let typeParameter of node.typeParameters) {
160             typeParameter.visit(this);
161             nameContext.add(typeParameter);
162         }
163         let checker = new NameResolver(nameContext);
164         node.type.visit(checker);
165     }
166     
167     visitStructType(node)
168     {
169         let nameContext = new NameContext(this._nameContext);
170         for (let typeParameter of node.typeParameters) {
171             typeParameter.visit(this);
172             nameContext.add(typeParameter);
173         }
174         let checker = new NameResolver(nameContext);
175         for (let field of node.fields)
176             field.visit(checker);
177     }
178     
179     _resolveTypeArguments(typeArguments)
180     {
181         for (let i = 0; i < typeArguments.length; ++i) {
182             let typeArgument = typeArguments[i];
183             if (typeArgument instanceof TypeOrVariableRef) {
184                 let thing = this._nameContext.get(NotFunc, typeArgument.name);
185                 if (!thing)
186                     new WTypeError(typeArgument.origin.originString, "Could not find type or variable named " + typeArgument.name);
187                 if (thing instanceof Value) {
188                     typeArguments[i] = new VariableRef(typeArgument.origin, typeArgument.name);
189                 } else
190                     typeArguments[i] = new TypeRef(typeArgument.origin, typeArgument.name, []);
191             }
192             
193             if (typeArgument[i] instanceof Value
194                 && !typeArgument[i].isConstexpr)
195                 throw new WTypeError(typeArgument[i].origin.originString, "Expected constexpr");
196         }
197     }
198     
199     visitTypeRef(node)
200     {
201         this._resolveTypeArguments(node.typeArguments);
202         
203         let type = this._nameContext.get(Type, node.name);
204         if (!type)
205             throw new WTypeError(node.origin.originString, "Could not find type named " + node.name);
206         if (!this._nameContext.isDefined(type))
207             throw new WTypeError(node.origin.originString, "Illegal forward use of type named " + node.name);
208         node.type = type;
209         
210         if (type.typeParameters.length != node.typeArguments.length)
211             throw new WTypeError(node.origin.originString, "Wrong number of type arguments (passed " + node.typeArguments.length + ", expected " + type.typeParameters.length + ")");
212         for (let i = 0; i < type.typeParameters.length; ++i) {
213             let parameterIsType = type.typeParameters[i] instanceof TypeVariable;
214             let argumentIsType = node.typeArguments[i] instanceof Type;
215             node.typeArguments[i].visit(this);
216             if (parameterIsType && !argumentIsType)
217                 throw new WTypeError(node.origin.originString, "Expected type, but got value at argument #" + i);
218             if (!parameterIsType && argumentIsType)
219                 throw new WTypeError(node.origin.originString, "Expected value, but got type at argument #" + i);
220         }
221
222         super.visitTypeRef(node);
223     }
224     
225     visitReferenceType(node)
226     {
227         let nameContext = new NameContext(this._nameContext);
228         nameContext.defineAll();
229         node.elementType.visit(new NameResolver(nameContext));
230     }
231     
232     visitVariableDecl(node)
233     {
234         this._nameContext.add(node);
235         node.type.visit(this);
236         if (node.initializer)
237             node.initializer.visit(this);
238     }
239     
240     visitVariableRef(node)
241     {
242         let result = this._nameContext.get(Value, node.name);
243         if (!result)
244             throw new WTypeError(node.origin.originString, "Could not find variable named " + node.name);
245         node.variable = result;
246     }
247     
248     visitReturn(node)
249     {
250         node.func = this._nameContext.currentStatement;
251         super.visitReturn(node);
252     }
253     
254     visitCallExpression(node)
255     {
256         this._resolveTypeArguments(node.typeArguments);
257         
258         let funcs = this._nameContext.get(Func, node.name);
259         if (funcs)
260             node.possibleOverloads = funcs;
261         else {
262             let type = this._nameContext.get(Type, node.name);
263             if (!type)
264                 throw new WTypeError(node.origin.originString, "Cannot find any function or type named " + node.name);
265             node.becomeCast(type);
266             node.possibleOverloads = this._nameContext.get(Func, "operator cast");
267             if (!node.possibleOverloads)
268                 throw new WTypeError(node.origin.originString, "Cannot find any operator cast implementations in cast to " + type);
269         }
270         
271         super.visitCallExpression(node);
272     }
273 }
274