ember-source 5.6.0-alpha.2 → 5.6.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build-metadata.json +3 -3
- package/dist/dependencies/@glimmer/debug.js +1533 -0
- package/dist/dependencies/@glimmer/destroyable.js +30 -59
- package/dist/dependencies/@glimmer/encoder.js +13 -24
- package/dist/dependencies/@glimmer/global-context.js +38 -41
- package/dist/dependencies/@glimmer/manager.js +144 -326
- package/dist/dependencies/@glimmer/node.js +14 -46
- package/dist/dependencies/@glimmer/opcode-compiler.js +1673 -2478
- package/dist/dependencies/@glimmer/owner.js +2 -5
- package/dist/dependencies/@glimmer/program.js +102 -185
- package/dist/dependencies/@glimmer/reference.js +58 -126
- package/dist/dependencies/@glimmer/runtime.js +4674 -5639
- package/dist/dependencies/@glimmer/util.js +340 -326
- package/dist/dependencies/@glimmer/validator.js +160 -217
- package/dist/dependencies/@glimmer/vm.js +174 -23
- package/dist/dependencies/@glimmer/wire-format.js +91 -34
- package/dist/dependencies/@simple-dom/document.js +1 -1
- package/dist/dependencies/backburner.js.js +1 -1
- package/dist/dependencies/router_js.js +15 -16
- package/dist/dependencies/rsvp.js +89 -88
- package/dist/ember-template-compiler.js +8574 -8350
- package/dist/ember-template-compiler.map +1 -1
- package/dist/ember-testing.js +107 -107
- package/dist/ember-testing.map +1 -1
- package/dist/ember.debug.js +11216 -9634
- package/dist/ember.debug.map +1 -1
- package/dist/header/license.js +1 -1
- package/dist/packages/@ember/-internals/glimmer/index.js +109 -80
- package/dist/packages/@ember/-internals/metal/index.js +5 -4
- package/dist/packages/@ember/-internals/utils/index.js +3 -4
- package/dist/packages/@ember/array/-internals.js +1 -2
- package/dist/packages/@ember/debug/lib/inspect.js +0 -1
- package/dist/packages/@ember/object/core.js +0 -1
- package/dist/packages/@ember/object/mixin.js +1 -2
- package/dist/packages/@ember/routing/route.js +23 -101
- package/dist/packages/@ember/routing/router.js +25 -84
- package/dist/packages/ember/version.js +1 -1
- package/dist/packages/ember-babel.js +13 -0
- package/docs/data.json +217 -242
- package/lib/index.js +1 -5
- package/package.json +26 -21
- package/types/stable/@ember/-internals/glimmer/index.d.ts +1 -1
- package/types/stable/@ember/-internals/glimmer/lib/component-managers/curly.d.ts +4 -4
- package/types/stable/@ember/-internals/glimmer/lib/component-managers/mount.d.ts +3 -3
- package/types/stable/@ember/-internals/glimmer/lib/component-managers/outlet.d.ts +5 -8
- package/types/stable/@ember/-internals/glimmer/lib/component-managers/root.d.ts +3 -3
- package/types/stable/@ember/-internals/glimmer/lib/renderer.d.ts +3 -3
- package/types/stable/@ember/-internals/glimmer/lib/resolver.d.ts +3 -3
- package/types/stable/@ember/-internals/glimmer/lib/syntax/utils.d.ts +3 -2
- package/types/stable/@ember/-internals/glimmer/lib/utils/iterator.d.ts +2 -2
- package/types/stable/@ember/-internals/glimmer/lib/utils/outlet.d.ts +39 -18
- package/types/stable/@ember/-internals/utility-types/index.d.ts +1 -0
- package/types/stable/@ember/-internals/views/lib/system/utils.d.ts +4 -3
- package/types/stable/@ember/routing/route.d.ts +6 -28
- package/dist/dependencies/@glimmer/low-level.js +0 -77
|
@@ -1,1807 +1,524 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { assert, deprecate } from '@glimmer/global-context';
|
|
1
|
+
import { EMPTY_STRING_ARRAY, isSmallInt, encodeImmediate, unwrap, reverse, assert as assert$1, Stack, isPresentArray, encodeHandle, expect, assign, dict, enumerate, EMPTY_ARRAY, debugToString } from '@glimmer/util';
|
|
2
|
+
import '@glimmer/debug';
|
|
3
|
+
import { Op, MachineOp, $v0, $fp, $sp, InternalComponentCapabilities, $s0, ContentType, TYPE_SIZE, isMachineOp, MACHINE_MASK, $s1, ARG_SHIFT } from '@glimmer/vm';
|
|
5
4
|
import { DEBUG } from '@glimmer/env';
|
|
6
5
|
import { InstructionEncoderImpl } from '@glimmer/encoder';
|
|
6
|
+
import { SexpOpcodes } from '@glimmer/wire-format';
|
|
7
|
+
import { hasCapability } from '@glimmer/manager';
|
|
8
|
+
import { assert, deprecate } from '@glimmer/global-context';
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
constructor(blocks) {
|
|
10
|
-
this.blocks = blocks;
|
|
11
|
-
this.names = blocks ? Object.keys(blocks) : [];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get(name) {
|
|
15
|
-
if (!this.blocks) return null;
|
|
16
|
-
return this.blocks[name] || null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
has(name) {
|
|
20
|
-
let {
|
|
21
|
-
blocks
|
|
22
|
-
} = this;
|
|
23
|
-
return blocks !== null && name in blocks;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
with(name, block) {
|
|
27
|
-
let {
|
|
28
|
-
blocks
|
|
29
|
-
} = this;
|
|
30
|
-
|
|
31
|
-
if (blocks) {
|
|
32
|
-
return new NamedBlocksImpl(assign({}, blocks, {
|
|
33
|
-
[name]: block
|
|
34
|
-
}));
|
|
35
|
-
} else {
|
|
36
|
-
return new NamedBlocksImpl({
|
|
37
|
-
[name]: block
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
get hasAny() {
|
|
43
|
-
return this.blocks !== null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
const EMPTY_BLOCKS = new NamedBlocksImpl(null);
|
|
48
|
-
function namedBlocks(blocks) {
|
|
49
|
-
if (blocks === null) {
|
|
50
|
-
return EMPTY_BLOCKS;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let out = dict();
|
|
54
|
-
let [keys, values] = blocks;
|
|
55
|
-
|
|
56
|
-
for (let i = 0; i < keys.length; i++) {
|
|
57
|
-
out[keys[i]] = values[i];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return new NamedBlocksImpl(out);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function labelOperand(value) {
|
|
64
|
-
return {
|
|
65
|
-
type: 1
|
|
66
|
-
/* Label */
|
|
67
|
-
,
|
|
68
|
-
value
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function evalSymbolsOperand() {
|
|
72
|
-
return {
|
|
73
|
-
type: 3
|
|
74
|
-
/* EvalSymbols */
|
|
75
|
-
,
|
|
76
|
-
value: undefined
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function isStrictMode() {
|
|
80
|
-
return {
|
|
81
|
-
type: 2
|
|
82
|
-
/* IsStrictMode */
|
|
83
|
-
,
|
|
84
|
-
value: undefined
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
function blockOperand(value) {
|
|
88
|
-
return {
|
|
89
|
-
type: 4
|
|
90
|
-
/* Block */
|
|
91
|
-
,
|
|
92
|
-
value
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function stdlibOperand(value) {
|
|
96
|
-
return {
|
|
97
|
-
type: 5
|
|
98
|
-
/* StdLib */
|
|
99
|
-
,
|
|
100
|
-
value
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
function nonSmallIntOperand(value) {
|
|
104
|
-
return {
|
|
105
|
-
type: 6
|
|
106
|
-
/* NonSmallInt */
|
|
107
|
-
,
|
|
108
|
-
value
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function symbolTableOperand(value) {
|
|
112
|
-
return {
|
|
113
|
-
type: 7
|
|
114
|
-
/* SymbolTable */
|
|
115
|
-
,
|
|
116
|
-
value
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function layoutOperand(value) {
|
|
120
|
-
return {
|
|
121
|
-
type: 8
|
|
122
|
-
/* Layout */
|
|
123
|
-
,
|
|
124
|
-
value
|
|
125
|
-
};
|
|
126
|
-
}
|
|
10
|
+
let debugCompiler;
|
|
127
11
|
|
|
128
12
|
function isGetLikeTuple(opcode) {
|
|
129
13
|
return Array.isArray(opcode) && opcode.length === 2;
|
|
130
14
|
}
|
|
131
|
-
|
|
132
15
|
function makeResolutionTypeVerifier(typeToVerify) {
|
|
133
16
|
return opcode => {
|
|
134
17
|
if (!isGetLikeTuple(opcode)) return false;
|
|
135
18
|
let type = opcode[0];
|
|
136
|
-
return type ===
|
|
137
|
-
/* GetStrictFree */
|
|
138
|
-
|| type === 32
|
|
139
|
-
/* GetTemplateSymbol */
|
|
140
|
-
|| type === typeToVerify;
|
|
19
|
+
return type === SexpOpcodes.GetStrictKeyword || type === SexpOpcodes.GetLexicalSymbol || type === typeToVerify;
|
|
141
20
|
};
|
|
142
21
|
}
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
);
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
);
|
|
153
|
-
const isGetFreeComponentOrHelper = makeResolutionTypeVerifier(35
|
|
154
|
-
/* GetFreeAsComponentOrHelperHead */
|
|
155
|
-
);
|
|
156
|
-
const isGetFreeOptionalComponentOrHelper = makeResolutionTypeVerifier(34
|
|
157
|
-
/* GetFreeAsComponentOrHelperHeadOrThisFallback */
|
|
158
|
-
);
|
|
159
|
-
|
|
22
|
+
const isGetFreeComponent = makeResolutionTypeVerifier(SexpOpcodes.GetFreeAsComponentHead);
|
|
23
|
+
const isGetFreeModifier = makeResolutionTypeVerifier(SexpOpcodes.GetFreeAsModifierHead);
|
|
24
|
+
const isGetFreeHelper = makeResolutionTypeVerifier(SexpOpcodes.GetFreeAsHelperHead);
|
|
25
|
+
const isGetFreeComponentOrHelper = makeResolutionTypeVerifier(SexpOpcodes.GetFreeAsComponentOrHelperHead);
|
|
26
|
+
const isGetFreeOptionalHelper = makeResolutionTypeVerifier(SexpOpcodes.GetFreeAsHelperHeadOrThisFallback);
|
|
27
|
+
function isGetFreeDeprecatedHelper(opcode) {
|
|
28
|
+
return Array.isArray(opcode) && opcode[0] === SexpOpcodes.GetFreeAsDeprecatedHelperHeadOrThisFallback;
|
|
29
|
+
}
|
|
30
|
+
const isGetFreeOptionalComponentOrHelper = makeResolutionTypeVerifier(SexpOpcodes.GetFreeAsComponentOrHelperHeadOrThisFallback);
|
|
160
31
|
function assertResolverInvariants(meta) {
|
|
161
32
|
if (DEBUG) {
|
|
162
33
|
if (!meta.upvars) {
|
|
163
34
|
throw new Error('Attempted to resolve a component, helper, or modifier, but no free vars were found');
|
|
164
35
|
}
|
|
165
|
-
|
|
166
36
|
if (!meta.owner) {
|
|
167
37
|
throw new Error('Attempted to resolve a component, helper, or modifier, but no owner was associated with the template it was being resolved from');
|
|
168
38
|
}
|
|
169
39
|
}
|
|
170
|
-
|
|
171
40
|
return meta;
|
|
172
41
|
}
|
|
42
|
+
|
|
173
43
|
/**
|
|
174
44
|
* <Foo/>
|
|
175
45
|
* <Foo></Foo>
|
|
176
46
|
* <Foo @arg={{true}} />
|
|
177
47
|
*/
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
48
|
+
function resolveComponent(resolver, constants, meta, _ref) {
|
|
49
|
+
let [, expr, then] = _ref;
|
|
50
|
+
assert$1(isGetFreeComponent(expr), 'Attempted to resolve a component with incorrect opcode');
|
|
181
51
|
let type = expr[0];
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
scopeValues,
|
|
194
|
-
owner
|
|
195
|
-
} = meta;
|
|
196
|
-
let definition = scopeValues[expr[1]];
|
|
197
|
-
then(constants.component(definition, owner));
|
|
198
|
-
} else {
|
|
52
|
+
if (DEBUG && expr[0] === SexpOpcodes.GetStrictKeyword) {
|
|
53
|
+
throw new Error(`Attempted to resolve a component in a strict mode template, but that value was not in scope: ${meta.upvars[expr[1]] ?? '{unknown variable}'}`);
|
|
54
|
+
}
|
|
55
|
+
if (type === SexpOpcodes.GetLexicalSymbol) {
|
|
56
|
+
let {
|
|
57
|
+
scopeValues,
|
|
58
|
+
owner
|
|
59
|
+
} = meta;
|
|
60
|
+
let definition = expect(scopeValues, 'BUG: scopeValues must exist if template symbol is used')[expr[1]];
|
|
61
|
+
then(constants.component(definition, expect(owner, 'BUG: expected owner when resolving component definition')));
|
|
62
|
+
} else {
|
|
199
63
|
let {
|
|
200
64
|
upvars,
|
|
201
65
|
owner
|
|
202
66
|
} = assertResolverInvariants(meta);
|
|
203
|
-
let name = upvars[expr[1]];
|
|
67
|
+
let name = unwrap(upvars[expr[1]]);
|
|
204
68
|
let definition = resolver.lookupComponent(name, owner);
|
|
205
|
-
|
|
206
69
|
if (DEBUG && (typeof definition !== 'object' || definition === null)) {
|
|
207
70
|
throw new Error(`Attempted to resolve \`${name}\`, which was expected to be a component, but nothing was found.`);
|
|
208
71
|
}
|
|
209
|
-
|
|
210
72
|
then(constants.resolvedComponent(definition, name));
|
|
211
73
|
}
|
|
212
74
|
}
|
|
75
|
+
|
|
213
76
|
/**
|
|
214
77
|
* (helper)
|
|
215
78
|
* (helper arg)
|
|
216
79
|
*/
|
|
217
|
-
|
|
218
|
-
|
|
80
|
+
function resolveHelper(resolver, constants, meta, _ref2) {
|
|
81
|
+
let [, expr, then] = _ref2;
|
|
82
|
+
assert$1(isGetFreeHelper(expr), 'Attempted to resolve a helper with incorrect opcode');
|
|
219
83
|
let type = expr[0];
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
} else if (type === 31
|
|
230
|
-
/* GetStrictFree */
|
|
231
|
-
) {
|
|
232
|
-
then(lookupBuiltInHelper(expr, resolver, meta, constants, 'helper'));
|
|
233
|
-
} else {
|
|
84
|
+
if (type === SexpOpcodes.GetLexicalSymbol) {
|
|
85
|
+
let {
|
|
86
|
+
scopeValues
|
|
87
|
+
} = meta;
|
|
88
|
+
let definition = expect(scopeValues, 'BUG: scopeValues must exist if template symbol is used')[expr[1]];
|
|
89
|
+
then(constants.helper(definition));
|
|
90
|
+
} else if (type === SexpOpcodes.GetStrictKeyword) {
|
|
91
|
+
then(lookupBuiltInHelper(expr, resolver, meta, constants, 'helper'));
|
|
92
|
+
} else {
|
|
234
93
|
let {
|
|
235
94
|
upvars,
|
|
236
95
|
owner
|
|
237
96
|
} = assertResolverInvariants(meta);
|
|
238
|
-
let name = upvars[expr[1]];
|
|
97
|
+
let name = unwrap(upvars[expr[1]]);
|
|
239
98
|
let helper = resolver.lookupHelper(name, owner);
|
|
240
|
-
|
|
241
99
|
if (DEBUG && helper === null) {
|
|
242
100
|
throw new Error(`Attempted to resolve \`${name}\`, which was expected to be a helper, but nothing was found.`);
|
|
243
101
|
}
|
|
244
|
-
|
|
245
102
|
then(constants.helper(helper, name));
|
|
246
103
|
}
|
|
247
104
|
}
|
|
105
|
+
|
|
248
106
|
/**
|
|
249
107
|
* <div {{modifier}}/>
|
|
250
108
|
* <div {{modifier arg}}/>
|
|
251
109
|
* <Foo {{modifier}}/>
|
|
252
110
|
*/
|
|
253
|
-
|
|
254
|
-
|
|
111
|
+
function resolveModifier(resolver, constants, meta, _ref3) {
|
|
112
|
+
let [, expr, then] = _ref3;
|
|
113
|
+
assert$1(isGetFreeModifier(expr), 'Attempted to resolve a modifier with incorrect opcode');
|
|
255
114
|
let type = expr[0];
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (DEBUG && modifier === null) {
|
|
275
|
-
throw new Error(`Attempted to resolve a modifier in a strict mode template, but it was not in scope: ${name}`);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
then(constants.modifier(modifier, name));
|
|
279
|
-
} else {
|
|
115
|
+
if (type === SexpOpcodes.GetLexicalSymbol) {
|
|
116
|
+
let {
|
|
117
|
+
scopeValues
|
|
118
|
+
} = meta;
|
|
119
|
+
let definition = expect(scopeValues, 'BUG: scopeValues must exist if template symbol is used')[expr[1]];
|
|
120
|
+
then(constants.modifier(definition));
|
|
121
|
+
} else if (type === SexpOpcodes.GetStrictKeyword) {
|
|
122
|
+
let {
|
|
123
|
+
upvars
|
|
124
|
+
} = assertResolverInvariants(meta);
|
|
125
|
+
let name = unwrap(upvars[expr[1]]);
|
|
126
|
+
let modifier = resolver.lookupBuiltInModifier(name);
|
|
127
|
+
if (DEBUG && modifier === null) {
|
|
128
|
+
throw new Error(`Attempted to resolve a modifier in a strict mode template, but it was not in scope: ${name}`);
|
|
129
|
+
}
|
|
130
|
+
then(constants.modifier(modifier, name));
|
|
131
|
+
} else {
|
|
280
132
|
let {
|
|
281
133
|
upvars,
|
|
282
134
|
owner
|
|
283
135
|
} = assertResolverInvariants(meta);
|
|
284
|
-
let name = upvars[expr[1]];
|
|
136
|
+
let name = unwrap(upvars[expr[1]]);
|
|
285
137
|
let modifier = resolver.lookupModifier(name, owner);
|
|
286
|
-
|
|
287
138
|
if (DEBUG && modifier === null) {
|
|
288
139
|
throw new Error(`Attempted to resolve \`${name}\`, which was expected to be a modifier, but nothing was found.`);
|
|
289
140
|
}
|
|
290
|
-
|
|
291
141
|
then(constants.modifier(modifier, name));
|
|
292
142
|
}
|
|
293
143
|
}
|
|
144
|
+
|
|
294
145
|
/**
|
|
295
146
|
* {{component-or-helper arg}}
|
|
296
147
|
*/
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}]
|
|
148
|
+
function resolveComponentOrHelper(resolver, constants, meta, _ref4) {
|
|
149
|
+
let [, expr, {
|
|
150
|
+
ifComponent,
|
|
151
|
+
ifHelper
|
|
152
|
+
}] = _ref4;
|
|
153
|
+
assert$1(isGetFreeComponentOrHelper(expr), 'Attempted to resolve a component or helper with incorrect opcode');
|
|
302
154
|
let type = expr[0];
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
throw new Error(`Attempted to use a value as either a component or helper, but it did not have a component manager or helper manager associated with it. The value was: ${debugToString(definition)}`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
ifHelper(helper);
|
|
326
|
-
} else if (type === 31
|
|
327
|
-
/* GetStrictFree */
|
|
328
|
-
) {
|
|
329
|
-
ifHelper(lookupBuiltInHelper(expr, resolver, meta, constants, 'component or helper'));
|
|
330
|
-
} else {
|
|
155
|
+
if (type === SexpOpcodes.GetLexicalSymbol) {
|
|
156
|
+
let {
|
|
157
|
+
scopeValues,
|
|
158
|
+
owner
|
|
159
|
+
} = meta;
|
|
160
|
+
let definition = expect(scopeValues, 'BUG: scopeValues must exist if template symbol is used')[expr[1]];
|
|
161
|
+
let component = constants.component(definition, expect(owner, 'BUG: expected owner when resolving component definition'), true);
|
|
162
|
+
if (component !== null) {
|
|
163
|
+
ifComponent(component);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
let helper = constants.helper(definition, null, true);
|
|
167
|
+
if (DEBUG && helper === null) {
|
|
168
|
+
throw new Error(`Attempted to use a value as either a component or helper, but it did not have a component manager or helper manager associated with it. The value was: ${debugToString(definition)}`);
|
|
169
|
+
}
|
|
170
|
+
ifHelper(expect(helper, 'BUG: helper must exist'));
|
|
171
|
+
} else if (type === SexpOpcodes.GetStrictKeyword) {
|
|
172
|
+
ifHelper(lookupBuiltInHelper(expr, resolver, meta, constants, 'component or helper'));
|
|
173
|
+
} else {
|
|
331
174
|
let {
|
|
332
175
|
upvars,
|
|
333
176
|
owner
|
|
334
177
|
} = assertResolverInvariants(meta);
|
|
335
|
-
let name = upvars[expr[1]];
|
|
178
|
+
let name = unwrap(upvars[expr[1]]);
|
|
336
179
|
let definition = resolver.lookupComponent(name, owner);
|
|
337
|
-
|
|
338
180
|
if (definition !== null) {
|
|
339
181
|
ifComponent(constants.resolvedComponent(definition, name));
|
|
340
182
|
} else {
|
|
341
183
|
let helper = resolver.lookupHelper(name, owner);
|
|
342
|
-
|
|
343
184
|
if (DEBUG && helper === null) {
|
|
344
185
|
throw new Error(`Attempted to resolve \`${name}\`, which was expected to be a component or helper, but nothing was found.`);
|
|
345
186
|
}
|
|
346
|
-
|
|
347
187
|
ifHelper(constants.helper(helper, name));
|
|
348
188
|
}
|
|
349
189
|
}
|
|
350
190
|
}
|
|
191
|
+
|
|
351
192
|
/**
|
|
352
193
|
* <Foo @arg={{helper}}>
|
|
353
194
|
*/
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}]
|
|
195
|
+
function resolveOptionalHelper(resolver, constants, meta, _ref5) {
|
|
196
|
+
let [, expr, {
|
|
197
|
+
ifHelper
|
|
198
|
+
}] = _ref5;
|
|
199
|
+
assert$1(isGetFreeOptionalHelper(expr) || isGetFreeDeprecatedHelper(expr), 'Attempted to resolve a helper with incorrect opcode');
|
|
358
200
|
let {
|
|
359
201
|
upvars,
|
|
360
202
|
owner
|
|
361
203
|
} = assertResolverInvariants(meta);
|
|
362
|
-
let name = upvars[expr[1]];
|
|
204
|
+
let name = unwrap(upvars[expr[1]]);
|
|
363
205
|
let helper = resolver.lookupHelper(name, owner);
|
|
364
|
-
|
|
365
206
|
if (helper) {
|
|
366
207
|
ifHelper(constants.helper(helper, name), name, meta.moduleName);
|
|
367
208
|
}
|
|
368
209
|
}
|
|
210
|
+
|
|
369
211
|
/**
|
|
370
212
|
* {{maybeHelperOrComponent}}
|
|
371
213
|
*/
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}]
|
|
214
|
+
function resolveOptionalComponentOrHelper(resolver, constants, meta, _ref6) {
|
|
215
|
+
let [, expr, {
|
|
216
|
+
ifComponent,
|
|
217
|
+
ifHelper,
|
|
218
|
+
ifValue
|
|
219
|
+
}] = _ref6;
|
|
220
|
+
assert$1(isGetFreeOptionalComponentOrHelper(expr), 'Attempted to resolve an optional component or helper with incorrect opcode');
|
|
378
221
|
let type = expr[0];
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
let definition = scopeValues[expr[1]];
|
|
388
|
-
|
|
389
|
-
if (typeof definition !== 'function' && (typeof definition !== 'object' || definition === null)) {
|
|
390
|
-
// The value is not an object, so it can't be a component or helper.
|
|
391
|
-
ifValue(constants.value(definition));
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
let component = constants.component(definition, owner, true);
|
|
396
|
-
|
|
397
|
-
if (component !== null) {
|
|
398
|
-
ifComponent(component);
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
let helper = constants.helper(definition, null, true);
|
|
403
|
-
|
|
404
|
-
if (helper !== null) {
|
|
405
|
-
ifHelper(helper);
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
|
|
222
|
+
if (type === SexpOpcodes.GetLexicalSymbol) {
|
|
223
|
+
let {
|
|
224
|
+
scopeValues,
|
|
225
|
+
owner
|
|
226
|
+
} = meta;
|
|
227
|
+
let definition = expect(scopeValues, 'BUG: scopeValues must exist if template symbol is used')[expr[1]];
|
|
228
|
+
if (typeof definition !== 'function' && (typeof definition !== 'object' || definition === null)) {
|
|
229
|
+
// The value is not an object, so it can't be a component or helper.
|
|
409
230
|
ifValue(constants.value(definition));
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
let component = constants.component(definition, expect(owner, 'BUG: expected owner when resolving component definition'), true);
|
|
234
|
+
if (component !== null) {
|
|
235
|
+
ifComponent(component);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
let helper = constants.helper(definition, null, true);
|
|
239
|
+
if (helper !== null) {
|
|
240
|
+
ifHelper(helper);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
ifValue(constants.value(definition));
|
|
244
|
+
} else if (type === SexpOpcodes.GetStrictKeyword) {
|
|
245
|
+
ifHelper(lookupBuiltInHelper(expr, resolver, meta, constants, 'value'));
|
|
246
|
+
} else {
|
|
415
247
|
let {
|
|
416
248
|
upvars,
|
|
417
249
|
owner
|
|
418
250
|
} = assertResolverInvariants(meta);
|
|
419
|
-
let name = upvars[expr[1]];
|
|
251
|
+
let name = unwrap(upvars[expr[1]]);
|
|
420
252
|
let definition = resolver.lookupComponent(name, owner);
|
|
421
|
-
|
|
422
253
|
if (definition !== null) {
|
|
423
254
|
ifComponent(constants.resolvedComponent(definition, name));
|
|
424
255
|
return;
|
|
425
256
|
}
|
|
426
|
-
|
|
427
257
|
let helper = resolver.lookupHelper(name, owner);
|
|
428
|
-
|
|
429
258
|
if (helper !== null) {
|
|
430
259
|
ifHelper(constants.helper(helper, name));
|
|
431
260
|
}
|
|
432
261
|
}
|
|
433
262
|
}
|
|
434
|
-
|
|
435
263
|
function lookupBuiltInHelper(expr, resolver, meta, constants, type) {
|
|
436
264
|
let {
|
|
437
265
|
upvars
|
|
438
266
|
} = assertResolverInvariants(meta);
|
|
439
|
-
let name = upvars[expr[1]];
|
|
267
|
+
let name = unwrap(upvars[expr[1]]);
|
|
440
268
|
let helper = resolver.lookupBuiltInHelper(name);
|
|
441
|
-
|
|
442
269
|
if (DEBUG && helper === null) {
|
|
443
270
|
// Keyword helper did not exist, which means that we're attempting to use a
|
|
444
271
|
// value of some kind that is not in scope
|
|
445
|
-
throw new Error(`Attempted to resolve a ${type} in a strict mode template, but that value was not in scope: ${meta.upvars[expr[1]]}`);
|
|
272
|
+
throw new Error(`Attempted to resolve a ${type} in a strict mode template, but that value was not in scope: ${meta.upvars[expr[1]] ?? '{unknown variable}'}`);
|
|
446
273
|
}
|
|
447
|
-
|
|
448
274
|
return constants.helper(helper, name);
|
|
449
275
|
}
|
|
450
276
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
277
|
+
const HighLevelResolutionOpcodes = {
|
|
278
|
+
Modifier: 1003,
|
|
279
|
+
Component: 1004,
|
|
280
|
+
Helper: 1005,
|
|
281
|
+
OptionalHelper: 1006,
|
|
282
|
+
ComponentOrHelper: 1007,
|
|
283
|
+
OptionalComponentOrHelper: 1008,
|
|
284
|
+
Free: 1009,
|
|
285
|
+
Local: 1010,
|
|
286
|
+
TemplateLocal: 1011
|
|
287
|
+
};
|
|
288
|
+
const HighLevelBuilderOpcodes = {
|
|
289
|
+
Label: 1000,
|
|
290
|
+
StartLabels: 1001,
|
|
291
|
+
StopLabels: 1002,
|
|
292
|
+
Start: 1000,
|
|
293
|
+
End: 1002
|
|
294
|
+
};
|
|
467
295
|
|
|
296
|
+
const HighLevelOperands = {
|
|
297
|
+
Label: 1,
|
|
298
|
+
IsStrictMode: 2,
|
|
299
|
+
DebugSymbols: 3,
|
|
300
|
+
Block: 4,
|
|
301
|
+
StdLib: 5,
|
|
302
|
+
NonSmallInt: 6,
|
|
303
|
+
SymbolTable: 7,
|
|
304
|
+
Layout: 8
|
|
305
|
+
};
|
|
306
|
+
function labelOperand(value) {
|
|
307
|
+
return {
|
|
308
|
+
type: HighLevelOperands.Label,
|
|
309
|
+
value
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function debugSymbolsOperand() {
|
|
313
|
+
return {
|
|
314
|
+
type: HighLevelOperands.DebugSymbols,
|
|
315
|
+
value: undefined
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
function isStrictMode() {
|
|
319
|
+
return {
|
|
320
|
+
type: HighLevelOperands.IsStrictMode,
|
|
321
|
+
value: undefined
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function blockOperand(value) {
|
|
325
|
+
return {
|
|
326
|
+
type: HighLevelOperands.Block,
|
|
327
|
+
value
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function stdlibOperand(value) {
|
|
331
|
+
return {
|
|
332
|
+
type: HighLevelOperands.StdLib,
|
|
333
|
+
value
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function nonSmallIntOperand(value) {
|
|
337
|
+
assert$1(!isSmallInt(value), 'Attempted to make a operand for an int that was not a small int, you should encode this as an immediate');
|
|
338
|
+
return {
|
|
339
|
+
type: HighLevelOperands.NonSmallInt,
|
|
340
|
+
value
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function symbolTableOperand(value) {
|
|
344
|
+
return {
|
|
345
|
+
type: HighLevelOperands.SymbolTable,
|
|
346
|
+
value
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function layoutOperand(value) {
|
|
350
|
+
return {
|
|
351
|
+
type: HighLevelOperands.Layout,
|
|
352
|
+
value
|
|
353
|
+
};
|
|
468
354
|
}
|
|
469
355
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
expr(op, part);
|
|
356
|
+
class Labels {
|
|
357
|
+
labels = dict();
|
|
358
|
+
targets = [];
|
|
359
|
+
label(name, index) {
|
|
360
|
+
this.labels[name] = index;
|
|
476
361
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
});
|
|
482
|
-
EXPRESSIONS.add(28
|
|
483
|
-
/* Call */
|
|
484
|
-
, (op, [, expression, positional, named]) => {
|
|
485
|
-
if (isGetFreeHelper(expression)) {
|
|
486
|
-
op(1005
|
|
487
|
-
/* ResolveHelper */
|
|
488
|
-
, expression, handle => {
|
|
489
|
-
Call(op, handle, positional, named);
|
|
490
|
-
});
|
|
491
|
-
} else {
|
|
492
|
-
expr(op, expression);
|
|
493
|
-
CallDynamic(op, positional, named);
|
|
494
|
-
}
|
|
495
|
-
});
|
|
496
|
-
EXPRESSIONS.add(50
|
|
497
|
-
/* Curry */
|
|
498
|
-
, (op, [, expr, type, positional, named]) => {
|
|
499
|
-
Curry(op, type, expr, positional, named);
|
|
500
|
-
});
|
|
501
|
-
EXPRESSIONS.add(30
|
|
502
|
-
/* GetSymbol */
|
|
503
|
-
, (op, [, sym, path]) => {
|
|
504
|
-
op(21
|
|
505
|
-
/* GetVariable */
|
|
506
|
-
, sym);
|
|
507
|
-
withPath(op, path);
|
|
508
|
-
});
|
|
509
|
-
EXPRESSIONS.add(32
|
|
510
|
-
/* GetTemplateSymbol */
|
|
511
|
-
, (op, [, sym, path]) => {
|
|
512
|
-
op(1011
|
|
513
|
-
/* ResolveTemplateLocal */
|
|
514
|
-
, sym, handle => {
|
|
515
|
-
op(29
|
|
516
|
-
/* ConstantReference */
|
|
517
|
-
, handle);
|
|
518
|
-
withPath(op, path);
|
|
519
|
-
});
|
|
520
|
-
});
|
|
521
|
-
EXPRESSIONS.add(31
|
|
522
|
-
/* GetStrictFree */
|
|
523
|
-
, (op, [, sym, _path]) => {
|
|
524
|
-
op(1009
|
|
525
|
-
/* ResolveFree */
|
|
526
|
-
, sym, _handle => {// TODO: Implement in strict mode
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
EXPRESSIONS.add(34
|
|
530
|
-
/* GetFreeAsComponentOrHelperHeadOrThisFallback */
|
|
531
|
-
, () => {
|
|
532
|
-
// TODO: The logic for this opcode currently exists in STATEMENTS.Append, since
|
|
533
|
-
// we want different wrapping logic depending on if we are invoking a component,
|
|
534
|
-
// helper, or {{this}} fallback. Eventually we fix the opcodes so that we can
|
|
535
|
-
// traverse the subexpression tree like normal in this location.
|
|
536
|
-
throw new Error('unimplemented opcode');
|
|
537
|
-
});
|
|
538
|
-
EXPRESSIONS.add(36
|
|
539
|
-
/* GetFreeAsHelperHeadOrThisFallback */
|
|
540
|
-
, (op, expr) => {
|
|
541
|
-
// <div id={{baz}}>
|
|
542
|
-
op(1010
|
|
543
|
-
/* ResolveLocal */
|
|
544
|
-
, expr[1], _name => {
|
|
545
|
-
op(1006
|
|
546
|
-
/* ResolveOptionalHelper */
|
|
547
|
-
, expr, {
|
|
548
|
-
ifHelper: handle => {
|
|
549
|
-
Call(op, handle, null, null);
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
});
|
|
553
|
-
});
|
|
554
|
-
EXPRESSIONS.add(99
|
|
555
|
-
/* GetFreeAsDeprecatedHelperHeadOrThisFallback */
|
|
556
|
-
, (op, expr) => {
|
|
557
|
-
// <Foo @bar={{baz}}>
|
|
558
|
-
op(1010
|
|
559
|
-
/* ResolveLocal */
|
|
560
|
-
, expr[1], _name => {
|
|
561
|
-
op(1006
|
|
562
|
-
/* ResolveOptionalHelper */
|
|
563
|
-
, expr, {
|
|
564
|
-
ifHelper: (handle, name, moduleName) => {
|
|
565
|
-
assert(expr[2] && expr[2].length === 1, '[BUG] Missing argument name');
|
|
566
|
-
let arg = expr[2][0];
|
|
567
|
-
deprecate(`The \`${name}\` helper was used in the \`${moduleName}\` template as \`${arg}={{${name}}}\`. ` + `This is ambigious between wanting the \`${arg}\` argument to be the \`${name}\` helper itself, ` + `or the result of invoking the \`${name}\` helper (current behavior). ` + `This implicit invocation behavior has been deprecated.\n\n` + `Instead, please explicitly invoke the helper with parenthesis, i.e. \`${arg}={{(${name})}}\`.\n\n` + `Note: the parenthesis are only required in this exact scenario where an ambiguity is present – where ` + `\`${name}\` referes to a global helper (as opposed to a local variable), AND ` + `the \`${name}\` helper invocation does not take any arguments, AND ` + `this occurs in a named argument position of a component invocation.\n\n` + `We expect this combination to be quite rare, as most helpers require at least one argument. ` + `There is no need to refactor helper invocations in cases where this deprecation was not triggered.`, false, {
|
|
568
|
-
id: 'argument-less-helper-paren-less-invocation'
|
|
569
|
-
});
|
|
570
|
-
Call(op, handle, null, null);
|
|
571
|
-
}
|
|
572
|
-
});
|
|
573
|
-
});
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
function withPath(op, path) {
|
|
577
|
-
if (path === undefined || path.length === 0) return;
|
|
578
|
-
|
|
579
|
-
for (let i = 0; i < path.length; i++) {
|
|
580
|
-
op(22
|
|
581
|
-
/* GetProperty */
|
|
582
|
-
, path[i]);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
EXPRESSIONS.add(27
|
|
587
|
-
/* Undefined */
|
|
588
|
-
, op => PushPrimitiveReference(op, undefined));
|
|
589
|
-
EXPRESSIONS.add(48
|
|
590
|
-
/* HasBlock */
|
|
591
|
-
, (op, [, block]) => {
|
|
592
|
-
expr(op, block);
|
|
593
|
-
op(25
|
|
594
|
-
/* HasBlock */
|
|
595
|
-
);
|
|
596
|
-
});
|
|
597
|
-
EXPRESSIONS.add(49
|
|
598
|
-
/* HasBlockParams */
|
|
599
|
-
, (op, [, block]) => {
|
|
600
|
-
expr(op, block);
|
|
601
|
-
op(24
|
|
602
|
-
/* SpreadBlock */
|
|
603
|
-
);
|
|
604
|
-
op(61
|
|
605
|
-
/* CompileBlock */
|
|
606
|
-
);
|
|
607
|
-
op(26
|
|
608
|
-
/* HasBlockParams */
|
|
609
|
-
);
|
|
610
|
-
});
|
|
611
|
-
EXPRESSIONS.add(52
|
|
612
|
-
/* IfInline */
|
|
613
|
-
, (op, [, condition, truthy, falsy]) => {
|
|
614
|
-
// Push in reverse order
|
|
615
|
-
expr(op, falsy);
|
|
616
|
-
expr(op, truthy);
|
|
617
|
-
expr(op, condition);
|
|
618
|
-
op(109
|
|
619
|
-
/* IfInline */
|
|
620
|
-
);
|
|
621
|
-
});
|
|
622
|
-
EXPRESSIONS.add(51
|
|
623
|
-
/* Not */
|
|
624
|
-
, (op, [, value]) => {
|
|
625
|
-
expr(op, value);
|
|
626
|
-
op(110
|
|
627
|
-
/* Not */
|
|
628
|
-
);
|
|
629
|
-
});
|
|
630
|
-
EXPRESSIONS.add(53
|
|
631
|
-
/* GetDynamicVar */
|
|
632
|
-
, (op, [, expression]) => {
|
|
633
|
-
expr(op, expression);
|
|
634
|
-
op(111
|
|
635
|
-
/* GetDynamicVar */
|
|
636
|
-
);
|
|
637
|
-
});
|
|
638
|
-
EXPRESSIONS.add(54
|
|
639
|
-
/* Log */
|
|
640
|
-
, (op, [, positional]) => {
|
|
641
|
-
op(0
|
|
642
|
-
/* PushFrame */
|
|
643
|
-
);
|
|
644
|
-
SimpleArgs(op, positional, null, false);
|
|
645
|
-
op(112
|
|
646
|
-
/* Log */
|
|
647
|
-
);
|
|
648
|
-
op(1
|
|
649
|
-
/* PopFrame */
|
|
650
|
-
);
|
|
651
|
-
op(36
|
|
652
|
-
/* Fetch */
|
|
653
|
-
, $v0);
|
|
654
|
-
});
|
|
655
|
-
|
|
656
|
-
function expr(op, expression) {
|
|
657
|
-
if (Array.isArray(expression)) {
|
|
658
|
-
EXPRESSIONS.compile(op, expression);
|
|
659
|
-
} else {
|
|
660
|
-
PushPrimitive(op, expression);
|
|
661
|
-
op(31
|
|
662
|
-
/* PrimitiveReference */
|
|
663
|
-
);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* Compile arguments, pushing an Arguments object onto the stack.
|
|
669
|
-
*
|
|
670
|
-
* @param args.params
|
|
671
|
-
* @param args.hash
|
|
672
|
-
* @param args.blocks
|
|
673
|
-
* @param args.atNames
|
|
674
|
-
*/
|
|
675
|
-
|
|
676
|
-
function CompileArgs(op, positional, named, blocks, atNames) {
|
|
677
|
-
let blockNames = blocks.names;
|
|
678
|
-
|
|
679
|
-
for (let i = 0; i < blockNames.length; i++) {
|
|
680
|
-
PushYieldableBlock(op, blocks.get(blockNames[i]));
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
let count = CompilePositional(op, positional);
|
|
684
|
-
let flags = count << 4;
|
|
685
|
-
if (atNames) flags |= 0b1000;
|
|
686
|
-
|
|
687
|
-
if (blocks) {
|
|
688
|
-
flags |= 0b111;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
let names = EMPTY_ARRAY;
|
|
692
|
-
|
|
693
|
-
if (named) {
|
|
694
|
-
names = named[0];
|
|
695
|
-
let val = named[1];
|
|
696
|
-
|
|
697
|
-
for (let i = 0; i < val.length; i++) {
|
|
698
|
-
expr(op, val[i]);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
op(82
|
|
703
|
-
/* PushArgs */
|
|
704
|
-
, names, blockNames, flags);
|
|
705
|
-
}
|
|
706
|
-
function SimpleArgs(op, positional, named, atNames) {
|
|
707
|
-
if (positional === null && named === null) {
|
|
708
|
-
op(83
|
|
709
|
-
/* PushEmptyArgs */
|
|
710
|
-
);
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
let count = CompilePositional(op, positional);
|
|
715
|
-
let flags = count << 4;
|
|
716
|
-
if (atNames) flags |= 0b1000;
|
|
717
|
-
let names = EMPTY_STRING_ARRAY;
|
|
718
|
-
|
|
719
|
-
if (named) {
|
|
720
|
-
names = named[0];
|
|
721
|
-
let val = named[1];
|
|
722
|
-
|
|
723
|
-
for (let i = 0; i < val.length; i++) {
|
|
724
|
-
expr(op, val[i]);
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
op(82
|
|
729
|
-
/* PushArgs */
|
|
730
|
-
, names, EMPTY_STRING_ARRAY, flags);
|
|
731
|
-
}
|
|
732
|
-
/**
|
|
733
|
-
* Compile an optional list of positional arguments, which pushes each argument
|
|
734
|
-
* onto the stack and returns the number of parameters compiled
|
|
735
|
-
*
|
|
736
|
-
* @param positional an optional list of positional arguments
|
|
737
|
-
*/
|
|
738
|
-
|
|
739
|
-
function CompilePositional(op, positional) {
|
|
740
|
-
if (positional === null) return 0;
|
|
741
|
-
|
|
742
|
-
for (let i = 0; i < positional.length; i++) {
|
|
743
|
-
expr(op, positional[i]);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
return positional.length;
|
|
747
|
-
}
|
|
748
|
-
function meta(layout) {
|
|
749
|
-
var _a, _b;
|
|
750
|
-
|
|
751
|
-
let [, symbols,, upvars] = layout.block;
|
|
752
|
-
return {
|
|
753
|
-
evalSymbols: evalSymbols(layout),
|
|
754
|
-
upvars: upvars,
|
|
755
|
-
scopeValues: (_b = (_a = layout.scope) === null || _a === void 0 ? void 0 : _a.call(layout)) !== null && _b !== void 0 ? _b : null,
|
|
756
|
-
isStrictMode: layout.isStrictMode,
|
|
757
|
-
moduleName: layout.moduleName,
|
|
758
|
-
owner: layout.owner,
|
|
759
|
-
size: symbols.length
|
|
760
|
-
};
|
|
761
|
-
}
|
|
762
|
-
function evalSymbols(layout) {
|
|
763
|
-
let {
|
|
764
|
-
block
|
|
765
|
-
} = layout;
|
|
766
|
-
let [, symbols, hasEval] = block;
|
|
767
|
-
return hasEval ? symbols : null;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* Push a reference onto the stack corresponding to a statically known primitive
|
|
772
|
-
* @param value A JavaScript primitive (undefined, null, boolean, number or string)
|
|
773
|
-
*/
|
|
774
|
-
|
|
775
|
-
function PushPrimitiveReference(op, value) {
|
|
776
|
-
PushPrimitive(op, value);
|
|
777
|
-
op(31
|
|
778
|
-
/* PrimitiveReference */
|
|
779
|
-
);
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Push an encoded representation of a JavaScript primitive on the stack
|
|
783
|
-
*
|
|
784
|
-
* @param value A JavaScript primitive (undefined, null, boolean, number or string)
|
|
785
|
-
*/
|
|
786
|
-
|
|
787
|
-
function PushPrimitive(op, primitive) {
|
|
788
|
-
let p = primitive;
|
|
789
|
-
|
|
790
|
-
if (typeof p === 'number') {
|
|
791
|
-
p = isSmallInt(p) ? encodeImmediate(p) : nonSmallIntOperand(p);
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
op(30
|
|
795
|
-
/* Primitive */
|
|
796
|
-
, p);
|
|
797
|
-
}
|
|
798
|
-
/**
|
|
799
|
-
* Invoke a foreign function (a "helper") based on a statically known handle
|
|
800
|
-
*
|
|
801
|
-
* @param op The op creation function
|
|
802
|
-
* @param handle A handle
|
|
803
|
-
* @param positional An optional list of expressions to compile
|
|
804
|
-
* @param named An optional list of named arguments (name + expression) to compile
|
|
805
|
-
*/
|
|
806
|
-
|
|
807
|
-
function Call(op, handle, positional, named) {
|
|
808
|
-
op(0
|
|
809
|
-
/* PushFrame */
|
|
810
|
-
);
|
|
811
|
-
SimpleArgs(op, positional, named, false);
|
|
812
|
-
op(16
|
|
813
|
-
/* Helper */
|
|
814
|
-
, handle);
|
|
815
|
-
op(1
|
|
816
|
-
/* PopFrame */
|
|
817
|
-
);
|
|
818
|
-
op(36
|
|
819
|
-
/* Fetch */
|
|
820
|
-
, $v0);
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* Invoke a foreign function (a "helper") based on a dynamically loaded definition
|
|
824
|
-
*
|
|
825
|
-
* @param op The op creation function
|
|
826
|
-
* @param positional An optional list of expressions to compile
|
|
827
|
-
* @param named An optional list of named arguments (name + expression) to compile
|
|
828
|
-
*/
|
|
829
|
-
|
|
830
|
-
function CallDynamic(op, positional, named, append) {
|
|
831
|
-
op(0
|
|
832
|
-
/* PushFrame */
|
|
833
|
-
);
|
|
834
|
-
SimpleArgs(op, positional, named, false);
|
|
835
|
-
op(33
|
|
836
|
-
/* Dup */
|
|
837
|
-
, $fp, 1);
|
|
838
|
-
op(107
|
|
839
|
-
/* DynamicHelper */
|
|
840
|
-
);
|
|
841
|
-
|
|
842
|
-
if (append) {
|
|
843
|
-
op(36
|
|
844
|
-
/* Fetch */
|
|
845
|
-
, $v0);
|
|
846
|
-
append();
|
|
847
|
-
op(1
|
|
848
|
-
/* PopFrame */
|
|
849
|
-
);
|
|
850
|
-
op(34
|
|
851
|
-
/* Pop */
|
|
852
|
-
, 1);
|
|
853
|
-
} else {
|
|
854
|
-
op(1
|
|
855
|
-
/* PopFrame */
|
|
856
|
-
);
|
|
857
|
-
op(34
|
|
858
|
-
/* Pop */
|
|
859
|
-
, 1);
|
|
860
|
-
op(36
|
|
861
|
-
/* Fetch */
|
|
862
|
-
, $v0);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
/**
|
|
866
|
-
* Evaluate statements in the context of new dynamic scope entries. Move entries from the
|
|
867
|
-
* stack into named entries in the dynamic scope, then evaluate the statements, then pop
|
|
868
|
-
* the dynamic scope
|
|
869
|
-
*
|
|
870
|
-
* @param names a list of dynamic scope names
|
|
871
|
-
* @param block a function that returns a list of statements to evaluate
|
|
872
|
-
*/
|
|
873
|
-
|
|
874
|
-
function DynamicScope(op, names, block) {
|
|
875
|
-
op(59
|
|
876
|
-
/* PushDynamicScope */
|
|
877
|
-
);
|
|
878
|
-
op(58
|
|
879
|
-
/* BindDynamicScope */
|
|
880
|
-
, names);
|
|
881
|
-
block();
|
|
882
|
-
op(60
|
|
883
|
-
/* PopDynamicScope */
|
|
884
|
-
);
|
|
885
|
-
}
|
|
886
|
-
function Curry(op, type, definition, positional, named) {
|
|
887
|
-
op(0
|
|
888
|
-
/* PushFrame */
|
|
889
|
-
);
|
|
890
|
-
SimpleArgs(op, positional, named, false);
|
|
891
|
-
op(86
|
|
892
|
-
/* CaptureArgs */
|
|
893
|
-
);
|
|
894
|
-
expr(op, definition);
|
|
895
|
-
op(77
|
|
896
|
-
/* Curry */
|
|
897
|
-
, type, isStrictMode());
|
|
898
|
-
op(1
|
|
899
|
-
/* PopFrame */
|
|
900
|
-
);
|
|
901
|
-
op(36
|
|
902
|
-
/* Fetch */
|
|
903
|
-
, $v0);
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
/**
|
|
907
|
-
* Yield to a block located at a particular symbol location.
|
|
908
|
-
*
|
|
909
|
-
* @param to the symbol containing the block to yield to
|
|
910
|
-
* @param params optional block parameters to yield to the block
|
|
911
|
-
*/
|
|
912
|
-
|
|
913
|
-
function YieldBlock(op, to, positional) {
|
|
914
|
-
SimpleArgs(op, positional, null, true);
|
|
915
|
-
op(23
|
|
916
|
-
/* GetBlock */
|
|
917
|
-
, to);
|
|
918
|
-
op(24
|
|
919
|
-
/* SpreadBlock */
|
|
920
|
-
);
|
|
921
|
-
op(61
|
|
922
|
-
/* CompileBlock */
|
|
923
|
-
);
|
|
924
|
-
op(64
|
|
925
|
-
/* InvokeYield */
|
|
926
|
-
);
|
|
927
|
-
op(40
|
|
928
|
-
/* PopScope */
|
|
929
|
-
);
|
|
930
|
-
op(1
|
|
931
|
-
/* PopFrame */
|
|
932
|
-
);
|
|
933
|
-
}
|
|
934
|
-
/**
|
|
935
|
-
* Push an (optional) yieldable block onto the stack. The yieldable block must be known
|
|
936
|
-
* statically at compile time.
|
|
937
|
-
*
|
|
938
|
-
* @param block An optional Compilable block
|
|
939
|
-
*/
|
|
940
|
-
|
|
941
|
-
function PushYieldableBlock(op, block) {
|
|
942
|
-
PushSymbolTable(op, block && block[1]);
|
|
943
|
-
op(62
|
|
944
|
-
/* PushBlockScope */
|
|
945
|
-
);
|
|
946
|
-
PushCompilable(op, block);
|
|
947
|
-
}
|
|
948
|
-
/**
|
|
949
|
-
* Invoke a block that is known statically at compile time.
|
|
950
|
-
*
|
|
951
|
-
* @param block a Compilable block
|
|
952
|
-
*/
|
|
953
|
-
|
|
954
|
-
function InvokeStaticBlock(op, block) {
|
|
955
|
-
op(0
|
|
956
|
-
/* PushFrame */
|
|
957
|
-
);
|
|
958
|
-
PushCompilable(op, block);
|
|
959
|
-
op(61
|
|
960
|
-
/* CompileBlock */
|
|
961
|
-
);
|
|
962
|
-
op(2
|
|
963
|
-
/* InvokeVirtual */
|
|
964
|
-
);
|
|
965
|
-
op(1
|
|
966
|
-
/* PopFrame */
|
|
967
|
-
);
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Invoke a static block, preserving some number of stack entries for use in
|
|
971
|
-
* updating.
|
|
972
|
-
*
|
|
973
|
-
* @param block A compilable block
|
|
974
|
-
* @param callerCount A number of stack entries to preserve
|
|
975
|
-
*/
|
|
976
|
-
|
|
977
|
-
function InvokeStaticBlockWithStack(op, block, callerCount) {
|
|
978
|
-
let parameters = block[1];
|
|
979
|
-
let calleeCount = parameters.length;
|
|
980
|
-
let count = Math.min(callerCount, calleeCount);
|
|
981
|
-
|
|
982
|
-
if (count === 0) {
|
|
983
|
-
InvokeStaticBlock(op, block);
|
|
984
|
-
return;
|
|
362
|
+
target(at, target) {
|
|
363
|
+
this.targets.push({
|
|
364
|
+
at,
|
|
365
|
+
target
|
|
366
|
+
});
|
|
985
367
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
)
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
/* Dup */
|
|
999
|
-
, $fp, callerCount - i);
|
|
1000
|
-
op(19
|
|
1001
|
-
/* SetVariable */
|
|
1002
|
-
, parameters[i]);
|
|
368
|
+
patch(heap) {
|
|
369
|
+
let {
|
|
370
|
+
targets,
|
|
371
|
+
labels
|
|
372
|
+
} = this;
|
|
373
|
+
for (const {
|
|
374
|
+
at,
|
|
375
|
+
target
|
|
376
|
+
} of targets) {
|
|
377
|
+
let address = labels[target] - at;
|
|
378
|
+
assert$1(heap.getbyaddr(at) === -1, 'Expected heap to contain a placeholder, but it did not');
|
|
379
|
+
heap.setbyaddr(at, address);
|
|
1003
380
|
}
|
|
1004
381
|
}
|
|
1005
|
-
|
|
1006
|
-
PushCompilable(op, block);
|
|
1007
|
-
op(61
|
|
1008
|
-
/* CompileBlock */
|
|
1009
|
-
);
|
|
1010
|
-
op(2
|
|
1011
|
-
/* InvokeVirtual */
|
|
1012
|
-
);
|
|
1013
|
-
|
|
1014
|
-
if (count) {
|
|
1015
|
-
op(40
|
|
1016
|
-
/* PopScope */
|
|
1017
|
-
);
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
op(1
|
|
1021
|
-
/* PopFrame */
|
|
1022
|
-
);
|
|
1023
|
-
}
|
|
1024
|
-
function PushSymbolTable(op, parameters) {
|
|
1025
|
-
if (parameters !== null) {
|
|
1026
|
-
op(63
|
|
1027
|
-
/* PushSymbolTable */
|
|
1028
|
-
, symbolTableOperand({
|
|
1029
|
-
parameters
|
|
1030
|
-
}));
|
|
1031
|
-
} else {
|
|
1032
|
-
PushPrimitive(op, null);
|
|
1033
|
-
}
|
|
1034
382
|
}
|
|
1035
|
-
function
|
|
1036
|
-
if (
|
|
1037
|
-
|
|
383
|
+
function encodeOp(encoder, constants, resolver, meta, op) {
|
|
384
|
+
if (isBuilderOpcode(op[0])) {
|
|
385
|
+
let [type, ...operands] = op;
|
|
386
|
+
encoder.push(constants, type, ...operands);
|
|
1038
387
|
} else {
|
|
1039
|
-
op
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
, clause.label);
|
|
1083
|
-
op(34
|
|
1084
|
-
/* Pop */
|
|
1085
|
-
, 1);
|
|
1086
|
-
clause.callback(); // The first match is special: it is placed directly before the END
|
|
1087
|
-
// label, so no additional jump is needed at the end of it.
|
|
1088
|
-
|
|
1089
|
-
if (i !== 0) {
|
|
1090
|
-
op(4
|
|
1091
|
-
/* Jump */
|
|
1092
|
-
, labelOperand('END'));
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
op(1000
|
|
1097
|
-
/* Label */
|
|
1098
|
-
, 'END');
|
|
1099
|
-
op(1002
|
|
1100
|
-
/* StopLabels */
|
|
1101
|
-
);
|
|
1102
|
-
op(70
|
|
1103
|
-
/* Exit */
|
|
1104
|
-
);
|
|
1105
|
-
}
|
|
1106
|
-
/**
|
|
1107
|
-
* A convenience for pushing some arguments on the stack and
|
|
1108
|
-
* running some code if the code needs to be re-executed during
|
|
1109
|
-
* updating execution if some of the arguments have changed.
|
|
1110
|
-
*
|
|
1111
|
-
* # Initial Execution
|
|
1112
|
-
*
|
|
1113
|
-
* The `args` function should push zero or more arguments onto
|
|
1114
|
-
* the stack and return the number of arguments pushed.
|
|
1115
|
-
*
|
|
1116
|
-
* The `body` function provides the instructions to execute both
|
|
1117
|
-
* during initial execution and during updating execution.
|
|
1118
|
-
*
|
|
1119
|
-
* Internally, this function starts by pushing a new frame, so
|
|
1120
|
-
* that the body can return and sets the return point ($ra) to
|
|
1121
|
-
* the ENDINITIAL label.
|
|
1122
|
-
*
|
|
1123
|
-
* It then executes the `args` function, which adds instructions
|
|
1124
|
-
* responsible for pushing the arguments for the block to the
|
|
1125
|
-
* stack. These arguments will be restored to the stack before
|
|
1126
|
-
* updating execution.
|
|
1127
|
-
*
|
|
1128
|
-
* Next, it adds the Enter opcode, which marks the current position
|
|
1129
|
-
* in the DOM, and remembers the current $pc (the next instruction)
|
|
1130
|
-
* as the first instruction to execute during updating execution.
|
|
1131
|
-
*
|
|
1132
|
-
* Next, it runs `body`, which adds the opcodes that should
|
|
1133
|
-
* execute both during initial execution and during updating execution.
|
|
1134
|
-
* If the `body` wishes to finish early, it should Jump to the
|
|
1135
|
-
* `FINALLY` label.
|
|
1136
|
-
*
|
|
1137
|
-
* Next, it adds the FINALLY label, followed by:
|
|
1138
|
-
*
|
|
1139
|
-
* - the Exit opcode, which finalizes the marked DOM started by the
|
|
1140
|
-
* Enter opcode.
|
|
1141
|
-
* - the Return opcode, which returns to the current return point
|
|
1142
|
-
* ($ra).
|
|
1143
|
-
*
|
|
1144
|
-
* Finally, it adds the ENDINITIAL label followed by the PopFrame
|
|
1145
|
-
* instruction, which restores $fp, $sp and $ra.
|
|
1146
|
-
*
|
|
1147
|
-
* # Updating Execution
|
|
1148
|
-
*
|
|
1149
|
-
* Updating execution for this `replayable` occurs if the `body` added an
|
|
1150
|
-
* assertion, via one of the `JumpIf`, `JumpUnless` or `AssertSame` opcodes.
|
|
1151
|
-
*
|
|
1152
|
-
* If, during updating executon, the assertion fails, the initial VM is
|
|
1153
|
-
* restored, and the stored arguments are pushed onto the stack. The DOM
|
|
1154
|
-
* between the starting and ending markers is cleared, and the VM's cursor
|
|
1155
|
-
* is set to the area just cleared.
|
|
1156
|
-
*
|
|
1157
|
-
* The return point ($ra) is set to -1, the exit instruction.
|
|
1158
|
-
*
|
|
1159
|
-
* Finally, the $pc is set to to the instruction saved off by the
|
|
1160
|
-
* Enter opcode during initial execution, and execution proceeds as
|
|
1161
|
-
* usual.
|
|
1162
|
-
*
|
|
1163
|
-
* The only difference is that when a `Return` instruction is
|
|
1164
|
-
* encountered, the program jumps to -1 rather than the END label,
|
|
1165
|
-
* and the PopFrame opcode is not needed.
|
|
1166
|
-
*/
|
|
1167
|
-
|
|
1168
|
-
function Replayable(op, args, body) {
|
|
1169
|
-
// Start a new label frame, to give END and RETURN
|
|
1170
|
-
// a unique meaning.
|
|
1171
|
-
op(1001
|
|
1172
|
-
/* StartLabels */
|
|
1173
|
-
);
|
|
1174
|
-
op(0
|
|
1175
|
-
/* PushFrame */
|
|
1176
|
-
); // If the body invokes a block, its return will return to
|
|
1177
|
-
// END. Otherwise, the return in RETURN will return to END.
|
|
1178
|
-
|
|
1179
|
-
op(6
|
|
1180
|
-
/* ReturnTo */
|
|
1181
|
-
, labelOperand('ENDINITIAL')); // Push the arguments onto the stack. The args() function
|
|
1182
|
-
// tells us how many stack elements to retain for re-execution
|
|
1183
|
-
// when updating.
|
|
1184
|
-
|
|
1185
|
-
let count = args(); // Start a new updating closure, remembering `count` elements
|
|
1186
|
-
// from the stack. Everything after this point, and before END,
|
|
1187
|
-
// will execute both initially and to update the block.
|
|
1188
|
-
//
|
|
1189
|
-
// The enter and exit opcodes also track the area of the DOM
|
|
1190
|
-
// associated with this block. If an assertion inside the block
|
|
1191
|
-
// fails (for example, the test value changes from true to false
|
|
1192
|
-
// in an #if), the DOM is cleared and the program is re-executed,
|
|
1193
|
-
// restoring `count` elements to the stack and executing the
|
|
1194
|
-
// instructions between the enter and exit.
|
|
1195
|
-
|
|
1196
|
-
op(69
|
|
1197
|
-
/* Enter */
|
|
1198
|
-
, count); // Evaluate the body of the block. The body of the block may
|
|
1199
|
-
// return, which will jump execution to END during initial
|
|
1200
|
-
// execution, and exit the updating routine.
|
|
1201
|
-
|
|
1202
|
-
body(); // All execution paths in the body should run the FINALLY once
|
|
1203
|
-
// they are done. It is executed both during initial execution
|
|
1204
|
-
// and during updating execution.
|
|
1205
|
-
|
|
1206
|
-
op(1000
|
|
1207
|
-
/* Label */
|
|
1208
|
-
, 'FINALLY'); // Finalize the DOM.
|
|
1209
|
-
|
|
1210
|
-
op(70
|
|
1211
|
-
/* Exit */
|
|
1212
|
-
); // In initial execution, this is a noop: it returns to the
|
|
1213
|
-
// immediately following opcode. In updating execution, this
|
|
1214
|
-
// exits the updating routine.
|
|
1215
|
-
|
|
1216
|
-
op(5
|
|
1217
|
-
/* Return */
|
|
1218
|
-
); // Cleanup code for the block. Runs on initial execution
|
|
1219
|
-
// but not on updating.
|
|
1220
|
-
|
|
1221
|
-
op(1000
|
|
1222
|
-
/* Label */
|
|
1223
|
-
, 'ENDINITIAL');
|
|
1224
|
-
op(1
|
|
1225
|
-
/* PopFrame */
|
|
1226
|
-
);
|
|
1227
|
-
op(1002
|
|
1228
|
-
/* StopLabels */
|
|
1229
|
-
);
|
|
1230
|
-
}
|
|
1231
|
-
/**
|
|
1232
|
-
* A specialized version of the `replayable` convenience that allows the
|
|
1233
|
-
* caller to provide different code based upon whether the item at
|
|
1234
|
-
* the top of the stack is true or false.
|
|
1235
|
-
*
|
|
1236
|
-
* As in `replayable`, the `ifTrue` and `ifFalse` code can invoke `return`.
|
|
1237
|
-
*
|
|
1238
|
-
* During the initial execution, a `return` will continue execution
|
|
1239
|
-
* in the cleanup code, which finalizes the current DOM block and pops
|
|
1240
|
-
* the current frame.
|
|
1241
|
-
*
|
|
1242
|
-
* During the updating execution, a `return` will exit the updating
|
|
1243
|
-
* routine, as it can reuse the DOM block and is always only a single
|
|
1244
|
-
* frame deep.
|
|
1245
|
-
*/
|
|
1246
|
-
|
|
1247
|
-
function ReplayableIf(op, args, ifTrue, ifFalse) {
|
|
1248
|
-
return Replayable(op, args, () => {
|
|
1249
|
-
// If the conditional is false, jump to the ELSE label.
|
|
1250
|
-
op(66
|
|
1251
|
-
/* JumpUnless */
|
|
1252
|
-
, labelOperand('ELSE')); // Otherwise, execute the code associated with the true branch.
|
|
1253
|
-
|
|
1254
|
-
ifTrue(); // We're done, so return. In the initial execution, this runs
|
|
1255
|
-
// the cleanup code. In the updating VM, it exits the updating
|
|
1256
|
-
// routine.
|
|
1257
|
-
|
|
1258
|
-
op(4
|
|
1259
|
-
/* Jump */
|
|
1260
|
-
, labelOperand('FINALLY'));
|
|
1261
|
-
op(1000
|
|
1262
|
-
/* Label */
|
|
1263
|
-
, 'ELSE'); // If the conditional is false, and code associatied ith the
|
|
1264
|
-
// false branch was provided, execute it. If there was no code
|
|
1265
|
-
// associated with the false branch, jumping to the else statement
|
|
1266
|
-
// has no other behavior.
|
|
1267
|
-
|
|
1268
|
-
if (ifFalse !== undefined) {
|
|
1269
|
-
ifFalse();
|
|
388
|
+
switch (op[0]) {
|
|
389
|
+
case HighLevelBuilderOpcodes.Label:
|
|
390
|
+
return encoder.label(op[1]);
|
|
391
|
+
case HighLevelBuilderOpcodes.StartLabels:
|
|
392
|
+
return encoder.startLabels();
|
|
393
|
+
case HighLevelBuilderOpcodes.StopLabels:
|
|
394
|
+
return encoder.stopLabels();
|
|
395
|
+
case HighLevelResolutionOpcodes.Component:
|
|
396
|
+
return resolveComponent(resolver, constants, meta, op);
|
|
397
|
+
case HighLevelResolutionOpcodes.Modifier:
|
|
398
|
+
return resolveModifier(resolver, constants, meta, op);
|
|
399
|
+
case HighLevelResolutionOpcodes.Helper:
|
|
400
|
+
return resolveHelper(resolver, constants, meta, op);
|
|
401
|
+
case HighLevelResolutionOpcodes.ComponentOrHelper:
|
|
402
|
+
return resolveComponentOrHelper(resolver, constants, meta, op);
|
|
403
|
+
case HighLevelResolutionOpcodes.OptionalHelper:
|
|
404
|
+
return resolveOptionalHelper(resolver, constants, meta, op);
|
|
405
|
+
case HighLevelResolutionOpcodes.OptionalComponentOrHelper:
|
|
406
|
+
return resolveOptionalComponentOrHelper(resolver, constants, meta, op);
|
|
407
|
+
case HighLevelResolutionOpcodes.Local:
|
|
408
|
+
{
|
|
409
|
+
let freeVar = op[1];
|
|
410
|
+
let name = expect(meta.upvars, 'BUG: attempted to resolve value but no upvars found')[freeVar];
|
|
411
|
+
let andThen = op[2];
|
|
412
|
+
andThen(name, meta.moduleName);
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
case HighLevelResolutionOpcodes.TemplateLocal:
|
|
416
|
+
{
|
|
417
|
+
let [, valueIndex, then] = op;
|
|
418
|
+
let value = expect(meta.scopeValues, 'BUG: Attempted to gect a template local, but template does not have any')[valueIndex];
|
|
419
|
+
then(constants.value(value));
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
case HighLevelResolutionOpcodes.Free:
|
|
423
|
+
if (DEBUG) {
|
|
424
|
+
let [, upvarIndex] = op;
|
|
425
|
+
let freeName = expect(meta.upvars, 'BUG: attempted to resolve value but no upvars found')[upvarIndex];
|
|
426
|
+
throw new Error(`Attempted to resolve a value in a strict mode template, but that value was not in scope: ${freeName}`);
|
|
427
|
+
}
|
|
428
|
+
break;
|
|
429
|
+
default:
|
|
430
|
+
throw new Error(`Unexpected high level opcode ${op[0]}`);
|
|
1270
431
|
}
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
const ATTRS_BLOCK = '&attrs';
|
|
1275
|
-
function InvokeComponent(op, component, _elementBlock, positional, named, _blocks) {
|
|
1276
|
-
let {
|
|
1277
|
-
compilable,
|
|
1278
|
-
capabilities,
|
|
1279
|
-
handle
|
|
1280
|
-
} = component;
|
|
1281
|
-
let elementBlock = _elementBlock ? [_elementBlock, []] : null;
|
|
1282
|
-
let blocks = Array.isArray(_blocks) || _blocks === null ? namedBlocks(_blocks) : _blocks;
|
|
1283
|
-
|
|
1284
|
-
if (compilable) {
|
|
1285
|
-
op(78
|
|
1286
|
-
/* PushComponentDefinition */
|
|
1287
|
-
, handle);
|
|
1288
|
-
InvokeStaticComponent(op, {
|
|
1289
|
-
capabilities: capabilities,
|
|
1290
|
-
layout: compilable,
|
|
1291
|
-
elementBlock,
|
|
1292
|
-
positional,
|
|
1293
|
-
named,
|
|
1294
|
-
blocks
|
|
1295
|
-
});
|
|
1296
|
-
} else {
|
|
1297
|
-
op(78
|
|
1298
|
-
/* PushComponentDefinition */
|
|
1299
|
-
, handle);
|
|
1300
|
-
InvokeNonStaticComponent(op, {
|
|
1301
|
-
capabilities: capabilities,
|
|
1302
|
-
elementBlock,
|
|
1303
|
-
positional,
|
|
1304
|
-
named,
|
|
1305
|
-
atNames: true,
|
|
1306
|
-
blocks
|
|
1307
|
-
});
|
|
1308
432
|
}
|
|
1309
433
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
,
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
434
|
+
class EncoderImpl {
|
|
435
|
+
labelsStack = new Stack();
|
|
436
|
+
encoder = new InstructionEncoderImpl([]);
|
|
437
|
+
errors = [];
|
|
438
|
+
handle;
|
|
439
|
+
constructor(heap, meta, stdlib) {
|
|
440
|
+
this.heap = heap;
|
|
441
|
+
this.meta = meta;
|
|
442
|
+
this.stdlib = stdlib;
|
|
443
|
+
this.handle = heap.malloc();
|
|
444
|
+
}
|
|
445
|
+
error(error) {
|
|
446
|
+
this.encoder.encode(Op.Primitive, 0);
|
|
447
|
+
this.errors.push(error);
|
|
448
|
+
}
|
|
449
|
+
commit(size) {
|
|
450
|
+
let handle = this.handle;
|
|
451
|
+
this.heap.pushMachine(MachineOp.Return);
|
|
452
|
+
this.heap.finishMalloc(handle, size);
|
|
453
|
+
if (isPresentArray(this.errors)) {
|
|
454
|
+
return {
|
|
455
|
+
errors: this.errors,
|
|
456
|
+
handle
|
|
457
|
+
};
|
|
1328
458
|
} else {
|
|
1329
|
-
|
|
1330
|
-
/* ResolveDynamicComponent */
|
|
1331
|
-
, isStrictMode());
|
|
459
|
+
return handle;
|
|
1332
460
|
}
|
|
1333
|
-
|
|
1334
|
-
op(79
|
|
1335
|
-
/* PushDynamicComponentInstance */
|
|
1336
|
-
);
|
|
1337
|
-
InvokeNonStaticComponent(op, {
|
|
1338
|
-
capabilities: true,
|
|
1339
|
-
elementBlock,
|
|
1340
|
-
positional,
|
|
1341
|
-
named,
|
|
1342
|
-
atNames,
|
|
1343
|
-
blocks
|
|
1344
|
-
});
|
|
1345
|
-
op(1000
|
|
1346
|
-
/* Label */
|
|
1347
|
-
, 'ELSE');
|
|
1348
|
-
});
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
function InvokeStaticComponent(op, {
|
|
1352
|
-
capabilities,
|
|
1353
|
-
layout,
|
|
1354
|
-
elementBlock,
|
|
1355
|
-
positional,
|
|
1356
|
-
named,
|
|
1357
|
-
blocks
|
|
1358
|
-
}) {
|
|
1359
|
-
let {
|
|
1360
|
-
symbolTable
|
|
1361
|
-
} = layout;
|
|
1362
|
-
let bailOut = symbolTable.hasEval || hasCapability(capabilities, 4
|
|
1363
|
-
/* PrepareArgs */
|
|
1364
|
-
);
|
|
1365
|
-
|
|
1366
|
-
if (bailOut) {
|
|
1367
|
-
InvokeNonStaticComponent(op, {
|
|
1368
|
-
capabilities,
|
|
1369
|
-
elementBlock,
|
|
1370
|
-
positional,
|
|
1371
|
-
named,
|
|
1372
|
-
atNames: true,
|
|
1373
|
-
blocks,
|
|
1374
|
-
layout
|
|
1375
|
-
});
|
|
1376
|
-
return;
|
|
1377
461
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
, $sp, 1);
|
|
1385
|
-
op(35
|
|
1386
|
-
/* Load */
|
|
1387
|
-
, $s0);
|
|
1388
|
-
op(0
|
|
1389
|
-
/* PushFrame */
|
|
1390
|
-
); // Setup arguments
|
|
1391
|
-
|
|
1392
|
-
let {
|
|
1393
|
-
symbols
|
|
1394
|
-
} = symbolTable; // As we push values onto the stack, we store the symbols associated with them
|
|
1395
|
-
// so that we can set them on the scope later on with SetVariable and SetBlock
|
|
1396
|
-
|
|
1397
|
-
let blockSymbols = [];
|
|
1398
|
-
let argSymbols = [];
|
|
1399
|
-
let argNames = []; // First we push the blocks onto the stack
|
|
1400
|
-
|
|
1401
|
-
let blockNames = blocks.names; // Starting with the attrs block, if it exists and is referenced in the component
|
|
1402
|
-
|
|
1403
|
-
if (elementBlock !== null) {
|
|
1404
|
-
let symbol = symbols.indexOf(ATTRS_BLOCK);
|
|
1405
|
-
|
|
1406
|
-
if (symbol !== -1) {
|
|
1407
|
-
PushYieldableBlock(op, elementBlock);
|
|
1408
|
-
blockSymbols.push(symbol);
|
|
462
|
+
push(constants, type) {
|
|
463
|
+
let {
|
|
464
|
+
heap
|
|
465
|
+
} = this;
|
|
466
|
+
if (DEBUG && type > TYPE_SIZE) {
|
|
467
|
+
throw new Error(`Opcode type over 8-bits. Got ${type}.`);
|
|
1409
468
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
let symbol = symbols.indexOf(`&${name}`);
|
|
1417
|
-
|
|
1418
|
-
if (symbol !== -1) {
|
|
1419
|
-
PushYieldableBlock(op, blocks.get(name));
|
|
1420
|
-
blockSymbols.push(symbol);
|
|
469
|
+
let machine = isMachineOp(type) ? MACHINE_MASK : 0;
|
|
470
|
+
let first = type | machine | (arguments.length <= 2 ? 0 : arguments.length - 2) << ARG_SHIFT;
|
|
471
|
+
heap.pushRaw(first);
|
|
472
|
+
for (let i = 0; i < (arguments.length <= 2 ? 0 : arguments.length - 2); i++) {
|
|
473
|
+
let op = i + 2 < 2 || arguments.length <= i + 2 ? undefined : arguments[i + 2];
|
|
474
|
+
heap.pushRaw(this.operand(constants, op));
|
|
1421
475
|
}
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
argSymbols.push(symbol);
|
|
1449
|
-
}
|
|
1450
|
-
} // Finally, push the VM arguments themselves. These args won't need access
|
|
1451
|
-
// to blocks (they aren't accessible from userland anyways), so we push an
|
|
1452
|
-
// empty array instead of the actual block names.
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
op(82
|
|
1456
|
-
/* PushArgs */
|
|
1457
|
-
, names, EMPTY_STRING_ARRAY, flags); // And push an extra pop operation to remove the args before we begin setting
|
|
1458
|
-
// variables on the local context
|
|
1459
|
-
|
|
1460
|
-
argSymbols.push(-1);
|
|
1461
|
-
} else if (named !== null) {
|
|
1462
|
-
// If the component does not have the `createArgs` capability, then the only
|
|
1463
|
-
// expressions we need to push onto the stack are those that are actually
|
|
1464
|
-
// referenced in the template of the invoked component (e.g. have symbols).
|
|
1465
|
-
let names = named[0];
|
|
1466
|
-
let val = named[1];
|
|
1467
|
-
|
|
1468
|
-
for (let i = 0; i < val.length; i++) {
|
|
1469
|
-
let name = names[i];
|
|
1470
|
-
let symbol = symbols.indexOf(name);
|
|
1471
|
-
|
|
1472
|
-
if (symbol !== -1) {
|
|
1473
|
-
expr(op, val[i]);
|
|
1474
|
-
argSymbols.push(symbol);
|
|
1475
|
-
argNames.push(name);
|
|
476
|
+
}
|
|
477
|
+
operand(constants, operand) {
|
|
478
|
+
if (typeof operand === 'number') {
|
|
479
|
+
return operand;
|
|
480
|
+
}
|
|
481
|
+
if (typeof operand === 'object' && operand !== null) {
|
|
482
|
+
if (Array.isArray(operand)) {
|
|
483
|
+
return encodeHandle(constants.array(operand));
|
|
484
|
+
} else {
|
|
485
|
+
switch (operand.type) {
|
|
486
|
+
case HighLevelOperands.Label:
|
|
487
|
+
this.currentLabels.target(this.heap.offset, operand.value);
|
|
488
|
+
return -1;
|
|
489
|
+
case HighLevelOperands.IsStrictMode:
|
|
490
|
+
return encodeHandle(constants.value(this.meta.isStrictMode));
|
|
491
|
+
case HighLevelOperands.DebugSymbols:
|
|
492
|
+
return encodeHandle(constants.array(this.meta.evalSymbols || EMPTY_STRING_ARRAY));
|
|
493
|
+
case HighLevelOperands.Block:
|
|
494
|
+
return encodeHandle(constants.value(compilableBlock(operand.value, this.meta)));
|
|
495
|
+
case HighLevelOperands.StdLib:
|
|
496
|
+
return expect(this.stdlib, 'attempted to encode a stdlib operand, but the encoder did not have a stdlib. Are you currently building the stdlib?')[operand.value];
|
|
497
|
+
case HighLevelOperands.NonSmallInt:
|
|
498
|
+
case HighLevelOperands.SymbolTable:
|
|
499
|
+
case HighLevelOperands.Layout:
|
|
500
|
+
return constants.value(operand.value);
|
|
501
|
+
}
|
|
1476
502
|
}
|
|
1477
503
|
}
|
|
504
|
+
return encodeHandle(constants.value(operand));
|
|
1478
505
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
/* BeginComponentTransaction */
|
|
1482
|
-
, $s0);
|
|
1483
|
-
|
|
1484
|
-
if (hasCapability(capabilities, 64
|
|
1485
|
-
/* DynamicScope */
|
|
1486
|
-
)) {
|
|
1487
|
-
op(59
|
|
1488
|
-
/* PushDynamicScope */
|
|
1489
|
-
);
|
|
506
|
+
get currentLabels() {
|
|
507
|
+
return expect(this.labelsStack.current, 'bug: not in a label stack');
|
|
1490
508
|
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
/* CreateInstance */
|
|
1494
|
-
)) {
|
|
1495
|
-
op(87
|
|
1496
|
-
/* CreateComponent */
|
|
1497
|
-
, blocks.has('default') | 0, $s0);
|
|
509
|
+
label(name) {
|
|
510
|
+
this.currentLabels.label(name, this.heap.offset + 1);
|
|
1498
511
|
}
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
/* CreateArgs */
|
|
1506
|
-
)) {
|
|
1507
|
-
op(90
|
|
1508
|
-
/* GetComponentSelf */
|
|
1509
|
-
, $s0);
|
|
1510
|
-
} else {
|
|
1511
|
-
op(90
|
|
1512
|
-
/* GetComponentSelf */
|
|
1513
|
-
, $s0, argNames);
|
|
1514
|
-
} // Setup the new root scope for the component
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
op(37
|
|
1518
|
-
/* RootScope */
|
|
1519
|
-
, symbols.length + 1, Object.keys(blocks).length > 0 ? 1 : 0); // Pop the self reference off the stack and set it to the symbol for `this`
|
|
1520
|
-
// in the new scope. This is why all subsequent symbols are increased by one.
|
|
1521
|
-
|
|
1522
|
-
op(19
|
|
1523
|
-
/* SetVariable */
|
|
1524
|
-
, 0); // Going in reverse, now we pop the args/blocks off the stack, starting with
|
|
1525
|
-
// arguments, and assign them to their symbols in the new scope.
|
|
1526
|
-
|
|
1527
|
-
for (let i = argSymbols.length - 1; i >= 0; i--) {
|
|
1528
|
-
let symbol = argSymbols[i];
|
|
1529
|
-
|
|
1530
|
-
if (symbol === -1) {
|
|
1531
|
-
// The expression was not bound to a local symbol, it was only pushed to be
|
|
1532
|
-
// used with VM args in the javascript side
|
|
1533
|
-
op(34
|
|
1534
|
-
/* Pop */
|
|
1535
|
-
, 1);
|
|
1536
|
-
} else {
|
|
1537
|
-
op(19
|
|
1538
|
-
/* SetVariable */
|
|
1539
|
-
, symbol + 1);
|
|
1540
|
-
}
|
|
1541
|
-
} // if any positional params exist, pop them off the stack as well
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
if (positional !== null) {
|
|
1545
|
-
op(34
|
|
1546
|
-
/* Pop */
|
|
1547
|
-
, positional.length);
|
|
1548
|
-
} // Finish up by popping off and assigning blocks
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
for (let i = blockSymbols.length - 1; i >= 0; i--) {
|
|
1552
|
-
let symbol = blockSymbols[i];
|
|
1553
|
-
op(20
|
|
1554
|
-
/* SetBlock */
|
|
1555
|
-
, symbol + 1);
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
op(28
|
|
1559
|
-
/* Constant */
|
|
1560
|
-
, layoutOperand(layout));
|
|
1561
|
-
op(61
|
|
1562
|
-
/* CompileBlock */
|
|
1563
|
-
);
|
|
1564
|
-
op(2
|
|
1565
|
-
/* InvokeVirtual */
|
|
1566
|
-
);
|
|
1567
|
-
op(100
|
|
1568
|
-
/* DidRenderLayout */
|
|
1569
|
-
, $s0);
|
|
1570
|
-
op(1
|
|
1571
|
-
/* PopFrame */
|
|
1572
|
-
);
|
|
1573
|
-
op(40
|
|
1574
|
-
/* PopScope */
|
|
1575
|
-
);
|
|
1576
|
-
|
|
1577
|
-
if (hasCapability(capabilities, 64
|
|
1578
|
-
/* DynamicScope */
|
|
1579
|
-
)) {
|
|
1580
|
-
op(60
|
|
1581
|
-
/* PopDynamicScope */
|
|
1582
|
-
);
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
op(98
|
|
1586
|
-
/* CommitComponentTransaction */
|
|
1587
|
-
);
|
|
1588
|
-
op(35
|
|
1589
|
-
/* Load */
|
|
1590
|
-
, $s0);
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
function InvokeNonStaticComponent(op, {
|
|
1594
|
-
capabilities,
|
|
1595
|
-
elementBlock,
|
|
1596
|
-
positional,
|
|
1597
|
-
named,
|
|
1598
|
-
atNames,
|
|
1599
|
-
blocks: namedBlocks,
|
|
1600
|
-
layout
|
|
1601
|
-
}) {
|
|
1602
|
-
let bindableBlocks = !!namedBlocks;
|
|
1603
|
-
let bindableAtNames = capabilities === true || hasCapability(capabilities, 4
|
|
1604
|
-
/* PrepareArgs */
|
|
1605
|
-
) || !!(named && named[0].length !== 0);
|
|
1606
|
-
let blocks = namedBlocks.with('attrs', elementBlock);
|
|
1607
|
-
op(36
|
|
1608
|
-
/* Fetch */
|
|
1609
|
-
, $s0);
|
|
1610
|
-
op(33
|
|
1611
|
-
/* Dup */
|
|
1612
|
-
, $sp, 1);
|
|
1613
|
-
op(35
|
|
1614
|
-
/* Load */
|
|
1615
|
-
, $s0);
|
|
1616
|
-
op(0
|
|
1617
|
-
/* PushFrame */
|
|
1618
|
-
);
|
|
1619
|
-
CompileArgs(op, positional, named, blocks, atNames);
|
|
1620
|
-
op(85
|
|
1621
|
-
/* PrepareArgs */
|
|
1622
|
-
, $s0);
|
|
1623
|
-
invokePreparedComponent(op, blocks.has('default'), bindableBlocks, bindableAtNames, () => {
|
|
1624
|
-
if (layout) {
|
|
1625
|
-
op(63
|
|
1626
|
-
/* PushSymbolTable */
|
|
1627
|
-
, symbolTableOperand(layout.symbolTable));
|
|
1628
|
-
op(28
|
|
1629
|
-
/* Constant */
|
|
1630
|
-
, layoutOperand(layout));
|
|
1631
|
-
op(61
|
|
1632
|
-
/* CompileBlock */
|
|
1633
|
-
);
|
|
1634
|
-
} else {
|
|
1635
|
-
op(92
|
|
1636
|
-
/* GetComponentLayout */
|
|
1637
|
-
, $s0);
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
op(95
|
|
1641
|
-
/* PopulateLayout */
|
|
1642
|
-
, $s0);
|
|
1643
|
-
});
|
|
1644
|
-
op(35
|
|
1645
|
-
/* Load */
|
|
1646
|
-
, $s0);
|
|
1647
|
-
}
|
|
1648
|
-
function WrappedComponent(op, layout, attrsBlockNumber) {
|
|
1649
|
-
op(1001
|
|
1650
|
-
/* StartLabels */
|
|
1651
|
-
);
|
|
1652
|
-
WithSavedRegister(op, $s1, () => {
|
|
1653
|
-
op(91
|
|
1654
|
-
/* GetComponentTagName */
|
|
1655
|
-
, $s0);
|
|
1656
|
-
op(31
|
|
1657
|
-
/* PrimitiveReference */
|
|
1658
|
-
);
|
|
1659
|
-
op(33
|
|
1660
|
-
/* Dup */
|
|
1661
|
-
, $sp, 0);
|
|
1662
|
-
});
|
|
1663
|
-
op(66
|
|
1664
|
-
/* JumpUnless */
|
|
1665
|
-
, labelOperand('BODY'));
|
|
1666
|
-
op(36
|
|
1667
|
-
/* Fetch */
|
|
1668
|
-
, $s1);
|
|
1669
|
-
op(89
|
|
1670
|
-
/* PutComponentOperations */
|
|
1671
|
-
);
|
|
1672
|
-
op(49
|
|
1673
|
-
/* OpenDynamicElement */
|
|
1674
|
-
);
|
|
1675
|
-
op(99
|
|
1676
|
-
/* DidCreateElement */
|
|
1677
|
-
, $s0);
|
|
1678
|
-
YieldBlock(op, attrsBlockNumber, null);
|
|
1679
|
-
op(54
|
|
1680
|
-
/* FlushElement */
|
|
1681
|
-
);
|
|
1682
|
-
op(1000
|
|
1683
|
-
/* Label */
|
|
1684
|
-
, 'BODY');
|
|
1685
|
-
InvokeStaticBlock(op, [layout.block[0], []]);
|
|
1686
|
-
op(36
|
|
1687
|
-
/* Fetch */
|
|
1688
|
-
, $s1);
|
|
1689
|
-
op(66
|
|
1690
|
-
/* JumpUnless */
|
|
1691
|
-
, labelOperand('END'));
|
|
1692
|
-
op(55
|
|
1693
|
-
/* CloseElement */
|
|
1694
|
-
);
|
|
1695
|
-
op(1000
|
|
1696
|
-
/* Label */
|
|
1697
|
-
, 'END');
|
|
1698
|
-
op(35
|
|
1699
|
-
/* Load */
|
|
1700
|
-
, $s1);
|
|
1701
|
-
op(1002
|
|
1702
|
-
/* StopLabels */
|
|
1703
|
-
);
|
|
1704
|
-
}
|
|
1705
|
-
function invokePreparedComponent(op, hasBlock, bindableBlocks, bindableAtNames, populateLayout = null) {
|
|
1706
|
-
op(97
|
|
1707
|
-
/* BeginComponentTransaction */
|
|
1708
|
-
, $s0);
|
|
1709
|
-
op(59
|
|
1710
|
-
/* PushDynamicScope */
|
|
1711
|
-
);
|
|
1712
|
-
op(87
|
|
1713
|
-
/* CreateComponent */
|
|
1714
|
-
, hasBlock | 0, $s0); // this has to run after createComponent to allow
|
|
1715
|
-
// for late-bound layouts, but a caller is free
|
|
1716
|
-
// to populate the layout earlier if it wants to
|
|
1717
|
-
// and do nothing here.
|
|
1718
|
-
|
|
1719
|
-
if (populateLayout) {
|
|
1720
|
-
populateLayout();
|
|
512
|
+
startLabels() {
|
|
513
|
+
this.labelsStack.push(new Labels());
|
|
514
|
+
}
|
|
515
|
+
stopLabels() {
|
|
516
|
+
let label = expect(this.labelsStack.pop(), 'unbalanced push and pop labels');
|
|
517
|
+
label.patch(this.heap);
|
|
1721
518
|
}
|
|
1722
|
-
|
|
1723
|
-
op(88
|
|
1724
|
-
/* RegisterComponentDestructor */
|
|
1725
|
-
, $s0);
|
|
1726
|
-
op(90
|
|
1727
|
-
/* GetComponentSelf */
|
|
1728
|
-
, $s0);
|
|
1729
|
-
op(38
|
|
1730
|
-
/* VirtualRootScope */
|
|
1731
|
-
, $s0);
|
|
1732
|
-
op(19
|
|
1733
|
-
/* SetVariable */
|
|
1734
|
-
, 0);
|
|
1735
|
-
op(94
|
|
1736
|
-
/* SetupForEval */
|
|
1737
|
-
, $s0);
|
|
1738
|
-
if (bindableAtNames) op(17
|
|
1739
|
-
/* SetNamedVariables */
|
|
1740
|
-
, $s0);
|
|
1741
|
-
if (bindableBlocks) op(18
|
|
1742
|
-
/* SetBlocks */
|
|
1743
|
-
, $s0);
|
|
1744
|
-
op(34
|
|
1745
|
-
/* Pop */
|
|
1746
|
-
, 1);
|
|
1747
|
-
op(96
|
|
1748
|
-
/* InvokeComponentLayout */
|
|
1749
|
-
, $s0);
|
|
1750
|
-
op(100
|
|
1751
|
-
/* DidRenderLayout */
|
|
1752
|
-
, $s0);
|
|
1753
|
-
op(1
|
|
1754
|
-
/* PopFrame */
|
|
1755
|
-
);
|
|
1756
|
-
op(40
|
|
1757
|
-
/* PopScope */
|
|
1758
|
-
);
|
|
1759
|
-
op(60
|
|
1760
|
-
/* PopDynamicScope */
|
|
1761
|
-
);
|
|
1762
|
-
op(98
|
|
1763
|
-
/* CommitComponentTransaction */
|
|
1764
|
-
);
|
|
1765
|
-
}
|
|
1766
|
-
function InvokeBareComponent(op) {
|
|
1767
|
-
op(36
|
|
1768
|
-
/* Fetch */
|
|
1769
|
-
, $s0);
|
|
1770
|
-
op(33
|
|
1771
|
-
/* Dup */
|
|
1772
|
-
, $sp, 1);
|
|
1773
|
-
op(35
|
|
1774
|
-
/* Load */
|
|
1775
|
-
, $s0);
|
|
1776
|
-
op(0
|
|
1777
|
-
/* PushFrame */
|
|
1778
|
-
);
|
|
1779
|
-
op(83
|
|
1780
|
-
/* PushEmptyArgs */
|
|
1781
|
-
);
|
|
1782
|
-
op(85
|
|
1783
|
-
/* PrepareArgs */
|
|
1784
|
-
, $s0);
|
|
1785
|
-
invokePreparedComponent(op, false, false, true, () => {
|
|
1786
|
-
op(92
|
|
1787
|
-
/* GetComponentLayout */
|
|
1788
|
-
, $s0);
|
|
1789
|
-
op(95
|
|
1790
|
-
/* PopulateLayout */
|
|
1791
|
-
, $s0);
|
|
1792
|
-
});
|
|
1793
|
-
op(35
|
|
1794
|
-
/* Load */
|
|
1795
|
-
, $s0);
|
|
1796
519
|
}
|
|
1797
|
-
function
|
|
1798
|
-
op
|
|
1799
|
-
/* Fetch */
|
|
1800
|
-
, register);
|
|
1801
|
-
block();
|
|
1802
|
-
op(35
|
|
1803
|
-
/* Load */
|
|
1804
|
-
, register);
|
|
520
|
+
function isBuilderOpcode(op) {
|
|
521
|
+
return op < HighLevelBuilderOpcodes.Start;
|
|
1805
522
|
}
|
|
1806
523
|
|
|
1807
524
|
class StdLib {
|
|
@@ -1812,837 +529,1008 @@ class StdLib {
|
|
|
1812
529
|
this.trustingNonDynamicAppend = trustingNonDynamicAppend;
|
|
1813
530
|
this.cautiousNonDynamicAppend = cautiousNonDynamicAppend;
|
|
1814
531
|
}
|
|
1815
|
-
|
|
1816
532
|
get 'trusting-append'() {
|
|
1817
533
|
return this.trustingGuardedAppend;
|
|
1818
534
|
}
|
|
1819
|
-
|
|
1820
535
|
get 'cautious-append'() {
|
|
1821
536
|
return this.cautiousGuardedAppend;
|
|
1822
537
|
}
|
|
1823
|
-
|
|
1824
538
|
get 'trusting-non-dynamic-append'() {
|
|
1825
539
|
return this.trustingNonDynamicAppend;
|
|
1826
540
|
}
|
|
541
|
+
get 'cautious-non-dynamic-append'() {
|
|
542
|
+
return this.cautiousNonDynamicAppend;
|
|
543
|
+
}
|
|
544
|
+
getAppend(trusting) {
|
|
545
|
+
return trusting ? this.trustingGuardedAppend : this.cautiousGuardedAppend;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
class NamedBlocksImpl {
|
|
550
|
+
names;
|
|
551
|
+
constructor(blocks) {
|
|
552
|
+
this.blocks = blocks;
|
|
553
|
+
this.names = blocks ? Object.keys(blocks) : [];
|
|
554
|
+
}
|
|
555
|
+
get(name) {
|
|
556
|
+
if (!this.blocks) return null;
|
|
557
|
+
return this.blocks[name] || null;
|
|
558
|
+
}
|
|
559
|
+
has(name) {
|
|
560
|
+
let {
|
|
561
|
+
blocks
|
|
562
|
+
} = this;
|
|
563
|
+
return blocks !== null && name in blocks;
|
|
564
|
+
}
|
|
565
|
+
with(name, block) {
|
|
566
|
+
let {
|
|
567
|
+
blocks
|
|
568
|
+
} = this;
|
|
569
|
+
if (blocks) {
|
|
570
|
+
return new NamedBlocksImpl(assign({}, blocks, {
|
|
571
|
+
[name]: block
|
|
572
|
+
}));
|
|
573
|
+
} else {
|
|
574
|
+
return new NamedBlocksImpl({
|
|
575
|
+
[name]: block
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
get hasAny() {
|
|
580
|
+
return this.blocks !== null;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
const EMPTY_BLOCKS = new NamedBlocksImpl(null);
|
|
584
|
+
function namedBlocks(blocks) {
|
|
585
|
+
if (blocks === null) {
|
|
586
|
+
return EMPTY_BLOCKS;
|
|
587
|
+
}
|
|
588
|
+
let out = dict();
|
|
589
|
+
let [keys, values] = blocks;
|
|
590
|
+
for (const [i, key] of enumerate(keys)) {
|
|
591
|
+
out[key] = unwrap(values[i]);
|
|
592
|
+
}
|
|
593
|
+
return new NamedBlocksImpl(out);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Push a reference onto the stack corresponding to a statically known primitive
|
|
598
|
+
* @param value A JavaScript primitive (undefined, null, boolean, number or string)
|
|
599
|
+
*/
|
|
600
|
+
function PushPrimitiveReference(op, value) {
|
|
601
|
+
PushPrimitive(op, value);
|
|
602
|
+
op(Op.PrimitiveReference);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Push an encoded representation of a JavaScript primitive on the stack
|
|
607
|
+
*
|
|
608
|
+
* @param value A JavaScript primitive (undefined, null, boolean, number or string)
|
|
609
|
+
*/
|
|
610
|
+
function PushPrimitive(op, primitive) {
|
|
611
|
+
let p = primitive;
|
|
612
|
+
if (typeof p === 'number') {
|
|
613
|
+
p = isSmallInt(p) ? encodeImmediate(p) : nonSmallIntOperand(p);
|
|
614
|
+
}
|
|
615
|
+
op(Op.Primitive, p);
|
|
616
|
+
}
|
|
1827
617
|
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
618
|
+
/**
|
|
619
|
+
* Invoke a foreign function (a "helper") based on a statically known handle
|
|
620
|
+
*
|
|
621
|
+
* @param op The op creation function
|
|
622
|
+
* @param handle A handle
|
|
623
|
+
* @param positional An optional list of expressions to compile
|
|
624
|
+
* @param named An optional list of named arguments (name + expression) to compile
|
|
625
|
+
*/
|
|
626
|
+
function Call(op, handle, positional, named) {
|
|
627
|
+
op(MachineOp.PushFrame);
|
|
628
|
+
SimpleArgs(op, positional, named, false);
|
|
629
|
+
op(Op.Helper, handle);
|
|
630
|
+
op(MachineOp.PopFrame);
|
|
631
|
+
op(Op.Fetch, $v0);
|
|
632
|
+
}
|
|
1831
633
|
|
|
1832
|
-
|
|
1833
|
-
|
|
634
|
+
/**
|
|
635
|
+
* Invoke a foreign function (a "helper") based on a dynamically loaded definition
|
|
636
|
+
*
|
|
637
|
+
* @param op The op creation function
|
|
638
|
+
* @param positional An optional list of expressions to compile
|
|
639
|
+
* @param named An optional list of named arguments (name + expression) to compile
|
|
640
|
+
*/
|
|
641
|
+
function CallDynamic(op, positional, named, append) {
|
|
642
|
+
op(MachineOp.PushFrame);
|
|
643
|
+
SimpleArgs(op, positional, named, false);
|
|
644
|
+
op(Op.Dup, $fp, 1);
|
|
645
|
+
op(Op.DynamicHelper);
|
|
646
|
+
if (append) {
|
|
647
|
+
op(Op.Fetch, $v0);
|
|
648
|
+
append();
|
|
649
|
+
op(MachineOp.PopFrame);
|
|
650
|
+
op(Op.Pop, 1);
|
|
651
|
+
} else {
|
|
652
|
+
op(MachineOp.PopFrame);
|
|
653
|
+
op(Op.Pop, 1);
|
|
654
|
+
op(Op.Fetch, $v0);
|
|
1834
655
|
}
|
|
1835
|
-
|
|
1836
656
|
}
|
|
1837
657
|
|
|
1838
|
-
|
|
1839
|
-
|
|
658
|
+
/**
|
|
659
|
+
* Evaluate statements in the context of new dynamic scope entries. Move entries from the
|
|
660
|
+
* stack into named entries in the dynamic scope, then evaluate the statements, then pop
|
|
661
|
+
* the dynamic scope
|
|
662
|
+
*
|
|
663
|
+
* @param names a list of dynamic scope names
|
|
664
|
+
* @param block a function that returns a list of statements to evaluate
|
|
665
|
+
*/
|
|
666
|
+
function DynamicScope(op, names, block) {
|
|
667
|
+
op(Op.PushDynamicScope);
|
|
668
|
+
op(Op.BindDynamicScope, names);
|
|
669
|
+
block();
|
|
670
|
+
op(Op.PopDynamicScope);
|
|
1840
671
|
}
|
|
1841
|
-
function
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
672
|
+
function Curry(op, type, definition, positional, named) {
|
|
673
|
+
op(MachineOp.PushFrame);
|
|
674
|
+
SimpleArgs(op, positional, named, false);
|
|
675
|
+
op(Op.CaptureArgs);
|
|
676
|
+
expr(op, definition);
|
|
677
|
+
op(Op.Curry, type, isStrictMode());
|
|
678
|
+
op(MachineOp.PopFrame);
|
|
679
|
+
op(Op.Fetch, $v0);
|
|
1848
680
|
}
|
|
1849
681
|
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
682
|
+
class Compilers {
|
|
683
|
+
names = {};
|
|
684
|
+
funcs = [];
|
|
685
|
+
add(name, func) {
|
|
686
|
+
this.names[name] = this.funcs.push(func) - 1;
|
|
687
|
+
}
|
|
688
|
+
compile(op, sexp) {
|
|
689
|
+
let name = sexp[0];
|
|
690
|
+
let index = unwrap(this.names[name]);
|
|
691
|
+
let func = this.funcs[index];
|
|
692
|
+
assert$1(!!func, `expected an implementation for ${sexp[0]}`);
|
|
693
|
+
func(op, sexp);
|
|
694
|
+
}
|
|
1860
695
|
}
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
, (op,
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
,
|
|
1869
|
-
|
|
1870
|
-
)
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
,
|
|
1874
|
-
|
|
1875
|
-
));
|
|
1876
|
-
STATEMENTS.add(4
|
|
1877
|
-
/* Modifier */
|
|
1878
|
-
, (op, [, expression, positional, named]) => {
|
|
1879
|
-
if (isGetFreeModifier(expression)) {
|
|
1880
|
-
op(1003
|
|
1881
|
-
/* ResolveModifier */
|
|
1882
|
-
, expression, handle => {
|
|
1883
|
-
op(0
|
|
1884
|
-
/* PushFrame */
|
|
1885
|
-
);
|
|
1886
|
-
SimpleArgs(op, positional, named, false);
|
|
1887
|
-
op(57
|
|
1888
|
-
/* Modifier */
|
|
1889
|
-
, handle);
|
|
1890
|
-
op(1
|
|
1891
|
-
/* PopFrame */
|
|
1892
|
-
);
|
|
696
|
+
|
|
697
|
+
const EXPRESSIONS = new Compilers();
|
|
698
|
+
EXPRESSIONS.add(SexpOpcodes.Concat, (op, _ref) => {
|
|
699
|
+
let [, parts] = _ref;
|
|
700
|
+
for (let part of parts) {
|
|
701
|
+
expr(op, part);
|
|
702
|
+
}
|
|
703
|
+
op(Op.Concat, parts.length);
|
|
704
|
+
});
|
|
705
|
+
EXPRESSIONS.add(SexpOpcodes.Call, (op, _ref2) => {
|
|
706
|
+
let [, expression, positional, named] = _ref2;
|
|
707
|
+
if (isGetFreeHelper(expression)) {
|
|
708
|
+
op(HighLevelResolutionOpcodes.Helper, expression, handle => {
|
|
709
|
+
Call(op, handle, positional, named);
|
|
1893
710
|
});
|
|
1894
711
|
} else {
|
|
1895
712
|
expr(op, expression);
|
|
1896
|
-
op
|
|
1897
|
-
/* PushFrame */
|
|
1898
|
-
);
|
|
1899
|
-
SimpleArgs(op, positional, named, false);
|
|
1900
|
-
op(33
|
|
1901
|
-
/* Dup */
|
|
1902
|
-
, $fp, 1);
|
|
1903
|
-
op(108
|
|
1904
|
-
/* DynamicModifier */
|
|
1905
|
-
);
|
|
1906
|
-
op(1
|
|
1907
|
-
/* PopFrame */
|
|
1908
|
-
);
|
|
713
|
+
CallDynamic(op, positional, named);
|
|
1909
714
|
}
|
|
1910
715
|
});
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
op(51
|
|
1915
|
-
/* StaticAttr */
|
|
1916
|
-
, inflateAttrName(name), value, namespace !== null && namespace !== void 0 ? namespace : null);
|
|
1917
|
-
});
|
|
1918
|
-
STATEMENTS.add(24
|
|
1919
|
-
/* StaticComponentAttr */
|
|
1920
|
-
, (op, [, name, value, namespace]) => {
|
|
1921
|
-
op(105
|
|
1922
|
-
/* StaticComponentAttr */
|
|
1923
|
-
, inflateAttrName(name), value, namespace !== null && namespace !== void 0 ? namespace : null);
|
|
1924
|
-
});
|
|
1925
|
-
STATEMENTS.add(15
|
|
1926
|
-
/* DynamicAttr */
|
|
1927
|
-
, (op, [, name, value, namespace]) => {
|
|
1928
|
-
expr(op, value);
|
|
1929
|
-
op(52
|
|
1930
|
-
/* DynamicAttr */
|
|
1931
|
-
, inflateAttrName(name), false, namespace !== null && namespace !== void 0 ? namespace : null);
|
|
1932
|
-
});
|
|
1933
|
-
STATEMENTS.add(22
|
|
1934
|
-
/* TrustingDynamicAttr */
|
|
1935
|
-
, (op, [, name, value, namespace]) => {
|
|
1936
|
-
expr(op, value);
|
|
1937
|
-
op(52
|
|
1938
|
-
/* DynamicAttr */
|
|
1939
|
-
, inflateAttrName(name), true, namespace !== null && namespace !== void 0 ? namespace : null);
|
|
1940
|
-
});
|
|
1941
|
-
STATEMENTS.add(16
|
|
1942
|
-
/* ComponentAttr */
|
|
1943
|
-
, (op, [, name, value, namespace]) => {
|
|
1944
|
-
expr(op, value);
|
|
1945
|
-
op(53
|
|
1946
|
-
/* ComponentAttr */
|
|
1947
|
-
, inflateAttrName(name), false, namespace !== null && namespace !== void 0 ? namespace : null);
|
|
716
|
+
EXPRESSIONS.add(SexpOpcodes.Curry, (op, _ref3) => {
|
|
717
|
+
let [, expr, type, positional, named] = _ref3;
|
|
718
|
+
Curry(op, type, expr, positional, named);
|
|
1948
719
|
});
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
op(53
|
|
1954
|
-
/* ComponentAttr */
|
|
1955
|
-
, inflateAttrName(name), true, namespace !== null && namespace !== void 0 ? namespace : null);
|
|
720
|
+
EXPRESSIONS.add(SexpOpcodes.GetSymbol, (op, _ref4) => {
|
|
721
|
+
let [, sym, path] = _ref4;
|
|
722
|
+
op(Op.GetVariable, sym);
|
|
723
|
+
withPath(op, path);
|
|
1956
724
|
});
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
725
|
+
EXPRESSIONS.add(SexpOpcodes.GetLexicalSymbol, (op, _ref5) => {
|
|
726
|
+
let [, sym, path] = _ref5;
|
|
727
|
+
op(HighLevelResolutionOpcodes.TemplateLocal, sym, handle => {
|
|
728
|
+
op(Op.ConstantReference, handle);
|
|
729
|
+
withPath(op, path);
|
|
730
|
+
});
|
|
1963
731
|
});
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
);
|
|
1970
|
-
op(48
|
|
1971
|
-
/* OpenElement */
|
|
1972
|
-
, inflateTagName(tag));
|
|
732
|
+
EXPRESSIONS.add(SexpOpcodes.GetStrictKeyword, (op, _ref6) => {
|
|
733
|
+
let [, sym, _path] = _ref6;
|
|
734
|
+
op(HighLevelResolutionOpcodes.Free, sym, _handle => {
|
|
735
|
+
// TODO: Implement in strict mode
|
|
736
|
+
});
|
|
1973
737
|
});
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
, expr, component => {
|
|
1981
|
-
InvokeComponent(op, component, elementBlock, null, named, blocks);
|
|
1982
|
-
});
|
|
1983
|
-
} else {
|
|
1984
|
-
// otherwise, the component name was an expression, so resolve the expression
|
|
1985
|
-
// and invoke it as a dynamic component
|
|
1986
|
-
InvokeDynamicComponent(op, expr, elementBlock, null, named, blocks, true, true);
|
|
1987
|
-
}
|
|
738
|
+
EXPRESSIONS.add(SexpOpcodes.GetFreeAsComponentOrHelperHeadOrThisFallback, () => {
|
|
739
|
+
// TODO: The logic for this opcode currently exists in STATEMENTS.Append, since
|
|
740
|
+
// we want different wrapping logic depending on if we are invoking a component,
|
|
741
|
+
// helper, or {{this}} fallback. Eventually we fix the opcodes so that we can
|
|
742
|
+
// traverse the subexpression tree like normal in this location.
|
|
743
|
+
throw new Error('unimplemented opcode');
|
|
1988
744
|
});
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
, (op, [, to, params]) => YieldBlock(op, to, params));
|
|
1992
|
-
STATEMENTS.add(17
|
|
1993
|
-
/* AttrSplat */
|
|
1994
|
-
, (op, [, to]) => YieldBlock(op, to, null));
|
|
1995
|
-
STATEMENTS.add(26
|
|
1996
|
-
/* Debugger */
|
|
1997
|
-
, (op, [, evalInfo]) => op(103
|
|
1998
|
-
/* Debugger */
|
|
1999
|
-
, evalSymbolsOperand(), evalInfo));
|
|
2000
|
-
STATEMENTS.add(1
|
|
2001
|
-
/* Append */
|
|
2002
|
-
, (op, [, value]) => {
|
|
2003
|
-
// Special case for static values
|
|
2004
|
-
if (!Array.isArray(value)) {
|
|
2005
|
-
op(41
|
|
2006
|
-
/* Text */
|
|
2007
|
-
, value === null || value === undefined ? '' : String(value));
|
|
2008
|
-
} else if (isGetFreeOptionalComponentOrHelper(value)) {
|
|
2009
|
-
op(1008
|
|
2010
|
-
/* ResolveOptionalComponentOrHelper */
|
|
2011
|
-
, value, {
|
|
2012
|
-
ifComponent(component) {
|
|
2013
|
-
InvokeComponent(op, component, null, null, null, null);
|
|
2014
|
-
},
|
|
745
|
+
EXPRESSIONS.add(SexpOpcodes.GetFreeAsHelperHeadOrThisFallback, (op, expr) => {
|
|
746
|
+
// <div id={{baz}}>
|
|
2015
747
|
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
);
|
|
748
|
+
op(HighLevelResolutionOpcodes.Local, expr[1], _name => {
|
|
749
|
+
op(HighLevelResolutionOpcodes.OptionalHelper, expr, {
|
|
750
|
+
ifHelper: handle => {
|
|
2020
751
|
Call(op, handle, null, null);
|
|
2021
|
-
op(3
|
|
2022
|
-
/* InvokeStatic */
|
|
2023
|
-
, stdlibOperand('cautious-non-dynamic-append'));
|
|
2024
|
-
op(1
|
|
2025
|
-
/* PopFrame */
|
|
2026
|
-
);
|
|
2027
|
-
},
|
|
2028
|
-
|
|
2029
|
-
ifValue(handle) {
|
|
2030
|
-
op(0
|
|
2031
|
-
/* PushFrame */
|
|
2032
|
-
);
|
|
2033
|
-
op(29
|
|
2034
|
-
/* ConstantReference */
|
|
2035
|
-
, handle);
|
|
2036
|
-
op(3
|
|
2037
|
-
/* InvokeStatic */
|
|
2038
|
-
, stdlibOperand('cautious-non-dynamic-append'));
|
|
2039
|
-
op(1
|
|
2040
|
-
/* PopFrame */
|
|
2041
|
-
);
|
|
2042
752
|
}
|
|
2043
|
-
|
|
2044
753
|
});
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
if (isGetFreeComponentOrHelper(expression)) {
|
|
2051
|
-
op(1007
|
|
2052
|
-
/* ResolveComponentOrHelper */
|
|
2053
|
-
, expression, {
|
|
2054
|
-
ifComponent(component) {
|
|
2055
|
-
InvokeComponent(op, component, null, positional, hashToArgs(named), null);
|
|
2056
|
-
},
|
|
2057
|
-
|
|
2058
|
-
ifHelper(handle) {
|
|
2059
|
-
op(0
|
|
2060
|
-
/* PushFrame */
|
|
2061
|
-
);
|
|
2062
|
-
Call(op, handle, positional, named);
|
|
2063
|
-
op(3
|
|
2064
|
-
/* InvokeStatic */
|
|
2065
|
-
, stdlibOperand('cautious-non-dynamic-append'));
|
|
2066
|
-
op(1
|
|
2067
|
-
/* PopFrame */
|
|
2068
|
-
);
|
|
2069
|
-
}
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
EXPRESSIONS.add(SexpOpcodes.GetFreeAsDeprecatedHelperHeadOrThisFallback, (op, expr) => {
|
|
757
|
+
// <Foo @bar={{baz}}>
|
|
2070
758
|
|
|
759
|
+
op(HighLevelResolutionOpcodes.Local, expr[1], _name => {
|
|
760
|
+
op(HighLevelResolutionOpcodes.OptionalHelper, expr, {
|
|
761
|
+
ifHelper: (handle, name, moduleName) => {
|
|
762
|
+
assert(expr[2] && expr[2].length === 1, '[BUG] Missing argument name');
|
|
763
|
+
let arg = expr[2][0];
|
|
764
|
+
deprecate(`The \`${name}\` helper was used in the \`${moduleName}\` template as \`${arg}={{${name}}}\`. ` + `This is ambigious between wanting the \`${arg}\` argument to be the \`${name}\` helper itself, ` + `or the result of invoking the \`${name}\` helper (current behavior). ` + `This implicit invocation behavior has been deprecated.\n\n` + `Instead, please explicitly invoke the helper with parenthesis, i.e. \`${arg}={{(${name})}}\`.\n\n` + `Note: the parenthesis are only required in this exact scenario where an ambiguity is present – where ` + `\`${name}\` referes to a global helper (as opposed to a local variable), AND ` + `the \`${name}\` helper invocation does not take any arguments, AND ` + `this occurs in a named argument position of a component invocation.\n\n` + `We expect this combination to be quite rare, as most helpers require at least one argument. ` + `There is no need to refactor helper invocations in cases where this deprecation was not triggered.`, false, {
|
|
765
|
+
id: 'argument-less-helper-paren-less-invocation'
|
|
2071
766
|
});
|
|
2072
|
-
|
|
2073
|
-
SwitchCases(op, () => {
|
|
2074
|
-
expr(op, expression);
|
|
2075
|
-
op(106
|
|
2076
|
-
/* DynamicContentType */
|
|
2077
|
-
);
|
|
2078
|
-
}, when => {
|
|
2079
|
-
when(0
|
|
2080
|
-
/* Component */
|
|
2081
|
-
, () => {
|
|
2082
|
-
op(81
|
|
2083
|
-
/* ResolveCurriedComponent */
|
|
2084
|
-
);
|
|
2085
|
-
op(79
|
|
2086
|
-
/* PushDynamicComponentInstance */
|
|
2087
|
-
);
|
|
2088
|
-
InvokeNonStaticComponent(op, {
|
|
2089
|
-
capabilities: true,
|
|
2090
|
-
elementBlock: null,
|
|
2091
|
-
positional,
|
|
2092
|
-
named,
|
|
2093
|
-
atNames: false,
|
|
2094
|
-
blocks: namedBlocks(null)
|
|
2095
|
-
});
|
|
2096
|
-
});
|
|
2097
|
-
when(1
|
|
2098
|
-
/* Helper */
|
|
2099
|
-
, () => {
|
|
2100
|
-
CallDynamic(op, positional, named, () => {
|
|
2101
|
-
op(3
|
|
2102
|
-
/* InvokeStatic */
|
|
2103
|
-
, stdlibOperand('cautious-non-dynamic-append'));
|
|
2104
|
-
});
|
|
2105
|
-
});
|
|
2106
|
-
});
|
|
767
|
+
Call(op, handle, null, null);
|
|
2107
768
|
}
|
|
2108
|
-
} else {
|
|
2109
|
-
op(0
|
|
2110
|
-
/* PushFrame */
|
|
2111
|
-
);
|
|
2112
|
-
expr(op, value);
|
|
2113
|
-
op(3
|
|
2114
|
-
/* InvokeStatic */
|
|
2115
|
-
, stdlibOperand('cautious-append'));
|
|
2116
|
-
op(1
|
|
2117
|
-
/* PopFrame */
|
|
2118
|
-
);
|
|
2119
|
-
}
|
|
2120
|
-
});
|
|
2121
|
-
STATEMENTS.add(2
|
|
2122
|
-
/* TrustingAppend */
|
|
2123
|
-
, (op, [, value]) => {
|
|
2124
|
-
if (!Array.isArray(value)) {
|
|
2125
|
-
op(41
|
|
2126
|
-
/* Text */
|
|
2127
|
-
, value === null || value === undefined ? '' : String(value));
|
|
2128
|
-
} else {
|
|
2129
|
-
op(0
|
|
2130
|
-
/* PushFrame */
|
|
2131
|
-
);
|
|
2132
|
-
expr(op, value);
|
|
2133
|
-
op(3
|
|
2134
|
-
/* InvokeStatic */
|
|
2135
|
-
, stdlibOperand('trusting-append'));
|
|
2136
|
-
op(1
|
|
2137
|
-
/* PopFrame */
|
|
2138
|
-
);
|
|
2139
|
-
}
|
|
2140
|
-
});
|
|
2141
|
-
STATEMENTS.add(6
|
|
2142
|
-
/* Block */
|
|
2143
|
-
, (op, [, expr, positional, named, blocks]) => {
|
|
2144
|
-
if (isGetFreeComponent(expr)) {
|
|
2145
|
-
op(1004
|
|
2146
|
-
/* ResolveComponent */
|
|
2147
|
-
, expr, component => {
|
|
2148
|
-
InvokeComponent(op, component, null, positional, hashToArgs(named), blocks);
|
|
2149
769
|
});
|
|
2150
|
-
}
|
|
2151
|
-
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
function withPath(op, path) {
|
|
773
|
+
if (path === undefined || path.length === 0) return;
|
|
774
|
+
for (let i = 0; i < path.length; i++) {
|
|
775
|
+
op(Op.GetProperty, path[i]);
|
|
2152
776
|
}
|
|
777
|
+
}
|
|
778
|
+
EXPRESSIONS.add(SexpOpcodes.Undefined, op => PushPrimitiveReference(op, undefined));
|
|
779
|
+
EXPRESSIONS.add(SexpOpcodes.HasBlock, (op, _ref7) => {
|
|
780
|
+
let [, block] = _ref7;
|
|
781
|
+
expr(op, block);
|
|
782
|
+
op(Op.HasBlock);
|
|
2153
783
|
});
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
if (insertBefore === undefined) {
|
|
2161
|
-
PushPrimitiveReference(op, undefined);
|
|
2162
|
-
} else {
|
|
2163
|
-
expr(op, insertBefore);
|
|
2164
|
-
}
|
|
2165
|
-
|
|
2166
|
-
expr(op, destination);
|
|
2167
|
-
op(33
|
|
2168
|
-
/* Dup */
|
|
2169
|
-
, $sp, 0);
|
|
2170
|
-
return 4;
|
|
2171
|
-
}, () => {
|
|
2172
|
-
op(50
|
|
2173
|
-
/* PushRemoteElement */
|
|
2174
|
-
);
|
|
2175
|
-
InvokeStaticBlock(op, block);
|
|
2176
|
-
op(56
|
|
2177
|
-
/* PopRemoteElement */
|
|
2178
|
-
);
|
|
2179
|
-
});
|
|
784
|
+
EXPRESSIONS.add(SexpOpcodes.HasBlockParams, (op, _ref8) => {
|
|
785
|
+
let [, block] = _ref8;
|
|
786
|
+
expr(op, block);
|
|
787
|
+
op(Op.SpreadBlock);
|
|
788
|
+
op(Op.CompileBlock);
|
|
789
|
+
op(Op.HasBlockParams);
|
|
2180
790
|
});
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
791
|
+
EXPRESSIONS.add(SexpOpcodes.IfInline, (op, _ref9) => {
|
|
792
|
+
let [, condition, truthy, falsy] = _ref9;
|
|
793
|
+
// Push in reverse order
|
|
794
|
+
expr(op, falsy);
|
|
795
|
+
expr(op, truthy);
|
|
2184
796
|
expr(op, condition);
|
|
2185
|
-
op(
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
797
|
+
op(Op.IfInline);
|
|
798
|
+
});
|
|
799
|
+
EXPRESSIONS.add(SexpOpcodes.Not, (op, _ref10) => {
|
|
800
|
+
let [, value] = _ref10;
|
|
801
|
+
expr(op, value);
|
|
802
|
+
op(Op.Not);
|
|
803
|
+
});
|
|
804
|
+
EXPRESSIONS.add(SexpOpcodes.GetDynamicVar, (op, _ref11) => {
|
|
805
|
+
let [, expression] = _ref11;
|
|
806
|
+
expr(op, expression);
|
|
807
|
+
op(Op.GetDynamicVar);
|
|
808
|
+
});
|
|
809
|
+
EXPRESSIONS.add(SexpOpcodes.Log, (op, _ref12) => {
|
|
810
|
+
let [, positional] = _ref12;
|
|
811
|
+
op(MachineOp.PushFrame);
|
|
812
|
+
SimpleArgs(op, positional, null, false);
|
|
813
|
+
op(Op.Log);
|
|
814
|
+
op(MachineOp.PopFrame);
|
|
815
|
+
op(Op.Fetch, $v0);
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
function expr(op, expression) {
|
|
819
|
+
if (Array.isArray(expression)) {
|
|
820
|
+
EXPRESSIONS.compile(op, expression);
|
|
2199
821
|
} else {
|
|
2200
|
-
|
|
822
|
+
PushPrimitive(op, expression);
|
|
823
|
+
op(Op.PrimitiveReference);
|
|
2201
824
|
}
|
|
825
|
+
}
|
|
2202
826
|
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
op(6
|
|
2216
|
-
/* ReturnTo */
|
|
2217
|
-
, labelOperand('ITER'));
|
|
2218
|
-
op(1000
|
|
2219
|
-
/* Label */
|
|
2220
|
-
, 'ITER');
|
|
2221
|
-
op(74
|
|
2222
|
-
/* Iterate */
|
|
2223
|
-
, labelOperand('BREAK'));
|
|
2224
|
-
op(1000
|
|
2225
|
-
/* Label */
|
|
2226
|
-
, 'BODY');
|
|
2227
|
-
InvokeStaticBlockWithStack(op, block, 2);
|
|
2228
|
-
op(34
|
|
2229
|
-
/* Pop */
|
|
2230
|
-
, 2);
|
|
2231
|
-
op(4
|
|
2232
|
-
/* Jump */
|
|
2233
|
-
, labelOperand('FINALLY'));
|
|
2234
|
-
op(1000
|
|
2235
|
-
/* Label */
|
|
2236
|
-
, 'BREAK');
|
|
2237
|
-
op(1
|
|
2238
|
-
/* PopFrame */
|
|
2239
|
-
);
|
|
2240
|
-
op(73
|
|
2241
|
-
/* ExitList */
|
|
2242
|
-
);
|
|
2243
|
-
op(4
|
|
2244
|
-
/* Jump */
|
|
2245
|
-
, labelOperand('FINALLY'));
|
|
2246
|
-
op(1000
|
|
2247
|
-
/* Label */
|
|
2248
|
-
, 'ELSE');
|
|
2249
|
-
|
|
2250
|
-
if (inverse) {
|
|
2251
|
-
InvokeStaticBlock(op, inverse);
|
|
827
|
+
/**
|
|
828
|
+
* Compile arguments, pushing an Arguments object onto the stack.
|
|
829
|
+
*
|
|
830
|
+
* @param args.params
|
|
831
|
+
* @param args.hash
|
|
832
|
+
* @param args.blocks
|
|
833
|
+
* @param args.atNames
|
|
834
|
+
*/
|
|
835
|
+
function CompileArgs(op, positional, named, blocks, atNames) {
|
|
836
|
+
let blockNames = blocks.names;
|
|
837
|
+
for (const name of blockNames) {
|
|
838
|
+
PushYieldableBlock(op, blocks.get(name));
|
|
2252
839
|
}
|
|
2253
|
-
}));
|
|
2254
|
-
STATEMENTS.add(43
|
|
2255
|
-
/* With */
|
|
2256
|
-
, (op, [, value, block, inverse]) => {
|
|
2257
|
-
ReplayableIf(op, () => {
|
|
2258
|
-
expr(op, value);
|
|
2259
|
-
op(33
|
|
2260
|
-
/* Dup */
|
|
2261
|
-
, $sp, 0);
|
|
2262
|
-
op(71
|
|
2263
|
-
/* ToBoolean */
|
|
2264
|
-
);
|
|
2265
|
-
return 2;
|
|
2266
|
-
}, () => {
|
|
2267
|
-
InvokeStaticBlockWithStack(op, block, 1);
|
|
2268
|
-
}, () => {
|
|
2269
|
-
if (inverse) {
|
|
2270
|
-
InvokeStaticBlock(op, inverse);
|
|
2271
|
-
}
|
|
2272
|
-
});
|
|
2273
|
-
});
|
|
2274
|
-
STATEMENTS.add(44
|
|
2275
|
-
/* Let */
|
|
2276
|
-
, (op, [, positional, block]) => {
|
|
2277
840
|
let count = CompilePositional(op, positional);
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
841
|
+
let flags = count << 4;
|
|
842
|
+
if (atNames) flags |= 0b1000;
|
|
843
|
+
if (blocks) {
|
|
844
|
+
flags |= 0b111;
|
|
845
|
+
}
|
|
846
|
+
let names = EMPTY_ARRAY;
|
|
2283
847
|
if (named) {
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
}
|
|
2289
|
-
} else {
|
|
2290
|
-
InvokeStaticBlock(op, block);
|
|
848
|
+
names = named[0];
|
|
849
|
+
let val = named[1];
|
|
850
|
+
for (let i = 0; i < val.length; i++) {
|
|
851
|
+
expr(op, val[i]);
|
|
852
|
+
}
|
|
2291
853
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
/* ResolveComponent */
|
|
2299
|
-
, expr, component => {
|
|
2300
|
-
InvokeComponent(op, component, null, positional, hashToArgs(named), blocks);
|
|
2301
|
-
});
|
|
2302
|
-
} else {
|
|
2303
|
-
InvokeDynamicComponent(op, expr, null, positional, named, blocks, false, false);
|
|
854
|
+
op(Op.PushArgs, names, blockNames, flags);
|
|
855
|
+
}
|
|
856
|
+
function SimpleArgs(op, positional, named, atNames) {
|
|
857
|
+
if (positional === null && named === null) {
|
|
858
|
+
op(Op.PushEmptyArgs);
|
|
859
|
+
return;
|
|
2304
860
|
}
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
861
|
+
let count = CompilePositional(op, positional);
|
|
862
|
+
let flags = count << 4;
|
|
863
|
+
if (atNames) flags |= 0b1000;
|
|
864
|
+
let names = EMPTY_STRING_ARRAY;
|
|
865
|
+
if (named) {
|
|
866
|
+
names = named[0];
|
|
867
|
+
let val = named[1];
|
|
868
|
+
for (let i = 0; i < val.length; i++) {
|
|
869
|
+
expr(op, val[i]);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
op(Op.PushArgs, names, EMPTY_STRING_ARRAY, flags);
|
|
2311
873
|
}
|
|
2312
874
|
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
this.compiled = null;
|
|
2324
|
-
} // Part of CompilableTemplate
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
compile(context) {
|
|
2328
|
-
return maybeCompile(this, context);
|
|
875
|
+
/**
|
|
876
|
+
* Compile an optional list of positional arguments, which pushes each argument
|
|
877
|
+
* onto the stack and returns the number of parameters compiled
|
|
878
|
+
*
|
|
879
|
+
* @param positional an optional list of positional arguments
|
|
880
|
+
*/
|
|
881
|
+
function CompilePositional(op, positional) {
|
|
882
|
+
if (positional === null) return 0;
|
|
883
|
+
for (let i = 0; i < positional.length; i++) {
|
|
884
|
+
expr(op, positional[i]);
|
|
2329
885
|
}
|
|
886
|
+
return positional.length;
|
|
887
|
+
}
|
|
888
|
+
function meta(layout) {
|
|
889
|
+
let [, symbols,, upvars] = layout.block;
|
|
890
|
+
return {
|
|
891
|
+
evalSymbols: evalSymbols(layout),
|
|
892
|
+
upvars: upvars,
|
|
893
|
+
scopeValues: layout.scope?.() ?? null,
|
|
894
|
+
isStrictMode: layout.isStrictMode,
|
|
895
|
+
moduleName: layout.moduleName,
|
|
896
|
+
owner: layout.owner,
|
|
897
|
+
size: symbols.length
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
function evalSymbols(layout) {
|
|
901
|
+
let {
|
|
902
|
+
block
|
|
903
|
+
} = layout;
|
|
904
|
+
let [, symbols, hasEval] = block;
|
|
905
|
+
return hasEval ? symbols : null;
|
|
906
|
+
}
|
|
2330
907
|
|
|
908
|
+
/**
|
|
909
|
+
* Yield to a block located at a particular symbol location.
|
|
910
|
+
*
|
|
911
|
+
* @param to the symbol containing the block to yield to
|
|
912
|
+
* @param params optional block parameters to yield to the block
|
|
913
|
+
*/
|
|
914
|
+
function YieldBlock(op, to, positional) {
|
|
915
|
+
SimpleArgs(op, positional, null, true);
|
|
916
|
+
op(Op.GetBlock, to);
|
|
917
|
+
op(Op.SpreadBlock);
|
|
918
|
+
op(Op.CompileBlock);
|
|
919
|
+
op(Op.InvokeYield);
|
|
920
|
+
op(Op.PopScope);
|
|
921
|
+
op(MachineOp.PopFrame);
|
|
2331
922
|
}
|
|
2332
923
|
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
924
|
+
/**
|
|
925
|
+
* Push an (optional) yieldable block onto the stack. The yieldable block must be known
|
|
926
|
+
* statically at compile time.
|
|
927
|
+
*
|
|
928
|
+
* @param block An optional Compilable block
|
|
929
|
+
*/
|
|
930
|
+
function PushYieldableBlock(op, block) {
|
|
931
|
+
PushSymbolTable(op, block && block[1]);
|
|
932
|
+
op(Op.PushBlockScope);
|
|
933
|
+
PushCompilable(op, block);
|
|
2339
934
|
}
|
|
2340
935
|
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
936
|
+
/**
|
|
937
|
+
* Invoke a block that is known statically at compile time.
|
|
938
|
+
*
|
|
939
|
+
* @param block a Compilable block
|
|
940
|
+
*/
|
|
941
|
+
function InvokeStaticBlock(op, block) {
|
|
942
|
+
op(MachineOp.PushFrame);
|
|
943
|
+
PushCompilable(op, block);
|
|
944
|
+
op(Op.CompileBlock);
|
|
945
|
+
op(MachineOp.InvokeVirtual);
|
|
946
|
+
op(MachineOp.PopFrame);
|
|
2351
947
|
}
|
|
2352
948
|
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
949
|
+
/**
|
|
950
|
+
* Invoke a static block, preserving some number of stack entries for use in
|
|
951
|
+
* updating.
|
|
952
|
+
*
|
|
953
|
+
* @param block A compilable block
|
|
954
|
+
* @param callerCount A number of stack entries to preserve
|
|
955
|
+
*/
|
|
956
|
+
function InvokeStaticBlockWithStack(op, block, callerCount) {
|
|
957
|
+
let parameters = block[1];
|
|
958
|
+
let calleeCount = parameters.length;
|
|
959
|
+
let count = Math.min(callerCount, calleeCount);
|
|
960
|
+
if (count === 0) {
|
|
961
|
+
InvokeStaticBlock(op, block);
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
op(MachineOp.PushFrame);
|
|
965
|
+
if (count) {
|
|
966
|
+
op(Op.ChildScope);
|
|
967
|
+
for (let i = 0; i < count; i++) {
|
|
968
|
+
op(Op.Dup, $fp, callerCount - i);
|
|
969
|
+
op(Op.SetVariable, parameters[i]);
|
|
2361
970
|
}
|
|
2362
|
-
} = context;
|
|
2363
|
-
|
|
2364
|
-
function pushOp(...op) {
|
|
2365
|
-
encodeOp(encoder, constants, resolver, meta, op);
|
|
2366
971
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
972
|
+
PushCompilable(op, block);
|
|
973
|
+
op(Op.CompileBlock);
|
|
974
|
+
op(MachineOp.InvokeVirtual);
|
|
975
|
+
if (count) {
|
|
976
|
+
op(Op.PopScope);
|
|
2370
977
|
}
|
|
2371
|
-
|
|
2372
|
-
let handle = context.encoder.commit(meta.size);
|
|
2373
|
-
|
|
2374
|
-
return handle;
|
|
978
|
+
op(MachineOp.PopFrame);
|
|
2375
979
|
}
|
|
2376
|
-
function
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
980
|
+
function PushSymbolTable(op, parameters) {
|
|
981
|
+
if (parameters !== null) {
|
|
982
|
+
op(Op.PushSymbolTable, symbolTableOperand({
|
|
983
|
+
parameters
|
|
984
|
+
}));
|
|
985
|
+
} else {
|
|
986
|
+
PushPrimitive(op, null);
|
|
987
|
+
}
|
|
2380
988
|
}
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
989
|
+
function PushCompilable(op, _block) {
|
|
990
|
+
if (_block === null) {
|
|
991
|
+
PushPrimitive(op, null);
|
|
992
|
+
} else {
|
|
993
|
+
op(Op.Constant, blockOperand(_block));
|
|
2386
994
|
}
|
|
995
|
+
}
|
|
2387
996
|
|
|
2388
|
-
|
|
2389
|
-
|
|
997
|
+
function SwitchCases(op, bootstrap, matcher) {
|
|
998
|
+
// Setup the switch DSL
|
|
999
|
+
let clauses = [];
|
|
1000
|
+
let count = 0;
|
|
1001
|
+
function when(match, callback) {
|
|
1002
|
+
clauses.push({
|
|
1003
|
+
match,
|
|
1004
|
+
callback,
|
|
1005
|
+
label: `CLAUSE${count++}`
|
|
1006
|
+
});
|
|
2390
1007
|
}
|
|
2391
1008
|
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
1009
|
+
// Call the callback
|
|
1010
|
+
matcher(when);
|
|
1011
|
+
|
|
1012
|
+
// Emit the opcodes for the switch
|
|
1013
|
+
op(Op.Enter, 1);
|
|
1014
|
+
bootstrap();
|
|
1015
|
+
op(HighLevelBuilderOpcodes.StartLabels);
|
|
1016
|
+
|
|
1017
|
+
// First, emit the jump opcodes. We don't need a jump for the last
|
|
1018
|
+
// opcode, since it bleeds directly into its clause.
|
|
1019
|
+
for (let clause of clauses.slice(0, -1)) {
|
|
1020
|
+
op(Op.JumpEq, labelOperand(clause.label), clause.match);
|
|
2397
1021
|
}
|
|
2398
1022
|
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
1023
|
+
// Enumerate the clauses in reverse order. Earlier matches will
|
|
1024
|
+
// require fewer checks.
|
|
1025
|
+
for (let i = clauses.length - 1; i >= 0; i--) {
|
|
1026
|
+
let clause = unwrap(clauses[i]);
|
|
1027
|
+
op(HighLevelBuilderOpcodes.Label, clause.label);
|
|
1028
|
+
op(Op.Pop, 1);
|
|
1029
|
+
clause.callback();
|
|
2404
1030
|
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
} = targets[i];
|
|
2410
|
-
let address = labels[target] - at;
|
|
2411
|
-
heap.setbyaddr(at, address);
|
|
1031
|
+
// The first match is special: it is placed directly before the END
|
|
1032
|
+
// label, so no additional jump is needed at the end of it.
|
|
1033
|
+
if (i !== 0) {
|
|
1034
|
+
op(MachineOp.Jump, labelOperand('END'));
|
|
2412
1035
|
}
|
|
2413
1036
|
}
|
|
2414
|
-
|
|
1037
|
+
op(HighLevelBuilderOpcodes.Label, 'END');
|
|
1038
|
+
op(HighLevelBuilderOpcodes.StopLabels);
|
|
1039
|
+
op(Op.Exit);
|
|
2415
1040
|
}
|
|
2416
|
-
function encodeOp(encoder, constants, resolver, meta, op) {
|
|
2417
|
-
if (isBuilderOpcode(op[0])) {
|
|
2418
|
-
let [type, ...operands] = op;
|
|
2419
|
-
encoder.push(constants, type, ...operands);
|
|
2420
|
-
} else {
|
|
2421
|
-
switch (op[0]) {
|
|
2422
|
-
case 1000
|
|
2423
|
-
/* Label */
|
|
2424
|
-
:
|
|
2425
|
-
return encoder.label(op[1]);
|
|
2426
1041
|
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
1042
|
+
/**
|
|
1043
|
+
* A convenience for pushing some arguments on the stack and
|
|
1044
|
+
* running some code if the code needs to be re-executed during
|
|
1045
|
+
* updating execution if some of the arguments have changed.
|
|
1046
|
+
*
|
|
1047
|
+
* # Initial Execution
|
|
1048
|
+
*
|
|
1049
|
+
* The `args` function should push zero or more arguments onto
|
|
1050
|
+
* the stack and return the number of arguments pushed.
|
|
1051
|
+
*
|
|
1052
|
+
* The `body` function provides the instructions to execute both
|
|
1053
|
+
* during initial execution and during updating execution.
|
|
1054
|
+
*
|
|
1055
|
+
* Internally, this function starts by pushing a new frame, so
|
|
1056
|
+
* that the body can return and sets the return point ($ra) to
|
|
1057
|
+
* the ENDINITIAL label.
|
|
1058
|
+
*
|
|
1059
|
+
* It then executes the `args` function, which adds instructions
|
|
1060
|
+
* responsible for pushing the arguments for the block to the
|
|
1061
|
+
* stack. These arguments will be restored to the stack before
|
|
1062
|
+
* updating execution.
|
|
1063
|
+
*
|
|
1064
|
+
* Next, it adds the Enter opcode, which marks the current position
|
|
1065
|
+
* in the DOM, and remembers the current $pc (the next instruction)
|
|
1066
|
+
* as the first instruction to execute during updating execution.
|
|
1067
|
+
*
|
|
1068
|
+
* Next, it runs `body`, which adds the opcodes that should
|
|
1069
|
+
* execute both during initial execution and during updating execution.
|
|
1070
|
+
* If the `body` wishes to finish early, it should Jump to the
|
|
1071
|
+
* `FINALLY` label.
|
|
1072
|
+
*
|
|
1073
|
+
* Next, it adds the FINALLY label, followed by:
|
|
1074
|
+
*
|
|
1075
|
+
* - the Exit opcode, which finalizes the marked DOM started by the
|
|
1076
|
+
* Enter opcode.
|
|
1077
|
+
* - the Return opcode, which returns to the current return point
|
|
1078
|
+
* ($ra).
|
|
1079
|
+
*
|
|
1080
|
+
* Finally, it adds the ENDINITIAL label followed by the PopFrame
|
|
1081
|
+
* instruction, which restores $fp, $sp and $ra.
|
|
1082
|
+
*
|
|
1083
|
+
* # Updating Execution
|
|
1084
|
+
*
|
|
1085
|
+
* Updating execution for this `replayable` occurs if the `body` added an
|
|
1086
|
+
* assertion, via one of the `JumpIf`, `JumpUnless` or `AssertSame` opcodes.
|
|
1087
|
+
*
|
|
1088
|
+
* If, during updating executon, the assertion fails, the initial VM is
|
|
1089
|
+
* restored, and the stored arguments are pushed onto the stack. The DOM
|
|
1090
|
+
* between the starting and ending markers is cleared, and the VM's cursor
|
|
1091
|
+
* is set to the area just cleared.
|
|
1092
|
+
*
|
|
1093
|
+
* The return point ($ra) is set to -1, the exit instruction.
|
|
1094
|
+
*
|
|
1095
|
+
* Finally, the $pc is set to to the instruction saved off by the
|
|
1096
|
+
* Enter opcode during initial execution, and execution proceeds as
|
|
1097
|
+
* usual.
|
|
1098
|
+
*
|
|
1099
|
+
* The only difference is that when a `Return` instruction is
|
|
1100
|
+
* encountered, the program jumps to -1 rather than the END label,
|
|
1101
|
+
* and the PopFrame opcode is not needed.
|
|
1102
|
+
*/
|
|
1103
|
+
function Replayable(op, args, body) {
|
|
1104
|
+
// Start a new label frame, to give END and RETURN
|
|
1105
|
+
// a unique meaning.
|
|
1106
|
+
|
|
1107
|
+
op(HighLevelBuilderOpcodes.StartLabels);
|
|
1108
|
+
op(MachineOp.PushFrame);
|
|
1109
|
+
|
|
1110
|
+
// If the body invokes a block, its return will return to
|
|
1111
|
+
// END. Otherwise, the return in RETURN will return to END.
|
|
1112
|
+
op(MachineOp.ReturnTo, labelOperand('ENDINITIAL'));
|
|
1113
|
+
|
|
1114
|
+
// Push the arguments onto the stack. The args() function
|
|
1115
|
+
// tells us how many stack elements to retain for re-execution
|
|
1116
|
+
// when updating.
|
|
1117
|
+
let count = args();
|
|
1118
|
+
|
|
1119
|
+
// Start a new updating closure, remembering `count` elements
|
|
1120
|
+
// from the stack. Everything after this point, and before END,
|
|
1121
|
+
// will execute both initially and to update the block.
|
|
1122
|
+
//
|
|
1123
|
+
// The enter and exit opcodes also track the area of the DOM
|
|
1124
|
+
// associated with this block. If an assertion inside the block
|
|
1125
|
+
// fails (for example, the test value changes from true to false
|
|
1126
|
+
// in an #if), the DOM is cleared and the program is re-executed,
|
|
1127
|
+
// restoring `count` elements to the stack and executing the
|
|
1128
|
+
// instructions between the enter and exit.
|
|
1129
|
+
op(Op.Enter, count);
|
|
2431
1130
|
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
1131
|
+
// Evaluate the body of the block. The body of the block may
|
|
1132
|
+
// return, which will jump execution to END during initial
|
|
1133
|
+
// execution, and exit the updating routine.
|
|
1134
|
+
body();
|
|
2436
1135
|
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
1136
|
+
// All execution paths in the body should run the FINALLY once
|
|
1137
|
+
// they are done. It is executed both during initial execution
|
|
1138
|
+
// and during updating execution.
|
|
1139
|
+
op(HighLevelBuilderOpcodes.Label, 'FINALLY');
|
|
2441
1140
|
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
:
|
|
2445
|
-
return resolveModifier(resolver, constants, meta, op);
|
|
1141
|
+
// Finalize the DOM.
|
|
1142
|
+
op(Op.Exit);
|
|
2446
1143
|
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
1144
|
+
// In initial execution, this is a noop: it returns to the
|
|
1145
|
+
// immediately following opcode. In updating execution, this
|
|
1146
|
+
// exits the updating routine.
|
|
1147
|
+
op(MachineOp.Return);
|
|
2451
1148
|
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
1149
|
+
// Cleanup code for the block. Runs on initial execution
|
|
1150
|
+
// but not on updating.
|
|
1151
|
+
op(HighLevelBuilderOpcodes.Label, 'ENDINITIAL');
|
|
1152
|
+
op(MachineOp.PopFrame);
|
|
1153
|
+
op(HighLevelBuilderOpcodes.StopLabels);
|
|
1154
|
+
}
|
|
2456
1155
|
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
1156
|
+
/**
|
|
1157
|
+
* A specialized version of the `replayable` convenience that allows the
|
|
1158
|
+
* caller to provide different code based upon whether the item at
|
|
1159
|
+
* the top of the stack is true or false.
|
|
1160
|
+
*
|
|
1161
|
+
* As in `replayable`, the `ifTrue` and `ifFalse` code can invoke `return`.
|
|
1162
|
+
*
|
|
1163
|
+
* During the initial execution, a `return` will continue execution
|
|
1164
|
+
* in the cleanup code, which finalizes the current DOM block and pops
|
|
1165
|
+
* the current frame.
|
|
1166
|
+
*
|
|
1167
|
+
* During the updating execution, a `return` will exit the updating
|
|
1168
|
+
* routine, as it can reuse the DOM block and is always only a single
|
|
1169
|
+
* frame deep.
|
|
1170
|
+
*/
|
|
1171
|
+
function ReplayableIf(op, args, ifTrue, ifFalse) {
|
|
1172
|
+
return Replayable(op, args, () => {
|
|
1173
|
+
// If the conditional is false, jump to the ELSE label.
|
|
1174
|
+
op(Op.JumpUnless, labelOperand('ELSE'));
|
|
1175
|
+
// Otherwise, execute the code associated with the true branch.
|
|
1176
|
+
ifTrue();
|
|
1177
|
+
// We're done, so return. In the initial execution, this runs
|
|
1178
|
+
// the cleanup code. In the updating VM, it exits the updating
|
|
1179
|
+
// routine.
|
|
1180
|
+
op(MachineOp.Jump, labelOperand('FINALLY'));
|
|
1181
|
+
op(HighLevelBuilderOpcodes.Label, 'ELSE');
|
|
2461
1182
|
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
1183
|
+
// If the conditional is false, and code associatied ith the
|
|
1184
|
+
// false branch was provided, execute it. If there was no code
|
|
1185
|
+
// associated with the false branch, jumping to the else statement
|
|
1186
|
+
// has no other behavior.
|
|
1187
|
+
if (ifFalse !== undefined) {
|
|
1188
|
+
ifFalse();
|
|
1189
|
+
}
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
2466
1192
|
|
|
2467
|
-
|
|
2468
|
-
/* ResolveLocal */
|
|
2469
|
-
:
|
|
2470
|
-
let freeVar = op[1];
|
|
2471
|
-
let name = meta.upvars[freeVar];
|
|
2472
|
-
let andThen = op[2];
|
|
2473
|
-
andThen(name, meta.moduleName);
|
|
2474
|
-
break;
|
|
1193
|
+
const ATTRS_BLOCK = '&attrs';
|
|
2475
1194
|
|
|
2476
|
-
|
|
2477
|
-
/* ResolveTemplateLocal */
|
|
2478
|
-
:
|
|
2479
|
-
let [, valueIndex, then] = op;
|
|
2480
|
-
let value = meta.scopeValues[valueIndex];
|
|
2481
|
-
then(constants.value(value));
|
|
2482
|
-
break;
|
|
1195
|
+
// {{component}}
|
|
2483
1196
|
|
|
2484
|
-
|
|
2485
|
-
/* ResolveFree */
|
|
2486
|
-
:
|
|
2487
|
-
if (DEBUG) {
|
|
2488
|
-
let [, upvarIndex] = op;
|
|
2489
|
-
let freeName = meta.upvars[upvarIndex];
|
|
2490
|
-
throw new Error(`Attempted to resolve a value in a strict mode template, but that value was not in scope: ${freeName}`);
|
|
2491
|
-
}
|
|
1197
|
+
// <Component>
|
|
2492
1198
|
|
|
2493
|
-
|
|
1199
|
+
// chokepoint
|
|
2494
1200
|
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
1201
|
+
function InvokeComponent(op, component, _elementBlock, positional, named, _blocks) {
|
|
1202
|
+
let {
|
|
1203
|
+
compilable,
|
|
1204
|
+
capabilities,
|
|
1205
|
+
handle
|
|
1206
|
+
} = component;
|
|
1207
|
+
let elementBlock = _elementBlock ? [_elementBlock, []] : null;
|
|
1208
|
+
let blocks = Array.isArray(_blocks) || _blocks === null ? namedBlocks(_blocks) : _blocks;
|
|
1209
|
+
if (compilable) {
|
|
1210
|
+
op(Op.PushComponentDefinition, handle);
|
|
1211
|
+
InvokeStaticComponent(op, {
|
|
1212
|
+
capabilities: capabilities,
|
|
1213
|
+
layout: compilable,
|
|
1214
|
+
elementBlock,
|
|
1215
|
+
positional,
|
|
1216
|
+
named,
|
|
1217
|
+
blocks
|
|
1218
|
+
});
|
|
1219
|
+
} else {
|
|
1220
|
+
op(Op.PushComponentDefinition, handle);
|
|
1221
|
+
InvokeNonStaticComponent(op, {
|
|
1222
|
+
capabilities: capabilities,
|
|
1223
|
+
elementBlock,
|
|
1224
|
+
positional,
|
|
1225
|
+
named,
|
|
1226
|
+
atNames: true,
|
|
1227
|
+
blocks
|
|
1228
|
+
});
|
|
2498
1229
|
}
|
|
2499
1230
|
}
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
error(error) {
|
|
2512
|
-
this.encoder.encode(30
|
|
2513
|
-
/* Primitive */
|
|
2514
|
-
, 0);
|
|
2515
|
-
this.errors.push(error);
|
|
2516
|
-
}
|
|
2517
|
-
|
|
2518
|
-
commit(size) {
|
|
2519
|
-
let handle = this.handle;
|
|
2520
|
-
this.heap.push(5
|
|
2521
|
-
/* Return */
|
|
2522
|
-
| 1024
|
|
2523
|
-
/* MACHINE_MASK */
|
|
2524
|
-
);
|
|
2525
|
-
this.heap.finishMalloc(handle, size);
|
|
2526
|
-
|
|
2527
|
-
if (this.errors.length) {
|
|
2528
|
-
return {
|
|
2529
|
-
errors: this.errors,
|
|
2530
|
-
handle
|
|
2531
|
-
};
|
|
1231
|
+
function InvokeDynamicComponent(op, definition, _elementBlock, positional, named, _blocks, atNames, curried) {
|
|
1232
|
+
let elementBlock = _elementBlock ? [_elementBlock, []] : null;
|
|
1233
|
+
let blocks = Array.isArray(_blocks) || _blocks === null ? namedBlocks(_blocks) : _blocks;
|
|
1234
|
+
Replayable(op, () => {
|
|
1235
|
+
expr(op, definition);
|
|
1236
|
+
op(Op.Dup, $sp, 0);
|
|
1237
|
+
return 2;
|
|
1238
|
+
}, () => {
|
|
1239
|
+
op(Op.JumpUnless, labelOperand('ELSE'));
|
|
1240
|
+
if (curried) {
|
|
1241
|
+
op(Op.ResolveCurriedComponent);
|
|
2532
1242
|
} else {
|
|
2533
|
-
|
|
1243
|
+
op(Op.ResolveDynamicComponent, isStrictMode());
|
|
2534
1244
|
}
|
|
1245
|
+
op(Op.PushDynamicComponentInstance);
|
|
1246
|
+
InvokeNonStaticComponent(op, {
|
|
1247
|
+
capabilities: true,
|
|
1248
|
+
elementBlock,
|
|
1249
|
+
positional,
|
|
1250
|
+
named,
|
|
1251
|
+
atNames,
|
|
1252
|
+
blocks
|
|
1253
|
+
});
|
|
1254
|
+
op(HighLevelBuilderOpcodes.Label, 'ELSE');
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
function InvokeStaticComponent(op, _ref) {
|
|
1258
|
+
let {
|
|
1259
|
+
capabilities,
|
|
1260
|
+
layout,
|
|
1261
|
+
elementBlock,
|
|
1262
|
+
positional,
|
|
1263
|
+
named,
|
|
1264
|
+
blocks
|
|
1265
|
+
} = _ref;
|
|
1266
|
+
let {
|
|
1267
|
+
symbolTable
|
|
1268
|
+
} = layout;
|
|
1269
|
+
let bailOut = symbolTable.hasEval || hasCapability(capabilities, InternalComponentCapabilities.prepareArgs);
|
|
1270
|
+
if (bailOut) {
|
|
1271
|
+
InvokeNonStaticComponent(op, {
|
|
1272
|
+
capabilities,
|
|
1273
|
+
elementBlock,
|
|
1274
|
+
positional,
|
|
1275
|
+
named,
|
|
1276
|
+
atNames: true,
|
|
1277
|
+
blocks,
|
|
1278
|
+
layout
|
|
1279
|
+
});
|
|
1280
|
+
return;
|
|
2535
1281
|
}
|
|
1282
|
+
op(Op.Fetch, $s0);
|
|
1283
|
+
op(Op.Dup, $sp, 1);
|
|
1284
|
+
op(Op.Load, $s0);
|
|
1285
|
+
op(MachineOp.PushFrame);
|
|
2536
1286
|
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
1287
|
+
// Setup arguments
|
|
1288
|
+
let {
|
|
1289
|
+
symbols
|
|
1290
|
+
} = symbolTable;
|
|
2541
1291
|
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
1292
|
+
// As we push values onto the stack, we store the symbols associated with them
|
|
1293
|
+
// so that we can set them on the scope later on with SetVariable and SetBlock
|
|
1294
|
+
let blockSymbols = [];
|
|
1295
|
+
let argSymbols = [];
|
|
1296
|
+
let argNames = [];
|
|
2547
1297
|
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
;
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
let op = args[i];
|
|
2558
|
-
heap.push(this.operand(constants, op));
|
|
1298
|
+
// First we push the blocks onto the stack
|
|
1299
|
+
let blockNames = blocks.names;
|
|
1300
|
+
|
|
1301
|
+
// Starting with the attrs block, if it exists and is referenced in the component
|
|
1302
|
+
if (elementBlock !== null) {
|
|
1303
|
+
let symbol = symbols.indexOf(ATTRS_BLOCK);
|
|
1304
|
+
if (symbol !== -1) {
|
|
1305
|
+
PushYieldableBlock(op, elementBlock);
|
|
1306
|
+
blockSymbols.push(symbol);
|
|
2559
1307
|
}
|
|
2560
1308
|
}
|
|
2561
1309
|
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
1310
|
+
// Followed by the other blocks, if they exist and are referenced in the component.
|
|
1311
|
+
// Also store the index of the associated symbol.
|
|
1312
|
+
for (const name of blockNames) {
|
|
1313
|
+
let symbol = symbols.indexOf(`&${name}`);
|
|
1314
|
+
if (symbol !== -1) {
|
|
1315
|
+
PushYieldableBlock(op, blocks.get(name));
|
|
1316
|
+
blockSymbols.push(symbol);
|
|
2565
1317
|
}
|
|
1318
|
+
}
|
|
2566
1319
|
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
/* Label */
|
|
2574
|
-
:
|
|
2575
|
-
this.currentLabels.target(this.heap.offset, operand.value);
|
|
2576
|
-
return -1;
|
|
1320
|
+
// Next up we have arguments. If the component has the `createArgs` capability,
|
|
1321
|
+
// then it wants access to the arguments in JavaScript. We can't know whether
|
|
1322
|
+
// or not an argument is used, so we have to give access to all of them.
|
|
1323
|
+
if (hasCapability(capabilities, InternalComponentCapabilities.createArgs)) {
|
|
1324
|
+
// First we push positional arguments
|
|
1325
|
+
let count = CompilePositional(op, positional);
|
|
2577
1326
|
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
1327
|
+
// setup the flags with the count of positionals, and to indicate that atNames
|
|
1328
|
+
// are used
|
|
1329
|
+
let flags = count << 4;
|
|
1330
|
+
flags |= 0b1000;
|
|
1331
|
+
let names = EMPTY_STRING_ARRAY;
|
|
2582
1332
|
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
1333
|
+
// Next, if named args exist, push them all. If they have an associated symbol
|
|
1334
|
+
// in the invoked component (e.g. they are used within its template), we push
|
|
1335
|
+
// that symbol. If not, we still push the expression as it may be used, and
|
|
1336
|
+
// we store the symbol as -1 (this is used later).
|
|
1337
|
+
if (named !== null) {
|
|
1338
|
+
names = named[0];
|
|
1339
|
+
let val = named[1];
|
|
1340
|
+
for (let i = 0; i < val.length; i++) {
|
|
1341
|
+
let symbol = symbols.indexOf(unwrap(names[i]));
|
|
1342
|
+
expr(op, val[i]);
|
|
1343
|
+
argSymbols.push(symbol);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
2587
1346
|
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
1347
|
+
// Finally, push the VM arguments themselves. These args won't need access
|
|
1348
|
+
// to blocks (they aren't accessible from userland anyways), so we push an
|
|
1349
|
+
// empty array instead of the actual block names.
|
|
1350
|
+
op(Op.PushArgs, names, EMPTY_STRING_ARRAY, flags);
|
|
2592
1351
|
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
1352
|
+
// And push an extra pop operation to remove the args before we begin setting
|
|
1353
|
+
// variables on the local context
|
|
1354
|
+
argSymbols.push(-1);
|
|
1355
|
+
} else if (named !== null) {
|
|
1356
|
+
// If the component does not have the `createArgs` capability, then the only
|
|
1357
|
+
// expressions we need to push onto the stack are those that are actually
|
|
1358
|
+
// referenced in the template of the invoked component (e.g. have symbols).
|
|
1359
|
+
let names = named[0];
|
|
1360
|
+
let val = named[1];
|
|
1361
|
+
for (let i = 0; i < val.length; i++) {
|
|
1362
|
+
let name = unwrap(names[i]);
|
|
1363
|
+
let symbol = symbols.indexOf(name);
|
|
1364
|
+
if (symbol !== -1) {
|
|
1365
|
+
expr(op, val[i]);
|
|
1366
|
+
argSymbols.push(symbol);
|
|
1367
|
+
argNames.push(name);
|
|
2609
1368
|
}
|
|
2610
1369
|
}
|
|
2611
|
-
|
|
2612
|
-
return encodeHandle(constants.value(operand));
|
|
2613
1370
|
}
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
1371
|
+
op(Op.BeginComponentTransaction, $s0);
|
|
1372
|
+
if (hasCapability(capabilities, InternalComponentCapabilities.dynamicScope)) {
|
|
1373
|
+
op(Op.PushDynamicScope);
|
|
2617
1374
|
}
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
1375
|
+
if (hasCapability(capabilities, InternalComponentCapabilities.createInstance)) {
|
|
1376
|
+
op(Op.CreateComponent, blocks.has('default') | 0, $s0);
|
|
1377
|
+
}
|
|
1378
|
+
op(Op.RegisterComponentDestructor, $s0);
|
|
1379
|
+
if (hasCapability(capabilities, InternalComponentCapabilities.createArgs)) {
|
|
1380
|
+
op(Op.GetComponentSelf, $s0);
|
|
1381
|
+
} else {
|
|
1382
|
+
op(Op.GetComponentSelf, $s0, argNames);
|
|
2621
1383
|
}
|
|
2622
1384
|
|
|
2623
|
-
|
|
2624
|
-
|
|
1385
|
+
// Setup the new root scope for the component
|
|
1386
|
+
op(Op.RootScope, symbols.length + 1, Object.keys(blocks).length > 0 ? 1 : 0);
|
|
1387
|
+
|
|
1388
|
+
// Pop the self reference off the stack and set it to the symbol for `this`
|
|
1389
|
+
// in the new scope. This is why all subsequent symbols are increased by one.
|
|
1390
|
+
op(Op.SetVariable, 0);
|
|
1391
|
+
|
|
1392
|
+
// Going in reverse, now we pop the args/blocks off the stack, starting with
|
|
1393
|
+
// arguments, and assign them to their symbols in the new scope.
|
|
1394
|
+
for (const symbol of reverse(argSymbols)) {
|
|
1395
|
+
// for (let i = argSymbols.length - 1; i >= 0; i--) {
|
|
1396
|
+
// let symbol = argSymbols[i];
|
|
1397
|
+
|
|
1398
|
+
if (symbol === -1) {
|
|
1399
|
+
// The expression was not bound to a local symbol, it was only pushed to be
|
|
1400
|
+
// used with VM args in the javascript side
|
|
1401
|
+
op(Op.Pop, 1);
|
|
1402
|
+
} else {
|
|
1403
|
+
op(Op.SetVariable, symbol + 1);
|
|
1404
|
+
}
|
|
2625
1405
|
}
|
|
2626
1406
|
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
1407
|
+
// if any positional params exist, pop them off the stack as well
|
|
1408
|
+
if (positional !== null) {
|
|
1409
|
+
op(Op.Pop, positional.length);
|
|
2630
1410
|
}
|
|
2631
1411
|
|
|
1412
|
+
// Finish up by popping off and assigning blocks
|
|
1413
|
+
for (const symbol of reverse(blockSymbols)) {
|
|
1414
|
+
op(Op.SetBlock, symbol + 1);
|
|
1415
|
+
}
|
|
1416
|
+
op(Op.Constant, layoutOperand(layout));
|
|
1417
|
+
op(Op.CompileBlock);
|
|
1418
|
+
op(MachineOp.InvokeVirtual);
|
|
1419
|
+
op(Op.DidRenderLayout, $s0);
|
|
1420
|
+
op(MachineOp.PopFrame);
|
|
1421
|
+
op(Op.PopScope);
|
|
1422
|
+
if (hasCapability(capabilities, InternalComponentCapabilities.dynamicScope)) {
|
|
1423
|
+
op(Op.PopDynamicScope);
|
|
1424
|
+
}
|
|
1425
|
+
op(Op.CommitComponentTransaction);
|
|
1426
|
+
op(Op.Load, $s0);
|
|
1427
|
+
}
|
|
1428
|
+
function InvokeNonStaticComponent(op, _ref2) {
|
|
1429
|
+
let {
|
|
1430
|
+
capabilities,
|
|
1431
|
+
elementBlock,
|
|
1432
|
+
positional,
|
|
1433
|
+
named,
|
|
1434
|
+
atNames,
|
|
1435
|
+
blocks: namedBlocks,
|
|
1436
|
+
layout
|
|
1437
|
+
} = _ref2;
|
|
1438
|
+
let bindableBlocks = !!namedBlocks;
|
|
1439
|
+
let bindableAtNames = capabilities === true || hasCapability(capabilities, InternalComponentCapabilities.prepareArgs) || !!(named && named[0].length !== 0);
|
|
1440
|
+
let blocks = namedBlocks.with('attrs', elementBlock);
|
|
1441
|
+
op(Op.Fetch, $s0);
|
|
1442
|
+
op(Op.Dup, $sp, 1);
|
|
1443
|
+
op(Op.Load, $s0);
|
|
1444
|
+
op(MachineOp.PushFrame);
|
|
1445
|
+
CompileArgs(op, positional, named, blocks, atNames);
|
|
1446
|
+
op(Op.PrepareArgs, $s0);
|
|
1447
|
+
invokePreparedComponent(op, blocks.has('default'), bindableBlocks, bindableAtNames, () => {
|
|
1448
|
+
if (layout) {
|
|
1449
|
+
op(Op.PushSymbolTable, symbolTableOperand(layout.symbolTable));
|
|
1450
|
+
op(Op.Constant, layoutOperand(layout));
|
|
1451
|
+
op(Op.CompileBlock);
|
|
1452
|
+
} else {
|
|
1453
|
+
op(Op.GetComponentLayout, $s0);
|
|
1454
|
+
}
|
|
1455
|
+
op(Op.PopulateLayout, $s0);
|
|
1456
|
+
});
|
|
1457
|
+
op(Op.Load, $s0);
|
|
1458
|
+
}
|
|
1459
|
+
function WrappedComponent(op, layout, attrsBlockNumber) {
|
|
1460
|
+
op(HighLevelBuilderOpcodes.StartLabels);
|
|
1461
|
+
WithSavedRegister(op, $s1, () => {
|
|
1462
|
+
op(Op.GetComponentTagName, $s0);
|
|
1463
|
+
op(Op.PrimitiveReference);
|
|
1464
|
+
op(Op.Dup, $sp, 0);
|
|
1465
|
+
});
|
|
1466
|
+
op(Op.JumpUnless, labelOperand('BODY'));
|
|
1467
|
+
op(Op.Fetch, $s1);
|
|
1468
|
+
op(Op.PutComponentOperations);
|
|
1469
|
+
op(Op.OpenDynamicElement);
|
|
1470
|
+
op(Op.DidCreateElement, $s0);
|
|
1471
|
+
YieldBlock(op, attrsBlockNumber, null);
|
|
1472
|
+
op(Op.FlushElement);
|
|
1473
|
+
op(HighLevelBuilderOpcodes.Label, 'BODY');
|
|
1474
|
+
InvokeStaticBlock(op, [layout.block[0], []]);
|
|
1475
|
+
op(Op.Fetch, $s1);
|
|
1476
|
+
op(Op.JumpUnless, labelOperand('END'));
|
|
1477
|
+
op(Op.CloseElement);
|
|
1478
|
+
op(HighLevelBuilderOpcodes.Label, 'END');
|
|
1479
|
+
op(Op.Load, $s1);
|
|
1480
|
+
op(HighLevelBuilderOpcodes.StopLabels);
|
|
1481
|
+
}
|
|
1482
|
+
function invokePreparedComponent(op, hasBlock, bindableBlocks, bindableAtNames) {
|
|
1483
|
+
let populateLayout = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
|
|
1484
|
+
op(Op.BeginComponentTransaction, $s0);
|
|
1485
|
+
op(Op.PushDynamicScope);
|
|
1486
|
+
op(Op.CreateComponent, hasBlock | 0, $s0);
|
|
1487
|
+
|
|
1488
|
+
// this has to run after createComponent to allow
|
|
1489
|
+
// for late-bound layouts, but a caller is free
|
|
1490
|
+
// to populate the layout earlier if it wants to
|
|
1491
|
+
// and do nothing here.
|
|
1492
|
+
if (populateLayout) {
|
|
1493
|
+
populateLayout();
|
|
1494
|
+
}
|
|
1495
|
+
op(Op.RegisterComponentDestructor, $s0);
|
|
1496
|
+
op(Op.GetComponentSelf, $s0);
|
|
1497
|
+
op(Op.VirtualRootScope, $s0);
|
|
1498
|
+
op(Op.SetVariable, 0);
|
|
1499
|
+
op(Op.SetupForEval, $s0);
|
|
1500
|
+
if (bindableAtNames) op(Op.SetNamedVariables, $s0);
|
|
1501
|
+
if (bindableBlocks) op(Op.SetBlocks, $s0);
|
|
1502
|
+
op(Op.Pop, 1);
|
|
1503
|
+
op(Op.InvokeComponentLayout, $s0);
|
|
1504
|
+
op(Op.DidRenderLayout, $s0);
|
|
1505
|
+
op(MachineOp.PopFrame);
|
|
1506
|
+
op(Op.PopScope);
|
|
1507
|
+
op(Op.PopDynamicScope);
|
|
1508
|
+
op(Op.CommitComponentTransaction);
|
|
1509
|
+
}
|
|
1510
|
+
function InvokeBareComponent(op) {
|
|
1511
|
+
op(Op.Fetch, $s0);
|
|
1512
|
+
op(Op.Dup, $sp, 1);
|
|
1513
|
+
op(Op.Load, $s0);
|
|
1514
|
+
op(MachineOp.PushFrame);
|
|
1515
|
+
op(Op.PushEmptyArgs);
|
|
1516
|
+
op(Op.PrepareArgs, $s0);
|
|
1517
|
+
invokePreparedComponent(op, false, false, true, () => {
|
|
1518
|
+
op(Op.GetComponentLayout, $s0);
|
|
1519
|
+
op(Op.PopulateLayout, $s0);
|
|
1520
|
+
});
|
|
1521
|
+
op(Op.Load, $s0);
|
|
2632
1522
|
}
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
;
|
|
1523
|
+
function WithSavedRegister(op, register, block) {
|
|
1524
|
+
op(Op.Fetch, register);
|
|
1525
|
+
block();
|
|
1526
|
+
op(Op.Load, register);
|
|
2638
1527
|
}
|
|
2639
1528
|
|
|
2640
1529
|
function main(op) {
|
|
2641
|
-
op(
|
|
2642
|
-
/* Main */
|
|
2643
|
-
, $s0);
|
|
1530
|
+
op(Op.Main, $s0);
|
|
2644
1531
|
invokePreparedComponent(op, false, false, true);
|
|
2645
1532
|
}
|
|
1533
|
+
|
|
2646
1534
|
/**
|
|
2647
1535
|
* Append content to the DOM. This standard function triages content and does the
|
|
2648
1536
|
* right thing based upon whether it's a string, safe string, component, fragment
|
|
@@ -2651,97 +1539,48 @@ function main(op) {
|
|
|
2651
1539
|
* @param trusting whether to interpolate a string as raw HTML (corresponds to
|
|
2652
1540
|
* triple curlies)
|
|
2653
1541
|
*/
|
|
2654
|
-
|
|
2655
1542
|
function StdAppend(op, trusting, nonDynamicAppend) {
|
|
2656
|
-
SwitchCases(op, () => op(
|
|
2657
|
-
|
|
2658
|
-
), when => {
|
|
2659
|
-
when(2
|
|
2660
|
-
/* String */
|
|
2661
|
-
, () => {
|
|
1543
|
+
SwitchCases(op, () => op(Op.ContentType), when => {
|
|
1544
|
+
when(ContentType.String, () => {
|
|
2662
1545
|
if (trusting) {
|
|
2663
|
-
op(
|
|
2664
|
-
|
|
2665
|
-
);
|
|
2666
|
-
op(43
|
|
2667
|
-
/* AppendHTML */
|
|
2668
|
-
);
|
|
1546
|
+
op(Op.AssertSame);
|
|
1547
|
+
op(Op.AppendHTML);
|
|
2669
1548
|
} else {
|
|
2670
|
-
op(
|
|
2671
|
-
/* AppendText */
|
|
2672
|
-
);
|
|
1549
|
+
op(Op.AppendText);
|
|
2673
1550
|
}
|
|
2674
1551
|
});
|
|
2675
|
-
|
|
2676
1552
|
if (typeof nonDynamicAppend === 'number') {
|
|
2677
|
-
when(
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
op(81
|
|
2681
|
-
/* ResolveCurriedComponent */
|
|
2682
|
-
);
|
|
2683
|
-
op(79
|
|
2684
|
-
/* PushDynamicComponentInstance */
|
|
2685
|
-
);
|
|
1553
|
+
when(ContentType.Component, () => {
|
|
1554
|
+
op(Op.ResolveCurriedComponent);
|
|
1555
|
+
op(Op.PushDynamicComponentInstance);
|
|
2686
1556
|
InvokeBareComponent(op);
|
|
2687
1557
|
});
|
|
2688
|
-
when(
|
|
2689
|
-
/* Helper */
|
|
2690
|
-
, () => {
|
|
1558
|
+
when(ContentType.Helper, () => {
|
|
2691
1559
|
CallDynamic(op, null, null, () => {
|
|
2692
|
-
op(
|
|
2693
|
-
/* InvokeStatic */
|
|
2694
|
-
, nonDynamicAppend);
|
|
1560
|
+
op(MachineOp.InvokeStatic, nonDynamicAppend);
|
|
2695
1561
|
});
|
|
2696
1562
|
});
|
|
2697
1563
|
} else {
|
|
2698
1564
|
// when non-dynamic, we can no longer call the value (potentially because we've already called it)
|
|
2699
1565
|
// this prevents infinite loops. We instead coerce the value, whatever it is, into the DOM.
|
|
2700
|
-
when(
|
|
2701
|
-
|
|
2702
|
-
, () => {
|
|
2703
|
-
op(47
|
|
2704
|
-
/* AppendText */
|
|
2705
|
-
);
|
|
1566
|
+
when(ContentType.Component, () => {
|
|
1567
|
+
op(Op.AppendText);
|
|
2706
1568
|
});
|
|
2707
|
-
when(
|
|
2708
|
-
|
|
2709
|
-
, () => {
|
|
2710
|
-
op(47
|
|
2711
|
-
/* AppendText */
|
|
2712
|
-
);
|
|
1569
|
+
when(ContentType.Helper, () => {
|
|
1570
|
+
op(Op.AppendText);
|
|
2713
1571
|
});
|
|
2714
1572
|
}
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
, () => {
|
|
2719
|
-
op(68
|
|
2720
|
-
/* AssertSame */
|
|
2721
|
-
);
|
|
2722
|
-
op(44
|
|
2723
|
-
/* AppendSafeHTML */
|
|
2724
|
-
);
|
|
1573
|
+
when(ContentType.SafeString, () => {
|
|
1574
|
+
op(Op.AssertSame);
|
|
1575
|
+
op(Op.AppendSafeHTML);
|
|
2725
1576
|
});
|
|
2726
|
-
when(
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
op(68
|
|
2730
|
-
/* AssertSame */
|
|
2731
|
-
);
|
|
2732
|
-
op(45
|
|
2733
|
-
/* AppendDocumentFragment */
|
|
2734
|
-
);
|
|
1577
|
+
when(ContentType.Fragment, () => {
|
|
1578
|
+
op(Op.AssertSame);
|
|
1579
|
+
op(Op.AppendDocumentFragment);
|
|
2735
1580
|
});
|
|
2736
|
-
when(
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
op(68
|
|
2740
|
-
/* AssertSame */
|
|
2741
|
-
);
|
|
2742
|
-
op(46
|
|
2743
|
-
/* AppendNode */
|
|
2744
|
-
);
|
|
1581
|
+
when(ContentType.Node, () => {
|
|
1582
|
+
op(Op.AssertSame);
|
|
1583
|
+
op(Op.AppendNode);
|
|
2745
1584
|
});
|
|
2746
1585
|
});
|
|
2747
1586
|
}
|
|
@@ -2763,22 +1602,21 @@ const STDLIB_META = {
|
|
|
2763
1602
|
owner: null,
|
|
2764
1603
|
size: 0
|
|
2765
1604
|
};
|
|
2766
|
-
|
|
2767
|
-
function build(program, callback) {
|
|
1605
|
+
function build(program, builder) {
|
|
2768
1606
|
let {
|
|
2769
1607
|
constants,
|
|
2770
1608
|
heap,
|
|
2771
1609
|
resolver
|
|
2772
1610
|
} = program;
|
|
2773
1611
|
let encoder = new EncoderImpl(heap, STDLIB_META);
|
|
2774
|
-
|
|
2775
|
-
|
|
1612
|
+
function pushOp() {
|
|
1613
|
+
for (var _len = arguments.length, op = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
1614
|
+
op[_key] = arguments[_key];
|
|
1615
|
+
}
|
|
2776
1616
|
encodeOp(encoder, constants, resolver, STDLIB_META, op);
|
|
2777
1617
|
}
|
|
2778
|
-
|
|
2779
|
-
callback(pushOp);
|
|
1618
|
+
builder(pushOp);
|
|
2780
1619
|
let result = encoder.commit(0);
|
|
2781
|
-
|
|
2782
1620
|
if (typeof result !== 'number') {
|
|
2783
1621
|
// This shouldn't be possible
|
|
2784
1622
|
throw new Error(`Unexpected errors compiling std`);
|
|
@@ -2788,16 +1626,385 @@ function build(program, callback) {
|
|
|
2788
1626
|
}
|
|
2789
1627
|
|
|
2790
1628
|
class CompileTimeCompilationContextImpl {
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
1629
|
+
constants;
|
|
1630
|
+
heap;
|
|
1631
|
+
stdlib;
|
|
1632
|
+
constructor(_ref, resolver, createOp) {
|
|
1633
|
+
let {
|
|
1634
|
+
constants,
|
|
1635
|
+
heap
|
|
1636
|
+
} = _ref;
|
|
2795
1637
|
this.resolver = resolver;
|
|
1638
|
+
this.createOp = createOp;
|
|
2796
1639
|
this.constants = constants;
|
|
2797
1640
|
this.heap = heap;
|
|
2798
1641
|
this.stdlib = compileStd(this);
|
|
2799
1642
|
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
function programCompilationContext(artifacts, resolver, createOp) {
|
|
1646
|
+
return new CompileTimeCompilationContextImpl(artifacts, resolver, createOp);
|
|
1647
|
+
}
|
|
1648
|
+
function templateCompilationContext(program, meta) {
|
|
1649
|
+
let encoder = new EncoderImpl(program.heap, meta, program.stdlib);
|
|
1650
|
+
return {
|
|
1651
|
+
program,
|
|
1652
|
+
encoder,
|
|
1653
|
+
meta
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
const STATEMENTS = new Compilers();
|
|
1658
|
+
const INFLATE_ATTR_TABLE = ['class', 'id', 'value', 'name', 'type', 'style', 'href'];
|
|
1659
|
+
const INFLATE_TAG_TABLE = ['div', 'span', 'p', 'a'];
|
|
1660
|
+
function inflateTagName(tagName) {
|
|
1661
|
+
return typeof tagName === 'string' ? tagName : INFLATE_TAG_TABLE[tagName];
|
|
1662
|
+
}
|
|
1663
|
+
function inflateAttrName(attrName) {
|
|
1664
|
+
return typeof attrName === 'string' ? attrName : INFLATE_ATTR_TABLE[attrName];
|
|
1665
|
+
}
|
|
1666
|
+
STATEMENTS.add(SexpOpcodes.Comment, (op, sexp) => op(Op.Comment, sexp[1]));
|
|
1667
|
+
STATEMENTS.add(SexpOpcodes.CloseElement, op => op(Op.CloseElement));
|
|
1668
|
+
STATEMENTS.add(SexpOpcodes.FlushElement, op => op(Op.FlushElement));
|
|
1669
|
+
STATEMENTS.add(SexpOpcodes.Modifier, (op, _ref) => {
|
|
1670
|
+
let [, expression, positional, named] = _ref;
|
|
1671
|
+
if (isGetFreeModifier(expression)) {
|
|
1672
|
+
op(HighLevelResolutionOpcodes.Modifier, expression, handle => {
|
|
1673
|
+
op(MachineOp.PushFrame);
|
|
1674
|
+
SimpleArgs(op, positional, named, false);
|
|
1675
|
+
op(Op.Modifier, handle);
|
|
1676
|
+
op(MachineOp.PopFrame);
|
|
1677
|
+
});
|
|
1678
|
+
} else {
|
|
1679
|
+
expr(op, expression);
|
|
1680
|
+
op(MachineOp.PushFrame);
|
|
1681
|
+
SimpleArgs(op, positional, named, false);
|
|
1682
|
+
op(Op.Dup, $fp, 1);
|
|
1683
|
+
op(Op.DynamicModifier);
|
|
1684
|
+
op(MachineOp.PopFrame);
|
|
1685
|
+
}
|
|
1686
|
+
});
|
|
1687
|
+
STATEMENTS.add(SexpOpcodes.StaticAttr, (op, _ref2) => {
|
|
1688
|
+
let [, name, value, namespace] = _ref2;
|
|
1689
|
+
op(Op.StaticAttr, inflateAttrName(name), value, namespace ?? null);
|
|
1690
|
+
});
|
|
1691
|
+
STATEMENTS.add(SexpOpcodes.StaticComponentAttr, (op, _ref3) => {
|
|
1692
|
+
let [, name, value, namespace] = _ref3;
|
|
1693
|
+
op(Op.StaticComponentAttr, inflateAttrName(name), value, namespace ?? null);
|
|
1694
|
+
});
|
|
1695
|
+
STATEMENTS.add(SexpOpcodes.DynamicAttr, (op, _ref4) => {
|
|
1696
|
+
let [, name, value, namespace] = _ref4;
|
|
1697
|
+
expr(op, value);
|
|
1698
|
+
op(Op.DynamicAttr, inflateAttrName(name), false, namespace ?? null);
|
|
1699
|
+
});
|
|
1700
|
+
STATEMENTS.add(SexpOpcodes.TrustingDynamicAttr, (op, _ref5) => {
|
|
1701
|
+
let [, name, value, namespace] = _ref5;
|
|
1702
|
+
expr(op, value);
|
|
1703
|
+
op(Op.DynamicAttr, inflateAttrName(name), true, namespace ?? null);
|
|
1704
|
+
});
|
|
1705
|
+
STATEMENTS.add(SexpOpcodes.ComponentAttr, (op, _ref6) => {
|
|
1706
|
+
let [, name, value, namespace] = _ref6;
|
|
1707
|
+
expr(op, value);
|
|
1708
|
+
op(Op.ComponentAttr, inflateAttrName(name), false, namespace ?? null);
|
|
1709
|
+
});
|
|
1710
|
+
STATEMENTS.add(SexpOpcodes.TrustingComponentAttr, (op, _ref7) => {
|
|
1711
|
+
let [, name, value, namespace] = _ref7;
|
|
1712
|
+
expr(op, value);
|
|
1713
|
+
op(Op.ComponentAttr, inflateAttrName(name), true, namespace ?? null);
|
|
1714
|
+
});
|
|
1715
|
+
STATEMENTS.add(SexpOpcodes.OpenElement, (op, _ref8) => {
|
|
1716
|
+
let [, tag] = _ref8;
|
|
1717
|
+
op(Op.OpenElement, inflateTagName(tag));
|
|
1718
|
+
});
|
|
1719
|
+
STATEMENTS.add(SexpOpcodes.OpenElementWithSplat, (op, _ref9) => {
|
|
1720
|
+
let [, tag] = _ref9;
|
|
1721
|
+
op(Op.PutComponentOperations);
|
|
1722
|
+
op(Op.OpenElement, inflateTagName(tag));
|
|
1723
|
+
});
|
|
1724
|
+
STATEMENTS.add(SexpOpcodes.Component, (op, _ref10) => {
|
|
1725
|
+
let [, expr, elementBlock, named, blocks] = _ref10;
|
|
1726
|
+
if (isGetFreeComponent(expr)) {
|
|
1727
|
+
op(HighLevelResolutionOpcodes.Component, expr, component => {
|
|
1728
|
+
InvokeComponent(op, component, elementBlock, null, named, blocks);
|
|
1729
|
+
});
|
|
1730
|
+
} else {
|
|
1731
|
+
// otherwise, the component name was an expression, so resolve the expression
|
|
1732
|
+
// and invoke it as a dynamic component
|
|
1733
|
+
InvokeDynamicComponent(op, expr, elementBlock, null, named, blocks, true, true);
|
|
1734
|
+
}
|
|
1735
|
+
});
|
|
1736
|
+
STATEMENTS.add(SexpOpcodes.Yield, (op, _ref11) => {
|
|
1737
|
+
let [, to, params] = _ref11;
|
|
1738
|
+
return YieldBlock(op, to, params);
|
|
1739
|
+
});
|
|
1740
|
+
STATEMENTS.add(SexpOpcodes.AttrSplat, (op, _ref12) => {
|
|
1741
|
+
let [, to] = _ref12;
|
|
1742
|
+
return YieldBlock(op, to, null);
|
|
1743
|
+
});
|
|
1744
|
+
STATEMENTS.add(SexpOpcodes.Debugger, (op, _ref13) => {
|
|
1745
|
+
let [, debugInfo] = _ref13;
|
|
1746
|
+
return op(Op.Debugger, debugSymbolsOperand(), debugInfo);
|
|
1747
|
+
});
|
|
1748
|
+
STATEMENTS.add(SexpOpcodes.Append, (op, _ref14) => {
|
|
1749
|
+
let [, value] = _ref14;
|
|
1750
|
+
// Special case for static values
|
|
1751
|
+
if (!Array.isArray(value)) {
|
|
1752
|
+
op(Op.Text, value === null || value === undefined ? '' : String(value));
|
|
1753
|
+
} else if (isGetFreeOptionalComponentOrHelper(value)) {
|
|
1754
|
+
op(HighLevelResolutionOpcodes.OptionalComponentOrHelper, value, {
|
|
1755
|
+
ifComponent(component) {
|
|
1756
|
+
InvokeComponent(op, component, null, null, null, null);
|
|
1757
|
+
},
|
|
1758
|
+
ifHelper(handle) {
|
|
1759
|
+
op(MachineOp.PushFrame);
|
|
1760
|
+
Call(op, handle, null, null);
|
|
1761
|
+
op(MachineOp.InvokeStatic, stdlibOperand('cautious-non-dynamic-append'));
|
|
1762
|
+
op(MachineOp.PopFrame);
|
|
1763
|
+
},
|
|
1764
|
+
ifValue(handle) {
|
|
1765
|
+
op(MachineOp.PushFrame);
|
|
1766
|
+
op(Op.ConstantReference, handle);
|
|
1767
|
+
op(MachineOp.InvokeStatic, stdlibOperand('cautious-non-dynamic-append'));
|
|
1768
|
+
op(MachineOp.PopFrame);
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
} else if (value[0] === SexpOpcodes.Call) {
|
|
1772
|
+
let [, expression, positional, named] = value;
|
|
1773
|
+
if (isGetFreeComponentOrHelper(expression)) {
|
|
1774
|
+
op(HighLevelResolutionOpcodes.ComponentOrHelper, expression, {
|
|
1775
|
+
ifComponent(component) {
|
|
1776
|
+
InvokeComponent(op, component, null, positional, hashToArgs(named), null);
|
|
1777
|
+
},
|
|
1778
|
+
ifHelper(handle) {
|
|
1779
|
+
op(MachineOp.PushFrame);
|
|
1780
|
+
Call(op, handle, positional, named);
|
|
1781
|
+
op(MachineOp.InvokeStatic, stdlibOperand('cautious-non-dynamic-append'));
|
|
1782
|
+
op(MachineOp.PopFrame);
|
|
1783
|
+
}
|
|
1784
|
+
});
|
|
1785
|
+
} else {
|
|
1786
|
+
SwitchCases(op, () => {
|
|
1787
|
+
expr(op, expression);
|
|
1788
|
+
op(Op.DynamicContentType);
|
|
1789
|
+
}, when => {
|
|
1790
|
+
when(ContentType.Component, () => {
|
|
1791
|
+
op(Op.ResolveCurriedComponent);
|
|
1792
|
+
op(Op.PushDynamicComponentInstance);
|
|
1793
|
+
InvokeNonStaticComponent(op, {
|
|
1794
|
+
capabilities: true,
|
|
1795
|
+
elementBlock: null,
|
|
1796
|
+
positional,
|
|
1797
|
+
named,
|
|
1798
|
+
atNames: false,
|
|
1799
|
+
blocks: namedBlocks(null)
|
|
1800
|
+
});
|
|
1801
|
+
});
|
|
1802
|
+
when(ContentType.Helper, () => {
|
|
1803
|
+
CallDynamic(op, positional, named, () => {
|
|
1804
|
+
op(MachineOp.InvokeStatic, stdlibOperand('cautious-non-dynamic-append'));
|
|
1805
|
+
});
|
|
1806
|
+
});
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
} else {
|
|
1810
|
+
op(MachineOp.PushFrame);
|
|
1811
|
+
expr(op, value);
|
|
1812
|
+
op(MachineOp.InvokeStatic, stdlibOperand('cautious-append'));
|
|
1813
|
+
op(MachineOp.PopFrame);
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1816
|
+
STATEMENTS.add(SexpOpcodes.TrustingAppend, (op, _ref15) => {
|
|
1817
|
+
let [, value] = _ref15;
|
|
1818
|
+
if (!Array.isArray(value)) {
|
|
1819
|
+
op(Op.Text, value === null || value === undefined ? '' : String(value));
|
|
1820
|
+
} else {
|
|
1821
|
+
op(MachineOp.PushFrame);
|
|
1822
|
+
expr(op, value);
|
|
1823
|
+
op(MachineOp.InvokeStatic, stdlibOperand('trusting-append'));
|
|
1824
|
+
op(MachineOp.PopFrame);
|
|
1825
|
+
}
|
|
1826
|
+
});
|
|
1827
|
+
STATEMENTS.add(SexpOpcodes.Block, (op, _ref16) => {
|
|
1828
|
+
let [, expr, positional, named, blocks] = _ref16;
|
|
1829
|
+
if (isGetFreeComponent(expr)) {
|
|
1830
|
+
op(HighLevelResolutionOpcodes.Component, expr, component => {
|
|
1831
|
+
InvokeComponent(op, component, null, positional, hashToArgs(named), blocks);
|
|
1832
|
+
});
|
|
1833
|
+
} else {
|
|
1834
|
+
InvokeDynamicComponent(op, expr, null, positional, named, blocks, false, false);
|
|
1835
|
+
}
|
|
1836
|
+
});
|
|
1837
|
+
STATEMENTS.add(SexpOpcodes.InElement, (op, _ref17) => {
|
|
1838
|
+
let [, block, guid, destination, insertBefore] = _ref17;
|
|
1839
|
+
ReplayableIf(op, () => {
|
|
1840
|
+
expr(op, guid);
|
|
1841
|
+
if (insertBefore === undefined) {
|
|
1842
|
+
PushPrimitiveReference(op, undefined);
|
|
1843
|
+
} else {
|
|
1844
|
+
expr(op, insertBefore);
|
|
1845
|
+
}
|
|
1846
|
+
expr(op, destination);
|
|
1847
|
+
op(Op.Dup, $sp, 0);
|
|
1848
|
+
return 4;
|
|
1849
|
+
}, () => {
|
|
1850
|
+
op(Op.PushRemoteElement);
|
|
1851
|
+
InvokeStaticBlock(op, block);
|
|
1852
|
+
op(Op.PopRemoteElement);
|
|
1853
|
+
});
|
|
1854
|
+
});
|
|
1855
|
+
STATEMENTS.add(SexpOpcodes.If, (op, _ref18) => {
|
|
1856
|
+
let [, condition, block, inverse] = _ref18;
|
|
1857
|
+
return ReplayableIf(op, () => {
|
|
1858
|
+
expr(op, condition);
|
|
1859
|
+
op(Op.ToBoolean);
|
|
1860
|
+
return 1;
|
|
1861
|
+
}, () => {
|
|
1862
|
+
InvokeStaticBlock(op, block);
|
|
1863
|
+
}, inverse ? () => {
|
|
1864
|
+
InvokeStaticBlock(op, inverse);
|
|
1865
|
+
} : undefined);
|
|
1866
|
+
});
|
|
1867
|
+
STATEMENTS.add(SexpOpcodes.Each, (op, _ref19) => {
|
|
1868
|
+
let [, value, key, block, inverse] = _ref19;
|
|
1869
|
+
return Replayable(op, () => {
|
|
1870
|
+
if (key) {
|
|
1871
|
+
expr(op, key);
|
|
1872
|
+
} else {
|
|
1873
|
+
PushPrimitiveReference(op, null);
|
|
1874
|
+
}
|
|
1875
|
+
expr(op, value);
|
|
1876
|
+
return 2;
|
|
1877
|
+
}, () => {
|
|
1878
|
+
op(Op.EnterList, labelOperand('BODY'), labelOperand('ELSE'));
|
|
1879
|
+
op(MachineOp.PushFrame);
|
|
1880
|
+
op(Op.Dup, $fp, 1);
|
|
1881
|
+
op(MachineOp.ReturnTo, labelOperand('ITER'));
|
|
1882
|
+
op(HighLevelBuilderOpcodes.Label, 'ITER');
|
|
1883
|
+
op(Op.Iterate, labelOperand('BREAK'));
|
|
1884
|
+
op(HighLevelBuilderOpcodes.Label, 'BODY');
|
|
1885
|
+
InvokeStaticBlockWithStack(op, block, 2);
|
|
1886
|
+
op(Op.Pop, 2);
|
|
1887
|
+
op(MachineOp.Jump, labelOperand('FINALLY'));
|
|
1888
|
+
op(HighLevelBuilderOpcodes.Label, 'BREAK');
|
|
1889
|
+
op(MachineOp.PopFrame);
|
|
1890
|
+
op(Op.ExitList);
|
|
1891
|
+
op(MachineOp.Jump, labelOperand('FINALLY'));
|
|
1892
|
+
op(HighLevelBuilderOpcodes.Label, 'ELSE');
|
|
1893
|
+
if (inverse) {
|
|
1894
|
+
InvokeStaticBlock(op, inverse);
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
});
|
|
1898
|
+
STATEMENTS.add(SexpOpcodes.With, (op, _ref20) => {
|
|
1899
|
+
let [, value, block, inverse] = _ref20;
|
|
1900
|
+
ReplayableIf(op, () => {
|
|
1901
|
+
expr(op, value);
|
|
1902
|
+
op(Op.Dup, $sp, 0);
|
|
1903
|
+
op(Op.ToBoolean);
|
|
1904
|
+
return 2;
|
|
1905
|
+
}, () => {
|
|
1906
|
+
InvokeStaticBlockWithStack(op, block, 1);
|
|
1907
|
+
}, () => {
|
|
1908
|
+
if (inverse) {
|
|
1909
|
+
InvokeStaticBlock(op, inverse);
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
});
|
|
1913
|
+
STATEMENTS.add(SexpOpcodes.Let, (op, _ref21) => {
|
|
1914
|
+
let [, positional, block] = _ref21;
|
|
1915
|
+
let count = CompilePositional(op, positional);
|
|
1916
|
+
InvokeStaticBlockWithStack(op, block, count);
|
|
1917
|
+
});
|
|
1918
|
+
STATEMENTS.add(SexpOpcodes.WithDynamicVars, (op, _ref22) => {
|
|
1919
|
+
let [, named, block] = _ref22;
|
|
1920
|
+
if (named) {
|
|
1921
|
+
let [names, expressions] = named;
|
|
1922
|
+
CompilePositional(op, expressions);
|
|
1923
|
+
DynamicScope(op, names, () => {
|
|
1924
|
+
InvokeStaticBlock(op, block);
|
|
1925
|
+
});
|
|
1926
|
+
} else {
|
|
1927
|
+
InvokeStaticBlock(op, block);
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1930
|
+
STATEMENTS.add(SexpOpcodes.InvokeComponent, (op, _ref23) => {
|
|
1931
|
+
let [, expr, positional, named, blocks] = _ref23;
|
|
1932
|
+
if (isGetFreeComponent(expr)) {
|
|
1933
|
+
op(HighLevelResolutionOpcodes.Component, expr, component => {
|
|
1934
|
+
InvokeComponent(op, component, null, positional, hashToArgs(named), blocks);
|
|
1935
|
+
});
|
|
1936
|
+
} else {
|
|
1937
|
+
InvokeDynamicComponent(op, expr, null, positional, named, blocks, false, false);
|
|
1938
|
+
}
|
|
1939
|
+
});
|
|
1940
|
+
function hashToArgs(hash) {
|
|
1941
|
+
if (hash === null) return null;
|
|
1942
|
+
let names = hash[0].map(key => `@${key}`);
|
|
1943
|
+
return [names, hash[1]];
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
const PLACEHOLDER_HANDLE = -1;
|
|
1947
|
+
class CompilableTemplateImpl {
|
|
1948
|
+
compiled = null;
|
|
1949
|
+
constructor(statements, meta,
|
|
1950
|
+
// Part of CompilableTemplate
|
|
1951
|
+
symbolTable) {
|
|
1952
|
+
let moduleName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'plain block';
|
|
1953
|
+
this.statements = statements;
|
|
1954
|
+
this.meta = meta;
|
|
1955
|
+
this.symbolTable = symbolTable;
|
|
1956
|
+
this.moduleName = moduleName;
|
|
1957
|
+
}
|
|
2800
1958
|
|
|
1959
|
+
// Part of CompilableTemplate
|
|
1960
|
+
compile(context) {
|
|
1961
|
+
return maybeCompile(this, context);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
function compilable(layout, moduleName) {
|
|
1965
|
+
let [statements, symbols, hasEval] = layout.block;
|
|
1966
|
+
return new CompilableTemplateImpl(statements, meta(layout), {
|
|
1967
|
+
symbols,
|
|
1968
|
+
hasEval
|
|
1969
|
+
}, moduleName);
|
|
1970
|
+
}
|
|
1971
|
+
function maybeCompile(compilable, context) {
|
|
1972
|
+
if (compilable.compiled !== null) return compilable.compiled;
|
|
1973
|
+
compilable.compiled = PLACEHOLDER_HANDLE;
|
|
1974
|
+
let {
|
|
1975
|
+
statements,
|
|
1976
|
+
meta
|
|
1977
|
+
} = compilable;
|
|
1978
|
+
let result = compileStatements(statements, meta, context);
|
|
1979
|
+
compilable.compiled = result;
|
|
1980
|
+
return result;
|
|
1981
|
+
}
|
|
1982
|
+
function compileStatements(statements, meta, syntaxContext) {
|
|
1983
|
+
let sCompiler = STATEMENTS;
|
|
1984
|
+
let context = templateCompilationContext(syntaxContext, meta);
|
|
1985
|
+
let {
|
|
1986
|
+
encoder,
|
|
1987
|
+
program: {
|
|
1988
|
+
constants,
|
|
1989
|
+
resolver
|
|
1990
|
+
}
|
|
1991
|
+
} = context;
|
|
1992
|
+
function pushOp() {
|
|
1993
|
+
for (var _len = arguments.length, op = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
1994
|
+
op[_key] = arguments[_key];
|
|
1995
|
+
}
|
|
1996
|
+
encodeOp(encoder, constants, resolver, meta, op);
|
|
1997
|
+
}
|
|
1998
|
+
for (const statement of statements) {
|
|
1999
|
+
sCompiler.compile(pushOp, statement);
|
|
2000
|
+
}
|
|
2001
|
+
let handle = context.encoder.commit(meta.size);
|
|
2002
|
+
return handle;
|
|
2003
|
+
}
|
|
2004
|
+
function compilableBlock(block, containing) {
|
|
2005
|
+
return new CompilableTemplateImpl(block[0], containing, {
|
|
2006
|
+
parameters: block[1] || EMPTY_ARRAY
|
|
2007
|
+
});
|
|
2801
2008
|
}
|
|
2802
2009
|
|
|
2803
2010
|
const DEFAULT_CAPABILITIES = {
|
|
@@ -2832,30 +2039,30 @@ const MINIMAL_CAPABILITIES = {
|
|
|
2832
2039
|
};
|
|
2833
2040
|
|
|
2834
2041
|
class WrappedBuilder {
|
|
2042
|
+
symbolTable;
|
|
2043
|
+
compiled = null;
|
|
2044
|
+
attrsBlockNumber;
|
|
2835
2045
|
constructor(layout, moduleName) {
|
|
2836
2046
|
this.layout = layout;
|
|
2837
2047
|
this.moduleName = moduleName;
|
|
2838
|
-
this.compiled = null;
|
|
2839
2048
|
let {
|
|
2840
2049
|
block
|
|
2841
2050
|
} = layout;
|
|
2842
2051
|
let [, symbols, hasEval] = block;
|
|
2843
|
-
symbols = symbols.slice();
|
|
2052
|
+
symbols = symbols.slice();
|
|
2844
2053
|
|
|
2054
|
+
// ensure ATTRS_BLOCK is always included (only once) in the list of symbols
|
|
2845
2055
|
let attrsBlockIndex = symbols.indexOf(ATTRS_BLOCK);
|
|
2846
|
-
|
|
2847
2056
|
if (attrsBlockIndex === -1) {
|
|
2848
2057
|
this.attrsBlockNumber = symbols.push(ATTRS_BLOCK);
|
|
2849
2058
|
} else {
|
|
2850
2059
|
this.attrsBlockNumber = attrsBlockIndex + 1;
|
|
2851
2060
|
}
|
|
2852
|
-
|
|
2853
2061
|
this.symbolTable = {
|
|
2854
2062
|
hasEval,
|
|
2855
2063
|
symbols
|
|
2856
2064
|
};
|
|
2857
2065
|
}
|
|
2858
|
-
|
|
2859
2066
|
compile(syntax) {
|
|
2860
2067
|
if (this.compiled !== null) return this.compiled;
|
|
2861
2068
|
let m = meta(this.layout);
|
|
@@ -2867,23 +2074,20 @@ class WrappedBuilder {
|
|
|
2867
2074
|
resolver
|
|
2868
2075
|
}
|
|
2869
2076
|
} = context;
|
|
2870
|
-
|
|
2871
|
-
|
|
2077
|
+
function pushOp() {
|
|
2078
|
+
for (var _len = arguments.length, op = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
2079
|
+
op[_key] = arguments[_key];
|
|
2080
|
+
}
|
|
2872
2081
|
encodeOp(encoder, constants, resolver, m, op);
|
|
2873
2082
|
}
|
|
2874
|
-
|
|
2875
2083
|
WrappedComponent(pushOp, this.layout, this.attrsBlockNumber);
|
|
2876
2084
|
let handle = context.encoder.commit(m.size);
|
|
2877
|
-
|
|
2878
2085
|
if (typeof handle !== 'number') {
|
|
2879
2086
|
return handle;
|
|
2880
2087
|
}
|
|
2881
|
-
|
|
2882
2088
|
this.compiled = handle;
|
|
2883
|
-
|
|
2884
2089
|
return handle;
|
|
2885
2090
|
}
|
|
2886
|
-
|
|
2887
2091
|
}
|
|
2888
2092
|
|
|
2889
2093
|
let clientId = 0;
|
|
@@ -2891,34 +2095,36 @@ let templateCacheCounters = {
|
|
|
2891
2095
|
cacheHit: 0,
|
|
2892
2096
|
cacheMiss: 0
|
|
2893
2097
|
};
|
|
2098
|
+
|
|
2099
|
+
// These interfaces are for backwards compatibility, some addons use these intimate APIs
|
|
2100
|
+
|
|
2894
2101
|
/**
|
|
2895
2102
|
* Wraps a template js in a template module to change it into a factory
|
|
2896
2103
|
* that handles lazy parsing the template and to create per env singletons
|
|
2897
2104
|
* of the template.
|
|
2898
2105
|
*/
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
}
|
|
2106
|
+
function templateFactory(_ref) {
|
|
2107
|
+
let {
|
|
2108
|
+
id: templateId,
|
|
2109
|
+
moduleName,
|
|
2110
|
+
block,
|
|
2111
|
+
scope,
|
|
2112
|
+
isStrictMode
|
|
2113
|
+
} = _ref;
|
|
2907
2114
|
// TODO(template-refactors): This should be removed in the near future, as it
|
|
2908
2115
|
// appears that id is unused. It is currently kept for backwards compat reasons.
|
|
2909
|
-
let id = templateId || `client-${clientId++}`;
|
|
2116
|
+
let id = templateId || `client-${clientId++}`;
|
|
2117
|
+
|
|
2118
|
+
// TODO: This caches JSON serialized output once in case a template is
|
|
2910
2119
|
// compiled by multiple owners, but we haven't verified if this is actually
|
|
2911
2120
|
// helpful. We should benchmark this in the future.
|
|
2912
|
-
|
|
2913
2121
|
let parsedBlock;
|
|
2914
2122
|
let ownerlessTemplate = null;
|
|
2915
2123
|
let templateCache = new WeakMap();
|
|
2916
|
-
|
|
2917
2124
|
let factory = owner => {
|
|
2918
2125
|
if (parsedBlock === undefined) {
|
|
2919
2126
|
parsedBlock = JSON.parse(block);
|
|
2920
2127
|
}
|
|
2921
|
-
|
|
2922
2128
|
if (owner === undefined) {
|
|
2923
2129
|
if (ownerlessTemplate === null) {
|
|
2924
2130
|
templateCacheCounters.cacheMiss++;
|
|
@@ -2933,12 +2139,9 @@ function templateFactory({
|
|
|
2933
2139
|
} else {
|
|
2934
2140
|
templateCacheCounters.cacheHit++;
|
|
2935
2141
|
}
|
|
2936
|
-
|
|
2937
2142
|
return ownerlessTemplate;
|
|
2938
2143
|
}
|
|
2939
|
-
|
|
2940
2144
|
let result = templateCache.get(owner);
|
|
2941
|
-
|
|
2942
2145
|
if (result === undefined) {
|
|
2943
2146
|
templateCacheCounters.cacheMiss++;
|
|
2944
2147
|
result = new TemplateImpl({
|
|
@@ -2953,52 +2156,44 @@ function templateFactory({
|
|
|
2953
2156
|
} else {
|
|
2954
2157
|
templateCacheCounters.cacheHit++;
|
|
2955
2158
|
}
|
|
2956
|
-
|
|
2957
2159
|
return result;
|
|
2958
2160
|
};
|
|
2959
|
-
|
|
2960
2161
|
factory.__id = id;
|
|
2961
2162
|
factory.__meta = {
|
|
2962
2163
|
moduleName
|
|
2963
2164
|
};
|
|
2964
2165
|
return factory;
|
|
2965
2166
|
}
|
|
2966
|
-
|
|
2967
2167
|
class TemplateImpl {
|
|
2168
|
+
result = 'ok';
|
|
2169
|
+
layout = null;
|
|
2170
|
+
wrappedLayout = null;
|
|
2968
2171
|
constructor(parsedLayout) {
|
|
2969
2172
|
this.parsedLayout = parsedLayout;
|
|
2970
|
-
this.result = 'ok';
|
|
2971
|
-
this.layout = null;
|
|
2972
|
-
this.wrappedLayout = null;
|
|
2973
2173
|
}
|
|
2974
|
-
|
|
2975
2174
|
get moduleName() {
|
|
2976
2175
|
return this.parsedLayout.moduleName;
|
|
2977
2176
|
}
|
|
2978
|
-
|
|
2979
2177
|
get id() {
|
|
2980
2178
|
return this.parsedLayout.id;
|
|
2981
|
-
}
|
|
2982
|
-
// only being exposed for backwards compatibility
|
|
2983
|
-
|
|
2179
|
+
}
|
|
2984
2180
|
|
|
2181
|
+
// TODO(template-refactors): This should be removed in the near future, it is
|
|
2182
|
+
// only being exposed for backwards compatibility
|
|
2985
2183
|
get referrer() {
|
|
2986
2184
|
return {
|
|
2987
2185
|
moduleName: this.parsedLayout.moduleName,
|
|
2988
2186
|
owner: this.parsedLayout.owner
|
|
2989
2187
|
};
|
|
2990
2188
|
}
|
|
2991
|
-
|
|
2992
2189
|
asLayout() {
|
|
2993
2190
|
if (this.layout) return this.layout;
|
|
2994
2191
|
return this.layout = compilable(assign({}, this.parsedLayout), this.moduleName);
|
|
2995
2192
|
}
|
|
2996
|
-
|
|
2997
2193
|
asWrappedLayout() {
|
|
2998
2194
|
if (this.wrappedLayout) return this.wrappedLayout;
|
|
2999
2195
|
return this.wrappedLayout = new WrappedBuilder(assign({}, this.parsedLayout), this.moduleName);
|
|
3000
2196
|
}
|
|
3001
|
-
|
|
3002
2197
|
}
|
|
3003
2198
|
|
|
3004
2199
|
export { CompileTimeCompilationContextImpl, DEFAULT_CAPABILITIES, EMPTY_BLOCKS, MINIMAL_CAPABILITIES, StdLib, WrappedBuilder, compilable, compileStatements, compileStd, debugCompiler, InvokeStaticBlock as invokeStaticBlock, InvokeStaticBlockWithStack as invokeStaticBlockWithStack, meta, programCompilationContext, templateCacheCounters, templateCompilationContext, templateFactory };
|