Skip to content
This repository has been archived by the owner on Feb 22, 2018. It is now read-only.

feat(AstParser): Made the AST parser private to the scope #788

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/parser_generator_for_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ main(arguments) {
'add(a,b)',
'notAProperty',
"'Foo'|uppercase",
"'f' + ('o'|uppercase) + 'o'",
"1|increment:2",
"'abcd'|substring:1:offset",
"'abcd'|substring:1:3|uppercase",
Expand Down
6 changes: 3 additions & 3 deletions lib/core/filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ class NgFilter {
@NgInjectableService()
class FilterMap extends AnnotationMap<NgFilter> {
Injector _injector;
FilterMap(Injector injector, MetadataExtractor extractMetadata) :
this._injector = injector,
super(injector, extractMetadata);
FilterMap(Injector injector, MetadataExtractor extractMetadata)
: this._injector = injector,
super(injector, extractMetadata);

call(String name) {
var filter = new NgFilter(name: name);
Expand Down
99 changes: 41 additions & 58 deletions lib/core/interpolate.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,12 @@
part of angular.core;

class Interpolation implements Function {
final String template;
final List<String> separators;
final List<String> expressions;
Function setter = (_) => _;

Interpolation(this.template, this.separators, this.expressions);

String call(List parts, [_]) {
if (parts == null) return separators.join('');
var sb = new StringBuffer();
for (var i = 0; i < parts.length; i++) {
sb.write(separators[i]);
var value = parts[i];
sb.write(value == null ? '' : '$value');
}
sb.write(separators.last);
return setter(sb.toString());
}
}

/**
* Compiles a string with markup into an interpolation function. This service
* is used by the HTML [Compiler] service for data binding.
*
* Compiles a string with markup into an expression. This service is used by the
* HTML [Compiler] service for data binding.
*
* var $interpolate = ...; // injected
* var exp = $interpolate('Hello {{name}}!');
* expect(exp({name:'Angular'}).toEqual('Hello Angular!');
* expect(exp).toEqual('"Hello "+(name)+"!"');
*/
@NgInjectableService()
class Interpolate implements Function {
Expand All @@ -37,49 +15,54 @@ class Interpolate implements Function {
Interpolate(this._parse);

/**
* Compiles markup text into interpolation function.
* Compiles markup text into expression.
*
* - `template`: The markup text to interpolate in form `foo {{expr}} bar`.
* - `mustHaveExpression`: if set to true then the interpolation string must
* have embedded expression in order to return an interpolation function.
* Strings with no embedded expression will return null for the
* interpolation function.
* - `startSymbol`: The symbol to start interpolation. '{{' by default.
* - `endSymbol`: The symbol to end interpolation. '}}' by default.
* - [template]: The markup text to interpolate in form `foo {{expr}} bar`.
* - [mustHaveExpression]: if set to true then the interpolation string must
* have embedded expression in order to return an expression. Strings with
* no embedded expression will return null.
* - [startSymbol]: The symbol to start interpolation. '{{' by default.
* - [endSymbol]: The symbol to end interpolation. '}}' by default.
*/
Interpolation call(String template, [bool mustHaveExpression = false,
String startSymbol = '{{', String endSymbol = '}}']) {
int startSymbolLength = startSymbol.length;
int endSymbolLength = endSymbol.length;
int startIndex;
int endIndex;

String call(String template, [bool mustHaveExpression = false,
String startSymbol = '{{', String endSymbol = '}}']) {
if (template == null || template.isEmpty) return "";

final startLen = startSymbol.length;
final endLen = endSymbol.length;
final length = template.length;

int startIdx;
int endIdx;
int index = 0;
int length = template.length;

bool hasInterpolation = false;
bool shouldAddSeparator = true;

String exp;
final separators = <String>[];
final expressions = <String>[];
final expParts = <String>[];

while (index < length) {
if (((startIndex = template.indexOf(startSymbol, index)) != -1) &&
((endIndex = template.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
separators.add(template.substring(index, startIndex));
exp = template.substring(startIndex + startSymbolLength, endIndex);
expressions.add(exp);
index = endIndex + endSymbolLength;
startIdx = template.indexOf(startSymbol, index);
endIdx = template.indexOf(endSymbol, startIdx + startLen);
if (startIdx != -1 && endIdx != -1) {
if (index < startIdx) {
// Empty strings could be stripped thanks to the stringify
// filter
expParts.add('"${template.substring(index, startIdx)}"');
}
expParts.add('(' + template.substring(startIdx + startLen, endIdx) +
'|stringify)');

index = endIdx + endLen;
hasInterpolation = true;
} else {
// we did not find anything, so we have to add the remainder to the
// chunks array
separators.add(template.substring(index));
shouldAddSeparator = false;
// we did not find any interpolation, so add the remainder
expParts.add('"${template.substring(index)}"');
break;
}
}
if (shouldAddSeparator) separators.add('');
return (!mustHaveExpression || hasInterpolation)
? new Interpolation(template, separators, expressions)
: null;

return !mustHaveExpression || hasInterpolation ? expParts.join('+') : null;
}
}
}
42 changes: 15 additions & 27 deletions lib/core/parser/dynamic_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,52 +78,40 @@ class DynamicParserBackend extends ParserBackend {
return new Filter(expression, name, arguments, allArguments);
}

Expression newChain(expressions)
=> new Chain(expressions);
Expression newAssign(target, value)
=> new Assign(target, value);
Expression newChain(expressions) => new Chain(expressions);
Expression newAssign(target, value) => new Assign(target, value);
Expression newConditional(condition, yes, no)
=> new Conditional(condition, yes, no);

Expression newAccessKeyed(object, key)
=> new AccessKeyed(object, key);
Expression newAccessKeyed(object, key) => new AccessKeyed(object, key);
Expression newCallFunction(function, arguments)
=> new CallFunction(function, arguments);

Expression newPrefixNot(expression)
=> new PrefixNot(expression);
Expression newPrefixNot(expression) => new PrefixNot(expression);

Expression newBinary(operation, left, right)
=> new Binary(operation, left, right);

Expression newLiteralPrimitive(value)
=> new LiteralPrimitive(value);
Expression newLiteralArray(elements)
=> new LiteralArray(elements);
Expression newLiteralObject(keys, values)
=> new LiteralObject(keys, values);
Expression newLiteralString(value)
=> new LiteralString(value);
Expression newLiteralPrimitive(value) => new LiteralPrimitive(value);
Expression newLiteralArray(elements) => new LiteralArray(elements);
Expression newLiteralObject(keys, values) => new LiteralObject(keys, values);
Expression newLiteralString(value) => new LiteralString(value);


Expression newAccessScope(name) {
Getter getter = _closures.lookupGetter(name);
Setter setter = _closures.lookupSetter(name);
if (getter != null && setter != null) {
return new AccessScopeFast(name, getter, setter);
} else {
return new AccessScope(name);
}
return (getter != null && setter != null)
? new AccessScopeFast(name, getter, setter)
: new AccessScope(name);
}

Expression newAccessMember(object, name) {
Getter getter = _closures.lookupGetter(name);
Setter setter = _closures.lookupSetter(name);
if (getter != null && setter != null) {
return new AccessMemberFast(object, name, getter, setter);
} else {
return new AccessMember(object, name);
}
return (getter != null && setter != null)
? new AccessMemberFast(object, name, getter, setter)
: new AccessMember(object, name);
}

Expression newCallScope(name, arguments) {
Expand All @@ -137,7 +125,7 @@ class DynamicParserBackend extends ParserBackend {
Expression newCallMember(object, name, arguments) {
Function constructor = _computeCallConstructor(
_callMemberConstructors, name, arguments);
return (constructor != null)
return constructor != null
? constructor(object, name, arguments, _closures)
: new CallMember(object, name, arguments);
}
Expand Down
16 changes: 8 additions & 8 deletions lib/core/parser/eval.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,26 @@ class Conditional extends syntax.Conditional {
Conditional(syntax.Expression condition,
syntax.Expression yes, syntax.Expression no)
: super(condition, yes, no);
eval(scope, [FilterMap filters]) => toBool(condition.eval(scope))
? yes.eval(scope)
: no.eval(scope);
eval(scope, [FilterMap filters]) => toBool(condition.eval(scope, filters))
? yes.eval(scope, filters)
: no.eval(scope, filters);
}

class PrefixNot extends syntax.Prefix {
PrefixNot(syntax.Expression expression) : super('!', expression);
eval(scope, [FilterMap filters]) => !toBool(expression.eval(scope));
eval(scope, [FilterMap filters]) => !toBool(expression.eval(scope, filters));
}

class Binary extends syntax.Binary {
Binary(String operation, syntax.Expression left, syntax.Expression right):
super(operation, left, right);
eval(scope, [FilterMap filters]) {
var left = this.left.eval(scope);
var left = this.left.eval(scope, filters);
switch (operation) {
case '&&': return toBool(left) && toBool(this.right.eval(scope));
case '||': return toBool(left) || toBool(this.right.eval(scope));
case '&&': return toBool(left) && toBool(this.right.eval(scope, filters));
case '||': return toBool(left) || toBool(this.right.eval(scope, filters));
}
var right = this.right.eval(scope);
var right = this.right.eval(scope, filters);

// Null check for the operations.
if (left == null || right == null) {
Expand Down
12 changes: 6 additions & 6 deletions lib/core/parser/eval_calls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ class CallScope extends syntax.CallScope with CallReflective {
CallScope(name, arguments)
: super(name, arguments),
symbol = newSymbol(name);
eval(scope, [FilterMap filters]) => _eval(scope, scope);
eval(scope, [FilterMap filters]) => _eval(scope, scope, filters);
}

class CallMember extends syntax.CallMember with CallReflective {
final Symbol symbol;
CallMember(object, name, arguments)
: super(object, name, arguments),
symbol = newSymbol(name);
eval(scope, [FilterMap filters]) => _eval(scope, object.eval(scope, filters));
eval(scope, [FilterMap filters]) => _eval(scope, object.eval(scope, filters),
filters);
}

class CallScopeFast0 extends syntax.CallScope with CallFast {
Expand Down Expand Up @@ -106,13 +107,12 @@ abstract class CallReflective {
Symbol get symbol;
syntax.CallArguments get arguments;

// TODO(kasperl): This seems broken -- it needs filters.
_eval(scope, holder) {
List positionals = evalList(scope, arguments.positionals);
_eval(scope, holder, FilterMap filters) {
List positionals = evalList(scope, arguments.positionals, filters);
if (arguments.named.isNotEmpty) {
var named = new Map<Symbol, dynamic>();
arguments.named.forEach((String name, value) {
named[new Symbol(name)] = value.eval(scope);
named[new Symbol(name)] = value.eval(scope, filters);
});
if (holder is Map) {
var fn = ensureFunctionFromMap(holder, name);
Expand Down
2 changes: 1 addition & 1 deletion lib/core/parser/static_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class StaticParserFunctions {
class StaticParser implements Parser<Expression> {
final StaticParserFunctions _functions;
final DynamicParser _fallbackParser;
final Map<String, Expression> _cache = {};
final _cache = <String, Expression>{};
StaticParser(this._functions, this._fallbackParser);

Expression call(String input) {
Expand Down
12 changes: 6 additions & 6 deletions lib/core/parser/syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ abstract class Expression {
bool get isAssignable => false;
bool get isChain => false;

eval(scope, [FilterMap filters = defaultFilterMap])
=> throw new EvalError("Cannot evaluate $this");
assign(scope, value)
=> throw new EvalError("Cannot assign to $this");
bind(context, [LocalsWrapper wrapper])
=> new BoundExpression(this, context, wrapper);
eval(scope, [FilterMap filters = defaultFilterMap]) =>
throw new EvalError("Cannot evaluate $this");
assign(scope, value) =>
throw new EvalError("Cannot assign to $this");
bind(context, [LocalsWrapper wrapper]) =>
new BoundExpression(this, context, wrapper);

accept(Visitor visitor);
String toString() => Unparser.unparse(this);
Expand Down
5 changes: 3 additions & 2 deletions lib/core/parser/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ class EvalError {

/// Evaluate the [list] in context of the [scope].
List evalList(scope, List<Expression> list, [FilterMap filters]) {
int length = list.length;
for (int cacheLength = _evalListCache.length; cacheLength <= length; cacheLength++) {
final length = list.length;
int cacheLength = _evalListCache.length;
for (; cacheLength <= length; cacheLength++) {
_evalListCache.add(new List(cacheLength));
}
List result = _evalListCache[length];
Expand Down
Loading