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

Commit

Permalink
feat(parser): Add support for named arguments.
Browse files Browse the repository at this point in the history
Closes #762
  • Loading branch information
kasperl authored and mhevery committed Mar 20, 2014
1 parent d9ceeac commit 18ceb4d
Show file tree
Hide file tree
Showing 17 changed files with 622 additions and 159 deletions.
53 changes: 53 additions & 0 deletions bin/parser_generator_for_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -443,5 +443,58 @@ main(arguments) {
'x."foo"',
'{(:0}',
'{1234:0}',

"sub1(1)",
"sub1(3, b: 2)",
"sub2()",
"sub2(a: 3)",
"sub2(a: 3, b: 2)",
"sub2(b: 4)",

"o.sub1(1)",
"o.sub1(3, b: 2)",
"o.sub2()",
"o.sub2(a: 3)",
"o.sub2(a: 3, b: 2)",
"o.sub2(b: 4)",

"(sub1)(1)",
"(sub1)(3, b: 2)",
"(sub2)()",
"(sub2)(a: 3)",
"(sub2)(a: 3, b: 2)",
"(sub2)(b: 4)",

'foo(a: 0, a: 1)',
'foo(a: 0, b: 1, a: 2)',
'foo(0, a: 1, a: 2)',
'foo(0, a: 1, b: 2, a: 3)',

'foo(if: 0)',
'foo(a: 0, class: 0)',

'foo(a: 0)',
'foo(a: 0, b: 1)',
'foo(b: 1, a: 0)',
'foo(0)',
'foo(0, a: 0)',
'foo(0, a: 0, b: 1)',
'foo(0, b: 1, a: 0)',

'o.foo(a: 0)',
'o.foo(a: 0, b: 1)',
'o.foo(b: 1, a: 0)',
'o.foo(0)',
'o.foo(0, a: 0)',
'o.foo(0, a: 0, b: 1)',
'o.foo(0, b: 1, a: 0)',

'(foo)(a: 0)',
'(foo)(a: 0, b: 1)',
'(foo)(b: 1, a: 0)',
'(foo)(0)',
'(foo)(0, a: 0)',
'(foo)(0, a: 0, b: 1)',
'(foo)(0, b: 1, a: 0)',
]);
}
18 changes: 15 additions & 3 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ packages:
analyzer:
description: analyzer
source: hosted
version: "0.11.10"
version: "0.12.2"
angular:
description:
path: ".."
Expand All @@ -15,30 +15,42 @@ packages:
description: args
source: hosted
version: "0.9.0"
barback:
description: barback
source: hosted
version: "0.11.1"
browser:
description: browser
source: hosted
version: "0.9.1"
code_transformers:
description: code_transformers
source: hosted
version: "0.0.1-dev.2"
collection:
description: collection
source: hosted
version: "0.9.1"
di:
description: di
source: hosted
version: "0.0.33"
version: "0.0.34"
html5lib:
description: html5lib
source: hosted
version: "0.9.2"
intl:
description: intl
source: hosted
version: "0.9.7"
version: "0.8.10+4"
logging:
description: logging
source: hosted
version: "0.9.1+1"
meta:
description: meta
source: hosted
version: "0.8.8"
path:
description: path
source: hosted
Expand Down
7 changes: 4 additions & 3 deletions lib/change_detection/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class PureFunctionAST extends AST {
super('$name(${_argList(argsAST)})');

WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
watchGroup.addFunctionWatch(fn, argsAST, expression);
watchGroup.addFunctionWatch(fn, argsAST, const {}, expression);
}

/**
Expand All @@ -96,15 +96,16 @@ class MethodAST extends AST {
final AST lhsAST;
final String name;
final List<AST> argsAST;
final Map<Symbol, AST> namedArgsAST;

MethodAST(lhsAST, name, argsAST)
MethodAST(lhsAST, name, argsAST, [this.namedArgsAST = const {}])
: lhsAST = lhsAST,
name = name,
argsAST = argsAST,
super('$lhsAST.$name(${_argList(argsAST)})');

WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
watchGroup.addMethodWatch(lhsAST, name, argsAST, expression);
watchGroup.addMethodWatch(lhsAST, name, argsAST, namedArgsAST, expression);
}


Expand Down
73 changes: 52 additions & 21 deletions lib/change_detection/watch_group.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,9 @@ class WatchGroup implements _EvalWatchList, _WatchGroupList {
* - [expression] normalized expression used for caching.
*/
_EvalWatchRecord addFunctionWatch(/* dartbug.com/16401 Function */ fn, List<AST> argsAST,
Map<Symbol, AST> namedArgsAST,
String expression) =>
_addEvalWatch(null, fn, null, argsAST, expression);
_addEvalWatch(null, fn, null, argsAST, namedArgsAST, expression);

