Skip to content

Commit

Permalink
feat(compiler): integrate compiler with view engine - hello world
Browse files Browse the repository at this point in the history
Part of #14013
  • Loading branch information
tbosch committed Feb 3, 2017
1 parent 63211e3 commit 68b2407
Show file tree
Hide file tree
Showing 25 changed files with 419 additions and 124 deletions.
11 changes: 10 additions & 1 deletion modules/@angular/compiler/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@
* found in the LICENSE file at https://angular.io/license
*/

import {MissingTranslationStrategy, ViewEncapsulation, isDevMode} from '@angular/core';
import {InjectionToken, MissingTranslationStrategy, ViewEncapsulation, isDevMode} from '@angular/core';

import {CompileIdentifierMetadata} from './compile_metadata';
import {Identifiers, createIdentifier} from './identifiers';


/**
* Temporal switch for the compiler to use the new view engine,
* until it is fully integrated.
*
* Only works in Jit for now.
*/
export const USE_VIEW_ENGINE = new InjectionToken<boolean>('UseViewEngine');

export class CompilerConfig {
public renderTypes: RenderTypes;
public defaultEncapsulation: ViewEncapsulation;
Expand Down
39 changes: 38 additions & 1 deletion modules/@angular/compiler/src/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';

import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, ComponentRef_, DebugAppView, DebugContext, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewContainer, ViewType, balanceAnimationKeyframes, clearStyles, collectAndResolveStyles, devModeEqual, prepareFinalAnimationStyles, reflector, registerModuleFactory, renderStyles, view_utils} from './private_import_core';
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, ComponentRef_, DebugAppView, DebugContext, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewContainer, ViewType, balanceAnimationKeyframes, clearStyles, collectAndResolveStyles, devModeEqual, prepareFinalAnimationStyles, reflector, registerModuleFactory, renderStyles, viewEngine, view_utils} from './private_import_core';

const APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
const VIEW_UTILS_MODULE_URL = assetUrl('core', 'linker/view_utils');
const VIEW_ENGINE_MODULE_URL = assetUrl('core', 'view/index');
const CD_MODULE_URL = assetUrl('core', 'change_detection/change_detection');

const ANIMATION_STYLE_UTIL_ASSET_URL = assetUrl('core', 'animation/animation_style_util');
Expand Down Expand Up @@ -363,6 +364,42 @@ export class Identifiers {
};
static noop:
IdentifierSpec = {name: 'noop', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.noop};

static viewDef: IdentifierSpec = {
name: 'viewDef',
moduleUrl: VIEW_ENGINE_MODULE_URL,
runtime: viewEngine.viewDef
};
static elementDef: IdentifierSpec = {
name: 'elementDef',
moduleUrl: VIEW_ENGINE_MODULE_URL,
runtime: viewEngine.elementDef
};
static textDef: IdentifierSpec = {
name: 'textDef',
moduleUrl: VIEW_ENGINE_MODULE_URL,
runtime: viewEngine.textDef
};
static directiveDef: IdentifierSpec = {
name: 'directiveDef',
moduleUrl: VIEW_ENGINE_MODULE_URL,
runtime: viewEngine.directiveDef
};
static setCurrentNode: IdentifierSpec = {
name: 'setCurrentNode',
moduleUrl: VIEW_ENGINE_MODULE_URL,
runtime: viewEngine.setCurrentNode
};
static checkNodeInline: IdentifierSpec = {
name: 'checkNodeInline',
moduleUrl: VIEW_ENGINE_MODULE_URL,
runtime: viewEngine.checkNodeInline
};
static checkNodeDynamic: IdentifierSpec = {
name: 'checkNodeDynamic',
moduleUrl: VIEW_ENGINE_MODULE_URL,
runtime: viewEngine.checkNodeDynamic
};
}

