Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / ARES-6 / Basic / ast.js
1 /*
2  * Copyright (C) 2016 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 const Basic = {};
28
29 Basic.NumberApply = function(state)
30 {
31     // I'd call this arguments but we're in strict mode.
32     let parameters = this.parameters.map(value => value.evaluate(state));
33     
34     return state.getValue(this.name, parameters.length).apply(state, parameters);
35 };
36
37 Basic.Variable = function(state)
38 {
39     let parameters = this.parameters.map(value => value.evaluate(state));
40     
41     return state.getValue(this.name, parameters.length).leftApply(state, parameters);
42 }
43
44 Basic.Const = function(state)
45 {
46     return this.value;
47 }
48
49 Basic.NumberPow = function(state)
50 {
51     return Math.pow(this.left.evaluate(state), this.right.evaluate(state));
52 }
53
54 Basic.NumberMul = function(state)
55 {
56     return this.left.evaluate(state) * this.right.evaluate(state);
57 }
58
59 Basic.NumberDiv = function(state)
60 {
61     return this.left.evaluate(state) / this.right.evaluate(state);
62 }
63
64 Basic.NumberNeg = function(state)
65 {
66     return -this.term.evaluate(state);
67 }
68
69 Basic.NumberAdd = function(state)
70 {
71     return this.left.evaluate(state) + this.right.evaluate(state);
72 }
73
74 Basic.NumberSub = function(state)
75 {
76     return this.left.evaluate(state) - this.right.evaluate(state);
77 }
78
79 Basic.StringVar = function(state)
80 {
81     let value = state.stringValues.get(this.name);
82     if (value == null)
83         state.abort("Could not find string variable " + this.name);
84     return value;
85 }
86
87 Basic.Equals = function(state)
88 {
89     return this.left.evaluate(state) == this.right.evaluate(state);
90 }
91
92 Basic.NotEquals = function(state)
93 {
94     return this.left.evaluate(state) != this.right.evaluate(state);
95 }
96
97 Basic.LessThan = function(state)
98 {
99     return this.left.evaluate(state) < this.right.evaluate(state);
100 }
101
102 Basic.GreaterThan = function(state)
103 {
104     return this.left.evaluate(state) > this.right.evaluate(state);
105 }
106
107 Basic.LessEqual = function(state)
108 {
109     return this.left.evaluate(state) <= this.right.evaluate(state);
110 }
111
112 Basic.GreaterEqual = function(state)
113 {
114     return this.left.evaluate(state) >= this.right.evaluate(state);
115 }
116
117 Basic.GoTo = function*(state)
118 {
119     state.nextLineNumber = this.target;
120 }
121
122 Basic.GoSub = function*(state)
123 {
124     state.subStack.push(state.nextLineNumber);
125     state.nextLineNumber = this.target;
126 }
127
128 Basic.Def = function*(state)
129 {
130     state.validate(!state.values.has(this.name), "Cannot redefine function");
131     state.values.set(this.name, new NumberFunction(this.parameters, this.expression));
132 }
133
134 Basic.Let = function*(state)
135 {
136     this.variable.evaluate(state).assign(this.expression.evaluate(state));
137 }
138
139 Basic.If = function*(state)
140 {
141     if (this.condition.evaluate(state))
142         state.nextLineNumber = this.target;
143 }
144
145 Basic.Return = function*(state)
146 {
147     this.validate(state.subStack.length, "Not in a subroutine");
148     this.nextLineNumber = state.subStack.pop();
149 }
150
151 Basic.Stop = function*(state)
152 {
153     state.nextLineNumber = null;
154 }
155
156 Basic.On = function*(state)
157 {
158     let index = this.expression.evaluate(state);
159     if (!(index >= 1) || !(index <= this.targets.length))
160         state.abort("Index out of bounds: " + index);
161     this.nextLineNumber = this.targets[Math.floor(index)];
162 }
163
164 Basic.For = function*(state)
165 {
166     let sideState = state.getSideState(this);
167     sideState.variable = state.getValue(this.variable, 0).leftApply(state, []);
168     sideState.initialValue = this.initial.evaluate(state);
169     sideState.limitValue = this.limit.evaluate(state);
170     sideState.stepValue = this.step.evaluate(state);
171     sideState.variable.assign(sideState.initialValue);
172     sideState.shouldStop = function() {
173         return (sideState.variable.value - sideState.limitValue) * Math.sign(sideState.stepValue) > 0;
174     };
175     if (sideState.shouldStop())
176         this.nextLineNumber = this.target.lineNumber + 1;
177 }
178
179 Basic.Next = function*(state)
180 {
181     let sideState = state.getSideState(this.target);
182     sideState.variable.assign(sideState.variable.value + sideState.stepValue);
183     if (sideState.shouldStop())
184         return;
185     state.nextLineNumber = this.target.lineNumber + 1;
186 }
187
188 Basic.Next.isBlockEnd = true;
189
190 Basic.Print = function*(state)
191 {
192     let string = "";
193     for (let item of this.items) {
194         switch (item.kind) {
195         case "comma":
196             while (string.length % 14)
197                 string += " ";
198             break;
199         case "tab": {
200             let value = item.value.evaluate(state);
201             value = Math.max(Math.round(value), 1);
202             while (string.length % value)
203                 string += " ";
204             break;
205         }
206         case "string":
207         case "number":
208             string += item.value.evaluate(state);
209             break;
210         default:
211             throw new Error("Bad item kind: " + item.kind);
212         }
213     }
214     
215     yield {kind: "output", string};
216 }
217
218 Basic.Input = function*(state)
219 {
220     let results = yield {kind: "input", numItems: this.items.length};
221     state.validate(results != null && results.length == this.items.length, "Input did not get the right number of items");
222     for (let i = 0; i < results.length; ++i)
223         this.items[i].evaluate(state).assign(results[i]);
224 }
225
226 Basic.Read = function*(state)
227 {
228     for (let item of this.items) {
229         state.validate(state.dataIndex < state.program.data.length, "Attempting to read past the end of data");
230         item.assign(state.program.data[state.dataIndex++]);
231     }
232 }
233
234 Basic.Restore = function*(state)
235 {
236     state.dataIndex = 0;
237 }
238
239 Basic.Dim = function*(state)
240 {
241     for (let item of this.items) {
242         state.validate(!state.values.has(item.name), "Variable " + item.name + " already exists");
243         state.validate(item.bounds.length, "Dim statement is for arrays");
244         state.values.set(item.name, new NumberArray(item.bounds.map(bound => bound + 1)));
245     }
246 }
247
248 Basic.Randomize = function*(state)
249 {
250     state.rng = createRNGWithRandomSeed();
251 }
252
253 Basic.End = function*(state)
254 {
255     state.nextLineNumber = null;
256 }
257
258 Basic.End.isBlockEnd = true;
259
260 Basic.Program = function* programGenerator(state)
261 {
262     state.validate(state.program == this, "State must match program");
263     let maxLineNumber = Math.max(...this.statements.keys());
264     while (state.nextLineNumber != null) {
265         state.validate(state.nextLineNumber <= maxLineNumber, "Went out of bounds of the program");
266         let statement = this.statements.get(state.nextLineNumber++);
267         if (statement == null || statement.process == null)
268             continue;
269         state.statement = statement;
270         yield* statement.process(state);
271     }
272 }
273