Skip to content

Commit

Permalink
feat(Reflection): extract reflection capabilities into a separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
vsavkin committed Nov 25, 2014
1 parent 044625a commit 6e8175a
Show file tree
Hide file tree
Showing 46 changed files with 637 additions and 416 deletions.
1 change: 1 addition & 0 deletions karma-dart.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ module.exports = function(config) {
// Local dependencies, transpiled from the source.
'/packages/core': 'http://localhost:9877/base/modules/core/src',
'/packages/change_detection': 'http://localhost:9877/base/modules/change_detection/src',
'/packages/reflection': 'http://localhost:9877/base/modules/reflection/src',
'/packages/di': 'http://localhost:9877/base/modules/di/src',
'/packages/facade': 'http://localhost:9877/base/modules/facade/src',
'/packages/test_lib': 'http://localhost:9877/base/modules/test_lib/src',
Expand Down
12 changes: 5 additions & 7 deletions modules/benchmarks/src/compiler/compiler_benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import {MapWrapper} from 'facade/collection';
import {AnnotatedType} from 'core/compiler/annotated_type';

import {Parser} from 'change_detection/parser/parser';
import {ClosureMap} from 'change_detection/parser/closure_map';
import {Lexer} from 'change_detection/parser/lexer';

import {Compiler} from 'core/compiler/compiler';
import {Reflector} from 'core/compiler/reflector';
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';

import {Component} from 'core/annotations/annotations';
import {Decorator} from 'core/annotations/annotations';
Expand All @@ -22,10 +21,9 @@ var compiler;
var annotatedComponent;

function setup() {
var closureMap = new ClosureMap();
var reflector = new CachingReflector();
compiler = new Compiler(null, reflector, new Parser(new Lexer(), closureMap), closureMap);
annotatedComponent = reflector.annotatedType(BenchmarkComponent);
var reader = new CachingDirectiveMetadataReader();
compiler = new Compiler(null, reader, new Parser(new Lexer()));
annotatedComponent = reader.annotatedType(BenchmarkComponent);
}

export function main() {
Expand Down Expand Up @@ -63,7 +61,7 @@ function loadTemplate(templateId, repeatCount) {
}

// Caching reflector as reflection in Dart using Mirrors
class CachingReflector extends Reflector {
class CachingDirectiveMetadataReader extends DirectiveMetadataReader {
_cache: Map;
constructor() {
this._cache = MapWrapper.create();
Expand Down
5 changes: 1 addition & 4 deletions modules/change_detection/src/parser/ast.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {FIELD, autoConvertAdd, isBlank, isPresent, FunctionWrapper, BaseException} from "facade/lang";
import {List, Map, ListWrapper, MapWrapper} from "facade/collection";
import {ClosureMap} from "./closure_map";

export class AST {
eval(context) {
Expand Down Expand Up @@ -316,11 +315,9 @@ export class MethodCall extends AST {

export class FunctionCall extends AST {
target:AST;
closureMap:ClosureMap;
args:List;
constructor(target:AST, closureMap:ClosureMap, args:List) {
constructor(target:AST, args:List) {
this.target = target;
this.closureMap = closureMap;
this.args = args;
}

Expand Down
22 changes: 0 additions & 22 deletions modules/change_detection/src/parser/closure_map.dart

This file was deleted.

18 changes: 0 additions & 18 deletions modules/change_detection/src/parser/closure_map.es6

This file was deleted.

30 changes: 15 additions & 15 deletions modules/change_detection/src/parser/parser.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {FIELD, int, isBlank, BaseException, StringWrapper} from 'facade/lang';
import {FIELD, int, isBlank, isPresent, BaseException, StringWrapper} from 'facade/lang';
import {ListWrapper, List} from 'facade/collection';
import {Lexer, EOF, Token, $PERIOD, $COLON, $SEMICOLON, $LBRACKET, $RBRACKET,
$COMMA, $LBRACE, $RBRACE, $LPAREN, $RPAREN} from './lexer';
import {ClosureMap} from './closure_map';
import {reflector, Reflector} from 'reflection/reflection';
import {
AST,
ImplicitReceiver,
Expand All @@ -29,41 +29,41 @@ var _implicitReceiver = new ImplicitReceiver();

export class Parser {
_lexer:Lexer;
_closureMap:ClosureMap;
constructor(lexer:Lexer, closureMap:ClosureMap){
_reflector:Reflector;
constructor(lexer:Lexer, providedReflector:Reflector = null){
this._lexer = lexer;
this._closureMap = closureMap;
this._reflector = isPresent(providedReflector) ? providedReflector : reflector;
}

parseAction(input:string):ASTWithSource {
var tokens = this._lexer.tokenize(input);
var ast = new _ParseAST(input, tokens, this._closureMap, true).parseChain();
var ast = new _ParseAST(input, tokens, this._reflector, true).parseChain();
return new ASTWithSource(ast, input);
}

parseBinding(input:string):ASTWithSource {
var tokens = this._lexer.tokenize(input);
var ast = new _ParseAST(input, tokens, this._closureMap, false).parseChain();
var ast = new _ParseAST(input, tokens, this._reflector, false).parseChain();
return new ASTWithSource(ast, input);
}

parseTemplateBindings(input:string):List<TemplateBinding> {
var tokens = this._lexer.tokenize(input);
return new _ParseAST(input, tokens, this._closureMap, false).parseTemplateBindings();
return new _ParseAST(input, tokens, this._reflector, false).parseTemplateBindings();
}
}

class _ParseAST {
input:string;
tokens:List<Token>;
closureMap:ClosureMap;
reflector:Reflector;
parseAction:boolean;
index:int;
constructor(input:string, tokens:List, closureMap:ClosureMap, parseAction:boolean) {
constructor(input:string, tokens:List, reflector:Reflector, parseAction:boolean) {
this.input = input;
this.tokens = tokens;
this.index = 0;
this.closureMap = closureMap;
this.reflector = reflector;
this.parseAction = parseAction;
}

Expand Down Expand Up @@ -311,7 +311,7 @@ class _ParseAST {
} else if (this.optionalCharacter($LPAREN)) {
var args = this.parseCallArguments();
this.expectCharacter($RPAREN);
result = new FunctionCall(result, this.closureMap, args);
result = new FunctionCall(result, args);

} else {
return result;
Expand Down Expand Up @@ -398,12 +398,12 @@ class _ParseAST {
if (this.optionalCharacter($LPAREN)) {
var args = this.parseCallArguments();
this.expectCharacter($RPAREN);
var fn = this.closureMap.fn(id);
var fn = this.reflector.method(id);
return new MethodCall(receiver, fn, args);

} else {
var getter = this.closureMap.getter(id);
var setter = this.closureMap.setter(id);
var getter = this.reflector.getter(id);
var setter = this.reflector.setter(id);
return new AccessMember(receiver, id, getter, setter);
}
}
Expand Down
1 change: 0 additions & 1 deletion modules/change_detection/src/record.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {ProtoRecordRange, RecordRange} from './record_range';
import {FIELD, isPresent, isBlank, int, StringWrapper, FunctionWrapper, BaseException} from 'facade/lang';
import {List, Map, ListWrapper, MapWrapper} from 'facade/collection';
import {ClosureMap} from 'change_detection/parser/closure_map';

var _fresh = new Object();

Expand Down
3 changes: 1 addition & 2 deletions modules/change_detection/test/change_detector_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {isPresent} from 'facade/lang';
import {List, ListWrapper, MapWrapper} from 'facade/collection';
import {Parser} from 'change_detection/parser/parser';
import {Lexer} from 'change_detection/parser/lexer';
import {ClosureMap} from 'change_detection/parser/closure_map';

import {
ChangeDetector,
Expand All @@ -18,7 +17,7 @@ import {Record} from 'change_detection/record';

export function main() {
function ast(exp:string) {
var parser = new Parser(new Lexer(), new ClosureMap());
var parser = new Parser(new Lexer());
return parser.parseBinding(exp).ast;
}

Expand Down
4 changes: 2 additions & 2 deletions modules/change_detection/test/parser/parser_spec.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {ddescribe, describe, it, xit, iit, expect, beforeEach} from 'test_lib/test_lib';
import {BaseException, isBlank, isPresent} from 'facade/lang';
import {reflector} from 'reflection/reflection';
import {MapWrapper, ListWrapper} from 'facade/collection';
import {Parser} from 'change_detection/parser/parser';
import {Lexer} from 'change_detection/parser/lexer';
import {Formatter, LiteralPrimitive} from 'change_detection/parser/ast';
import {ClosureMap} from 'change_detection/parser/closure_map';

class TestData {
a;
Expand All @@ -31,7 +31,7 @@ export function main() {
}

function createParser() {
return new Parser(new Lexer(), new ClosureMap());
return new Parser(new Lexer(), reflector);
}

function parseAction(text) {
Expand Down
1 change: 0 additions & 1 deletion modules/change_detection/test/record_range_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {List, ListWrapper, MapWrapper} from 'facade/collection';
import {isPresent} from 'facade/lang';
import {Parser} from 'change_detection/parser/parser';
import {Lexer} from 'change_detection/parser/lexer';
import {ClosureMap} from 'change_detection/parser/closure_map';

import {
ChangeDetector,
Expand Down
17 changes: 11 additions & 6 deletions modules/core/src/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ import {Type, FIELD, isBlank, isPresent, BaseException} from 'facade/lang';
import {DOM, Element} from 'facade/dom';
import {Compiler} from './compiler/compiler';
import {ProtoView} from './compiler/view';
import {ClosureMap} from 'change_detection/parser/closure_map';
import {Reflector, reflector} from 'reflection/reflection';
import {ReflectionCapabilities} from 'reflection/reflection_capabilities';
import {Parser} from 'change_detection/parser/parser';
import {Lexer} from 'change_detection/parser/lexer';
import {ChangeDetector} from 'change_detection/change_detector';
import {RecordRange} from 'change_detection/record_range';
import {TemplateLoader} from './compiler/template_loader';
import {Reflector} from './compiler/reflector';
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
import {AnnotatedType} from './compiler/annotated_type';
import {ListWrapper} from 'facade/collection';

var _rootInjector: Injector;

// Contains everything that is safe to share between applications.
var _rootBindings = [Compiler, TemplateLoader, Reflector, Parser, Lexer, ClosureMap];
var _rootBindings = [
bind(Reflector).toValue(reflector), Compiler, TemplateLoader, DirectiveMetadataReader, Parser, Lexer
];

export var appViewToken = new Object();
export var appWatchGroupToken = new Object();
Expand All @@ -27,12 +30,12 @@ export var appDocumentToken = new Object();
// Exported only for tests that need to overwrite default document binding.
export function documentDependentBindings(appComponentType) {
return [
bind(appComponentAnnotatedTypeToken).toFactory((reflector) => {
bind(appComponentAnnotatedTypeToken).toFactory((reader) => {
// TODO(rado): inspect annotation here and warn if there are bindings,
// lightDomServices, and other component annotations that are skipped
// for bootstrapping components.
return reflector.annotatedType(appComponentType);
}, [Reflector]),
return reader.annotatedType(appComponentType);
}, [DirectiveMetadataReader]),

bind(appElementToken).toFactory((appComponentAnnotatedType, appDocument) => {
var selector = appComponentAnnotatedType.annotation.selector;
Expand Down Expand Up @@ -71,6 +74,8 @@ function _injectorBindings(appComponentType) {
// Multiple calls to this method are allowed. Each application would only share
// _rootInjector, which is not user-configurable by design, thus safe to share.
export function bootstrap(appComponentType: Type, bindings=null) {
reflector.reflectionCapabilities = new ReflectionCapabilities();

// TODO(rado): prepopulate template cache, so applications with only
// index.html and main.js are possible.
if (isBlank(_rootInjector)) _rootInjector = new Injector(_rootBindings);
Expand Down
17 changes: 7 additions & 10 deletions modules/core/src/compiler/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import {List, ListWrapper} from 'facade/collection';
import {DOM, Element} from 'facade/dom';

import {Parser} from 'change_detection/parser/parser';
import {ClosureMap} from 'change_detection/parser/closure_map';

import {Reflector} from './reflector';
import {DirectiveMetadataReader} from './directive_metadata_reader';
import {ProtoView} from './view';
import {CompilePipeline} from './pipeline/compile_pipeline';
import {CompileElement} from './pipeline/compile_element';
Expand All @@ -22,31 +21,29 @@ import {Component} from '../annotations/annotations';
*/
export class Compiler {
_templateLoader:TemplateLoader;
_reflector: Reflector;
_reader: DirectiveMetadataReader;
_parser:Parser;
_closureMap:ClosureMap;
constructor(templateLoader:TemplateLoader, reflector: Reflector, parser:Parser, closureMap:ClosureMap) {
constructor(templateLoader:TemplateLoader, reader: DirectiveMetadataReader, parser:Parser) {
this._templateLoader = templateLoader;
this._reflector = reflector;
this._reader = reader;
this._parser = parser;
this._closureMap = closureMap;
}

createSteps(component:AnnotatedType):List<CompileStep> {
var annotation: Component = component.annotation;
var directives = annotation.template.directives;
var annotatedDirectives = ListWrapper.create();
for (var i=0; i<directives.length; i++) {
ListWrapper.push(annotatedDirectives, this._reflector.annotatedType(directives[i]));
ListWrapper.push(annotatedDirectives, this._reader.annotatedType(directives[i]));
}
return createDefaultSteps(this._parser, this._closureMap, annotatedDirectives);
return createDefaultSteps(this._parser, annotatedDirectives);
}

compile(component:Type, templateRoot:Element = null):Promise<ProtoView> {
// TODO load all components transitively from the cache first
var cache = null;
return PromiseWrapper.resolve(this.compileWithCache(
cache, this._reflector.annotatedType(component), templateRoot)
cache, this._reader.annotatedType(component), templateRoot)
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Type, isPresent, BaseException} from 'facade/lang';
import {Type, isPresent, BaseException, stringify} from 'facade/lang';
import {Directive} from '../annotations/annotations';
import {AnnotatedType} from './annotated_type';
import {reflector} from 'reflection/reflection';

/**
* Interface representing a way of extracting [Directive] annotations from
Expand All @@ -10,17 +11,17 @@ import {AnnotatedType} from './annotated_type';
* 2) Dart reflective implementation
* 3) Dart transformer generated implementation
*/
export class Reflector {
export class DirectiveMetadataReader {
annotatedType(type:Type):AnnotatedType {
var annotations = type.annotations;
if (annotations) {
var annotations = reflector.annotations(type);
if (isPresent(annotations)) {
for (var i=0; i<annotations.length; i++) {
var annotation = annotations[i];
if (annotation instanceof Directive) {
return new AnnotatedType(type, annotation);
}
}
}
throw new BaseException('No Directive annotation found on ' + type.name);
throw new BaseException(`No Directive annotation found on ${stringify(type)}`);
}
}
Loading

0 comments on commit 6e8175a

Please sign in to comment.