feat(compiler): implement "enableIvy" compiler option (#21427)
The "enableIvy" compiler option is the initial implementation of the Render3 (or Ivy) code generation. This commit enables generation generating "Hello, World" (example in the test) but not much else. It is currenly only useful for internal Ivy testing as Ivy is in development. PR Close #21427
This commit is contained in:

committed by
Miško Hevery

parent
ce8b5877e2
commit
64d16dee02
141
packages/compiler/src/constant_pool.ts
Normal file
141
packages/compiler/src/constant_pool.ts
Normal file
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as o from './output/output_ast';
|
||||
import {OutputContext, error} from './util';
|
||||
|
||||
export const enum DefinitionKind {Injector, Directive, Component}
|
||||
|
||||
/**
|
||||
* A node that is a place-holder that allows the node to be replaced when the actual
|
||||
* node is known.
|
||||
*
|
||||
* This allows the constant pool to change an expression from a direct reference to
|
||||
* a constant to a shared constant. It returns a fix-up node that is later allowed to
|
||||
* change the referenced expression.
|
||||
*/
|
||||
class FixupExpression extends o.Expression {
|
||||
constructor(public resolved: o.Expression) { super(resolved.type); }
|
||||
|
||||
shared: boolean;
|
||||
|
||||
visitExpression(visitor: o.ExpressionVisitor, context: any): any {
|
||||
this.resolved.visitExpression(visitor, context);
|
||||
}
|
||||
|
||||
isEquivalent(e: o.Expression): boolean {
|
||||
return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
|
||||
}
|
||||
|
||||
fixup(expression: o.Expression) {
|
||||
this.resolved = expression;
|
||||
this.shared = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A constant pool allows a code emitter to share constant in an output context.
|
||||
*
|
||||
* The constant pool also supports sharing access to ivy definitions references.
|
||||
*/
|
||||
export class ConstantPool {
|
||||
statements: o.Statement[] = [];
|
||||
private literals = new Map<string, FixupExpression>();
|
||||
private injectorDefinitions = new Map<any, FixupExpression>();
|
||||
private directiveDefinitions = new Map<any, FixupExpression>();
|
||||
private componentDefintions = new Map<any, FixupExpression>();
|
||||
|
||||
private nextNameIndex = 0;
|
||||
|
||||
getConstLiteral(literal: o.Expression): o.Expression {
|
||||
const key = this.keyOf(literal);
|
||||
let fixup = this.literals.get(key);
|
||||
if (!fixup) {
|
||||
fixup = new FixupExpression(literal);
|
||||
this.literals.set(key, fixup);
|
||||
} else if (!fixup.shared) {
|
||||
// Replace the expression with a variable
|
||||
const name = this.freshName();
|
||||
this.statements.push(
|
||||
o.variable(name).set(literal).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
fixup.fixup(o.variable(name));
|
||||
}
|
||||
return fixup;
|
||||
}
|
||||
|
||||
getDefinition(type: any, kind: DefinitionKind, ctx: OutputContext): o.Expression {
|
||||
const declarations = kind == DefinitionKind.Component ?
|
||||
this.componentDefintions :
|
||||
kind == DefinitionKind.Directive ? this.directiveDefinitions : this.injectorDefinitions;
|
||||
let fixup = declarations.get(type);
|
||||
if (!fixup) {
|
||||
const property = kind == DefinitionKind.Component ?
|
||||
'ngComponentDef' :
|
||||
kind == DefinitionKind.Directive ? 'ngDirectiveDef' : 'ngInjectorDef';
|
||||
fixup = new FixupExpression(ctx.importExpr(type).prop(property));
|
||||
declarations.set(type, fixup);
|
||||
} else if (!fixup.shared) {
|
||||
const name = this.freshName();
|
||||
this.statements.push(
|
||||
o.variable(name).set(fixup.resolved).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
fixup.fixup(o.variable(name));
|
||||
}
|
||||
return fixup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a unique name.
|
||||
*
|
||||
* The name might be unique among different prefixes if any of the prefixes end in
|
||||
* a digit so the prefix should be a constant string (not based on user input) and
|
||||
* must not end in a digit.
|
||||
*/
|
||||
uniqueName(prefix: string): string { return `${prefix}${this.nextNameIndex++}`; }
|
||||
|
||||
private freshName(): string { return this.uniqueName(`_$`); }
|
||||
|
||||
private keyOf(expression: o.Expression) {
|
||||
return expression.visitExpression(new KeyVisitor(), null);
|
||||
}
|
||||
}
|
||||
|
||||
class KeyVisitor implements o.ExpressionVisitor {
|
||||
visitLiteralExpr(ast: o.LiteralExpr): string { return `${ast.value}`; }
|
||||
visitLiteralArrayExpr(ast: o.LiteralArrayExpr): string {
|
||||
return ast.entries.map(entry => entry.visitExpression(this, null)).join(',');
|
||||
}
|
||||
|
||||
visitLiteralMapExpr(ast: o.LiteralMapExpr): string {
|
||||
const entries =
|
||||
ast.entries.map(entry => `${entry.key}:${entry.value.visitExpression(this, null)}`);
|
||||
return `{${entries.join(',')}`;
|
||||
}
|
||||
|
||||
visitReadVarExpr = invalid;
|
||||
visitWriteVarExpr = invalid;
|
||||
visitWriteKeyExpr = invalid;
|
||||
visitWritePropExpr = invalid;
|
||||
visitInvokeMethodExpr = invalid;
|
||||
visitInvokeFunctionExpr = invalid;
|
||||
visitInstantiateExpr = invalid;
|
||||
visitExternalExpr = invalid;
|
||||
visitConditionalExpr = invalid;
|
||||
visitNotExpr = invalid;
|
||||
visitAssertNotNullExpr = invalid;
|
||||
visitCastExpr = invalid;
|
||||
visitFunctionExpr = invalid;
|
||||
visitBinaryOperatorExpr = invalid;
|
||||
visitReadPropExpr = invalid;
|
||||
visitReadKeyExpr = invalid;
|
||||
visitCommaExpr = invalid;
|
||||
}
|
||||
|
||||
function invalid<T>(arg: o.Expression | o.Statement): never {
|
||||
throw new Error(
|
||||
`Invalid state: Visitor ${this.constructor.name} doesn't handle ${o.constructor.name}`);
|
||||
}
|
Reference in New Issue
Block a user