Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
program?: CompilableProgram;
}
export const DEFAULT_TEST_META: AnnotatedModuleLocator = Object.freeze({
kind: 'unknown',
meta: {},
module: 'some/template',
name: 'default',
});
export class TestCompilationContext implements WholeProgramCompilationContext, RuntimeProgram {
readonly runtimeResolver = new LazyRuntimeResolver();
readonly constants = new Constants(this.runtimeResolver);
readonly resolverDelegate = new LazyCompileTimeLookup(this.runtimeResolver);
readonly heap = new CompileTimeHeapImpl();
readonly mode = CompileMode.jit;
readonly stdlib: STDLib;
constructor() {
this.stdlib = compileStd(this);
this._opcode = new RuntimeOpImpl(this.heap);
}
// TODO: This sucks
private _opcode: RuntimeOpImpl;
opcode(offset: number): RuntimeOpImpl {
this._opcode.offset = offset;
return this._opcode;
}
}
// they are done. It is executed both during initial execution
// and during updating execution.
op('Label', 'FINALLY'),
// Finalize the DOM.
op(Op.Exit),
// In initial execution, this is a noop: it returns to the
// immediately following opcode. In updating execution, this
// exits the updating routine.
op(MachineOp.Return),
// Cleanup code for the block. Runs on initial execution
// but not on updating.
op('Label', 'ENDINITIAL'),
op(MachineOp.PopFrame),
op('StopLabels'),
] as T;
}
args,
body,
}: {
args(): { count: number; actions: T };
body(): T;
}): T {
// Push the arguments onto the stack. The args() function
// tells us how many stack elements to retain for re-execution
// when updating.
let { count, actions } = args();
// Start a new label frame, to give END and RETURN
// a unique meaning.
return [
op('StartLabels'),
op(MachineOp.PushFrame),
// If the body invokes a block, its return will return to
// END. Otherwise, the return in RETURN will return to END.
op(MachineOp.ReturnTo, label('ENDINITIAL')),
actions,
// 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
switch (expressionContext) {
case ExpressionContext.Expression: {
// in classic mode, this is always a this-fallback
let name = context.meta.upvars![freeVar];
concatExpressions(
encoder,
context,
[op(Op.GetVariable, 0), op(Op.GetProperty, name)],
constants
);
break;
}
case ExpressionContext.AppendSingleId: {
let resolver = context.syntax.program.resolverDelegate;
let name = context.meta.upvars![freeVar];
let resolvedHelper = resolver.lookupHelper(name, context.meta.referrer);
let expressions: ExpressionCompileActions;
if (resolvedHelper) {
expressions = Call({ handle: resolvedHelper, params: null, hash: null });
} else {
// in classic mode, this is always a this-fallback
expressions = [op(Op.GetVariable, 0), op(Op.GetProperty, name)];
}
concatExpressions(encoder, context, expressions, constants);
break;
case HighLevelResolutionOpcode.ResolveFree: {
throw new Error('Unimplemented HighLevelResolutionOpcode.ResolveFree');
}
case HighLevelResolutionOpcode.ResolveContextualFree: {
let { freeVar, context: expressionContext } = operation.op1;
if (context.meta.asPartial) {
let name = context.meta.upvars![freeVar];
concatExpressions(encoder, context, [op(Op.ResolveMaybeLocal, name)], constants);
break;
}
switch (expressionContext) {
case ExpressionContext.Expression: {
// in classic mode, this is always a this-fallback
let name = context.meta.upvars![freeVar];
concatExpressions(
encoder,
context,
[op(Op.GetVariable, 0), op(Op.GetProperty, name)],
constants
);
break;
}
case ExpressionContext.AppendSingleId: {
let resolver = context.syntax.program.resolverDelegate;
let name = context.meta.upvars![freeVar];
// opcode, since it bleeds directly into its clause.
for (let clause of clauses.slice(0, -1)) {
out.push(op(Op.JumpEq, label(clause.label), clause.match));
}
// Enumerate the clauses in reverse order. Earlier matches will
// require fewer checks.
for (let i = clauses.length - 1; i >= 0; i--) {
let clause = clauses[i];
out.push(op('Label', clause.label), op(Op.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) {
out.push(op(MachineOp.Jump, label('END')));
}
}
out.push(op('Label', 'END'), op('StopLabels'), op(Op.Exit));
return out;
}
body: () => {
let out = [
// If the conditional is false, jump to the ELSE label.
op(Op.JumpUnless, label('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.
op(MachineOp.Jump, label('FINALLY')),
op('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) {
out.push(ifFalse());
}
export { CompilableTemplate };
export class BundleCompilerCompilationContext implements WholeProgramCompilationContext {
readonly compilableTemplates = new ModuleLocatorMap();
readonly compiledBlocks = new ModuleLocatorMap();
readonly meta = new ModuleLocatorMap();
// implement WholeProgramCompilationContext
readonly constants: CompileTimeConstants;
readonly resolverDelegate: BundleCompilerLookup = new BundleCompilerLookup(
this.delegate,
this.compilableTemplates,
this.meta
);
readonly heap: CompileTimeHeap = new HeapImpl();
readonly mode = CompileMode.aot;
readonly stdlib: STDLib;
constructor(
readonly delegate: BundleCompilerDelegate,
options: BundleCompilerOptions
) {
if (options.constants) {
this.constants = options.constants;
} else {
this.constants = new DebugConstants();
}
this.stdlib = compileStd(this);
}
}
function invokeStatic(
context: SyntaxCompilationContext,
action: InvokeStaticOp
): StatementCompileActions {
let compilable = action.op1;
if (context.program.mode === CompileMode.aot) {
let handle = compilable.compile(context);
// 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) {
return op(MachineOp.InvokeStatic, () => compilable.compile(context));
} else {
return op(MachineOp.InvokeStatic, handle);
}
} else {
return [op(Op.Constant, other(action.op1)), op(Op.CompileBlock), op(MachineOp.InvokeVirtual)];
}
}
function invokeStatic(
context: SyntaxCompilationContext,
action: InvokeStaticOp
): StatementCompileActions {
let compilable = action.op1;
if (context.program.mode === CompileMode.aot) {
let handle = compilable.compile(context);
// 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) {
return op(MachineOp.InvokeStatic, () => compilable.compile(context));
} else {
return op(MachineOp.InvokeStatic, handle);
}
} else {
return [op(Op.Constant, other(action.op1)), op(Op.CompileBlock), op(MachineOp.InvokeVirtual)];
}
}