[WHLSL] Call expressions shouldn't have type arguments
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / Rewriter.js
1 /*
2  * Copyright (C) 2018 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 // FIXME: This should have sensible behavior when it encounters definitions that it cannot handle. Right
28 // now we are hackishly preventing this by wrapping things in TypeRef. That's probably wrong.
29 // https://bugs.webkit.org/show_bug.cgi?id=176208
30 class Rewriter {
31     constructor()
32     {
33         this._mapping = new Map();
34     }
35     
36     _mapNode(oldItem, newItem)
37     {
38         this._mapping.set(oldItem, newItem);
39         return newItem;
40     }
41     
42     _getMapping(oldItem)
43     {
44         let result = this._mapping.get(oldItem);
45         if (result)
46             return result;
47         return oldItem;
48     }
49     
50     // We return identity for anything that is not inside a function/struct body. When processing
51     // function bodies, we only recurse into them and never out of them - for example if there is a
52     // function call to another function then we don't rewrite the other function. This is how we stop
53     // that.
54     visitFuncDef(node) { return node; }
55     visitNativeFunc(node) { return node; }
56     visitNativeType(node) { return node; }
57     visitTypeDef(node) { return node; }
58     visitStructType(node) { return node; }
59     visitEnumType(node) { return node; }
60     
61     visitFuncParameter(node)
62     {
63         let result = new FuncParameter(node.origin, node.name, node.type.visit(this));
64         this._mapNode(node, result);
65         result.ePtr = node.ePtr;
66         return result;
67     }
68     
69     visitVariableDecl(node)
70     {
71         let result = new VariableDecl(
72             node.origin, node.name,
73             node.type.visit(this),
74             Node.visit(node.initializer, this));
75         this._mapNode(node, result);
76         result.ePtr = node.ePtr;
77         return result;
78     }
79     
80     visitBlock(node)
81     {
82         let result = new Block(node.origin);
83         for (let statement of node.statements)
84             result.add(statement.visit(this));
85         return result;
86     }
87     
88     visitCommaExpression(node)
89     {
90         return new CommaExpression(node.origin, node.list.map(expression => {
91             let result = expression.visit(this);
92             if (!result)
93                 throw new Error("Null result from " + expression);
94             return result;
95         }));
96     }
97     
98     visitTypeRef(node)
99     {
100         let result = new TypeRef(node.origin, node.name);
101         if (node.type)
102             result.type = Node.visit(node.type, this);
103         return result;
104     }
105     
106     visitField(node)
107     {
108         return new Field(node.origin, node.name, node.type.visit(this));
109     }
110     
111     visitEnumMember(node)
112     {
113         return new EnumMember(node.origin, node.name, node.value.visit(this));
114     }
115     
116     visitEnumLiteral(node)
117     {
118         let result = new EnumLiteral(node.origin, node.member);
119         result.ePtr = node.ePtr;
120         return result;
121     }
122     
123     visitReferenceType(node)
124     {
125         return new node.constructor(node.origin, node.addressSpace, node.elementType.visit(this));
126     }
127     
128     visitPtrType(node)
129     {
130         return this.visitReferenceType(node);
131     }
132     
133     visitArrayRefType(node)
134     {
135         return this.visitReferenceType(node);
136     }
137     
138     visitArrayType(node)
139     {
140         return new ArrayType(node.origin, node.elementType.visit(this), node.numElements.visit(this));
141     }
142     
143     visitAssignment(node)
144     {
145         let result = new Assignment(node.origin, node.lhs.visit(this), node.rhs.visit(this));
146         result.type = Node.visit(node.type, this);
147         return result;
148     }
149     
150     visitReadModifyWriteExpression(node)
151     {
152         let result = new ReadModifyWriteExpression(node.origin, node.lValue.visit(this));
153         result.oldValueVar = node.oldValueVar.visit(this);
154         result.newValueVar = node.newValueVar.visit(this);
155         result.newValueExp = node.newValueExp.visit(this);
156         result.resultExp = node.resultExp.visit(this);
157         return result;
158     }
159     
160     visitDereferenceExpression(node)
161     {
162         let result = new DereferenceExpression(node.origin, node.ptr.visit(this));
163         result.type = Node.visit(node.type, this);
164         result.addressSpace = node.addressSpace;
165         return result;
166     }
167     
168     _handlePropertyAccessExpression(result, node)
169     {
170         result.possibleGetOverloads = node.possibleGetOverloads;
171         result.possibleSetOverloads = node.possibleSetOverloads;
172         result.possibleAndOverloads = node.possibleAndOverloads;
173         result.baseType = Node.visit(node.baseType, this);
174         result.callForGet = Node.visit(node.callForGet, this);
175         result.resultTypeForGet = Node.visit(node.resultTypeForGet, this);
176         result.callForAnd = Node.visit(node.callForAnd, this);
177         result.resultTypeForAnd = Node.visit(node.resultTypeForAnd, this);
178         result.callForSet = Node.visit(node.callForSet, this);
179         result.errorForSet = node.errorForSet;
180         result.updateCalls();
181     }
182     
183     visitDotExpression(node)
184     {
185         let result = new DotExpression(node.origin, node.struct.visit(this), node.fieldName);
186         this._handlePropertyAccessExpression(result, node);
187         return result;
188     }
189     
190     visitIndexExpression(node)
191     {
192         let result = new IndexExpression(node.origin, node.array.visit(this), node.index.visit(this));
193         this._handlePropertyAccessExpression(result, node);
194         return result;
195     }
196     
197     visitMakePtrExpression(node)
198     {
199         let result = new MakePtrExpression(node.origin, node.lValue.visit(this));
200         result.ePtr = node.ePtr;
201         return result;
202     }
203     
204     visitMakeArrayRefExpression(node)
205     {
206         let result = new MakeArrayRefExpression(node.origin, node.lValue.visit(this));
207         if (node.numElements)
208             result.numElements = node.numElements.visit(this);
209         result.ePtr = node.ePtr;
210         return result;
211     }
212     
213     visitConvertPtrToArrayRefExpression(node)
214     {
215         let result = new ConvertPtrToArrayRefExpression(node.origin, node.lValue.visit(this));
216         result.ePtr = node.ePtr;
217         return result;
218     }
219     
220     visitVariableRef(node)
221     {
222         let result = new VariableRef(node.origin, node.name);
223         result.variable = this._getMapping(node.variable);
224         return result;
225     }
226     
227     visitReturn(node)
228     {
229         return new Return(node.origin, Node.visit(node.value, this));
230     }
231     
232     visitContinue(node)
233     {
234         return new Continue(node.origin);
235     }
236     
237     visitBreak(node)
238     {
239         return new Break(node.origin);
240     }
241
242     visitTrapStatement(node)
243     {
244         return new TrapStatement(node.origin);
245     }
246     
247     visitGenericLiteral(node)
248     {
249         // FIXME: This doesn't seem right.
250         let result = new IntLiteral(node.origin, node.value);
251         result.type = node.type.visit(this);
252         result.ePtr = node.ePtr;
253         return result;
254     }
255     
256     visitGenericLiteralType(node)
257     {
258         let result = new node.constructor(node.origin, node.value);
259         result.type = Node.visit(node.type, this);
260         result.preferredType = node.preferredType.visit(this);
261         return result;
262     }
263
264     visitBoolLiteral(node)
265     {
266         return node;
267     }
268     
269     visitNullLiteral(node)
270     {
271         let result = new NullLiteral(node.origin);
272         result.type = node.type.visit(this);
273         result.ePtr = node.ePtr;
274         return result;
275     }
276     
277     visitNullType(node)
278     {
279         let result = new NullType(node.origin);
280         result.type = Node.visit(node.type, this);
281         return result;
282     }
283
284     processDerivedCallData(node, result)
285     {
286         let argumentTypes = node.argumentTypes;
287         if (argumentTypes)
288             result.argumentTypes = argumentTypes.map(argumentType => argumentType.visit(this));
289         result.func = node.func;
290         result.possibleOverloads = node.possibleOverloads;
291         if (node.isCast)
292             result.setCastData(node.returnType.visit(this));
293         result.resultType = Node.visit(node.resultType, this);
294         result.resultEPtr = node.resultEPtr;
295         return result;
296     }
297
298     visitCallExpression(node)
299     {
300         let result = new CallExpression(
301             node.origin, node.name,
302             node.argumentList.map(argument => Node.visit(argument, this)));
303         return this.processDerivedCallData(node, result);
304     }
305     
306     visitFunctionLikeBlock(node)
307     {
308         let result = new FunctionLikeBlock(
309             node.origin,
310             node.func.visit(this),
311             node.argumentList.map(arg => arg.visit(this))
312         );
313         result.returnEPtr = node.returnEPtr;
314         return result;
315     }
316     
317     visitLogicalNot(node)
318     {
319         let result = new LogicalNot(node.origin, node.operand.visit(this));
320         result.ePtr = node.ePtr;
321         return result;
322     }
323     
324     visitLogicalExpression(node)
325     {
326         let result = new LogicalExpression(node.origin, node.text, node.left.visit(this), node.right.visit(this));
327         result.ePtr = node.ePtr;
328         return result;
329     }
330
331     visitIfStatement(node)
332     {
333         return new IfStatement(node.origin, node.conditional.visit(this), node.body.visit(this), Node.visit(node.elseBody, this));
334     }
335
336     visitWhileLoop(node)
337     {
338         return new WhileLoop(node.origin, node.conditional.visit(this), node.body.visit(this));
339     }
340
341     visitDoWhileLoop(node)
342     {
343         return new DoWhileLoop(node.origin, node.body.visit(this), node.conditional.visit(this));
344     }
345
346     visitForLoop(node)
347     {
348         return new ForLoop(node.origin,
349             Node.visit(node.initialization, this),
350             Node.visit(node.condition, this),
351             Node.visit(node.increment, this),
352             node.body.visit(this));
353     }
354     
355     visitSwitchStatement(node)
356     {
357         let result = new SwitchStatement(node.origin, Node.visit(node.value, this));
358         for (let switchCase of node.switchCases)
359             result.add(switchCase.visit(this));
360         result.type = Node.visit(node.type, this);
361         return result;
362     }
363     
364     visitSwitchCase(node)
365     {
366         return new SwitchCase(node.origin, Node.visit(node.value, this), node.body.visit(this));
367     }
368     
369     visitAnonymousVariable(node)
370     {
371         let result = new AnonymousVariable(node.origin, Node.visit(node.type, this));
372         result._index = node._index;
373         this._mapNode(node, result);
374         result.ePtr = node.ePtr;
375         return result;
376     }
377     
378     visitIdentityExpression(node)
379     {
380         return new IdentityExpression(node.target.visit(this));
381     }
382
383     visitVectorType(node)
384     {
385         const vecType = new VectorType(node.origin, node.name);
386         vecType._elementType = node.elementType.visit(this);
387         return vecType;
388     }
389 }
390