Skip to content

Instantly share code, notes, and snippets.

@GavinJoyce
Created October 9, 2018 10:12
Show Gist options
  • Save GavinJoyce/649ae8f874c0bb2acab79759f07d243e to your computer and use it in GitHub Desktop.
Save GavinJoyce/649ae8f874c0bb2acab79759f07d243e to your computer and use it in GitHub Desktop.
enifed('@glimmer/opcode-compiler', ['exports', '@ember/polyfills', 'ember-babel', '@glimmer/util', '@glimmer/vm', '@glimmer/wire-format', '@glimmer/encoder', '@glimmer/program'], function (exports, _polyfills, _emberBabel, _util, _vm, _wireFormat, _encoder, _program) {
'use strict';
exports.PLACEHOLDER_HANDLE = exports.WrappedBuilder = exports.logOpcode = exports.debugSlice = exports.debug = exports.templateFactory = exports.PartialDefinition = exports.StdOpcodeBuilder = exports.OpcodeBuilder = exports.EagerOpcodeBuilder = exports.LazyOpcodeBuilder = exports.CompilableProgram = exports.CompilableBlock = exports.debugCompiler = exports.AbstractCompiler = exports.compile = exports.LazyCompiler = exports.Macros = exports.ATTRS_BLOCK = undefined;
var PLACEHOLDER_HANDLE = -1;
var Ops$1;
(function (Ops$$1) {
Ops$$1[Ops$$1["OpenComponentElement"] = 0] = "OpenComponentElement";
Ops$$1[Ops$$1["DidCreateElement"] = 1] = "DidCreateElement";
Ops$$1[Ops$$1["SetComponentAttrs"] = 2] = "SetComponentAttrs";
Ops$$1[Ops$$1["DidRenderLayout"] = 3] = "DidRenderLayout";
Ops$$1[Ops$$1["Debugger"] = 4] = "Debugger";
})(Ops$1 || (Ops$1 = {}));
var Ops$2 = _wireFormat.Ops;
var ATTRS_BLOCK = '&attrs';
var Compilers = function () {
function Compilers() {
var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
(0, _emberBabel.classCallCheck)(this, Compilers);
this.offset = offset;
this.names = (0, _util.dict)();
this.funcs = [];
}
Compilers.prototype.add = function add(name, func) {
this.funcs.push(func);
this.names[name] = this.funcs.length - 1;
};
Compilers.prototype.compile = function compile(sexp, builder) {
var name = sexp[this.offset];
var index = this.names[name];
var func = this.funcs[index];
func(sexp, builder);
};
return Compilers;
}();
var _statementCompiler = void 0;
function statementCompiler() {
if (_statementCompiler) {
return _statementCompiler;
}
var STATEMENTS = _statementCompiler = new Compilers();
STATEMENTS.add(Ops$2.Text, function (sexp, builder) {
builder.text(sexp[1]);
});
STATEMENTS.add(Ops$2.Comment, function (sexp, builder) {
builder.comment(sexp[1]);
});
STATEMENTS.add(Ops$2.CloseElement, function (_sexp, builder) {
builder.closeElement();
});
STATEMENTS.add(Ops$2.FlushElement, function (_sexp, builder) {
builder.flushElement();
});
STATEMENTS.add(Ops$2.Modifier, function (sexp, builder) {
var referrer = builder.referrer;
var name = sexp[1],
params = sexp[2],
hash = sexp[3];
var handle = builder.compiler.resolveModifier(name, referrer);
if (handle !== null) {
builder.modifier(handle, params, hash);
} else {
throw new Error('Compile Error ' + name + ' is not a modifier: Helpers may not be used in the element form.');
}
});
STATEMENTS.add(Ops$2.StaticAttr, function (sexp, builder) {
var name = sexp[1],
value = sexp[2],
namespace = sexp[3];
builder.staticAttr(name, namespace, value);
});
STATEMENTS.add(Ops$2.DynamicAttr, function (sexp, builder) {
dynamicAttr(sexp, false, builder);
});
STATEMENTS.add(Ops$2.TrustingAttr, function (sexp, builder) {
dynamicAttr(sexp, true, builder);
});
STATEMENTS.add(Ops$2.OpenElement, function (sexp, builder) {
builder.openPrimitiveElement(sexp[1]);
});
STATEMENTS.add(Ops$2.OpenSplattedElement, function (sexp, builder) {
builder.setComponentAttrs(true);
builder.putComponentOperations();
builder.openPrimitiveElement(sexp[1]);
});
STATEMENTS.add(Ops$2.DynamicComponent, function (sexp, builder) {
var definition = sexp[1],
attrs = sexp[2],
args = sexp[3],
template = sexp[4];
var block = builder.template(template);
var attrsBlock = null;
if (attrs.length > 0) {
var wrappedAttrs = [[Ops$2.ClientSideStatement, Ops$1.SetComponentAttrs, true]].concat(attrs, [[Ops$2.ClientSideStatement, Ops$1.SetComponentAttrs, false]]);
attrsBlock = builder.inlineBlock({ statements: wrappedAttrs, parameters: _util.EMPTY_ARRAY });
}
builder.dynamicComponent(definition, attrsBlock, null, args, false, block, null);
});
STATEMENTS.add(Ops$2.Component, function (sexp, builder) {
var tag = sexp[1],
_attrs = sexp[2],
args = sexp[3],
block = sexp[4];
var referrer = builder.referrer;
var _builder$compiler$res = builder.compiler.resolveLayoutForTag(tag, referrer),
handle = _builder$compiler$res.handle,
capabilities = _builder$compiler$res.capabilities,
compilable = _builder$compiler$res.compilable;
if (handle !== null && capabilities !== null) {
var attrs = [[Ops$2.ClientSideStatement, Ops$1.SetComponentAttrs, true]].concat(_attrs, [[Ops$2.ClientSideStatement, Ops$1.SetComponentAttrs, false]]);
var attrsBlock = builder.inlineBlock({ statements: attrs, parameters: _util.EMPTY_ARRAY });
var child = builder.template(block);
if (compilable) {
builder.pushComponentDefinition(handle);
builder.invokeStaticComponent(capabilities, compilable, attrsBlock, null, args, false, child && child);
} else {
builder.pushComponentDefinition(handle);
builder.invokeComponent(capabilities, attrsBlock, null, args, false, child && child);
}
} else {
throw new Error('Compile Error: Cannot find component ' + tag);
}
});
STATEMENTS.add(Ops$2.Partial, function (sexp, builder) {
var name = sexp[1],
evalInfo = sexp[2];
var referrer = builder.referrer;
builder.replayableIf({
args: function () {
builder.expr(name);
builder.dup();
return 2;
},
ifTrue: function () {
builder.invokePartial(referrer, builder.evalSymbols(), evalInfo);
builder.popScope();
builder.popFrame(); // FIXME: WAT
}
});
});
STATEMENTS.add(Ops$2.Yield, function (sexp, builder) {
var to = sexp[1],
params = sexp[2];
builder.yield(to, params);
});
STATEMENTS.add(Ops$2.AttrSplat, function (sexp, builder) {
var to = sexp[1];
builder.yield(to, []);
builder.setComponentAttrs(false);
});
STATEMENTS.add(Ops$2.Debugger, function (sexp, builder) {
var evalInfo = sexp[1];
builder.debugger(builder.evalSymbols(), evalInfo);
});
STATEMENTS.add(Ops$2.ClientSideStatement, function (sexp, builder) {
CLIENT_SIDE.compile(sexp, builder);
});
STATEMENTS.add(Ops$2.Append, function (sexp, builder) {
var value = sexp[1],
trusting = sexp[2];
var returned = builder.compileInline(sexp) || value;
if (returned === true) return;
builder.guardedAppend(value, trusting);
});
STATEMENTS.add(Ops$2.Block, function (sexp, builder) {
var name = sexp[1],
params = sexp[2],
hash = sexp[3],
_template = sexp[4],
_inverse = sexp[5];
var template = builder.template(_template);
var inverse = builder.template(_inverse);
var templateBlock = template && template;
var inverseBlock = inverse && inverse;
builder.compileBlock(name, params, hash, templateBlock, inverseBlock);
});
var CLIENT_SIDE = new Compilers(1);
CLIENT_SIDE.add(Ops$1.OpenComponentElement, function (sexp, builder) {
builder.putComponentOperations();
builder.openPrimitiveElement(sexp[2]);
});
CLIENT_SIDE.add(Ops$1.DidCreateElement, function (_sexp, builder) {
builder.didCreateElement(_vm.Register.s0);
});
CLIENT_SIDE.add(Ops$1.SetComponentAttrs, function (sexp, builder) {
builder.setComponentAttrs(sexp[2]);
});
CLIENT_SIDE.add(Ops$1.Debugger, function () {
// tslint:disable-next-line:no-debugger
debugger;
});
CLIENT_SIDE.add(Ops$1.DidRenderLayout, function (_sexp, builder) {
builder.didRenderLayout(_vm.Register.s0);
});
return STATEMENTS;
}
function dynamicAttr(sexp, trusting, builder) {
var name = sexp[1],
value = sexp[2],
namespace = sexp[3];
builder.expr(value);
if (namespace) {
builder.dynamicAttr(name, namespace, trusting);
} else {
builder.dynamicAttr(name, null, trusting);
}
}
var _expressionCompiler = void 0;
function expressionCompiler() {
if (_expressionCompiler) {
return _expressionCompiler;
}
var EXPRESSIONS = _expressionCompiler = new Compilers();
EXPRESSIONS.add(Ops$2.Unknown, function (sexp, builder) {
var compiler = builder.compiler,
referrer = builder.referrer,
asPartial = builder.containingLayout.asPartial;
var name = sexp[1];
var handle = compiler.resolveHelper(name, referrer);
if (handle !== null) {
builder.helper(handle, null, null);
} else if (asPartial) {
builder.resolveMaybeLocal(name);
} else {
builder.getVariable(0);
builder.getProperty(name);
}
});
EXPRESSIONS.add(Ops$2.Concat, function (sexp, builder) {
var parts = sexp[1];
for (var i = 0; i < parts.length; i++) {
builder.expr(parts[i]);
}
builder.concat(parts.length);
});
EXPRESSIONS.add(Ops$2.Helper, function (sexp, builder) {
var compiler = builder.compiler,
referrer = builder.referrer;
var name = sexp[1],
params = sexp[2],
hash = sexp[3];
// TODO: triage this in the WF compiler
if (name === 'component') {
var definition = params[0],
restArgs = params.slice(1);
builder.curryComponent(definition, restArgs, hash, true);
return;
}
var handle = compiler.resolveHelper(name, referrer);
if (handle !== null) {
builder.helper(handle, params, hash);
} else {
throw new Error('Compile Error: ' + name + ' is not a helper');
}
});
EXPRESSIONS.add(Ops$2.Get, function (sexp, builder) {
var head = sexp[1],
path = sexp[2];
builder.getVariable(head);
for (var i = 0; i < path.length; i++) {
builder.getProperty(path[i]);
}
});
EXPRESSIONS.add(Ops$2.MaybeLocal, function (sexp, builder) {
var path = sexp[1];
if (builder.containingLayout.asPartial) {
var head = path[0];
path = path.slice(1);
builder.resolveMaybeLocal(head);
} else {
builder.getVariable(0);
}
for (var i = 0; i < path.length; i++) {
builder.getProperty(path[i]);
}
});
EXPRESSIONS.add(Ops$2.Undefined, function (_sexp, builder) {
return builder.pushPrimitiveReference(undefined);
});
EXPRESSIONS.add(Ops$2.HasBlock, function (sexp, builder) {
builder.hasBlock(sexp[1]);
});
EXPRESSIONS.add(Ops$2.HasBlockParams, function (sexp, builder) {
builder.hasBlockParams(sexp[1]);
});
return EXPRESSIONS;
}
var Macros = function Macros() {
(0, _emberBabel.classCallCheck)(this, Macros);
var _populateBuiltins = populateBuiltins(),
blocks = _populateBuiltins.blocks,
inlines = _populateBuiltins.inlines;
this.blocks = blocks;
this.inlines = inlines;
};
var Blocks = function () {
function Blocks() {
(0, _emberBabel.classCallCheck)(this, Blocks);
this.names = (0, _util.dict)();
this.funcs = [];
}
Blocks.prototype.add = function add(name, func) {
this.funcs.push(func);
this.names[name] = this.funcs.length - 1;
};
Blocks.prototype.addMissing = function addMissing(func) {
this.missing = func;
};
Blocks.prototype.compile = function compile(name, params, hash, template, inverse, builder) {
var index = this.names[name];
if (index === undefined) {
var func = this.missing;
var handled = func(name, params, hash, template, inverse, builder);
} else {
var _func = this.funcs[index];
_func(params, hash, template, inverse, builder);
}
};
return Blocks;
}();
var Inlines = function () {
function Inlines() {
(0, _emberBabel.classCallCheck)(this, Inlines);
this.names = (0, _util.dict)();
this.funcs = [];
}
Inlines.prototype.add = function add(name, func) {
this.funcs.push(func);
this.names[name] = this.funcs.length - 1;
};
Inlines.prototype.addMissing = function addMissing(func) {
this.missing = func;
};
Inlines.prototype.compile = function compile(sexp, builder) {
var value = sexp[1];
// TODO: Fix this so that expression macros can return
// things like components, so that {{component foo}}
// is the same as {{(component foo)}}
if (!Array.isArray(value)) return ['expr', value];
var name = void 0;
var params = void 0;
var hash = void 0;
if (value[0] === Ops$2.Helper) {
name = value[1];
params = value[2];
hash = value[3];
} else if (value[0] === Ops$2.Unknown) {
name = value[1];
params = hash = null;
} else {
return ['expr', value];
}
var index = this.names[name];
if (index === undefined && this.missing) {
var func = this.missing;
var returned = func(name, params, hash, builder);
return returned === false ? ['expr', value] : returned;
} else if (index !== undefined) {
var _func2 = this.funcs[index];
var _returned = _func2(name, params, hash, builder);
return _returned === false ? ['expr', value] : _returned;
} else {
return ['expr', value];
}
};
return Inlines;
}();
function populateBuiltins() {
var blocks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Blocks();
var inlines = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Inlines();
blocks.add('if', function (params, _hash, template, inverse, builder) {
// PutArgs
// Test(Environment)
// Enter(BEGIN, END)
// BEGIN: Noop
// JumpUnless(ELSE)
// Evaluate(default)
// Jump(END)
// ELSE: Noop
// Evalulate(inverse)
// END: Noop
// Exit
if (!params || params.length !== 1) {
throw new Error('SYNTAX ERROR: #if requires a single argument');
}
builder.replayableIf({
args: function () {
builder.expr(params[0]);
builder.toBoolean();
return 1;
},
ifTrue: function () {
builder.invokeStaticBlock(template);
},
ifFalse: function () {
if (inverse) {
builder.invokeStaticBlock(inverse);
}
}
});
});
blocks.add('unless', function (params, _hash, template, inverse, builder) {
// PutArgs
// Test(Environment)
// Enter(BEGIN, END)
// BEGIN: Noop
// JumpUnless(ELSE)
// Evaluate(default)
// Jump(END)
// ELSE: Noop
// Evalulate(inverse)
// END: Noop
// Exit
if (!params || params.length !== 1) {
throw new Error('SYNTAX ERROR: #unless requires a single argument');
}
builder.replayableIf({
args: function () {
builder.expr(params[0]);
builder.toBoolean();
return 1;
},
ifTrue: function () {
if (inverse) {
builder.invokeStaticBlock(inverse);
}
},
ifFalse: function () {
builder.invokeStaticBlock(template);
}
});
});
blocks.add('with', function (params, _hash, template, inverse, builder) {
// PutArgs
// Test(Environment)
// Enter(BEGIN, END)
// BEGIN: Noop
// JumpUnless(ELSE)
// Evaluate(default)
// Jump(END)
// ELSE: Noop
// Evalulate(inverse)
// END: Noop
// Exit
if (!params || params.length !== 1) {
throw new Error('SYNTAX ERROR: #with requires a single argument');
}
builder.replayableIf({
args: function () {
builder.expr(params[0]);
builder.dup();
builder.toBoolean();
return 2;
},
ifTrue: function () {
builder.invokeStaticBlock(template, 1);
},
ifFalse: function () {
if (inverse) {
builder.invokeStaticBlock(inverse);
}
}
});
});
blocks.add('each', function (params, hash, template, inverse, builder) {
// Enter(BEGIN, END)
// BEGIN: Noop
// PutArgs
// PutIterable
// JumpUnless(ELSE)
// EnterList(BEGIN2, END2)
// ITER: Noop
// NextIter(BREAK)
// BEGIN2: Noop
// PushChildScope
// Evaluate(default)
// PopScope
// END2: Noop
// Exit
// Jump(ITER)
// BREAK: Noop
// ExitList
// Jump(END)
// ELSE: Noop
// Evalulate(inverse)
// END: Noop
// Exit
builder.replayable({
args: function () {
if (hash && hash[0][0] === 'key') {
builder.expr(hash[1][0]);
} else {
builder.pushPrimitiveReference(null);
}
builder.expr(params[0]);
return 2;
},
body: function () {
builder.putIterator();
builder.jumpUnless('ELSE');
builder.pushFrame();
builder.dup(_vm.Register.fp, 1);
builder.returnTo('ITER');
builder.enterList('BODY');
builder.label('ITER');
builder.iterate('BREAK');
builder.label('BODY');
builder.invokeStaticBlock(template, 2);
builder.pop(2);
builder.jump('FINALLY');
builder.label('BREAK');
builder.exitList();
builder.popFrame();
builder.jump('FINALLY');
builder.label('ELSE');
if (inverse) {
builder.invokeStaticBlock(inverse);
}
}
});
});
blocks.add('in-element', function (params, hash, template, _inverse, builder) {
if (!params || params.length !== 1) {
throw new Error('SYNTAX ERROR: #in-element requires a single argument');
}
builder.replayableIf({
args: function () {
var keys = hash[0],
values = hash[1];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key === 'nextSibling' || key === 'guid') {
builder.expr(values[i]);
} else {
throw new Error('SYNTAX ERROR: #in-element does not take a `' + keys[0] + '` option');
}
}
builder.expr(params[0]);
builder.dup();
return 4;
},
ifTrue: function () {
builder.pushRemoteElement();
builder.invokeStaticBlock(template);
builder.popRemoteElement();
}
});
});
blocks.add('-with-dynamic-vars', function (_params, hash, template, _inverse, builder) {
if (hash) {
var names = hash[0],
expressions = hash[1];
builder.compileParams(expressions);
builder.pushDynamicScope();
builder.bindDynamicScope(names);
builder.invokeStaticBlock(template);
builder.popDynamicScope();
} else {
builder.invokeStaticBlock(template);
}
});
blocks.add('component', function (_params, hash, template, inverse, builder) {
var tag = _params[0];
if (typeof tag === 'string') {
var returned = builder.staticComponentHelper(_params[0], hash, template);
if (returned) return;
}
var definition = _params[0],
params = _params.slice(1);
builder.dynamicComponent(definition, null, params, hash, true, template, inverse);
});
inlines.add('component', function (_name, _params, hash, builder) {
var tag = _params && _params[0];
if (typeof tag === 'string') {
var returned = builder.staticComponentHelper(tag, hash, null);
if (returned) return true;
}
var definition = _params[0],
params = _params.slice(1);
builder.dynamicComponent(definition, null, params, hash, true, null, null);
return true;
});
return { blocks: blocks, inlines: inlines };
}
var PLACEHOLDER_HANDLE$1 = -1;
var CompilableProgram = function () {
function CompilableProgram(compiler, layout) {
(0, _emberBabel.classCallCheck)(this, CompilableProgram);
this.compiler = compiler;
this.layout = layout;
this.compiled = null;
}
CompilableProgram.prototype.compile = function compile() {
if (this.compiled !== null) return this.compiled;
this.compiled = PLACEHOLDER_HANDLE$1;
var statements = this.layout.block.statements;
return this.compiled = this.compiler.add(statements, this.layout);
};
(0, _emberBabel.createClass)(CompilableProgram, [{
key: 'symbolTable',
get: function () {
return this.layout.block;
}
}]);
return CompilableProgram;
}();
var CompilableBlock = function () {
function CompilableBlock(compiler, parsed) {
(0, _emberBabel.classCallCheck)(this, CompilableBlock);
this.compiler = compiler;
this.parsed = parsed;
this.compiled = null;
}
CompilableBlock.prototype.compile = function compile() {
if (this.compiled !== null) return this.compiled;
// Track that compilation has started but not yet finished by temporarily
// using a placeholder handle. In eager compilation mode, where compile()
// may be called recursively, we use this as a signal that the handle cannot
// be known synchronously and must be linked lazily.
this.compiled = PLACEHOLDER_HANDLE$1;
var _parsed = this.parsed,
statements = _parsed.block.statements,
containingLayout = _parsed.containingLayout;
return this.compiled = this.compiler.add(statements, containingLayout);
};
(0, _emberBabel.createClass)(CompilableBlock, [{
key: 'symbolTable',
get: function () {
return this.parsed.block;
}
}]);
return CompilableBlock;
}();
function compile(statements, builder, compiler) {
var sCompiler = statementCompiler();
for (var i = 0; i < statements.length; i++) {
sCompiler.compile(statements[i], builder);
}
var handle = builder.commit();
return handle;
}
function debugSlice(program, start, end) {}
function logOpcode(type, params) {
var out = type;
if (params) {
var args = Object.keys(params).map(function (p) {
return ' ' + p + '=' + json(params[p]);
}).join('');
out += args;
}
return '(' + out + ')';
}
function json(param) {}
function debug(pos, c, op) {
for (var _len = arguments.length, operands = Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
operands[_key - 3] = arguments[_key];
}
var metadata = null;
if (!metadata) {
throw (0, _util.unreachable)('Missing Opcode Metadata for ' + op);
}
var out = (0, _util.dict)();
metadata.ops.forEach(function (operand, index) {
var op = operands[index];
switch (operand.type) {
case 'to':
out[operand.name] = pos + op;
break;
case 'i32':
case 'symbol':
case 'block':
out[operand.name] = op;
break;
case 'handle':
out[operand.name] = c.resolveHandle(op);
break;
case 'str':
out[operand.name] = c.getString(op);
break;
case 'option-str':
out[operand.name] = op ? c.getString(op) : null;
break;
case 'str-array':
out[operand.name] = c.getStringArray(op);
break;
case 'array':
out[operand.name] = c.getArray(op);
break;
case 'bool':
out[operand.name] = !!op;
break;
case 'primitive':
out[operand.name] = decodePrimitive(op, c);
break;
case 'register':
out[operand.name] = _vm.Register[op];
break;
case 'serializable':
out[operand.name] = c.getSerializable(op);
break;
case 'lazy-constant':
out[operand.name] = c.getOther(op);
break;
}
});
return [metadata.name, out];
}
function decodePrimitive(primitive, constants) {
var flag = primitive & 7; // 111
var value = primitive >> 3;
switch (flag) {
case 0 /* NUMBER */:
return value;
case 1 /* FLOAT */:
return constants.getNumber(value);
case 2 /* STRING */:
return constants.getString(value);
case 3 /* BOOLEAN_OR_VOID */:
switch (value) {
case 0:
return false;
case 1:
return true;
case 2:
return null;
case 3:
return undefined;
}
case 4 /* NEGATIVE */:
return constants.getNumber(value);
default:
throw (0, _util.unreachable)();
}
}
var StdLib = function () {
function StdLib(main, trustingGuardedAppend, cautiousGuardedAppend) {
(0, _emberBabel.classCallCheck)(this, StdLib);
this.main = main;
this.trustingGuardedAppend = trustingGuardedAppend;
this.cautiousGuardedAppend = cautiousGuardedAppend;
}
StdLib.compile = function compile(compiler) {
var main = this.std(compiler, function (b) {
return b.main();
});
var trustingGuardedAppend = this.std(compiler, function (b) {
return b.stdAppend(true);
});
var cautiousGuardedAppend = this.std(compiler, function (b) {
return b.stdAppend(false);
});
return new StdLib(main, trustingGuardedAppend, cautiousGuardedAppend);
};
StdLib.std = function std(compiler, callback) {
return StdOpcodeBuilder.build(compiler, callback);
};
StdLib.prototype.getAppend = function getAppend(trusting) {
return trusting ? this.trustingGuardedAppend : this.cautiousGuardedAppend;
};
return StdLib;
}();
var AbstractCompiler = function () {
function AbstractCompiler(macros, program, resolver) {
(0, _emberBabel.classCallCheck)(this, AbstractCompiler);
this.macros = macros;
this.program = program;
this.resolver = resolver;
this.initialize();
}
AbstractCompiler.prototype.initialize = function initialize() {
this.stdLib = StdLib.compile(this);
};
AbstractCompiler.prototype.compileInline = function compileInline(sexp, builder) {
var inlines = this.macros.inlines;
return inlines.compile(sexp, builder);
};
AbstractCompiler.prototype.compileBlock = function compileBlock(name, params, hash, template, inverse, builder) {
var blocks = this.macros.blocks;
blocks.compile(name, params, hash, template, inverse, builder);
};
AbstractCompiler.prototype.add = function add(statements, containingLayout) {
return compile(statements, this.builderFor(containingLayout), this);
};
AbstractCompiler.prototype.commit = function commit(scopeSize, buffer) {
var heap = this.program.heap;
// TODO: change the whole malloc API and do something more efficient
var handle = heap.malloc();
for (var i = 0; i < buffer.length; i++) {
var value = buffer[i];
if (typeof value === 'function') {
heap.pushPlaceholder(value);
} else {
heap.push(value);
}
}
heap.finishMalloc(handle, scopeSize);
return handle;
};
AbstractCompiler.prototype.resolveLayoutForTag = function resolveLayoutForTag(tag, referrer) {
var resolver = this.resolver;
var handle = resolver.lookupComponentDefinition(tag, referrer);
if (handle === null) return { handle: null, capabilities: null, compilable: null };
return this.resolveLayoutForHandle(handle);
};
AbstractCompiler.prototype.resolveLayoutForHandle = function resolveLayoutForHandle(handle) {
var resolver = this.resolver;
var capabilities = resolver.getCapabilities(handle);
var compilable = null;
if (!capabilities.dynamicLayout) {
compilable = resolver.getLayout(handle);
}
return {
handle: handle,
capabilities: capabilities,
compilable: compilable
};
};
AbstractCompiler.prototype.resolveModifier = function resolveModifier(name, referrer) {
return this.resolver.lookupModifier(name, referrer);
};
AbstractCompiler.prototype.resolveHelper = function resolveHelper(name, referrer) {
return this.resolver.lookupHelper(name, referrer);
};
(0, _emberBabel.createClass)(AbstractCompiler, [{
key: 'constants',
get: function () {
return this.program.constants;
}
}]);
return AbstractCompiler;
}();
var debugCompiler = void 0;
var WrappedBuilder = function () {
function WrappedBuilder(compiler, layout) {
(0, _emberBabel.classCallCheck)(this, WrappedBuilder);
this.compiler = compiler;
this.layout = layout;
this.compiled = null;
var block = layout.block;
var symbols = block.symbols.slice();
// ensure ATTRS_BLOCK is always included (only once) in the list of symbols
var attrsBlockIndex = symbols.indexOf(ATTRS_BLOCK);
if (attrsBlockIndex === -1) {
this.attrsBlockNumber = symbols.push(ATTRS_BLOCK);
} else {
this.attrsBlockNumber = attrsBlockIndex + 1;
}
this.symbolTable = {
hasEval: block.hasEval,
symbols: symbols
};
}
WrappedBuilder.prototype.compile = function compile() {
if (this.compiled !== null) return this.compiled;
//========DYNAMIC
// PutValue(TagExpr)
// Test
// JumpUnless(BODY)
// PutComponentOperations
// OpenDynamicPrimitiveElement
// DidCreateElement
// ...attr statements...
// FlushElement
// BODY: Noop
// ...body statements...
// PutValue(TagExpr)
// Test
// JumpUnless(END)
// CloseElement
// END: Noop
// DidRenderLayout
// Exit
//
//========STATIC
// OpenPrimitiveElementOpcode
// DidCreateElement
// ...attr statements...
// FlushElement
// ...body statements...
// CloseElement
// DidRenderLayout
// Exit
var compiler = this.compiler,
layout = this.layout;
var b = compiler.builderFor(layout);
b.startLabels();
b.fetch(_vm.Register.s1);
b.getComponentTagName(_vm.Register.s0);
b.primitiveReference();
b.dup();
b.load(_vm.Register.s1);
b.jumpUnless('BODY');
b.fetch(_vm.Register.s1);
b.setComponentAttrs(true);
b.putComponentOperations();
b.openDynamicElement();
b.didCreateElement(_vm.Register.s0);
b.yield(this.attrsBlockNumber, []);
b.setComponentAttrs(false);
b.flushElement();
b.label('BODY');
b.invokeStaticBlock(blockFor(layout, compiler));
b.fetch(_vm.Register.s1);
b.jumpUnless('END');
b.closeElement();
b.label('END');
b.load(_vm.Register.s1);
b.stopLabels();
var handle = b.commit();
return this.compiled = handle;
};
return WrappedBuilder;
}();
function blockFor(layout, compiler) {
return new CompilableBlock(compiler, {
block: {
statements: layout.block.statements,
parameters: _util.EMPTY_ARRAY
},
containingLayout: layout
});
}
var ComponentBuilder = function () {
function ComponentBuilder(builder) {
(0, _emberBabel.classCallCheck)(this, ComponentBuilder);
this.builder = builder;
}
ComponentBuilder.prototype.static = function _static(handle, args) {
var params = args[0],
hash = args[1],
_default = args[2],
inverse = args[3];
var builder = this.builder;
if (handle !== null) {
var _builder$compiler$res2 = builder.compiler.resolveLayoutForHandle(handle),
capabilities = _builder$compiler$res2.capabilities,
compilable = _builder$compiler$res2.compilable;
if (compilable) {
builder.pushComponentDefinition(handle);
builder.invokeStaticComponent(capabilities, compilable, null, params, hash, false, _default, inverse);
} else {
builder.pushComponentDefinition(handle);
builder.invokeComponent(capabilities, null, params, hash, false, _default, inverse);
}
}
};
return ComponentBuilder;
}();
var Labels = function () {
function Labels() {
(0, _emberBabel.classCallCheck)(this, Labels);
this.labels = (0, _util.dict)();
this.targets = [];
}
Labels.prototype.label = function label(name, index) {
this.labels[name] = index;
};
Labels.prototype.target = function target(at, _target) {
this.targets.push({ at: at, target: _target });
};
Labels.prototype.patch = function patch(encoder) {
var targets = this.targets,
labels = this.labels;
for (var i = 0; i < targets.length; i++) {
var _targets$i = targets[i],
at = _targets$i.at,
target = _targets$i.target;
var address = labels[target] - at;
encoder.patch(at, address);
}
};
return Labels;
}();
var StdOpcodeBuilder = function () {
function StdOpcodeBuilder(compiler) {
var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
(0, _emberBabel.classCallCheck)(this, StdOpcodeBuilder);
this.size = size;
this.encoder = new _encoder.InstructionEncoder([]);
this.labelsStack = new _util.Stack();
this.compiler = compiler;
}
StdOpcodeBuilder.build = function build(compiler, callback) {
var builder = new StdOpcodeBuilder(compiler);
callback(builder);
return builder.commit();
};
StdOpcodeBuilder.prototype.push = function push(name) {
switch (arguments.length) {
case 1:
return this.encoder.encode(name, 0);
case 2:
return this.encoder.encode(name, 0, arguments[1]);
case 3:
return this.encoder.encode(name, 0, arguments[1], arguments[2]);
default:
return this.encoder.encode(name, 0, arguments[1], arguments[2], arguments[3]);
}
};
StdOpcodeBuilder.prototype.pushMachine = function pushMachine(name) {
switch (arguments.length) {
case 1:
return this.encoder.encode(name, 1024 /* MACHINE_MASK */);
case 2:
return this.encoder.encode(name, 1024 /* MACHINE_MASK */, arguments[1]);
case 3:
return this.encoder.encode(name, 1024 /* MACHINE_MASK */, arguments[1], arguments[2]);
default:
return this.encoder.encode(name, 1024 /* MACHINE_MASK */, arguments[1], arguments[2], arguments[3]);
}
};
StdOpcodeBuilder.prototype.commit = function commit() {
this.pushMachine(24 /* Return */);
return this.compiler.commit(this.size, this.encoder.buffer);
};
StdOpcodeBuilder.prototype.reserve = function reserve(name) {
this.encoder.encode(name, 0, -1);
};
StdOpcodeBuilder.prototype.reserveWithOperand = function reserveWithOperand(name, operand) {
this.encoder.encode(name, 0, -1, operand);
};
StdOpcodeBuilder.prototype.reserveMachine = function reserveMachine(name) {
this.encoder.encode(name, 1024 /* MACHINE_MASK */, -1);
};
StdOpcodeBuilder.prototype.main = function main() {
this.push(68 /* Main */, _vm.Register.s0);
this.invokePreparedComponent(false, false, true);
};
StdOpcodeBuilder.prototype.appendHTML = function appendHTML() {
this.push(28 /* AppendHTML */);
};
StdOpcodeBuilder.prototype.appendSafeHTML = function appendSafeHTML() {
this.push(29 /* AppendSafeHTML */);
};
StdOpcodeBuilder.prototype.appendDocumentFragment = function appendDocumentFragment() {
this.push(30 /* AppendDocumentFragment */);
};
StdOpcodeBuilder.prototype.appendNode = function appendNode() {
this.push(31 /* AppendNode */);
};
StdOpcodeBuilder.prototype.appendText = function appendText() {
this.push(32 /* AppendText */);
};
StdOpcodeBuilder.prototype.beginComponentTransaction = function beginComponentTransaction() {
this.push(91 /* BeginComponentTransaction */);
};
StdOpcodeBuilder.prototype.commitComponentTransaction = function commitComponentTransaction() {
this.push(92 /* CommitComponentTransaction */);
};
StdOpcodeBuilder.prototype.pushDynamicScope = function pushDynamicScope() {
this.push(44 /* PushDynamicScope */);
};
StdOpcodeBuilder.prototype.popDynamicScope = function popDynamicScope() {
this.push(45 /* PopDynamicScope */);
};
StdOpcodeBuilder.prototype.pushRemoteElement = function pushRemoteElement() {
this.push(41 /* PushRemoteElement */);
};
StdOpcodeBuilder.prototype.popRemoteElement = function popRemoteElement() {
this.push(42 /* PopRemoteElement */);
};
StdOpcodeBuilder.prototype.pushRootScope = function pushRootScope(symbols, bindCallerScope) {
this.push(20 /* RootScope */, symbols, bindCallerScope ? 1 : 0);
};
StdOpcodeBuilder.prototype.pushVirtualRootScope = function pushVirtualRootScope(register) {
this.push(21 /* VirtualRootScope */, register);
};
StdOpcodeBuilder.prototype.pushChildScope = function pushChildScope() {
this.push(22 /* ChildScope */);
};
StdOpcodeBuilder.prototype.popScope = function popScope() {
this.push(23 /* PopScope */);
};
StdOpcodeBuilder.prototype.prepareArgs = function prepareArgs(state) {
this.push(79 /* PrepareArgs */, state);
};
StdOpcodeBuilder.prototype.createComponent = function createComponent(state, hasDefault) {
var flag = hasDefault | 0;
this.push(81 /* CreateComponent */, flag, state);
};
StdOpcodeBuilder.prototype.registerComponentDestructor = function registerComponentDestructor(state) {
this.push(82 /* RegisterComponentDestructor */, state);
};
StdOpcodeBuilder.prototype.putComponentOperations = function putComponentOperations() {
this.push(83 /* PutComponentOperations */);
};
StdOpcodeBuilder.prototype.getComponentSelf = function getComponentSelf(state) {
this.push(84 /* GetComponentSelf */, state);
};
StdOpcodeBuilder.prototype.getComponentTagName = function getComponentTagName(state) {
this.push(85 /* GetComponentTagName */, state);
};
StdOpcodeBuilder.prototype.getComponentLayout = function getComponentLayout(state) {
this.push(86 /* GetComponentLayout */, state);
};
StdOpcodeBuilder.prototype.setupForEval = function setupForEval(state) {
this.push(87 /* SetupForEval */, state);
};
StdOpcodeBuilder.prototype.invokeComponentLayout = function invokeComponentLayout(state) {
this.push(90 /* InvokeComponentLayout */, state);
};
StdOpcodeBuilder.prototype.didCreateElement = function didCreateElement(state) {
this.push(93 /* DidCreateElement */, state);
};
StdOpcodeBuilder.prototype.didRenderLayout = function didRenderLayout(state) {
this.push(94 /* DidRenderLayout */, state);
};
StdOpcodeBuilder.prototype.pushFrame = function pushFrame() {
this.pushMachine(57 /* PushFrame */);
};
StdOpcodeBuilder.prototype.popFrame = function popFrame() {
this.pushMachine(58 /* PopFrame */);
};
StdOpcodeBuilder.prototype.pushSmallFrame = function pushSmallFrame() {
this.pushMachine(59 /* PushSmallFrame */);
};
StdOpcodeBuilder.prototype.popSmallFrame = function popSmallFrame() {
this.pushMachine(60 /* PopSmallFrame */);
};
StdOpcodeBuilder.prototype.invokeVirtual = function invokeVirtual() {
this.pushMachine(49 /* InvokeVirtual */);
};
StdOpcodeBuilder.prototype.invokeYield = function invokeYield() {
this.push(51 /* InvokeYield */);
};
StdOpcodeBuilder.prototype.toBoolean = function toBoolean() {
this.push(63 /* ToBoolean */);
};
StdOpcodeBuilder.prototype.invokePreparedComponent = function invokePreparedComponent(hasBlock, bindableBlocks, bindableAtNames) {
var populateLayout = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
this.beginComponentTransaction();
this.pushDynamicScope();
this.createComponent(_vm.Register.s0, hasBlock);
// this has to run after createComponent to allow
// for late-bound layouts, but a caller is free
// to populate the layout earlier if it wants to
// and do nothing here.
if (populateLayout) populateLayout();
this.registerComponentDestructor(_vm.Register.s0);
this.getComponentSelf(_vm.Register.s0);
this.pushVirtualRootScope(_vm.Register.s0);
this.setVariable(0);
this.setupForEval(_vm.Register.s0);
if (bindableAtNames) this.setNamedVariables(_vm.Register.s0);
if (bindableBlocks) this.setBlocks(_vm.Register.s0);
this.pop();
this.invokeComponentLayout(_vm.Register.s0);
this.didRenderLayout(_vm.Register.s0);
this.popFrame();
this.popScope();
this.popDynamicScope();
this.commitComponentTransaction();
};
StdOpcodeBuilder.prototype.compileInline = function compileInline(sexp) {
return this.compiler.compileInline(sexp, this);
};
StdOpcodeBuilder.prototype.compileBlock = function compileBlock(name, params, hash, template, inverse) {
this.compiler.compileBlock(name, params, hash, template, inverse, this);
};
StdOpcodeBuilder.prototype.label = function label(name) {
this.labels.label(name, this.nextPos);
};
StdOpcodeBuilder.prototype.startLabels = function startLabels() {
this.labelsStack.push(new Labels());
};
StdOpcodeBuilder.prototype.stopLabels = function stopLabels() {
var label = this.labelsStack.pop();
label.patch(this.encoder);
};
StdOpcodeBuilder.prototype.pushCurriedComponent = function pushCurriedComponent() {
this.push(74 /* PushCurriedComponent */);
};
StdOpcodeBuilder.prototype.pushDynamicComponentInstance = function pushDynamicComponentInstance() {
this.push(73 /* PushDynamicComponentInstance */);
};
StdOpcodeBuilder.prototype.openDynamicElement = function openDynamicElement() {
this.push(34 /* OpenDynamicElement */);
};
StdOpcodeBuilder.prototype.flushElement = function flushElement() {
this.push(38 /* FlushElement */);
};
StdOpcodeBuilder.prototype.closeElement = function closeElement() {
this.push(39 /* CloseElement */);
};
StdOpcodeBuilder.prototype.putIterator = function putIterator() {
this.push(66 /* PutIterator */);
};
StdOpcodeBuilder.prototype.enterList = function enterList(start) {
this.reserve(64 /* EnterList */);
this.labels.target(this.pos, start);
};
StdOpcodeBuilder.prototype.exitList = function exitList() {
this.push(65 /* ExitList */);
};
StdOpcodeBuilder.prototype.iterate = function iterate(breaks) {
this.reserve(67 /* Iterate */);
this.labels.target(this.pos, breaks);
};
StdOpcodeBuilder.prototype.setNamedVariables = function setNamedVariables(state) {
this.push(2 /* SetNamedVariables */, state);
};
StdOpcodeBuilder.prototype.setBlocks = function setBlocks(state) {
this.push(3 /* SetBlocks */, state);
};
StdOpcodeBuilder.prototype.setVariable = function setVariable(symbol) {
this.push(4 /* SetVariable */, symbol);
};
StdOpcodeBuilder.prototype.setBlock = function setBlock(symbol) {
this.push(5 /* SetBlock */, symbol);
};
StdOpcodeBuilder.prototype.getVariable = function getVariable(symbol) {
this.push(6 /* GetVariable */, symbol);
};
StdOpcodeBuilder.prototype.getBlock = function getBlock(symbol) {
this.push(8 /* GetBlock */, symbol);
};
StdOpcodeBuilder.prototype.hasBlock = function hasBlock(symbol) {
this.push(9 /* HasBlock */, symbol);
};
StdOpcodeBuilder.prototype.concat = function concat(size) {
this.push(11 /* Concat */, size);
};
StdOpcodeBuilder.prototype.load = function load(register) {
this.push(18 /* Load */, register);
};
StdOpcodeBuilder.prototype.fetch = function fetch(register) {
this.push(19 /* Fetch */, register);
};
StdOpcodeBuilder.prototype.dup = function dup() {
var register = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _vm.Register.sp;
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
return this.push(16 /* Dup */, register, offset);
};
StdOpcodeBuilder.prototype.pop = function pop() {
var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
return this.push(17 /* Pop */, count);
};
StdOpcodeBuilder.prototype.returnTo = function returnTo(label) {
this.reserveMachine(25 /* ReturnTo */);
this.labels.target(this.pos, label);
};
StdOpcodeBuilder.prototype.primitiveReference = function primitiveReference() {
this.push(14 /* PrimitiveReference */);
};
StdOpcodeBuilder.prototype.reifyU32 = function reifyU32() {
this.push(15 /* ReifyU32 */);
};
StdOpcodeBuilder.prototype.enter = function enter(args) {
this.push(61 /* Enter */, args);
};
StdOpcodeBuilder.prototype.exit = function exit() {
this.push(62 /* Exit */);
};
StdOpcodeBuilder.prototype.return = function _return() {
this.pushMachine(24 /* Return */);
};
StdOpcodeBuilder.prototype.jump = function jump(target) {
this.reserveMachine(52 /* Jump */);
this.labels.target(this.pos, target);
};
StdOpcodeBuilder.prototype.jumpIf = function jumpIf(target) {
this.reserve(53 /* JumpIf */);
this.labels.target(this.pos, target);
};
StdOpcodeBuilder.prototype.jumpUnless = function jumpUnless(target) {
this.reserve(54 /* JumpUnless */);
this.labels.target(this.pos, target);
};
StdOpcodeBuilder.prototype.jumpEq = function jumpEq(value, target) {
this.reserveWithOperand(55 /* JumpEq */, value);
this.labels.target(this.pos, target);
};
StdOpcodeBuilder.prototype.assertSame = function assertSame() {
this.push(56 /* AssertSame */);
};
StdOpcodeBuilder.prototype.pushEmptyArgs = function pushEmptyArgs() {
this.push(77 /* PushEmptyArgs */);
};
StdOpcodeBuilder.prototype.switch = function _switch(_opcode, callback) {
var _this = this;
// Setup the switch DSL
var clauses = [];
var count = 0;
function when(match, callback) {
clauses.push({ match: match, callback: callback, label: 'CLAUSE' + count++ });
}
// Call the callback
callback(when);
// Emit the opcodes for the switch
this.enter(2);
this.assertSame();
this.reifyU32();
this.startLabels();
// First, emit the jump opcodes. We don't need a jump for the last
// opcode, since it bleeds directly into its clause.
clauses.slice(0, -1).forEach(function (clause) {
return _this.jumpEq(clause.match, clause.label);
});
// Enumerate the clauses in reverse order. Earlier matches will
// require fewer checks.
for (var i = clauses.length - 1; i >= 0; i--) {
var clause = clauses[i];
this.label(clause.label);
this.pop(2);
clause.callback();
// The first match is special: it is placed directly before the END
// label, so no additional jump is needed at the end of it.
if (i !== 0) {
this.jump('END');
}
}
this.label('END');
this.stopLabels();
this.exit();
};
StdOpcodeBuilder.prototype.stdAppend = function stdAppend(trusting) {
var _this2 = this;
this.switch(this.contentType(), function (when) {
when(1 /* String */, function () {
if (trusting) {
_this2.assertSame();
_this2.appendHTML();
} else {
_this2.appendText();
}
});
when(0 /* Component */, function () {
_this2.pushCurriedComponent();
_this2.pushDynamicComponentInstance();
_this2.invokeBareComponent();
});
when(3 /* SafeString */, function () {
_this2.assertSame();
_this2.appendSafeHTML();
});
when(4 /* Fragment */, function () {
_this2.assertSame();
_this2.appendDocumentFragment();
});
when(5 /* Node */, function () {
_this2.assertSame();
_this2.appendNode();
});
});
};
StdOpcodeBuilder.prototype.populateLayout = function populateLayout(state) {
this.push(89 /* PopulateLayout */, state);
};
StdOpcodeBuilder.prototype.invokeBareComponent = function invokeBareComponent() {
var _this3 = this;
this.fetch(_vm.Register.s0);
this.dup(_vm.Register.sp, 1);
this.load(_vm.Register.s0);
this.pushFrame();
this.pushEmptyArgs();
this.prepareArgs(_vm.Register.s0);
this.invokePreparedComponent(false, false, true, function () {
_this3.getComponentLayout(_vm.Register.s0);
_this3.populateLayout(_vm.Register.s0);
});
this.load(_vm.Register.s0);
};
StdOpcodeBuilder.prototype.isComponent = function isComponent() {
this.push(69 /* IsComponent */);
};
StdOpcodeBuilder.prototype.contentType = function contentType() {
this.push(70 /* ContentType */);
};
StdOpcodeBuilder.prototype.pushBlockScope = function pushBlockScope() {
this.push(47 /* PushBlockScope */);
};
(0, _emberBabel.createClass)(StdOpcodeBuilder, [{
key: 'pos',
get: function () {
return this.encoder.typePos;
}
}, {
key: 'nextPos',
get: function () {
return this.encoder.size;
}
}, {
key: 'labels',
get: function () {
return this.labelsStack.current;
}
}]);
return StdOpcodeBuilder;
}();
var OpcodeBuilder = function (_StdOpcodeBuilder) {
(0, _emberBabel.inherits)(OpcodeBuilder, _StdOpcodeBuilder);
function OpcodeBuilder(compiler, containingLayout) {
(0, _emberBabel.classCallCheck)(this, OpcodeBuilder);
var _this4 = (0, _emberBabel.possibleConstructorReturn)(this, _StdOpcodeBuilder.call(this, compiler, containingLayout ? containingLayout.block.symbols.length : 0));
_this4.containingLayout = containingLayout;
_this4.component = new ComponentBuilder(_this4);
_this4.expressionCompiler = expressionCompiler();
_this4.isComponentAttrs = false;
_this4.constants = compiler.constants;
_this4.stdLib = compiler.stdLib;
return _this4;
}
/// MECHANICS
OpcodeBuilder.prototype.setComponentAttrs = function setComponentAttrs(enabled) {
this.isComponentAttrs = enabled;
};
OpcodeBuilder.prototype.expr = function expr(expression) {
if (Array.isArray(expression)) {
this.expressionCompiler.compile(expression, this);
} else {
this.pushPrimitiveReference(expression);
}
};
OpcodeBuilder.prototype.pushArgs = function pushArgs(names, flags) {
var serialized = this.constants.stringArray(names);
this.push(76 /* PushArgs */, serialized, flags);
};
OpcodeBuilder.prototype.pushYieldableBlock = function pushYieldableBlock(block) {
this.pushSymbolTable(block && block.symbolTable);
this.pushBlockScope();
this.pushBlock(block);
};
OpcodeBuilder.prototype.curryComponent = function curryComponent(definition,
/* TODO: attrs: Option<RawInlineBlock>, */params, hash, synthetic) {
var referrer = this.containingLayout.referrer;
this.pushFrame();
this.compileArgs(params, hash, null, synthetic);
this.push(80 /* CaptureArgs */);
this.expr(definition);
this.push(71 /* CurryComponent */, this.constants.serializable(referrer));
this.popFrame();
this.fetch(_vm.Register.v0);
};
OpcodeBuilder.prototype.pushSymbolTable = function pushSymbolTable(table) {
if (table) {
var constant = this.constants.serializable(table);
this.push(48 /* PushSymbolTable */, constant);
} else {
this.primitive(null);
}
};
OpcodeBuilder.prototype.invokeComponent = function invokeComponent(capabilities, attrs, params, hash, synthetic, block) {
var _this5 = this;
var inverse = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
var layout = arguments[7];
this.fetch(_vm.Register.s0);
this.dup(_vm.Register.sp, 1);
this.load(_vm.Register.s0);
this.pushFrame();
var bindableBlocks = !!(block || inverse || attrs);
var bindableAtNames = capabilities === true || capabilities.prepareArgs || !!(hash && hash[0].length !== 0);
var blocks = { main: block, else: inverse, attrs: attrs };
this.compileArgs(params, hash, blocks, synthetic);
this.prepareArgs(_vm.Register.s0);
this.invokePreparedComponent(block !== null, bindableBlocks, bindableAtNames, function () {
if (layout) {
_this5.pushSymbolTable(layout.symbolTable);
_this5.pushLayout(layout);
_this5.resolveLayout();
} else {
_this5.getComponentLayout(_vm.Register.s0);
}
_this5.populateLayout(_vm.Register.s0);
});
this.load(_vm.Register.s0);
};
OpcodeBuilder.prototype.invokeStaticComponent = function invokeStaticComponent(capabilities, layout, attrs, params, hash, synthetic, block) {
var inverse = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
var symbolTable = layout.symbolTable;
var bailOut = symbolTable.hasEval || capabilities.prepareArgs;
if (bailOut) {
this.invokeComponent(capabilities, attrs, params, hash, synthetic, block, inverse, layout);
return;
}
this.fetch(_vm.Register.s0);
this.dup(_vm.Register.sp, 1);
this.load(_vm.Register.s0);
var symbols = symbolTable.symbols;
if (capabilities.createArgs) {
this.pushFrame();
this.compileArgs(null, hash, null, synthetic);
}
this.beginComponentTransaction();
if (capabilities.dynamicScope) {
this.pushDynamicScope();
}
if (capabilities.createInstance) {
this.createComponent(_vm.Register.s0, block !== null);
}
if (capabilities.createArgs) {
this.popFrame();
}
this.pushFrame();
this.registerComponentDestructor(_vm.Register.s0);
var bindings = [];
this.getComponentSelf(_vm.Register.s0);
bindings.push({ symbol: 0, isBlock: false });
for (var i = 0; i < symbols.length; i++) {
var symbol = symbols[i];
switch (symbol.charAt(0)) {
case '&':
var callerBlock = null;
if (symbol === '&default') {
callerBlock = block;
} else if (symbol === '&inverse') {
callerBlock = inverse;
} else if (symbol === ATTRS_BLOCK) {
callerBlock = attrs;
} else {
throw (0, _util.unreachable)();
}
if (callerBlock) {
this.pushYieldableBlock(callerBlock);
bindings.push({ symbol: i + 1, isBlock: true });
} else {
this.pushYieldableBlock(null);
bindings.push({ symbol: i + 1, isBlock: true });
}
break;
case '@':
if (!hash) {
break;
}
var keys = hash[0],
values = hash[1];
var lookupName = symbol;
if (synthetic) {
lookupName = symbol.slice(1);
}
var index = keys.indexOf(lookupName);
if (index !== -1) {
this.expr(values[index]);
bindings.push({ symbol: i + 1, isBlock: false });
}
break;
}
}
this.pushRootScope(symbols.length + 1, !!(block || inverse || attrs));
for (var _i = bindings.length - 1; _i >= 0; _i--) {
var _bindings$_i = bindings[_i],
_symbol = _bindings$_i.symbol,
isBlock = _bindings$_i.isBlock;
if (isBlock) {
this.setBlock(_symbol);
} else {
this.setVariable(_symbol);
}
}
this.invokeStatic(layout);
if (capabilities.createInstance) {
this.didRenderLayout(_vm.Register.s0);
}
this.popFrame();
this.popScope();
if (capabilities.dynamicScope) {
this.popDynamicScope();
}
this.commitComponentTransaction();
this.load(_vm.Register.s0);
};
OpcodeBuilder.prototype.dynamicComponent = function dynamicComponent(definition, attrs, params, hash, synthetic, block) {
var _this6 = this;
var inverse = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
this.replayable({
args: function () {
_this6.expr(definition);
_this6.dup();
return 2;
},
body: function () {
_this6.jumpUnless('ELSE');
_this6.resolveDynamicComponent(_this6.containingLayout.referrer);
_this6.pushDynamicComponentInstance();
_this6.invokeComponent(true, attrs, params, hash, synthetic, block, inverse);
_this6.label('ELSE');
}
});
};
OpcodeBuilder.prototype.yield = function _yield(to, params) {
this.compileArgs(params, null, null, false);
this.getBlock(to);
this.resolveBlock();
this.invokeYield();
this.popScope();
this.popFrame();
};
OpcodeBuilder.prototype.guardedAppend = function guardedAppend(expression, trusting) {
this.pushFrame();
this.expr(expression);
this.pushMachine(50 /* InvokeStatic */, this.stdLib.getAppend(trusting));
this.popFrame();
};
OpcodeBuilder.prototype.invokeStaticBlock = function invokeStaticBlock(block) {
var callerCount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var parameters = block.symbolTable.parameters;
var calleeCount = parameters.length;
var count = Math.min(callerCount, calleeCount);
this.pushFrame();
if (count) {
this.pushChildScope();
for (var i = 0; i < count; i++) {
this.dup(_vm.Register.fp, callerCount - i);
this.setVariable(parameters[i]);
}
}
this.pushBlock(block);
this.resolveBlock();
this.invokeVirtual();
if (count) {
this.popScope();
}
this.popFrame();
};
OpcodeBuilder.prototype.string = function string(_string) {
return this.constants.string(_string);
};
OpcodeBuilder.prototype.names = function names(_names) {
var names = [];
for (var i = 0; i < _names.length; i++) {
var n = _names[i];
names[i] = this.constants.string(n);
}
return this.constants.array(names);
};
OpcodeBuilder.prototype.symbols = function symbols(_symbols2) {
return this.constants.array(_symbols2);
};
OpcodeBuilder.prototype.primitive = function primitive(_primitive) {
var type = 0 /* NUMBER */;
var primitive = void 0;
switch (typeof _primitive) {
case 'number':
if (_primitive % 1 === 0) {
if (_primitive > -1) {
primitive = _primitive;
} else {
primitive = this.constants.number(_primitive);
type = 4 /* NEGATIVE */;
}
} else {
primitive = this.constants.number(_primitive);
type = 1 /* FLOAT */;
}
break;
case 'string':
primitive = this.string(_primitive);
type = 2 /* STRING */;
break;
case 'boolean':
primitive = _primitive | 0;
type = 3 /* BOOLEAN_OR_VOID */;
break;
case 'object':
// assume null
primitive = 2;
type = 3 /* BOOLEAN_OR_VOID */;
break;
case 'undefined':
primitive = 3;
type = 3 /* BOOLEAN_OR_VOID */;
break;
default:
throw new Error('Invalid primitive passed to pushPrimitive');
}
var immediate = this.sizeImmediate(primitive << 3 | type, primitive);
this.push(13 /* Primitive */, immediate);
};
OpcodeBuilder.prototype.sizeImmediate = function sizeImmediate(shifted, primitive) {
if (shifted >= 65535 /* MAX_SIZE */ || shifted < 0) {
return this.constants.number(primitive) << 3 | 5 /* BIG_NUM */;
}
return shifted;
};
OpcodeBuilder.prototype.pushPrimitiveReference = function pushPrimitiveReference(primitive) {
this.primitive(primitive);
this.primitiveReference();
};
OpcodeBuilder.prototype.pushComponentDefinition = function pushComponentDefinition(handle) {
this.push(72 /* PushComponentDefinition */, this.constants.handle(handle));
};
OpcodeBuilder.prototype.resolveDynamicComponent = function resolveDynamicComponent(referrer) {
this.push(75 /* ResolveDynamicComponent */, this.constants.serializable(referrer));
};
OpcodeBuilder.prototype.staticComponentHelper = function staticComponentHelper(tag, hash, template) {
var _compiler$resolveLayo = this.compiler.resolveLayoutForTag(tag, this.referrer),
handle = _compiler$resolveLayo.handle,
capabilities = _compiler$resolveLayo.capabilities,
compilable = _compiler$resolveLayo.compilable;
if (handle !== null && capabilities !== null) {
if (compilable) {
if (hash) {
for (var i = 0; i < hash.length; i = i + 2) {
hash[i][0] = '@' + hash[i][0];
}
}
this.pushComponentDefinition(handle);
this.invokeStaticComponent(capabilities, compilable, null, null, hash, false, template && template);
return true;
}
}
return false;
};
OpcodeBuilder.prototype.invokePartial = function invokePartial(referrer, symbols, evalInfo) {
var _meta = this.constants.serializable(referrer);
var _symbols = this.constants.stringArray(symbols);
var _evalInfo = this.constants.array(evalInfo);
this.push(95 /* InvokePartial */, _meta, _symbols, _evalInfo);
};
OpcodeBuilder.prototype.resolveMaybeLocal = function resolveMaybeLocal(name) {
this.push(96 /* ResolveMaybeLocal */, this.string(name));
};
OpcodeBuilder.prototype.debugger = function _debugger(symbols, evalInfo) {
this.push(97 /* Debugger */, this.constants.stringArray(symbols), this.constants.array(evalInfo));
};
OpcodeBuilder.prototype.text = function text(_text) {
this.push(26 /* Text */, this.constants.string(_text));
};
OpcodeBuilder.prototype.openPrimitiveElement = function openPrimitiveElement(tag) {
this.push(33 /* OpenElement */, this.constants.string(tag));
};
OpcodeBuilder.prototype.modifier = function modifier(locator, params, hash) {
this.pushFrame();
this.compileArgs(params, hash, null, true);
this.push(40 /* Modifier */, this.constants.handle(locator));
this.popFrame();
};
OpcodeBuilder.prototype.comment = function comment(_comment) {
var comment = this.constants.string(_comment);
this.push(27 /* Comment */, comment);
};
OpcodeBuilder.prototype.dynamicAttr = function dynamicAttr(_name, _namespace, trusting) {
var name = this.constants.string(_name);
var namespace = _namespace ? this.constants.string(_namespace) : 0;
if (this.isComponentAttrs) {
this.push(37 /* ComponentAttr */, name, trusting === true ? 1 : 0, namespace);
} else {
this.push(36 /* DynamicAttr */, name, trusting === true ? 1 : 0, namespace);
}
};
OpcodeBuilder.prototype.staticAttr = function staticAttr(_name, _namespace, _value) {
var name = this.constants.string(_name);
var namespace = _namespace ? this.constants.string(_namespace) : 0;
if (this.isComponentAttrs) {
this.pushPrimitiveReference(_value);
this.push(37 /* ComponentAttr */, name, 1, namespace);
} else {
var value = this.constants.string(_value);
this.push(35 /* StaticAttr */, name, value, namespace);
}
};
OpcodeBuilder.prototype.hasBlockParams = function hasBlockParams(to) {
this.getBlock(to);
this.resolveBlock();
this.push(10 /* HasBlockParams */);
};
OpcodeBuilder.prototype.getProperty = function getProperty(key) {
this.push(7 /* GetProperty */, this.string(key));
};
OpcodeBuilder.prototype.helper = function helper(_helper, params, hash) {
this.pushFrame();
this.compileArgs(params, hash, null, true);
this.push(1 /* Helper */, this.constants.handle(_helper));
this.popFrame();
this.fetch(_vm.Register.v0);
};
OpcodeBuilder.prototype.bindDynamicScope = function bindDynamicScope(_names) {
this.push(43 /* BindDynamicScope */, this.names(_names));
};
OpcodeBuilder.prototype.replayable = function replayable(_ref) {
var args = _ref.args,
body = _ref.body;
// Start a new label frame, to give END and RETURN
// a unique meaning.
this.startLabels();
this.pushFrame();
// If the body invokes a block, its return will return to
// END. Otherwise, the return in RETURN will return to END.
this.returnTo('ENDINITIAL');
// Push the arguments onto the stack. The args() function
// tells us how many stack elements to retain for re-execution
// when updating.
var count = args();
// Start a new updating closure, remembering `count` elements
// from the stack. Everything after this point, and before END,
// will execute both initially and to update the block.
//
// The enter and exit opcodes also track the area of the DOM
// associated with this block. If an assertion inside the block
// fails (for example, the test value changes from true to false
// in an #if), the DOM is cleared and the program is re-executed,
// restoring `count` elements to the stack and executing the
// instructions between the enter and exit.
this.enter(count);
// Evaluate the body of the block. The body of the block may
// return, which will jump execution to END during initial
// execution, and exit the updating routine.
body();
// All execution paths in the body should run the FINALLY once
// they are done. It is executed both during initial execution
// and during updating execution.
this.label('FINALLY');
// Finalize the DOM.
this.exit();
// In initial execution, this is a noop: it returns to the
// immediately following opcode. In updating execution, this
// exits the updating routine.
this.return();
// Cleanup code for the block. Runs on initial execution
// but not on updating.
this.label('ENDINITIAL');
this.popFrame();
this.stopLabels();
};
OpcodeBuilder.prototype.replayableIf = function replayableIf(_ref2) {
var _this7 = this;
var args = _ref2.args,
ifTrue = _ref2.ifTrue,
ifFalse = _ref2.ifFalse;
this.replayable({
args: args,
body: function () {
// If the conditional is false, jump to the ELSE label.
_this7.jumpUnless('ELSE');
// Otherwise, execute the code associated with the true branch.
ifTrue();
// We're done, so return. In the initial execution, this runs
// the cleanup code. In the updating VM, it exits the updating
// routine.
_this7.jump('FINALLY');
_this7.label('ELSE');
// If the conditional is false, and code associatied ith the
// false branch was provided, execute it. If there was no code
// associated with the false branch, jumping to the else statement
// has no other behavior.
if (ifFalse) {
ifFalse();
}
}
});
};
OpcodeBuilder.prototype.inlineBlock = function inlineBlock(block) {
return new CompilableBlock(this.compiler, {
block: block,
containingLayout: this.containingLayout
});
};
OpcodeBuilder.prototype.evalSymbols = function evalSymbols() {
var block = this.containingLayout.block;
return block.hasEval ? block.symbols : null;
};
OpcodeBuilder.prototype.compileParams = function compileParams(params) {
if (!params) return 0;
for (var i = 0; i < params.length; i++) {
this.expr(params[i]);
}
return params.length;
};
OpcodeBuilder.prototype.compileArgs = function compileArgs(params, hash, blocks, synthetic) {
if (blocks) {
this.pushYieldableBlock(blocks.main);
this.pushYieldableBlock(blocks.else);
this.pushYieldableBlock(blocks.attrs);
}
var count = this.compileParams(params);
var flags = count << 4;
if (synthetic) flags |= 8;
if (blocks) {
flags |= 7;
}
var names = _util.EMPTY_ARRAY;
if (hash) {
names = hash[0];
var val = hash[1];
for (var i = 0; i < val.length; i++) {
this.expr(val[i]);
}
}
this.pushArgs(names, flags);
};
OpcodeBuilder.prototype.template = function template(block) {
if (!block) return null;
return this.inlineBlock(block);
};
(0, _emberBabel.createClass)(OpcodeBuilder, [{
key: 'referrer',
get: function () {
return this.containingLayout && this.containingLayout.referrer;
}
}]);
return OpcodeBuilder;
}(StdOpcodeBuilder);
var LazyOpcodeBuilder = function (_OpcodeBuilder) {
(0, _emberBabel.inherits)(LazyOpcodeBuilder, _OpcodeBuilder);
function LazyOpcodeBuilder() {
(0, _emberBabel.classCallCheck)(this, LazyOpcodeBuilder);
return (0, _emberBabel.possibleConstructorReturn)(this, _OpcodeBuilder.apply(this, arguments));
}
LazyOpcodeBuilder.prototype.pushBlock = function pushBlock(block) {
if (block) {
this.pushOther(block);
} else {
this.primitive(null);
}
};
LazyOpcodeBuilder.prototype.resolveBlock = function resolveBlock() {
this.push(46 /* CompileBlock */);
};
LazyOpcodeBuilder.prototype.pushLayout = function pushLayout(layout) {
if (layout) {
this.pushOther(layout);
} else {
this.primitive(null);
}
};
LazyOpcodeBuilder.prototype.resolveLayout = function resolveLayout() {
this.push(46 /* CompileBlock */);
};
LazyOpcodeBuilder.prototype.invokeStatic = function invokeStatic(compilable) {
this.pushOther(compilable);
this.push(46 /* CompileBlock */);
this.pushMachine(49 /* InvokeVirtual */);
};
LazyOpcodeBuilder.prototype.pushOther = function pushOther(value) {
this.push(12 /* Constant */, this.other(value));
};
LazyOpcodeBuilder.prototype.other = function other(value) {
return this.constants.other(value);
};
return LazyOpcodeBuilder;
}(OpcodeBuilder);
var EagerOpcodeBuilder = function (_OpcodeBuilder2) {
(0, _emberBabel.inherits)(EagerOpcodeBuilder, _OpcodeBuilder2);
function EagerOpcodeBuilder() {
(0, _emberBabel.classCallCheck)(this, EagerOpcodeBuilder);
return (0, _emberBabel.possibleConstructorReturn)(this, _OpcodeBuilder2.apply(this, arguments));
}
EagerOpcodeBuilder.prototype.pushBlock = function pushBlock(block) {
var handle = block ? block.compile() : null;
this.primitive(handle);
};
EagerOpcodeBuilder.prototype.resolveBlock = function resolveBlock() {
return;
};
EagerOpcodeBuilder.prototype.pushLayout = function pushLayout(layout) {
if (layout) {
this.primitive(layout.compile());
} else {
this.primitive(null);
}
};
EagerOpcodeBuilder.prototype.resolveLayout = function resolveLayout() {};
EagerOpcodeBuilder.prototype.invokeStatic = function invokeStatic(compilable) {
var handle = compilable.compile();
// If the handle for the invoked component is not yet known (for example,
// because this is a recursive invocation and we're still compiling), push a
// function that will produce the correct handle when the heap is
// serialized.
if (handle === PLACEHOLDER_HANDLE$1) {
this.pushMachine(50 /* InvokeStatic */, function () {
return compilable.compile();
});
} else {
this.pushMachine(50 /* InvokeStatic */, handle);
}
};
return EagerOpcodeBuilder;
}(OpcodeBuilder);
var LazyCompiler = function (_AbstractCompiler) {
(0, _emberBabel.inherits)(LazyCompiler, _AbstractCompiler);
// FIXME: turn to static method
function LazyCompiler(lookup, resolver, macros) {
(0, _emberBabel.classCallCheck)(this, LazyCompiler);
var constants = new _program.LazyConstants(resolver);
var program = new _program.Program(constants);
return (0, _emberBabel.possibleConstructorReturn)(this, _AbstractCompiler.call(this, macros, program, lookup));
}
LazyCompiler.prototype.builderFor = function builderFor(containingLayout) {
return new LazyOpcodeBuilder(this, containingLayout);
};
return LazyCompiler;
}(AbstractCompiler);
var PartialDefinition = function () {
function PartialDefinition(name, // for debugging
template) {
(0, _emberBabel.classCallCheck)(this, PartialDefinition);
this.name = name;
this.template = template;
}
PartialDefinition.prototype.getPartial = function getPartial() {
var partial = this.template.asPartial();
var handle = partial.compile();
return { symbolTable: partial.symbolTable, handle: handle };
};
return PartialDefinition;
}();
var clientId = 0;
function templateFactory(_ref3) {
var templateId = _ref3.id,
meta = _ref3.meta,
block = _ref3.block;
var parsedBlock = void 0;
var id = templateId || 'client-' + clientId++;
var create = function (compiler, envMeta) {
var newMeta = envMeta ? (0, _util.assign)({}, envMeta, meta) : meta;
if (!parsedBlock) {
parsedBlock = JSON.parse(block);
}
return new TemplateImpl(compiler, { id: id, block: parsedBlock, referrer: newMeta });
};
return { id: id, meta: meta, create: create };
}
var TemplateImpl = function () {
function TemplateImpl(compiler, parsedLayout) {
(0, _emberBabel.classCallCheck)(this, TemplateImpl);
this.compiler = compiler;
this.parsedLayout = parsedLayout;
this.layout = null;
this.partial = null;
this.wrappedLayout = null;
var block = parsedLayout.block;
this.symbols = block.symbols;
this.hasEval = block.hasEval;
this.referrer = parsedLayout.referrer;
this.id = parsedLayout.id || 'client-' + clientId++;
}
TemplateImpl.prototype.asLayout = function asLayout() {
if (this.layout) return this.layout;
return this.layout = new CompilableProgram(this.compiler, (0, _polyfills.assign)({}, this.parsedLayout, { asPartial: false }));
};
TemplateImpl.prototype.asPartial = function asPartial() {
if (this.partial) return this.partial;
return this.layout = new CompilableProgram(this.compiler, (0, _polyfills.assign)({}, this.parsedLayout, { asPartial: true }));
};
TemplateImpl.prototype.asWrappedLayout = function asWrappedLayout() {
if (this.wrappedLayout) return this.wrappedLayout;
return this.wrappedLayout = new WrappedBuilder(this.compiler, (0, _polyfills.assign)({}, this.parsedLayout, { asPartial: false }));
};
return TemplateImpl;
}();
exports.ATTRS_BLOCK = ATTRS_BLOCK;
exports.Macros = Macros;
exports.LazyCompiler = LazyCompiler;
exports.compile = compile;
exports.AbstractCompiler = AbstractCompiler;
exports.debugCompiler = debugCompiler;
exports.CompilableBlock = CompilableBlock;
exports.CompilableProgram = CompilableProgram;
exports.LazyOpcodeBuilder = LazyOpcodeBuilder;
exports.EagerOpcodeBuilder = EagerOpcodeBuilder;
exports.OpcodeBuilder = OpcodeBuilder;
exports.StdOpcodeBuilder = StdOpcodeBuilder;
exports.PartialDefinition = PartialDefinition;
exports.templateFactory = templateFactory;
exports.debug = debug;
exports.debugSlice = debugSlice;
exports.logOpcode = logOpcode;
exports.WrappedBuilder = WrappedBuilder;
exports.PLACEHOLDER_HANDLE = PLACEHOLDER_HANDLE;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment