e6a7da057b1ab73f35a1bba026e5e0d7e1abb613
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / FuncInstantiator.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 class FuncInstantiator {
28     constructor(program)
29     {
30         this._program = program;
31         this._instances = new Map();
32     }
33     
34     // Returns a Func object that uniquely identifies a particular system of type arguments. You must
35     // intantiate things with concrete types, because this code casually assumes this. Note that this
36     // will return a different func from `func` no matter what. This ensures that we can use the
37     // returned func for rewrites that instantiate types without destroying our ability to do overload
38     // resolutions on the original Program.
39     getUnique(func, typeArguments)
40     {
41         let instances = this._instances.get(func);
42         if (!instances)
43             this._instances.set(func, instances = []);
44         
45         for (let instance of instances) {
46             let ok = true;
47             for (let i = instance.typeArguments.length; i--;) {
48                 if (!instance.typeArguments[i].equals(typeArguments[i])) {
49                     ok = false;
50                     break;
51                 }
52             }
53             if (!ok)
54                 continue;
55             return instance.func;
56         }
57         
58         let thisInstantiator = this;
59         class InstantiationSubstitution extends Substitution {
60             visitCallExpression(node)
61             {
62                 let result = super.visitCallExpression(node);
63                 
64                 // We may have to re-resolve the function call, if it was a call to a protocol
65                 // signature.
66                 if (result.func instanceof ProtocolFuncDecl) {
67                     let overload = thisInstantiator._program.resolveFuncOverload(result.name, result.typeArguments, result.argumentTypes);
68                     if (!overload.func)
69                         throw new Error("Could not resolve protocol signature function call during instantiation: " + result.func + (overload.failures.length ? "; tried:\n" + overload.failures.join("\n") : ""));
70                     result.resolve(overload);
71                 }
72                 
73                 return result;
74             }
75         }
76         
77         let substitution = new InstantiationSubstitution(func.typeParameters, typeArguments);
78         
79         class Instantiate {
80             visitFuncDef(func)
81             {
82                 return new FuncDef(
83                     func.origin, func.name,
84                     func.returnType.visit(substitution),
85                     [], // We're instantiated so we no longer take type parameters.
86                     func.parameters.map(parameter => parameter.visit(substitution)),
87                     func.body.visit(substitution));
88             }
89             
90             visitNativeFunc(func)
91             {
92                 return new NativeFuncInstance(
93                     func,
94                     func.returnType.visit(substitution),
95                     func.parameters.map(parameter => parameter.visit(substitution)),
96                     func.isCast);
97             }
98         }
99         let resultingFunc = func.visit(new Instantiate());
100         let instance = {func: resultingFunc, typeArguments};
101         instances.push(instance);
102         return resultingFunc;
103     }
104 }
105