/**
* Watch a method [name]ed represented by an [expression].
Expand All @@ -198,13 +199,16 @@ class WatchGroup implements _EvalWatchList, _WatchGroupList {
* - [expression] normalized expression used for caching.
*/
_EvalWatchRecord addMethodWatch(AST lhs, String name, List<AST> argsAST,
Map<Symbol, AST> namedArgsAST,
String expression) =>
_addEvalWatch(lhs, null, name, argsAST, expression);
_addEvalWatch(lhs, null, name, argsAST, namedArgsAST, expression);



_EvalWatchRecord _addEvalWatch(AST lhsAST, /* dartbug.com/16401 Function */ fn, String name,
List<AST> argsAST, String expression) {
List<AST> argsAST,
Map<Symbol, AST> namedArgsAST,
String expression) {
_InvokeHandler invokeHandler = new _InvokeHandler(this, expression);
var evalWatchRecord = new _EvalWatchRecord(this, invokeHandler, fn, name,
argsAST.length);
Expand All @@ -218,15 +222,24 @@ class WatchGroup implements _EvalWatchList, _WatchGroupList {
}

// Convert the args from AST to WatchRecords
var i = 0;
argsAST.map((ast) =>
_cache.putIfAbsent(ast.expression, () => ast.setupWatch(this)))
.forEach((WatchRecord<_Handler> record) {
var argHandler = new _ArgHandler(this, evalWatchRecord, i++);
_ArgHandlerList._add(invokeHandler, argHandler);
record.handler.addForwardHandler(argHandler);
argHandler.acceptValue(record.currentValue);
});
Iterable<WatchRecord<_Handler>> records = argsAST.map((ast) =>
_cache.putIfAbsent(ast.expression, () => ast.setupWatch(this)));
int i = 0;
records.forEach((WatchRecord<_Handler> record) {
_ArgHandler handler = new _PositionalArgHandler(this, evalWatchRecord, i++);
_ArgHandlerList._add(invokeHandler, handler);
record.handler.addForwardHandler(handler);
handler.acceptValue(record.currentValue);
});

namedArgsAST.forEach((Symbol name, AST ast) {
WatchRecord<_Handler> record = _cache.putIfAbsent(ast.expression,
() => ast.setupWatch(this));
_ArgHandler handler = new _NamedArgHandler(this, evalWatchRecord, name);
_ArgHandlerList._add(invokeHandler, handler);
record.handler.addForwardHandler(handler);
handler.acceptValue(record.currentValue);
});

// Must be done last
_EvalWatchList._add(this, evalWatchRecord);
Expand Down Expand Up @@ -615,25 +628,42 @@ class _CollectionHandler extends _Handler {
}
}

