6dba1532946cda78d7955c564bacccb68230762c
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / CallExpression.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 class CallExpression extends Expression {
28     constructor(origin, name, typeArguments, argumentList)
29     {
30         super(origin);
31         this._name = name;
32         this._typeArguments = typeArguments;
33         this._argumentList = argumentList;
34         this.func = null;
35         this._isCast = false;
36         this._returnType = null;
37     }
38     
39     get name() { return this._name; }
40     get typeArguments() { return this._typeArguments; }
41     get argumentList() { return this._argumentList; }
42     get isCast() { return this._isCast; }
43     get returnType() { return this._returnType; }
44     
45     static resolve(origin, possibleOverloads, name, argumentList, argumentTypes, returnType, program)
46     {
47         let call = new CallExpression(origin, name, [], argumentList);
48         call.argumentTypes = argumentTypes.map(argument => argument.visit(new AutoWrapper()));
49         call.possibleOverloads = possibleOverloads;
50         if (returnType)
51             call.setCastData(returnType);
52         return {call, resultType: call.resolve(possibleOverloads, program)};
53     }
54
55     resolve(possibleOverloads, program)
56     {
57         if (!possibleOverloads)
58             throw new WTypeError(this.origin.originString, "Did not find any functions named " + this.name);
59
60         let failures = [];
61         let overload = resolveOverloadImpl(possibleOverloads, this.argumentTypes, this.returnType);
62
63         if (!overload.func) {
64             const func = this._resolveByInstantiation(program);
65             if (func)
66                 overload.func = func;
67         }
68
69
70         if (!overload.func) {
71             failures.push(...overload.failures);
72             let message = "Did not find function named " + this.name + " for call with ";
73             message += "argument types (" + this.argumentTypes + ")";
74             if (this.returnType)
75                 message +=" and return type " + this.returnType;
76             if (failures.length)
77                 message += ", but considered:\n" + failures.join("\n")
78             throw new WTypeError(this.origin.originString, message);
79         }
80
81         for (let i = 0; i < this.argumentTypes.length; ++i) {
82             let argumentType = this.argumentTypes[i];
83             let parameterType = overload.func.parameters[i].type;
84             let result = argumentType.equalsWithCommit(parameterType);
85             if (!result)
86                 throw new Error("At " + this.origin.originString + " argument and parameter types not equal after type argument substitution: argument = " + argumentType + ", parameter = " + parameterType);
87         }
88         return this.resolveToOverload(overload);
89     }
90
91     _resolveByInstantiation(program)
92     {
93         let func;
94         if (this.name == "operator&[]")
95             func = this._resolveWithOperatorAnderIndexer(program);
96         else if (this.name == "operator.length")
97             func = this._resolveWithOperatorLength(program);
98         else
99             return null;
100
101         program.add(func);
102         return func;
103     }
104
105     _resolveWithOperatorAnderIndexer(program)
106     {
107         let arrayRefType = this.argumentTypes[0];
108         if (!arrayRefType.isArrayRef)
109             throw new WTypeError(this.origin.originString, `Expected ${arrayRefType} to be an array ref type for operator&[]`);
110
111         let indexType = this.argumentTypes[1];
112         const addressSpace = arrayRefType.addressSpace;
113
114         // The later checkLiteralTypes stage will verify that the literal can be represented as a uint.
115         const uintType = TypeRef.wrap(program.types.get("uint"));
116         indexType.type = uintType;
117
118         const elementType = this.argumentTypes[0].elementType;
119         this.resultType = this._returnType = TypeRef.wrap(new PtrType(this.origin, addressSpace, TypeRef.wrap(elementType)))
120
121         let arrayRefAccessor = new OperatorAnderIndexer(this.returnType.toString(), addressSpace);
122         const func = new NativeFunc(this.origin, "operator&[]", this.resultType, [
123             new FuncParameter(this.origin, null, arrayRefType),
124             new FuncParameter(this.origin, null, uintType)
125         ], false, null);
126
127         arrayRefAccessor.instantiateImplementation(func);
128
129         return func;
130     }
131
132     _resolveWithOperatorLength(program)
133     {
134         this.resultType = this._returnType = TypeRef.wrap(program.types.get("uint"));
135
136         if (this.argumentTypes[0].isArray) {
137             const arrayType = this.argumentTypes[0];
138             const func = new NativeFunc(this.origin, "operator.length", this.resultType, [
139                 new FuncParameter(this.origin, null, arrayType)
140             ], false, null);
141             func.implementation = (args, node) => EPtr.box(arrayType.numElementsValue);
142             return func;
143         } else if (this.argumentTypes[0].isArrayRef) {
144             const arrayRefType = this.argumentTypes[0];
145             const addressSpace = arrayRefType.addressSpace;
146             const operatorLength = new OperatorArrayRefLength(arrayRefType.toString(), addressSpace);
147             const func = new NativeFunc(this.origin, "operator.length", this.resultType, [
148                 new FuncParameter(this.origin, null, arrayRefType)
149             ], false, null);
150             operatorLength.instantiateImplementation(func);
151             return func;
152         } else
153             throw new WTypeError(this.origin.originString, `Expected ${this.argumentTypes[0]} to be array/array ref type for operator.length`);
154     }
155     
156     resolveToOverload(overload)
157     {
158         this.func = overload.func;
159         let result = overload.func.returnType;
160         if (!result)
161             throw new Error("Null return type");
162         result = result.visit(new AutoWrapper());
163         this.resultType = result;
164         return result;
165     }
166     
167     becomeCast(returnType)
168     {
169         this._returnType = new TypeRef(this.origin, this.name);
170         this._returnType.type = returnType;
171         this._name = "operator cast";
172         this._isCast = true;
173     }
174     
175     setCastData(returnType)
176     {
177         this._returnType = returnType;
178         this._isCast = true;
179     }
180     
181     toString()
182     {
183         return (this.isCast ? "operator " + this.returnType : this.name) +
184             "(" + this.argumentList + ")";
185     }
186 }
187