export function assetUrl(pkg: string, path: string = null, type: string = 'src'): string {
Expand Down
15 changes: 13 additions & 2 deletions modules/@angular/compiler/src/jit/compiler_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, InjectionToken, MissingTranslationStrategy, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';

import {AnimationParser} from '../animation/animation_parser';
import {CompilerConfig} from '../config';
import {CompilerConfig, USE_VIEW_ENGINE} from '../config';
import {DirectiveNormalizer} from '../directive_normalizer';
import {DirectiveResolver} from '../directive_resolver';
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
Expand All @@ -31,6 +31,7 @@ import {SummaryResolver} from '../summary_resolver';
import {TemplateParser} from '../template_parser/template_parser';
import {DEFAULT_PACKAGE_URL_PROVIDER, UrlResolver} from '../url_resolver';
import {ViewCompiler} from '../view_compiler/view_compiler';
import {ViewCompilerNext} from '../view_compiler_next/view_compiler';

import {JitCompiler} from './compiler';

Expand All @@ -42,6 +43,11 @@ const _NO_RESOURCE_LOADER: ResourceLoader = {

const baseHtmlParser = new InjectionToken('HtmlParser');

function viewCompilerFactory(
useViewEngine: boolean, cc: CompilerConfig, sr: ElementSchemaRegistry) {
return useViewEngine ? new ViewCompilerNext(cc, sr) : new ViewCompiler(cc, sr);
}

/**
* A set of providers that provide `JitCompiler` and its dependencies to use for
* template compilation.
Expand Down Expand Up @@ -81,7 +87,12 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
CompileMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
ViewCompiler,
{provide: USE_VIEW_ENGINE, useValue: false},
{
provide: ViewCompiler,
useFactory: viewCompilerFactory,
deps: [USE_VIEW_ENGINE, CompilerConfig, ElementSchemaRegistry]
},
NgModuleCompiler,
DirectiveWrapperCompiler,
{provide: CompilerConfig, useValue: new CompilerConfig()},
Expand Down
12 changes: 9 additions & 3 deletions modules/@angular/compiler/src/metadata_resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {StaticSymbol, StaticSymbolCache} from './aot/static_symbol';
import {ngfactoryFilePath} from './aot/util';
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
import * as cpl from './compile_metadata';
import {USE_VIEW_ENGINE} from './config';
import {DirectiveNormalizer} from './directive_normalizer';
import {DirectiveResolver} from './directive_resolver';
import {stringify} from './facade/lang';
Expand All @@ -20,7 +21,7 @@ import {CompilerInjectable} from './injectable';
import {hasLifecycleHook} from './lifecycle_reflector';
import {NgModuleResolver} from './ng_module_resolver';
import {PipeResolver} from './pipe_resolver';
import {ComponentStillLoadingError, LIFECYCLE_HOOKS_VALUES, ReflectorReader, reflector} from './private_import_core';
import {ComponentStillLoadingError, LIFECYCLE_HOOKS_VALUES, ReflectorReader, reflector, viewEngine} from './private_import_core';
import {ElementSchemaRegistry} from './schema/element_schema_registry';
import {SummaryResolver} from './summary_resolver';
import {getUrlScheme} from './url_resolver';
Expand Down Expand Up @@ -53,7 +54,8 @@ export class CompileMetadataResolver {
private _directiveNormalizer: DirectiveNormalizer,
@Optional() private _staticSymbolCache: StaticSymbolCache,
private _reflector: ReflectorReader = reflector,
@Optional() @Inject(ERROR_COLLECTOR_TOKEN) private _errorCollector?: ErrorCollector) {}
@Optional() @Inject(ERROR_COLLECTOR_TOKEN) private _errorCollector?: ErrorCollector,
@Optional() @Inject(USE_VIEW_ENGINE) private _useViewEngine?: boolean) {}

clearCacheFor(type: Type<any>) {
const dirMeta = this._directiveCache.get(type);
Expand Down Expand Up @@ -135,7 +137,11 @@ export class CompileMetadataResolver {
ngfactoryFilePath(dirType.filePath), cpl.componentFactoryName(dirType));
} else {
const hostView = this.getHostComponentViewClass(dirType);
return new ComponentFactory(selector, <any>hostView, dirType);
if (this._useViewEngine) {
return viewEngine.createComponentFactory(selector, dirType, <any>hostView);
} else {
return new ComponentFactory(selector, <any>hostView, dirType);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions modules/@angular/compiler/src/private_import_core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const registerModuleFactory: typeof r.registerModuleFactory = r.registerM
export type ViewType = typeof r._ViewType;
export const ViewType: typeof r.ViewType = r.ViewType;
export const view_utils: typeof r.view_utils = r.view_utils;
export const viewEngine: typeof r.viewEngine = r.viewEngine;
export const DebugContext: typeof r.DebugContext = r.DebugContext;
export const StaticNodeDebugInfo: typeof r.StaticNodeDebugInfo = r.StaticNodeDebugInfo;
export const devModeEqual: typeof r.devModeEqual = r.devModeEqual;
Expand Down
5 changes: 5 additions & 0 deletions modules/@angular/compiler/src/view_compiler_next/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Compiler Integration for new View Engine

This folder contains the code to integrate the compiler with the new view engine.

Note: This is work in progress, and once complete will replace the regular view_compiler folder.
181 changes: 181 additions & 0 deletions modules/@angular/compiler/src/view_compiler_next/view_compiler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/**
* @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 {AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompilePipeSummary, identifierModuleUrl, identifierName} from '../compile_metadata';
import {convertPropertyBinding} from '../compiler_util/expression_converter';
import {CompilerConfig} from '../config';
import {ASTWithSource, Interpolation} from '../expression_parser/ast';
import {Identifiers, createIdentifier} from '../identifiers';
import {CompilerInjectable} from '../injectable';
import * as o from '../output/output_ast';
import {viewEngine} from '../private_import_core';
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {ViewEncapsulationEnum} from '../view_compiler/constants';
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';

@CompilerInjectable()
export class ViewCompilerNext extends ViewCompiler {
constructor(
private _genConfigNext: CompilerConfig, private _schemaRegistryNext: ElementSchemaRegistry) {
super(_genConfigNext, _schemaRegistryNext);
}

compileComponent(
component: CompileDirectiveMetadata, template: TemplateAst[], styles: o.Expression,
pipes: CompilePipeSummary[],
compiledAnimations: AnimationEntryCompileResult[]): ViewCompileResult {
const visitor = new ViewBuilderVisitor();
templateVisitAll(visitor, template);

const statements: o.Statement[] = [];
const compName = identifierName(component.type) + (component.isHost ? `_Host` : '');
const viewName = `view_${compName}`;

const renderCompTypeName = `renderType_${compName}`;
statements.push(
createRenderComponentType(renderCompTypeName, component, styles, compiledAnimations));
const renderCompType = o.variable(renderCompTypeName);
statements.push(...visitor.build(viewName, o.importType(component.type), renderCompType));

return new ViewCompileResult(statements, viewName, []);
}
}

function createRenderComponentType(
renderCompTypeName: string, component: CompileDirectiveMetadata, styles: o.Expression,
animations: AnimationEntryCompileResult[]): o.Statement {
const compName = identifierName(component.type);
const compFilePath = identifierModuleUrl(component.type);
const renderCompTypeVar: o.ReadVarExpr = o.variable(renderCompTypeName);
return renderCompTypeVar
.set(o.importExpr(createIdentifier(Identifiers.createRenderComponentType)).callFn([
o.literal(''),
o.literal(component.template.ngContentSelectors.length),
ViewEncapsulationEnum.fromValue(component.template.encapsulation),
styles,
o.literalMap(
animations.map((entry): [string, o.Expression] => [entry.name, entry.fnExp]), null,
true),
]))
.toDeclStmt(o.importType(createIdentifier(Identifiers.RenderComponentType)));
}

const VIEW_VAR = o.variable('view');
const COMP_VAR = o.variable('comp');

class ViewBuilderVisitor implements TemplateAstVisitor {
private nodeDefs: o.Expression[] = [];
private updateStmts: o.Statement[] = [];
private bindingCount = 0;
private nodeCount = 0;

build(viewName: string, compType: o.Type, renderCompType: o.Expression): o.Statement[] {
const viewFlags = 0;
let updateFn: o.Expression;
if (this.updateStmts.length > 0) {
updateFn = o.fn(
[new o.FnParam(VIEW_VAR.name)],
[COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(compType), ...this.updateStmts]);
} else {
updateFn = o.NULL_EXPR;
}
const handleEventFn = o.NULL_EXPR;
const viewFactory = new o.DeclareFunctionStmt(
viewName, [],
[new o.ReturnStatement(o.importExpr(createIdentifier(Identifiers.viewDef)).callFn([
o.literal(viewFlags), o.literalArr(this.nodeDefs.slice().reverse()), updateFn,
handleEventFn, renderCompType
]))]);

return [viewFactory];
}

visitNgContent(ast: NgContentAst, context: any): any {}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {}
visitElement(ast: ElementAst, context: any): any {
// elementDef(
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
// childCount: number, name: string, fixedAttrs: {[name: string]: string} = {},
// bindings?:
// ([BindingType.ElementClass, string] | [BindingType.ElementStyle, string, string] |
// [BindingType.ElementAttribute | BindingType.ElementProperty, string,
// SecurityContext])[],
// outputs?: (string | [string, string])[]): NodeDef;
const nodeIndex = this.nodeCount++;
templateVisitAll(this, ast.directives);
templateVisitAll(this, ast.children);
const childCount = this.nodeCount - nodeIndex - 1;

const flags = o.literal(0);
const fixedAttrs = o.literalMap([]);
this.nodeDefs.push(o.importExpr(createIdentifier(Identifiers.elementDef)).callFn([
flags, o.NULL_EXPR, o.NULL_EXPR, o.literal(childCount), o.literal(ast.name), fixedAttrs
]));
}
visitReference(ast: ReferenceAst, context: any): any {}
visitVariable(ast: VariableAst, context: any): any {}
visitEvent(ast: BoundEventAst, context: any): any {}
visitElementProperty(ast: BoundElementPropertyAst, context: any): any {}
visitAttr(ast: AttrAst, context: any): any {}
visitBoundText(ast: BoundTextAst, context: any): any {
const nodeIndex = this.nodeCount++;
const astWithSource = <ASTWithSource>ast.value;
const inter = <Interpolation>astWithSource.ast;
this.updateStmts.push(o.importExpr(createIdentifier(Identifiers.setCurrentNode))
.callFn([o.variable('view'), o.literal(nodeIndex)])
.toStmt());
const exprs = inter.expressions.map((expr) => {
const bindingId = `bind_${this.bindingCount++}`;
const converted = convertPropertyBinding(null, null, COMP_VAR, expr, bindingId);
this.updateStmts.push(...converted.stmts);
return converted.currValExpr;
});
if (exprs.length > 10) {
this.updateStmts.push(o.importExpr(createIdentifier(Identifiers.checkNodeDynamic))
.callFn([o.literalArr(exprs)])
.toStmt());
} else {
this.updateStmts.push(
o.importExpr(createIdentifier(Identifiers.checkNodeInline)).callFn(exprs).toStmt());
}

// textDef(ngContentIndex: number, constants: string[]): NodeDef;
this.nodeDefs.push(o.importExpr(createIdentifier(Identifiers.textDef)).callFn([
o.NULL_EXPR, o.literalArr(inter.strings.map(s => o.literal(s)))
]));
}
visitText(ast: TextAst, context: any): any {
this.nodeCount++;
// textDef(ngContentIndex: number, constants: string[]): NodeDef;
this.nodeDefs.push(o.importExpr(createIdentifier(Identifiers.textDef)).callFn([
o.NULL_EXPR, o.literalArr([o.literal(ast.value)])
]));
}
visitDirective(ast: DirectiveAst, context: any): any {
this.nodeCount++;
const flags = 0;
const childCount = 0;
const deps: o.Expression[] = [];
let compView = o.NULL_EXPR;
if (ast.directive.isComponent) {
compView = o.importExpr({reference: ast.directive.componentViewType});
}
// directiveDef(
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], childCount: number, ctor:
// any,
// deps: ([DepFlags, any] | any)[], props?: {[name: string]: [number, string]},
// outputs?: {[name: string]: string}, component?: () => ViewDefinition): NodeDef;
this.nodeDefs.push(o.importExpr(createIdentifier(Identifiers.directiveDef)).callFn([
o.literal(flags), o.NULL_EXPR, o.literal(childCount), o.importExpr(ast.directive.type),
o.literalArr(deps), o.NULL_EXPR, o.NULL_EXPR, compView
]));
}
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any {}
}
3 changes: 3 additions & 0 deletions modules/@angular/core/src/core_private_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import * as reflection_types from './reflection/types';
import * as api from './render/api';
import * as decorators from './util/decorators';
import {isObservable, isPromise} from './util/lang';
import * as viewEngine from './view/index';

export const __core_private__: {
isDefaultChangeDetectionStrategy: typeof constants.isDefaultChangeDetectionStrategy,
Expand Down Expand Up @@ -110,6 +111,7 @@ export const __core_private__: {
isObservable: typeof isObservable,
AnimationTransition: typeof AnimationTransition
view_utils: typeof view_utils,
viewEngine: typeof viewEngine,
} = {
isDefaultChangeDetectionStrategy: constants.isDefaultChangeDetectionStrategy,
ChangeDetectorStatus: constants.ChangeDetectorStatus,
Expand All @@ -126,6 +128,7 @@ export const __core_private__: {
registerModuleFactory: ng_module_factory_loader.registerModuleFactory,
ViewType: view_type.ViewType,
view_utils: view_utils,
viewEngine: viewEngine,
ViewMetadata: metadata_view.ViewMetadata,
DebugContext: debug_context.DebugContext,
StaticNodeDebugInfo: debug_context.StaticNodeDebugInfo,
Expand Down
Loading

0 comments on commit 68b2407

Please sign in to comment.