WSL should allow you to say "protocol Foo : Bar { ... }"
[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         for (let parent of node.extends)
133             parent.visit(this);
134         let nameContext = new NameContext(this._nameContext);
135         nameContext.add(node.typeVariable);
136         let checker = new NameResolver(nameContext);
137         for (let signature of node.signatures)
138             signature.visit(checker);
139     }
140     
141     visitProtocolRef(node)
142     {
143         let result = this._nameContext.get(Protocol, node.name);
144         if (!result)
145             throw new WTypeError(node.origin.originString, "Could not find protocol named " + node.name);
146         node.protocolDecl = result;
147     }
148     
149     visitProtocolFuncDecl(node)
150     {
151         this.visitFunc(node);
152         let funcs = this._nameContext.get(Func, node.name);
153         if (!funcs)
154             throw new WTypeError(node.origin.originString, "Cannot find any functions named " + node.na,e);
155         node.possibleOverloads = funcs;
156     }
157     
158     visitTypeDef(node)
159     {
160         let nameContext = new NameContext(this._nameContext);
161         for (let typeParameter of node.typeParameters) {
162             typeParameter.visit(this);
163             nameContext.add(typeParameter);
164         }
165         let checker = new NameResolver(nameContext);
166         node.type.visit(checker);
167     }
168     
169     visitStructType(node)
170     {
171         let nameContext = new NameContext(this._nameContext);
172         for (let typeParameter of node.typeParameters) {
173             typeParameter.visit(this);
174             nameContext.add(typeParameter);
175         }
176         let checker = new NameResolver(nameContext);
177         for (let field of node.fields)
178             field.visit(checker);
179     }
180     
181     _resolveTypeArguments(typeArguments)
182     {
183         for (let i = 0; i < typeArguments.length; ++i) {
184             let typeArgument = typeArguments[i];
185             if (typeArgument instanceof TypeOrVariableRef) {
186                 let thing = this._nameContext.get(NotFunc, typeArgument.name);
187                 if (!thing)
188                     new WTypeError(typeArgument.origin.originString, "Could not find type or variable named " + typeArgument.name);
189                 if (thing instanceof Value) {
190                     typeArguments[i] = new VariableRef(typeArgument.origin, typeArgument.name);
191                 } else
192                     typeArguments[i] = new TypeRef(typeArgument.origin, typeArgument.name, []);
193             }
194             
195             if (typeArgument[i] instanceof Value
196                 && !typeArgument[i].isConstexpr)
197                 throw new WTypeError(typeArgument[i].origin.originString, "Expected constexpr");
198         }
199     }
200     
201     visitTypeRef(node)
202     {
203         this._resolveTypeArguments(node.typeArguments);
204         
205         let type = this._nameContext.get(Type, node.name);
206         if (!type)
207             throw new WTypeError(node.origin.originString, "Could not find type named " + node.name);
208         if (!this._nameContext.isDefined(type))
209             throw new WTypeError(node.origin.originString, "Illegal forward use of type named " + node.name);
210         node.type = type;
211         
212         if (type.typeParameters.length != node.typeArguments.length)
213             throw new WTypeError(node.origin.originString, "Wrong number of type arguments (passed " + node.typeArguments.length + ", expected " + type.typeParameters.length + ")");
214         for (let i = 0; i < type.typeParameters.length; ++i) {
215             let parameterIsType = type.typeParameters[i] instanceof TypeVariable;
216             let argumentIsType = node.typeArguments[i] instanceof Type;
217             node.typeArguments[i].visit(this);
218             if (parameterIsType && !argumentIsType)
219                 throw new WTypeError(node.origin.originString, "Expected type, but got value at argument #" + i);
220             if (!parameterIsType && argumentIsType)
221                 throw new WTypeError(node.origin.originString, "Expected value, but got type at argument #" + i);
222         }
223
224         super.visitTypeRef(node);
225     }
226     
227     visitReferenceType(node)
228     {
229         let nameContext = new NameContext(this._nameContext);
230         nameContext.defineAll();
231         node.elementType.visit(new NameResolver(nameContext));
232     }
233     
234     visitVariableDecl(node)
235     {
236         this._nameContext.add(node);
237         node.type.visit(this);
238         if (node.initializer)
239             node.initializer.visit(this);
240     }
241     
242     visitVariableRef(node)
243     {
244         let result = this._nameContext.get(Value, node.name);
245         if (!result)
246             throw new WTypeError(node.origin.originString, "Could not find variable named " + node.name);
247         node.variable = result;
248     }
249     
250     visitReturn(node)
251     {
252         node.func = this._nameContext.currentStatement;
253         super.visitReturn(node);
254     }
255     
256     visitCallExpression(node)
257     {
258         this._resolveTypeArguments(node.typeArguments);
259         
260         let funcs = this._nameContext.get(Func, node.name);
261         if (funcs)
262             node.possibleOverloads = funcs;
263         else {
264             let type = this._nameContext.get(Type, node.name);
265             if (!type)
266                 throw new WTypeError(node.origin.originString, "Cannot find any function or type named " + node.name);
267             node.becomeCast(type);
268             node.possibleOverloads = this._nameContext.get(Func, "operator cast");
269             if (!node.possibleOverloads)
270                 throw new WTypeError(node.origin.originString, "Cannot find any operator cast implementations in cast to " + type);
271         }
272         
273         super.visitCallExpression(node);
274     }
275 }
276