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

feat(AstParser): Made the AST parser private to the scope (was: fix(parser/eval): fix for '"s" + ("m"|filter) + "e"') #758

Closed
wants to merge 13 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: 4 additions & 2 deletions example/web/bouncing_balls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ class BallPositionDirective {
set position(BallModel model) {
element.style.backgroundColor = model.color;
scope
..watch('x', (x, _) => element.style.left = '${x + 10}px', context: model, readOnly: true)
..watch('y', (y, _) => element.style.top = '${y + 10}px', context: model, readOnly: true);
..watch('x', (x, _) => element.style.left = '${x + 10}px',
context: model, canChangeModel: false)
..watch('y', (y, _) => element.style.top = '${y + 10}px',
context: model, canChangeModel: false);
}
}

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
91 changes: 37 additions & 54 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.
*
* - `text`: The markup text to interpolate in form `foo {{expr}} bar`.
* - `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.
* 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 call(String template, [bool mustHaveExpression = false,
String startSymbol = '{{', String endSymbol = '}}']) {
int startSymbolLength = startSymbol.length;
int endSymbolLength = endSymbol.length;
int startIndex;
int endIndex;
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;
}
}
}
1 change: 0 additions & 1 deletion lib/core/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class NgCoreModule extends Module {
value(ScopeStats, new ScopeStats());
value(GetterCache, new GetterCache({}));
value(Object, {}); // RootScope context
type(AstParser);
type(NgZone);

type(Parser, implementedBy: DynamicParser);
Expand Down
48 changes: 17 additions & 31 deletions lib/core/parser/dynamic_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import 'package:angular/core/module.dart' show FilterMap, NgInjectableService;
import 'package:angular/core/parser/parser.dart';
import 'package:angular/core/parser/lexer.dart';
import 'package:angular/core/parser/dynamic_parser_impl.dart';
import 'package:angular/core/parser/syntax.dart' show defaultFilterMap;

import 'package:angular/core/parser/eval.dart';
import 'package:angular/core/parser/utils.dart' show EvalError;
Expand Down Expand Up @@ -46,7 +45,7 @@ class DynamicExpression extends Expression {
accept(Visitor visitor) => _expression.accept(visitor);
toString() => _expression.toString();

eval(scope, [FilterMap filters = defaultFilterMap]) {
eval(scope, FilterMap filters) {
try {
return _expression.eval(scope, filters);
} on EvalError catch (e, s) {
Expand All @@ -68,8 +67,7 @@ class DynamicParserBackend extends ParserBackend {
final ClosureMap _closures;
DynamicParserBackend(this._closures);

bool isAssignable(Expression expression)
=> expression.isAssignable;
bool isAssignable(Expression expression) => expression.isAssignable;

Expression newFilter(expression, name, arguments) {
List allArguments = new List(arguments.length + 1);
Expand All @@ -78,58 +76,46 @@ 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) {
Function constructor = _computeCallConstructor(
_callScopeConstructors, name, arguments.length);
return (constructor != null)
return constructor != null
? constructor(name, arguments, _closures)
: new CallScope(name, arguments);
}
Expand Down
Loading