refactor(ProtoRecord): switch to enum

This commit is contained in:
Victor Berchet 2015-06-09 15:45:45 +02:00
parent 6ca81fb98c
commit f2371487a1
7 changed files with 79 additions and 139 deletions

View File

@ -5,22 +5,7 @@ import {AbstractChangeDetector} from './abstract_change_detector';
import {ChangeDetectionUtil} from './change_detection_util';
import {DirectiveIndex, DirectiveRecord} from './directive_record';
import {
ProtoRecord,
RECORD_TYPE_SELF,
RECORD_TYPE_PROPERTY,
RECORD_TYPE_LOCAL,
RECORD_TYPE_INVOKE_METHOD,
RECORD_TYPE_CONST,
RECORD_TYPE_INVOKE_CLOSURE,
RECORD_TYPE_PRIMITIVE_OP,
RECORD_TYPE_KEYED_ACCESS,
RECORD_TYPE_PIPE,
RECORD_TYPE_BINDING_PIPE,
RECORD_TYPE_INTERPOLATE,
RECORD_TYPE_SAFE_PROPERTY,
RECORD_TYPE_SAFE_INVOKE_METHOD
} from './proto_record';
import {ProtoRecord, RecordType} from './proto_record';
/**
@ -163,7 +148,7 @@ export class ChangeDetectorJITGenerator {
_getNonNullPipeNames(): List<string> {
var pipes = [];
this.records.forEach((r) => {
if (r.mode === RECORD_TYPE_PIPE || r.mode === RECORD_TYPE_BINDING_PIPE) {
if (r.mode === RecordType.PIPE || r.mode === RecordType.BINDING_PIPE) {
pipes.push(this._pipeNames[r.selfIndex]);
}
});
@ -258,7 +243,7 @@ export class ChangeDetectorJITGenerator {
var change = this._changeNames[r.selfIndex];
var pipe = this._pipeNames[r.selfIndex];
var cdRef = r.mode === RECORD_TYPE_BINDING_PIPE ? "this.ref" : "null";
var cdRef = r.mode === RecordType.BINDING_PIPE ? "this.ref" : "null";
var protoIndex = r.selfIndex - 1;
var pipeType = r.name;
@ -315,47 +300,47 @@ export class ChangeDetectorJITGenerator {
var rhs;
switch (r.mode) {
case RECORD_TYPE_SELF:
case RecordType.SELF:
rhs = context;
break;
case RECORD_TYPE_CONST:
case RecordType.CONST:
rhs = JSON.stringify(r.funcOrValue);
break;
case RECORD_TYPE_PROPERTY:
case RecordType.PROPERTY:
rhs = `${context}.${r.name}`;
break;
case RECORD_TYPE_SAFE_PROPERTY:
case RecordType.SAFE_PROPERTY:
rhs = `${UTIL}.isValueBlank(${context}) ? null : ${context}.${r.name}`;
break;
case RECORD_TYPE_LOCAL:
case RecordType.LOCAL:
rhs = `${LOCALS_ACCESSOR}.get('${r.name}')`;
break;
case RECORD_TYPE_INVOKE_METHOD:
case RecordType.INVOKE_METHOD:
rhs = `${context}.${r.name}(${argString})`;
break;
case RECORD_TYPE_SAFE_INVOKE_METHOD:
case RecordType.SAFE_INVOKE_METHOD:
rhs = `${UTIL}.isValueBlank(${context}) ? null : ${context}.${r.name}(${argString})`;
break;
case RECORD_TYPE_INVOKE_CLOSURE:
case RecordType.INVOKE_CLOSURE:
rhs = `${context}(${argString})`;
break;
case RECORD_TYPE_PRIMITIVE_OP:
case RecordType.PRIMITIVE_OP:
rhs = `${UTIL}.${r.name}(${argString})`;
break;
case RECORD_TYPE_INTERPOLATE:
case RecordType.INTERPOLATE:
rhs = this._genInterpolation(r);
break;
case RECORD_TYPE_KEYED_ACCESS:
case RecordType.KEYED_ACCESS:
rhs = `${context}[${this._localNames[r.args[0]]}]`;
break;

View File

@ -1,6 +1,6 @@
import {isPresent} from 'angular2/src/facade/lang';
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
import {RECORD_TYPE_SELF, RECORD_TYPE_DIRECTIVE_LIFECYCLE, ProtoRecord} from './proto_record';
import {RecordType, ProtoRecord} from './proto_record';
/**
* Removes "duplicate" records. It assuming that record evaluation does not
@ -38,13 +38,13 @@ export function coalesce(records: List<ProtoRecord>): List<ProtoRecord> {
}
function _selfRecord(r: ProtoRecord, contextIndex: number, selfIndex: number): ProtoRecord {
return new ProtoRecord(RECORD_TYPE_SELF, "self", null, [], r.fixedArgs, contextIndex,
return new ProtoRecord(RecordType.SELF, "self", null, [], r.fixedArgs, contextIndex,
r.directiveIndex, selfIndex, r.bindingRecord, r.expressionAsString,
r.lastInBinding, r.lastInDirective);
}
function _findMatching(r: ProtoRecord, rs: List<ProtoRecord>) {
return ListWrapper.find(rs, (rr) => rr.mode !== RECORD_TYPE_DIRECTIVE_LIFECYCLE &&
return ListWrapper.find(rs, (rr) => rr.mode !== RecordType.DIRECTIVE_LIFECYCLE &&
rr.mode === r.mode && rr.funcOrValue === r.funcOrValue &&
rr.contextIndex === r.contextIndex &&
ListWrapper.equals(rr.args, r.args));
@ -61,4 +61,4 @@ function _replaceIndices(r: ProtoRecord, selfIndex: number, indexMap: Map<any, a
function _map(indexMap: Map<any, any>, value: number) {
var r = MapWrapper.get(indexMap, value);
return isPresent(r) ? r : value;
}
}

View File

@ -7,22 +7,7 @@ import {PipeRegistry} from './pipes/pipe_registry';
import {ChangeDetectionUtil, SimpleChange, uninitialized} from './change_detection_util';
import {
ProtoRecord,
RECORD_TYPE_SELF,
RECORD_TYPE_PROPERTY,
RECORD_TYPE_LOCAL,
RECORD_TYPE_INVOKE_METHOD,
RECORD_TYPE_CONST,
RECORD_TYPE_INVOKE_CLOSURE,
RECORD_TYPE_PRIMITIVE_OP,
RECORD_TYPE_KEYED_ACCESS,
RECORD_TYPE_PIPE,
RECORD_TYPE_BINDING_PIPE,
RECORD_TYPE_INTERPOLATE,
RECORD_TYPE_SAFE_PROPERTY,
RECORD_TYPE_SAFE_INVOKE_METHOD
} from './proto_record';
import {ProtoRecord, RecordType} from './proto_record';
import {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './exceptions';
@ -198,29 +183,29 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
_calculateCurrValue(proto: ProtoRecord) {
switch (proto.mode) {
case RECORD_TYPE_SELF:
case RecordType.SELF:
return this._readContext(proto);
case RECORD_TYPE_CONST:
case RecordType.CONST:
return proto.funcOrValue;
case RECORD_TYPE_PROPERTY:
case RecordType.PROPERTY:
var context = this._readContext(proto);
return proto.funcOrValue(context);
case RECORD_TYPE_SAFE_PROPERTY:
case RecordType.SAFE_PROPERTY:
var context = this._readContext(proto);
return isBlank(context) ? null : proto.funcOrValue(context);
case RECORD_TYPE_LOCAL:
case RecordType.LOCAL:
return this.locals.get(proto.name);
case RECORD_TYPE_INVOKE_METHOD:
case RecordType.INVOKE_METHOD:
var context = this._readContext(proto);
var args = this._readArgs(proto);
return proto.funcOrValue(context, args);
case RECORD_TYPE_SAFE_INVOKE_METHOD:
case RecordType.SAFE_INVOKE_METHOD:
var context = this._readContext(proto);
if (isBlank(context)) {
return null;
@ -228,15 +213,15 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
var args = this._readArgs(proto);
return proto.funcOrValue(context, args);
case RECORD_TYPE_KEYED_ACCESS:
case RecordType.KEYED_ACCESS:
var arg = this._readArgs(proto)[0];
return this._readContext(proto)[arg];
case RECORD_TYPE_INVOKE_CLOSURE:
case RecordType.INVOKE_CLOSURE:
return FunctionWrapper.apply(this._readContext(proto), this._readArgs(proto));
case RECORD_TYPE_INTERPOLATE:
case RECORD_TYPE_PRIMITIVE_OP:
case RecordType.INTERPOLATE:
case RecordType.PRIMITIVE_OP:
return FunctionWrapper.apply(proto.funcOrValue, this._readArgs(proto));
default:
@ -288,7 +273,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
//
// In the future, pipes declared in the bind configuration should
// be able to access the changeDetectorRef of that component.
var cdr = proto.mode === RECORD_TYPE_BINDING_PIPE ? this.ref : null;
var cdr = proto.mode === RecordType.BINDING_PIPE ? this.ref : null;
var pipe = this.pipeRegistry.get(proto.name, context, cdr);
this._writePipe(proto, pipe);
return pipe;

View File

@ -39,23 +39,7 @@ import {DirectiveRecord, DirectiveIndex} from './directive_record';
import {coalesce} from './coalesce';
import {
ProtoRecord,
RECORD_TYPE_SELF,
RECORD_TYPE_PROPERTY,
RECORD_TYPE_LOCAL,
RECORD_TYPE_INVOKE_METHOD,
RECORD_TYPE_CONST,
RECORD_TYPE_INVOKE_CLOSURE,
RECORD_TYPE_PRIMITIVE_OP,
RECORD_TYPE_KEYED_ACCESS,
RECORD_TYPE_PIPE,
RECORD_TYPE_BINDING_PIPE,
RECORD_TYPE_INTERPOLATE,
RECORD_TYPE_SAFE_PROPERTY,
RECORD_TYPE_SAFE_INVOKE_METHOD,
RECORD_TYPE_DIRECTIVE_LIFECYCLE
} from './proto_record';
import {ProtoRecord, RecordType} from './proto_record';
export class DynamicProtoChangeDetector extends ProtoChangeDetector {
_records: List<ProtoRecord>;
@ -124,7 +108,7 @@ class ProtoRecordBuilder {
if (b.isDirectiveLifecycle()) {
ListWrapper.push(
this.records,
new ProtoRecord(RECORD_TYPE_DIRECTIVE_LIFECYCLE, b.lifecycleEvent, null, [], [], -1, null,
new ProtoRecord(RecordType.DIRECTIVE_LIFECYCLE, b.lifecycleEvent, null, [], [], -1, null,
this.records.length + 1, b, null, false, false));
} else {
_ConvertAstIntoProtoRecords.append(this.records, b, variableNames);
@ -145,12 +129,12 @@ class _ConvertAstIntoProtoRecords implements AstVisitor {
visitInterpolation(ast: Interpolation) {
var args = this._visitAll(ast.expressions);
return this._addRecord(RECORD_TYPE_INTERPOLATE, "interpolate", _interpolationFn(ast.strings),
return this._addRecord(RecordType.INTERPOLATE, "interpolate", _interpolationFn(ast.strings),
args, ast.strings, 0);
}
visitLiteralPrimitive(ast: LiteralPrimitive) {
return this._addRecord(RECORD_TYPE_CONST, "literal", ast.value, [], null, 0);
return this._addRecord(RecordType.CONST, "literal", ast.value, [], null, 0);
}
visitAccessMember(ast: AccessMember) {
@ -158,49 +142,48 @@ class _ConvertAstIntoProtoRecords implements AstVisitor {
if (isPresent(this._variableNames) && ListWrapper.contains(this._variableNames, ast.name) &&
ast.receiver instanceof
ImplicitReceiver) {
return this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver);
return this._addRecord(RecordType.LOCAL, ast.name, ast.name, [], null, receiver);
} else {
return this._addRecord(RECORD_TYPE_PROPERTY, ast.name, ast.getter, [], null, receiver);
return this._addRecord(RecordType.PROPERTY, ast.name, ast.getter, [], null, receiver);
}
}
visitSafeAccessMember(ast: SafeAccessMember) {
var receiver = ast.receiver.visit(this);
return this._addRecord(RECORD_TYPE_SAFE_PROPERTY, ast.name, ast.getter, [], null, receiver);
return this._addRecord(RecordType.SAFE_PROPERTY, ast.name, ast.getter, [], null, receiver);
}
visitMethodCall(ast: MethodCall) {
var receiver = ast.receiver.visit(this);
var args = this._visitAll(ast.args);
if (isPresent(this._variableNames) && ListWrapper.contains(this._variableNames, ast.name)) {
var target = this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver);
return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target);
var target = this._addRecord(RecordType.LOCAL, ast.name, ast.name, [], null, receiver);
return this._addRecord(RecordType.INVOKE_CLOSURE, "closure", null, args, null, target);
} else {
return this._addRecord(RECORD_TYPE_INVOKE_METHOD, ast.name, ast.fn, args, null, receiver);
return this._addRecord(RecordType.INVOKE_METHOD, ast.name, ast.fn, args, null, receiver);
}
}
visitSafeMethodCall(ast: SafeMethodCall) {
var receiver = ast.receiver.visit(this);
var args = this._visitAll(ast.args);
return this._addRecord(RECORD_TYPE_SAFE_INVOKE_METHOD, ast.name, ast.fn, args, null, receiver);
return this._addRecord(RecordType.SAFE_INVOKE_METHOD, ast.name, ast.fn, args, null, receiver);
}
visitFunctionCall(ast: FunctionCall) {
var target = ast.target.visit(this);
var args = this._visitAll(ast.args);
return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target);
return this._addRecord(RecordType.INVOKE_CLOSURE, "closure", null, args, null, target);
}
visitLiteralArray(ast: LiteralArray) {
var primitiveName = `arrayFn${ast.expressions.length}`;
return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, primitiveName,
_arrayFn(ast.expressions.length), this._visitAll(ast.expressions), null,
0);
return this._addRecord(RecordType.PRIMITIVE_OP, primitiveName, _arrayFn(ast.expressions.length),
this._visitAll(ast.expressions), null, 0);
}
visitLiteralMap(ast: LiteralMap) {
return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, _mapPrimitiveName(ast.keys),
return this._addRecord(RecordType.PRIMITIVE_OP, _mapPrimitiveName(ast.keys),
ChangeDetectionUtil.mapFn(ast.keys), this._visitAll(ast.values), null,
0);
}
@ -208,13 +191,13 @@ class _ConvertAstIntoProtoRecords implements AstVisitor {
visitBinary(ast: Binary) {
var left = ast.left.visit(this);
var right = ast.right.visit(this);
return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, _operationToPrimitiveName(ast.operation),
return this._addRecord(RecordType.PRIMITIVE_OP, _operationToPrimitiveName(ast.operation),
_operationToFunction(ast.operation), [left, right], null, 0);
}
visitPrefixNot(ast: PrefixNot) {
var exp = ast.expression.visit(this);
return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, "operation_negate",
return this._addRecord(RecordType.PRIMITIVE_OP, "operation_negate",
ChangeDetectionUtil.operation_negate, [exp], null, 0);
}
@ -222,20 +205,20 @@ class _ConvertAstIntoProtoRecords implements AstVisitor {
var c = ast.condition.visit(this);
var t = ast.trueExp.visit(this);
var f = ast.falseExp.visit(this);
return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, "cond", ChangeDetectionUtil.cond, [c, t, f],
return this._addRecord(RecordType.PRIMITIVE_OP, "cond", ChangeDetectionUtil.cond, [c, t, f],
null, 0);
}
visitPipe(ast: Pipe) {
var value = ast.exp.visit(this);
var type = ast.inBinding ? RECORD_TYPE_BINDING_PIPE : RECORD_TYPE_PIPE;
var type = ast.inBinding ? RecordType.BINDING_PIPE : RecordType.PIPE;
return this._addRecord(type, ast.name, ast.name, [], null, value);
}
visitKeyedAccess(ast: KeyedAccess) {
var obj = ast.obj.visit(this);
var key = ast.key.visit(this);
return this._addRecord(RECORD_TYPE_KEYED_ACCESS, "keyedAccess", ChangeDetectionUtil.keyedAccess,
return this._addRecord(RecordType.KEYED_ACCESS, "keyedAccess", ChangeDetectionUtil.keyedAccess,
[key], null, obj);
}

View File

@ -2,35 +2,25 @@ import {List} from 'angular2/src/facade/collection';
import {BindingRecord} from './binding_record';
import {DirectiveIndex} from './directive_record';
export const RECORD_TYPE_SELF = 0;
export const RECORD_TYPE_CONST = 1;
export const RECORD_TYPE_PRIMITIVE_OP = 2;
export const RECORD_TYPE_PROPERTY = 3;
export const RECORD_TYPE_LOCAL = 4;
export const RECORD_TYPE_INVOKE_METHOD = 5;
export const RECORD_TYPE_INVOKE_CLOSURE = 6;
export const RECORD_TYPE_KEYED_ACCESS = 7;
export const RECORD_TYPE_PIPE = 8;
export const RECORD_TYPE_BINDING_PIPE = 9;
export const RECORD_TYPE_INTERPOLATE = 10;
export const RECORD_TYPE_SAFE_PROPERTY = 11;
export const RECORD_TYPE_SAFE_INVOKE_METHOD = 12;
export const RECORD_TYPE_DIRECTIVE_LIFECYCLE = 13;
export enum RecordType {
SELF, CONST, PRIMITIVE_OP, PROPERTY, LOCAL, INVOKE_METHOD, INVOKE_CLOSURE, KEYED_ACCESS, PIPE,
BINDING_PIPE, INTERPOLATE, SAFE_PROPERTY, SAFE_INVOKE_METHOD, DIRECTIVE_LIFECYCLE
}
export class ProtoRecord {
constructor(public mode: number, public name: string, public funcOrValue, public args: List<any>,
public fixedArgs: List<any>, public contextIndex: number,
constructor(public mode: RecordType, public name: string, public funcOrValue,
public args: List<any>, public fixedArgs: List<any>, public contextIndex: number,
public directiveIndex: DirectiveIndex, public selfIndex: number,
public bindingRecord: BindingRecord, public expressionAsString: string,
public lastInBinding: boolean, public lastInDirective: boolean) {}
isPureFunction(): boolean {
return this.mode === RECORD_TYPE_INTERPOLATE || this.mode === RECORD_TYPE_PRIMITIVE_OP;
return this.mode === RecordType.INTERPOLATE || this.mode === RecordType.PRIMITIVE_OP;
}
isPipeRecord(): boolean {
return this.mode === RECORD_TYPE_PIPE || this.mode === RECORD_TYPE_BINDING_PIPE;
return this.mode === RecordType.PIPE || this.mode === RecordType.BINDING_PIPE;
}
isLifeCycleRecord(): boolean { return this.mode === RECORD_TYPE_DIRECTIVE_LIFECYCLE; }
isLifeCycleRecord(): boolean { return this.mode === RecordType.DIRECTIVE_LIFECYCLE; }
}

View File

@ -186,7 +186,7 @@ class _CodegenState {
List<String> _getNonNullPipeNames() {
return _records
.where((r) =>
r.mode == RECORD_TYPE_PIPE || r.mode == RECORD_TYPE_BINDING_PIPE)
r.mode == RecordType.PIPE || r.mode == RecordType.BINDING_PIPE)
.map((r) => _pipeNames[r.selfIndex])
.toList();
}
@ -269,7 +269,7 @@ class _CodegenState {
var change = _changeNames[r.selfIndex];
var pipe = _pipeNames[r.selfIndex];
var cdRef = r.mode == RECORD_TYPE_BINDING_PIPE ? 'this.ref' : 'null';
var cdRef = r.mode == RecordType.BINDING_PIPE ? 'this.ref' : 'null';
var protoIndex = r.selfIndex - 1;
var pipeType = r.name;
@ -327,48 +327,48 @@ class _CodegenState {
var rhs;
switch (r.mode) {
case RECORD_TYPE_SELF:
case RecordType.SELF:
rhs = context;
break;
case RECORD_TYPE_CONST:
case RecordType.CONST:
rhs = JSON.encode(r.funcOrValue);
break;
case RECORD_TYPE_PROPERTY:
case RecordType.PROPERTY:
rhs = '$context.${r.name}';
break;
case RECORD_TYPE_SAFE_PROPERTY:
case RecordType.SAFE_PROPERTY:
rhs = '${_UTIL}.isValueBlank(${context}) ? null : ${context}.${r.name}';
break;
case RECORD_TYPE_LOCAL:
case RecordType.LOCAL:
rhs = '$_LOCALS_ACCESSOR.get("${r.name}")';
break;
case RECORD_TYPE_INVOKE_METHOD:
case RecordType.INVOKE_METHOD:
rhs = '$context.${r.name}($argString)';
break;
case RECORD_TYPE_SAFE_INVOKE_METHOD:
case RecordType.SAFE_INVOKE_METHOD:
rhs = '${_UTIL}.isValueBlank(${context}) '
'? null : ${context}.${r.name}(${argString})';
break;
case RECORD_TYPE_INVOKE_CLOSURE:
case RecordType.INVOKE_CLOSURE:
rhs = '$context($argString)';
break;
case RECORD_TYPE_PRIMITIVE_OP:
case RecordType.PRIMITIVE_OP:
rhs = '$_UTIL.${r.name}($argString)';
break;
case RECORD_TYPE_INTERPOLATE:
case RecordType.INTERPOLATE:
rhs = _genInterpolation(r);
break;
case RECORD_TYPE_KEYED_ACCESS:
case RecordType.KEYED_ACCESS:
rhs = '$context[${_localNames[r.args[0]]}]';
break;

View File

@ -1,14 +1,11 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
import {coalesce} from 'angular2/src/change_detection/coalesce';
import {
RECORD_TYPE_SELF,
RECORD_TYPE_DIRECTIVE_LIFECYCLE,
ProtoRecord
} from 'angular2/src/change_detection/proto_record';
import {RecordType, ProtoRecord} from 'angular2/src/change_detection/proto_record';
export function main() {
function r(funcOrValue, args, contextIndex, selfIndex, lastInBinding = false, mode = 99) {
function r(funcOrValue, args, contextIndex, selfIndex, lastInBinding = false,
mode = RecordType.PROPERTY) {
return new ProtoRecord(mode, "name", funcOrValue, args, null, contextIndex, null, selfIndex,
null, null, lastInBinding, false);
}
@ -51,14 +48,14 @@ export function main() {
var rs = coalesce([r("user", [], 0, 1, true), r("user", [], 0, 2, true)]);
expect(rs[1]).toEqual(new ProtoRecord(RECORD_TYPE_SELF, "self", null, [], null, 1, null, 2,
expect(rs[1]).toEqual(new ProtoRecord(RecordType.SELF, "self", null, [], null, 1, null, 2,
null, null, true, false));
});
it("should not coalesce directive lifecycle records", () => {
var rs = coalesce([
r("onCheck", [], 0, 1, true, RECORD_TYPE_DIRECTIVE_LIFECYCLE),
r("onCheck", [], 0, 1, true, RECORD_TYPE_DIRECTIVE_LIFECYCLE)
r("onCheck", [], 0, 1, true, RecordType.DIRECTIVE_LIFECYCLE),
r("onCheck", [], 0, 1, true, RecordType.DIRECTIVE_LIFECYCLE)
]);
expect(rs.length).toEqual(2);