Skip to content

Commit 7a70f8f

Browse files
committed
feat(compiler): initial version of the compiler.
Supports: - binds text nodes, element properties and directive properties - locates decorator, component and template directives. - inline templates of components The compiler is built using a pipeline design, see core/src/compiler/pipeline package. Integration tests to show how the compiler, change_detection and DI work together: core/test/compiler/integration_spec.js
1 parent 62efb56 commit 7a70f8f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2828
-337
lines changed

modules/benchmarks/src/compiler/selector_benchmark.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {SelectorMatcher, CssSelector} from "core/compiler/selector";
1+
import {SelectorMatcher} from "core/compiler/selector";
2+
import {CssSelector} from "core/compiler/selector";
23
import {StringWrapper, Math} from 'facade/lang';
34
import {ListWrapper} from 'facade/collection';
45

modules/change_detection/src/watch_group.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {ProtoRecord, Record} from './record';
22
import {FIELD, IMPLEMENTS, isBlank, isPresent} from 'facade/lang';
3-
import {AST, AccessMember, ImplicitReceiver, AstVisitor} from './parser/ast';
3+
import {AST, AccessMember, ImplicitReceiver, AstVisitor, Binary, LiteralPrimitive} from './parser/ast';
44

55
export class ProtoWatchGroup {
66
@FIELD('headRecord:ProtoRecord')
@@ -126,6 +126,17 @@ class ProtoRecordCreator {
126126
//do nothing
127127
}
128128

129+
// TODO: add tests for this method!
130+
visitLiteralPrimitive(ast:LiteralPrimitive) {
131+
// do nothing
132+
}
133+
134+
// TODO: add tests for this method!
135+
visitBinary(ast:Binary) {
136+
ast.left.visit(this);
137+
ast.right.visit(this);
138+
}
139+
129140
visitAccessMember(ast:AccessMember) {
130141
ast.receiver.visit(this);
131142
this.add(new ProtoRecord(this.protoWatchGroup, ast.name, null));

modules/core/src/annotations/component.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
import {Directive} from './directive';
2-
import {ABSTRACT, CONST} from 'facade/lang';
2+
import {CONST} from 'facade/lang';
33

44
export class Component extends Directive {
55
@CONST()
66
constructor({
77
selector,
8+
bind,
89
lightDomServices,
910
implementsTypes,
1011
template,
1112
elementServices,
1213
componentServices
1314
}:{
1415
selector:String,
16+
bind:Object,
1517
template:TemplateConfig,
1618
lightDomServices:DomServicesFunction,
1719
shadowDomServices:DomServicesFunction,
1820
componentServices:ComponentServicesFunction,
1921
implementsTypes:Array<Type>
20-
})
22+
}={})
2123
{
2224
super({
2325
selector: selector,
26+
bind: bind,
2427
lightDomServices: lightDomServices,
2528
implementsTypes: implementsTypes});
2629
this.template = template;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {Directive} from './directive';
2+
import {CONST} from 'facade/lang';
3+
4+
export class Decorator extends Directive {
5+
@CONST()
6+
constructor({
7+
selector,
8+
bind,
9+
lightDomServices,
10+
implementsTypes
11+
}:{
12+
selector:String,
13+
bind:Object,
14+
lightDomServices:ElementServicesFunction,
15+
implementsTypes:Array<Type>
16+
}={})
17+
{
18+
super({
19+
selector: selector,
20+
bind: bind,
21+
lightDomServices: lightDomServices,
22+
implementsTypes: implementsTypes
23+
});
24+
}
25+
}

modules/core/src/annotations/directive.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ export class Directive {
88
@CONST()
99
constructor({
1010
selector,
11+
bind,
1112
lightDomServices,
1213
implementsTypes
1314
}:{
1415
selector:String,
16+
bind:Object,
1517
lightDomServices:ElementServicesFunction,
1618
implementsTypes:Array<Type>
1719
})
1820
{
1921
this.selector = selector;
2022
this.lightDomServices = lightDomServices;
2123
this.implementsTypes = implementsTypes;
24+
this.bind = bind;
2225
}
2326
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {Directive} from './directive';
2+
import {CONST} from 'facade/lang';
3+
4+
export class Template extends Directive {
5+
@CONST()
6+
constructor({
7+
selector,
8+
bind,
9+
lightDomServices,
10+
implementsTypes
11+
}:{
12+
selector:String,
13+
bind:Object,
14+
lightDomServices:ElementServicesFunction,
15+
implementsTypes:Array<Type>
16+
}={})
17+
{
18+
super({
19+
selector: selector,
20+
bind: bind,
21+
lightDomServices: lightDomServices,
22+
implementsTypes: implementsTypes
23+
});
24+
}
25+
}

modules/core/src/annotations/template_config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@ export class TemplateConfig {
55
@CONST()
66
constructor({
77
url,
8+
inline,
89
directives,
910
formatters,
1011
source
1112
}: {
1213
url: String,
14+
inline: String,
1315
directives: List<Type>,
1416
formatters: List<Type>,
1517
source: List<TemplateConfig>
1618
})
1719
{
1820
this.url = url;
21+
this.inline = inline;
1922
this.directives = directives;
2023
this.formatters = formatters;
2124
this.source = source;

modules/core/src/compiler/annotated_type.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import {Type, FIELD} from 'facade/lang';
22
import {Directive} from '../annotations/directive'
33

4+
/**
5+
* Combination of a type with the Directive annotation
6+
*/
47
export class AnnotatedType {
5-
constructor(annotation:Directive, type:Type) {
8+
constructor(type:Type, annotation:Directive) {
69
this.annotation = annotation;
710
this.type = type;
811
}

modules/core/src/compiler/annotation_extractor.js

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,71 @@
1-
import {Type} from 'facade/lang';
2-
import {Promise} from 'facade/async';
3-
import {Element} from 'facade/dom';
4-
//import {ProtoView} from './view';
1+
import {Type, FIELD, isBlank, isPresent} from 'facade/lang';
2+
import {Promise, PromiseWrapper} from 'facade/async';
3+
import {List, ListWrapper} from 'facade/collection';
4+
import {DOM, Element} from 'facade/dom';
5+
6+
import {Parser} from 'change_detection/parser/parser';
7+
import {ClosureMap} from 'change_detection/parser/closure_map';
8+
9+
import {Reflector} from './reflector';
10+
import {ProtoView} from './view';
11+
import {CompilePipeline} from './pipeline/compile_pipeline';
12+
import {CompileElement} from './pipeline/compile_element';
13+
import {createDefaultSteps} from './pipeline/default_steps';
514
import {TemplateLoader} from './template_loader';
6-
import {FIELD} from 'facade/lang';
15+
import {AnnotatedType} from './annotated_type';
716

17+
/**
18+
* The compiler loads and translates the html templates of components into
19+
* nested ProtoViews. To decompose its functionality it uses
20+
* the CompilePipeline and the CompileSteps.
21+
*/
822
export class Compiler {
9-
10-
@FIELD('final _templateLoader:TemplateLoader')
11-
constructor(templateLoader:TemplateLoader) {
23+
constructor(templateLoader:TemplateLoader, reflector: Reflector, parser:Parser, closureMap:ClosureMap) {
1224
this._templateLoader = templateLoader;
25+
this._reflector = reflector;
26+
this._parser = parser;
27+
this._closureMap = closureMap;
1328
}
1429

15-
/**
16-
* # Why promise?
17-
* - compilation will load templates. Instantiating views before templates are loaded will
18-
* complicate the Directive code. BENEFIT: view instantiation become synchrnous.
19-
* # Why result that is independent of injector?
20-
* - don't know about injector in deserialization
21-
* - compile does not need the injector, only the ViewFactory does
22-
*/
23-
compile(component:Type, element:Element/* = null*/):Promise/*<ProtoView>*/ {
24-
return null;
30+
createSteps(component:AnnotatedType):List<CompileStep> {
31+
var directives = component.annotation.template.directives;
32+
var annotatedDirectives = ListWrapper.create();
33+
for (var i=0; i<directives.length; i++) {
34+
ListWrapper.push(annotatedDirectives, this._reflector.annotatedType(directives[i]));
35+
}
36+
return createDefaultSteps(this._parser, this._closureMap, annotatedDirectives);
2537
}
2638

39+
compile(component:Type, templateRoot:Element = null):Promise<ProtoView> {
40+
// TODO load all components transitively from the cache first
41+
var cache = null;
42+
return PromiseWrapper.resolve(this._compileAllCached(
43+
this._reflector.annotatedType(component),
44+
cache,
45+
templateRoot)
46+
);
47+
}
2748

49+
_compileAllCached(component:AnnotatedType, cache, templateRoot:Element = null):ProtoView {
50+
if (isBlank(templateRoot)) {
51+
// TODO: read out the cache if templateRoot = null. Could contain:
52+
// - templateRoot string
53+
// - precompiled template
54+
// - ProtoView
55+
templateRoot = DOM.createTemplate(component.annotation.template.inline);
56+
}
57+
var pipeline = new CompilePipeline(this.createSteps(component));
58+
var compileElements = pipeline.process(templateRoot);
59+
var rootProtoView = compileElements[0].inheritedProtoView;
60+
// TODO: put the rootProtoView into the cache to support recursive templates!
61+
62+
for (var i=0; i<compileElements.length; i++) {
63+
var ce = compileElements[i];
64+
if (isPresent(ce.componentDirective)) {
65+
ce.inheritedElementBinder.nestedProtoView = this._compileAllCached(ce.componentDirective, cache, null);
66+
}
67+
}
68+
69+
return rootProtoView;
70+
}
2871
}

0 commit comments

Comments
 (0)