WSL Node.prototype.visit should probably do memoization
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / Node.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 Node {
28     visit(visitor)
29     {
30         let memoTable = visitor._memoTable;
31         if (memoTable.has(this))
32             return memoTable.get(this);
33         
34         let visitFunc = visitor["visit" + this.constructor.name];
35         if (!visitFunc)
36             throw new Error("No visit function for " + this.constructor.name + " in " + visitor.constructor.name);
37         let returnValue = visitFunc.call(visitor, this);
38         if ("returnValue" in visitor)
39             returnValue = visitor.returnValue;
40         memoTable.set(this, returnValue);
41         return returnValue;
42     }
43     
44     unify(unificationContext, other)
45     {
46         if (!other)
47             throw new Error("Null other");
48         let unifyThis = this.unifyNode;
49         let unifyOther = other.unifyNode;
50         if (unifyThis == unifyOther)
51             return true;
52         if (unifyOther.typeVariableUnify(unificationContext, unifyThis))
53             return true;
54         return unifyThis.unifyImpl(unificationContext, unifyOther);
55     }
56     
57     unifyImpl(unificationContext, other)
58     {
59         if (other.typeVariableUnify(unificationContext, this))
60             return true;
61         return this == other;
62     }
63     
64     typeVariableUnify(unificationContext, other)
65     {
66         return false;
67     }
68     
69     _typeVariableUnifyImpl(unificationContext, other)
70     {
71         let realThis = unificationContext.find(this);
72         if (realThis != this)
73             return realThis.unify(unificationContext, other);
74         
75         unificationContext.union(this, other);
76         return true;
77     }
78     
79     // Most type variables don't care about this.
80     commitUnification(unificatoinContext) { }
81     
82     get unifyNode() { return this; }
83     get isUnifiable() { return false; }
84     
85     get isNative() { return false; }
86     
87     equals(other)
88     {
89         let unificationContext = new UnificationContext();
90         if (this.unify(unificationContext, other) && unificationContext.verify())
91             return unificationContext;
92         return false;
93     }
94     
95     equalsWithCommit(other)
96     {
97         let unificationContext = this.equals(other);
98         if (!unificationContext)
99             return false;
100         unificationContext.commit();
101         return unificationContext;
102     }
103     
104     substitute(parameters, argumentList)
105     {
106         return this.visit(new Substitution(parameters, argumentList));
107     }
108     
109     substituteToUnification(parameters, unificationContext)
110     {
111         return this.substitute(parameters, parameters.map(type => unificationContext.find(type)));
112     }
113 }