class _ArgHandler extends _Handler {
abstract class _ArgHandler extends _Handler {
_ArgHandler _previousArgHandler, _nextArgHandler;

// TODO(misko): Why do we override parent?
final _EvalWatchRecord watchRecord;
final int index;
_ArgHandler(WatchGroup watchGrp, String expression, this.watchRecord)
: super(watchGrp, expression);

_releaseWatch() => null;
}

_ArgHandler(WatchGroup watchGrp, this.watchRecord, int index)
: index = index,
super(watchGrp, 'arg[$index]');
class _PositionalArgHandler extends _ArgHandler {
final int index;
_PositionalArgHandler(WatchGroup watchGrp, _EvalWatchRecord record, int index)
: this.index = index,
super(watchGrp, 'arg[$index]', record);

void acceptValue(object) {
watchRecord.dirtyArgs = true;
watchRecord.args[index] = object;
}
}

class _NamedArgHandler extends _ArgHandler {
final Symbol name;

_NamedArgHandler(WatchGroup watchGrp, _EvalWatchRecord record, Symbol name)
: this.name = name,
super(watchGrp, 'namedArg[$name]', record);

void acceptValue(object) {
watchRecord.dirtyArgs = true;
watchRecord.namedArgs[name] = object;
}
}

class _InvokeHandler extends _Handler implements _ArgHandlerList {
_ArgHandler _argHandlerHead, _argHandlerTail;

Expand Down Expand Up @@ -675,6 +705,7 @@ class _EvalWatchRecord implements WatchRecord<_Handler>, Record<_Handler> {
WatchGroup watchGrp;
final _Handler handler;
final List args;
final Map<Symbol, dynamic> namedArgs = new Map<Symbol, dynamic>();
final Symbol symbol;
final String name;
int mode;
Expand Down Expand Up @@ -751,7 +782,7 @@ class _EvalWatchRecord implements WatchRecord<_Handler>, Record<_Handler> {
return false;
case _MODE_FUNCTION_:
if (!dirtyArgs) return false;
value = Function.apply(fn, args);
value = Function.apply(fn, args, namedArgs);
dirtyArgs = false;
break;
case _MODE_FUNCTION_APPLY_:
Expand All @@ -761,14 +792,14 @@ class _EvalWatchRecord implements WatchRecord<_Handler>, Record<_Handler> {
break;
case _MODE_FIELD_CLOSURE_:
var closure = _instanceMirror.getField(symbol).reflectee;
value = closure == null ? null : Function.apply(closure, args);
value = closure == null ? null : Function.apply(closure, args, namedArgs);
break;
case _MODE_MAP_CLOSURE_:
var closure = object[name];
value = closure == null ? null : Function.apply(closure, args);
value = closure == null ? null : Function.apply(closure, args, namedArgs);
break;
case _MODE_METHOD_:
value = _instanceMirror.invoke(symbol, args).reflectee;
value = _instanceMirror.invoke(symbol, args, namedArgs).reflectee;
break;
default:
assert(false);
Expand Down
22 changes: 12 additions & 10 deletions lib/core/parser/dynamic_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'package:angular/core/parser/utils.dart' show EvalError;
class ClosureMap {
Getter lookupGetter(String name) => null;
Setter lookupSetter(String name) => null;
Function lookupFunction(String name, int arity) => null;
Function lookupFunction(String name, CallArguments arguments) => null;
}

@NgInjectableService()
Expand Down Expand Up @@ -128,33 +128,35 @@ class DynamicParserBackend extends ParserBackend {

Expression newCallScope(name, arguments) {
Function constructor = _computeCallConstructor(
_callScopeConstructors, name, arguments.length);
_callScopeConstructors, name, arguments);
return (constructor != null)
? constructor(name, arguments, _closures)
: new CallScope(name, arguments);
}

Expression newCallMember(object, name, arguments) {
Function constructor = _computeCallConstructor(
_callMemberConstructors, name, arguments.length);
_callMemberConstructors, name, arguments);
return (constructor != null)
? constructor(object, name, arguments, _closures)
: new CallMember(object, name, arguments);
}

Function _computeCallConstructor(Map constructors, String name, int arity) {
Function function = _closures.lookupFunction(name, arity);
return (function == null) ? null : constructors[arity];
Function _computeCallConstructor(Map constructors,
String name,
CallArguments arguments) {
Function function = _closures.lookupFunction(name, arguments);
return (function == null) ? null : constructors[arguments.arity];
}

static final Map<int, Function> _callScopeConstructors = {
0: (n, a, c) => new CallScopeFast0(n, a, c.lookupFunction(n, 0)),
1: (n, a, c) => new CallScopeFast1(n, a, c.lookupFunction(n, 1)),
0: (n, a, c) => new CallScopeFast0(n, a, c.lookupFunction),
1: (n, a, c) => new CallScopeFast1(n, a, c.lookupFunction),
};

static final Map<int, Function> _callMemberConstructors = {
0: (o, n, a, c) => new CallMemberFast0(o, n, a, c.lookupFunction(n, 0)),
1: (o, n, a, c) => new CallMemberFast1(o, n, a, c.lookupFunction(n, 1)),
0: (o, n, a, c) => new CallMemberFast0(o, n, a, c.lookupFunction),
1: (o, n, a, c) => new CallMemberFast1(o, n, a, c.lookupFunction),
};
}

Loading

0 comments on commit 18ceb4d

Please sign in to comment.