Skip to content

Commit

Permalink
fix(parser): Allow access to Map properties in expressions
Browse files Browse the repository at this point in the history
E.g. `map.keys`, `map.length`, etc. This is a proposed solution to dart-archive#394.
  • Loading branch information
chalin committed Feb 24, 2014
1 parent 259ac5b commit 452b1ce
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 4 deletions.
5 changes: 5 additions & 0 deletions bin/parser_generator_for_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ main(arguments) {
'items[1].name',
'list[3] = 2',
'map["square"] = 6',
'map.isEmpty',
'map.isNotEmpty',
'map.keys',
'map.length',
'map.values',
'method',
'method()',
'notAFn()',
Expand Down
4 changes: 2 additions & 2 deletions lib/core/parser/eval_access.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ abstract class AccessReflective {
if (holder == null) {
_cachedKind = CACHED_VALUE;
return _cachedValue = null;
} else if (holder is Map) {
} else if (holder is Map && !isMapProperty(name)) {
_cachedKind = CACHED_MAP;
_cachedValue = null;
return holder[name];
Expand Down Expand Up @@ -204,7 +204,7 @@ abstract class AccessFast {

_eval(holder) {
if (holder == null) return null;
return (holder is Map) ? holder[name] : getter(holder);
return (holder is Map && !isMapProperty(name)) ? holder[name] : getter(holder);
}

_assign(scope, holder, value) {
Expand Down
10 changes: 10 additions & 0 deletions lib/core/parser/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,13 @@ setKeyed(object, key, value) {
}
return value;
}

final List<String> _MAP_PROPERTIES = const <String>[
"hashCode", // any reason to exclude this?
"isEmpty",
"isNotEmpty",
"keys",
"length",
"runtimeType", // any reason to exclude this?
"values"];
bool isMapProperty(String key) => _MAP_PROPERTIES.contains(key);
11 changes: 9 additions & 2 deletions lib/tools/parser_generator/dart_code_gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ library dart_code_gen;

import 'package:angular/tools/reserved_dart_keywords.dart';
import 'package:angular/core/parser/syntax.dart';
import 'package:angular/core/parser/utils.dart';

escape(String s) => s.replaceAllMapped(new RegExp(r'(\"|\$|\n)'), (m) {
var char = m[1];
Expand All @@ -11,7 +12,7 @@ escape(String s) => s.replaceAllMapped(new RegExp(r'(\"|\$|\n)'), (m) {

class DartCodeGen {
final HelperMap getters = new HelperMap('_',
getterTemplate, getterTemplateForReserved);
getterTemplate, getterTemplateForReserved, getterTemplateWithoutMapTest);
final HelperMap holders = new HelperMap('_ensure\$',
holderTemplate, holderTemplateForReserved);
final HelperMap setters = new HelperMap('_set\$',
Expand Down Expand Up @@ -223,14 +224,17 @@ class HelperMap {
final String prefix;
final Function template;
final Function templateForReserved;
final Function templateWithoutMapTest;

HelperMap(this.prefix, this.template, this.templateForReserved);
HelperMap(this.prefix, this.template, this.templateForReserved, [this.templateWithoutMapTest]);

String lookup(String key) {
String name = _computeName(key);
if (helpers.containsKey(key)) return name;
helpers[key] = isReserved(key)
? templateForReserved(name, key)
: isMapProperty(key) && templateWithoutMapTest != null
? templateWithoutMapTest(name, key)
: template(name, key);
return name;
}
Expand Down Expand Up @@ -261,6 +265,9 @@ $name(o) {
}
""";

String getterTemplateWithoutMapTest(String name, String key) => """
$name(o) => o == null ? null : o.$key;
""";

// ------------------------------------------------------------------
// Templates for generated holders (getters for assignment).
Expand Down
10 changes: 10 additions & 0 deletions test/core/parser/parser_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,16 @@ main() {
});


it('should evaluate map item and field access', () {
context['map'] = { 'a': 1.1, 'b': 'B' };
expect(eval("map.isEmpty")).toEqual(false);
expect(eval("map.isNotEmpty")).toEqual(true);
expect(eval("map.keys")).toEqual(['a', 'b']);
expect(eval("map.length")).toEqual(2);
expect(eval("map.values")).toEqual([1.1, 'B']);
});


it('should evaluate JSON', () {
expect(eval("[{}]")).toEqual([{}]);
expect(eval("[{a:[]}, {b:1}]")).toEqual([{"a":[]},{"b":1}]);
Expand Down

0 comments on commit 452b1ce

Please sign in to comment.