Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(509)

Side by Side Diff: pkg/polymer/lib/src/declaration.dart

Issue 173003006: Use smoke in polymer and polymer_expressions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of polymer; 5 part of polymer;
6 6
7 /** 7 /**
8 * **Warning**: this class is experiental and subject to change. 8 * **Warning**: this class is experiental and subject to change.
9 * 9 *
10 * The implementation for the `polymer-element` element. 10 * The implementation for the `polymer-element` element.
(...skipping 29 matching lines...) Expand all
40 // each level of the __proto__ like JS does. 40 // each level of the __proto__ like JS does.
41 PolymerDeclaration _super; 41 PolymerDeclaration _super;
42 PolymerDeclaration get superDeclaration => _super; 42 PolymerDeclaration get superDeclaration => _super;
43 43
44 String _extendsName; 44 String _extendsName;
45 45
46 String _name; 46 String _name;
47 String get name => _name; 47 String get name => _name;
48 48
49 /** 49 /**
50 * Map of publish properties. Can be a [VariableMirror] or a [MethodMirror] 50 * Map of publish properties. Can be a field or a property getter, but if this
51 * representing a getter. If it is a getter, there will also be a setter. 51 * map contains a getter, is because it also has a corresponding setter.
52 * 52 *
53 * Note: technically these are always single properties, so we could use 53 * Note: technically these are always single properties, so we could use a
54 * a Symbol instead of a PropertyPath. However there are lookups between 54 * Symbol instead of a PropertyPath. However there are lookups between this
55 * this map and [_observe] so it is easier to just track paths. 55 * map and [_observe] so it is easier to just track paths.
56 */ 56 */
57 Map<PropertyPath, DeclarationMirror> _publish; 57 Map<PropertyPath, smoke.Declaration> _publish;
58 58
59 /** The names of published properties for this polymer-element. */ 59 /** The names of published properties for this polymer-element. */
60 Iterable<String> get publishedProperties => 60 Iterable<String> get publishedProperties =>
61 _publish != null ? _publish.keys.map((p) => '$p') : const []; 61 _publish != null ? _publish.keys.map((p) => '$p') : const [];
62 62
63 /** Same as [_publish] but with lower case names. */ 63 /** Same as [_publish] but with lower case names. */
64 Map<String, DeclarationMirror> _publishLC; 64 Map<String, smoke.Declaration> _publishLC;
65 65
66 Map<PropertyPath, List<Symbol>> _observe; 66 Map<PropertyPath, List<Symbol>> _observe;
67 67
68 Map<String, Object> _instanceAttributes; 68 Map<String, Object> _instanceAttributes;
69 69
70 List<Element> _sheets; 70 List<Element> _sheets;
71 List<Element> get sheets => _sheets; 71 List<Element> get sheets => _sheets;
72 72
73 List<Element> _styles; 73 List<Element> _styles;
74 List<Element> get styles => _styles; 74 List<Element> get styles => _styles;
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 * prototype, which simplifies this method. 182 * prototype, which simplifies this method.
183 */ 183 */
184 void buildType(String name, String extendee) { 184 void buildType(String name, String extendee) {
185 // get our custom type 185 // get our custom type
186 _type = _getRegisteredType(name); 186 _type = _getRegisteredType(name);
187 187
188 // get basal prototype 188 // get basal prototype
189 _supertype = _getRegisteredType(extendee); 189 _supertype = _getRegisteredType(extendee);
190 if (_supertype != null) _super = _getDeclaration(extendee); 190 if (_supertype != null) _super = _getDeclaration(extendee);
191 191
192 var cls = reflectClass(_type); 192 // transcribe `attributes` declarations onto own prototype's `publish`
193 publishAttributes(_super);
193 194
194 // transcribe `attributes` declarations onto own prototype's `publish` 195 publishProperties();
195 publishAttributes(cls, _super);
196 196
197 publishProperties(_type); 197 inferObservers();
198
199 inferObservers(cls);
200 198
201 // desugar compound observer syntax, e.g. @ObserveProperty('a b c') 199 // desugar compound observer syntax, e.g. @ObserveProperty('a b c')
202 explodeObservers(cls); 200 explodeObservers();
203 201
204 // Skip the rest in Dart: 202 // Skip the rest in Dart:
205 // chain various meta-data objects to inherited versions 203 // chain various meta-data objects to inherited versions
206 // chain custom api to inherited 204 // chain custom api to inherited
207 // build side-chained lists to optimize iterations 205 // build side-chained lists to optimize iterations
208 // inherit publishing meta-data 206 // inherit publishing meta-data
209 // x-platform fixup 207 // x-platform fixup
210 } 208 }
211 209
212 /** Implement various declarative features. */ 210 /** Implement various declarative features. */
(...skipping 10 matching lines...) Expand all
223 // TODO(sorvell): install a helper method this.resolvePath to aid in 221 // TODO(sorvell): install a helper method this.resolvePath to aid in
224 // setting resource paths. e.g. 222 // setting resource paths. e.g.
225 // this.$.image.src = this.resolvePath('images/foo.png') 223 // this.$.image.src = this.resolvePath('images/foo.png')
226 // Potentially remove when spec bug is addressed. 224 // Potentially remove when spec bug is addressed.
227 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407 225 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407
228 // TODO(jmesserly): resolvePath not ported, see first comment in this class. 226 // TODO(jmesserly): resolvePath not ported, see first comment in this class.
229 227
230 // under ShadowDOMPolyfill, transforms to approximate missing CSS features 228 // under ShadowDOMPolyfill, transforms to approximate missing CSS features
231 _shimShadowDomStyling(templateContent, name, extendee); 229 _shimShadowDomStyling(templateContent, name, extendee);
232 230
233 var cls = reflectClass(type);
234 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient 231 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient
235 // lazy static initialization, can we get by without it? 232 // lazy static initialization, can we get by without it?
236 var registered = cls.declarations[#registerCallback]; 233 if (smoke.hasStaticMethod(type, #registerCallback)) {
237 if (registered != null && 234 smoke.invoke(type, #registerCallback, [this]);
238 registered is MethodMirror &&
239 registered.isStatic &&
240 registered.isRegularMethod) {
241 cls.invoke(#registerCallback, [this]);
242 } 235 }
243 } 236 }
244 237
245 // TODO(sorvell): remove when spec addressed: 238 // TODO(sorvell): remove when spec addressed:
246 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22460 239 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22460
247 // make <shadow></shadow> be <shadow><content></content></shadow> 240 // make <shadow></shadow> be <shadow><content></content></shadow>
248 void adjustShadowElement() { 241 void adjustShadowElement() {
249 // TODO(sorvell): avoid under SD polyfill until this bug is addressed: 242 // TODO(sorvell): avoid under SD polyfill until this bug is addressed:
250 // https://github.com/Polymer/ShadowDOM/issues/297 243 // https://github.com/Polymer/ShadowDOM/issues/297
251 if (!_hasShadowDomPolyfill) { 244 if (!_hasShadowDomPolyfill) {
252 final content = templateContent; 245 final content = templateContent;
253 if (content == null) return; 246 if (content == null) return;
254 247
255 for (var s in content.querySelectorAll('shadow')) { 248 for (var s in content.querySelectorAll('shadow')) {
256 if (s.nodes.isEmpty) s.append(new ContentElement()); 249 if (s.nodes.isEmpty) s.append(new ContentElement());
257 } 250 }
258 } 251 }
259 } 252 }
260 253
261 void registerType(String name) { 254 void registerType(String name) {
262 var baseTag; 255 var baseTag;
263 var decl = this; 256 var decl = this;
264 while (decl != null) { 257 while (decl != null) {
265 baseTag = decl.attributes['extends']; 258 baseTag = decl.attributes['extends'];
266 decl = decl.superDeclaration; 259 decl = decl.superDeclaration;
267 } 260 }
268 document.register(name, type, extendsTag: baseTag); 261 document.register(name, type, extendsTag: baseTag);
269 } 262 }
270 263
271 void publishAttributes(ClassMirror cls, PolymerDeclaration superDecl) { 264 void publishAttributes(PolymerDeclaration superDecl) {
272 // get properties to publish 265 // get properties to publish
273 if (superDecl != null && superDecl._publish != null) { 266 if (superDecl != null && superDecl._publish != null) {
274 // Dart note: even though we walk the type hierarchy in 267 // Dart note: even though we walk the type hierarchy in
275 // _getPublishedProperties, this will additionally include any names 268 // _getPublishedProperties, this will additionally include any names
276 // published via the `attributes` attribute. 269 // published via the `attributes` attribute.
277 _publish = new Map.from(superDecl._publish); 270 _publish = new Map.from(superDecl._publish);
278 } 271 }
279 272
280 _publish = _getPublishedProperties(cls, _publish); 273 _publish = _getPublishedProperties(_type, _publish);
281 274
282 // merge names from 'attributes' attribute 275 // merge names from 'attributes' attribute
283 var attrs = attributes['attributes']; 276 var attrs = attributes['attributes'];
284 if (attrs != null) { 277 if (attrs != null) {
285 // names='a b c' or names='a,b,c' 278 // names='a b c' or names='a,b,c'
286 // record each name for publishing 279 // record each name for publishing
287 for (var attr in attrs.split(_ATTRIBUTES_REGEX)) { 280 for (var attr in attrs.split(_ATTRIBUTES_REGEX)) {
288 // remove excess ws 281 // remove excess ws
289 attr = attr.trim(); 282 attr = attr.trim();
290 283
291 // do not override explicit entries 284 // do not override explicit entries
292 if (attr == '') continue; 285 if (attr == '') continue;
293 286
294 var property = new Symbol(attr); 287 var property = new Symbol(attr);
295 var path = new PropertyPath([property]); 288 var path = new PropertyPath([property]);
296 if (_publish != null && _publish.containsKey(path)) { 289 if (_publish != null && _publish.containsKey(path)) {
297 continue; 290 continue;
298 } 291 }
299 292
300 var mirror = _getProperty(cls, property); 293 var decl = smoke.getDeclaration(_type, property);
301 if (mirror == null) { 294 if (decl == null || !decl.isProperty || decl.isFinal) {
302 window.console.warn('property for attribute $attr of polymer-element ' 295 window.console.warn('property for attribute $attr of polymer-element '
303 'name=$name not found.'); 296 'name=$name not found.');
304 continue; 297 continue;
305 } 298 }
306 if (_publish == null) _publish = {}; 299 if (_publish == null) _publish = {};
307 _publish[path] = mirror; 300 _publish[path] = decl;
308 } 301 }
309 } 302 }
310 303
311 // NOTE: the following is not possible in Dart; fields must be declared. 304 // NOTE: the following is not possible in Dart; fields must be declared.
312 // install 'attributes' as properties on the prototype, 305 // install 'attributes' as properties on the prototype,
313 // but don't override 306 // but don't override
314 } 307 }
315 308
316 void accumulateInstanceAttributes() { 309 void accumulateInstanceAttributes() {
317 // inherit instance attributes 310 // inherit instance attributes
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 446
454 return new StyleElement() 447 return new StyleElement()
455 ..text = cssText 448 ..text = cssText
456 ..attributes[_STYLE_SCOPE_ATTRIBUTE] = '$name-$scopeDescriptor'; 449 ..attributes[_STYLE_SCOPE_ATTRIBUTE] = '$name-$scopeDescriptor';
457 } 450 }
458 451
459 /** 452 /**
460 * Fetch a list of all *Changed methods so we can observe the associated 453 * Fetch a list of all *Changed methods so we can observe the associated
461 * properties. 454 * properties.
462 */ 455 */
463 void inferObservers(ClassMirror cls) { 456 void inferObservers() {
464 if (cls == _htmlElementType) return; 457 var options = const smoke.QueryOptions(includeProperties: false,
465 inferObservers(cls.superclass); 458 includeMethods: true, includeInherited: true);
466 for (var method in cls.declarations.values) { 459 for (var decl in smoke.query(_type, options)) {
467 if (method is! MethodMirror || method.isStatic 460 String name = smoke.symbolToName(decl.name);
468 || !method.isRegularMethod) continue;
469
470 String name = MirrorSystem.getName(method.simpleName);
471 if (name.endsWith(_OBSERVE_SUFFIX) && name != 'attributeChanged') { 461 if (name.endsWith(_OBSERVE_SUFFIX) && name != 'attributeChanged') {
472 // TODO(jmesserly): now that we have a better system, should we 462 // TODO(jmesserly): now that we have a better system, should we
473 // deprecate *Changed methods? 463 // deprecate *Changed methods?
474 if (_observe == null) _observe = new HashMap(); 464 if (_observe == null) _observe = new HashMap();
475 name = name.substring(0, name.length - 7); 465 name = name.substring(0, name.length - 7);
476 _observe[new PropertyPath(name)] = [method.simpleName]; 466 _observe[new PropertyPath(name)] = [decl.name];
477 } 467 }
478 } 468 }
479 } 469 }
480 470
481 /** 471 /**
482 * Fetch a list of all methods annotated with [ObserveProperty] so we can 472 * Fetch a list of all methods annotated with [ObserveProperty] so we can
483 * observe the associated properties. 473 * observe the associated properties.
484 */ 474 */
485 void explodeObservers(ClassMirror cls) { 475 void explodeObservers() {
486 if (cls == _htmlElementType) return; 476 var options = const smoke.QueryOptions(includeProperties: false,
487 477 includeMethods: true, includeInherited: true,
488 explodeObservers(cls.superclass); 478 withAnnotations: const [ObserveProperty]);
489 for (var method in cls.declarations.values) { 479 for (var decl in smoke.query(_type, options)) {
490 if (method is! MethodMirror || method.isStatic 480 for (var meta in decl.annotations) {
491 || !method.isRegularMethod) continue; 481 if (meta is! ObserveProperty) continue;
492
493 for (var meta in method.metadata) {
494 if (meta.reflectee is! ObserveProperty) continue;
495
496 if (_observe == null) _observe = new HashMap(); 482 if (_observe == null) _observe = new HashMap();
497 483 for (String name in meta.names) {
498 for (String name in meta.reflectee.names) { 484 _observe.putIfAbsent(new PropertyPath(name), () => []).add(decl.name);
499 _observe.putIfAbsent(new PropertyPath(name), () => [])
500 .add(method.simpleName);
501 } 485 }
502 } 486 }
503 } 487 }
504 } 488 }
505 489
506 void publishProperties(Type type) { 490 void publishProperties() {
507 // Dart note: _publish was already populated by publishAttributes 491 // Dart note: _publish was already populated by publishAttributes
508 if (_publish != null) _publishLC = _lowerCaseMap(_publish); 492 if (_publish != null) _publishLC = _lowerCaseMap(_publish);
509 } 493 }
510 494
511 Map<String, dynamic> _lowerCaseMap(Map<PropertyPath, dynamic> properties) { 495 Map<String, dynamic> _lowerCaseMap(Map<PropertyPath, dynamic> properties) {
512 final map = new Map<String, dynamic>(); 496 final map = new Map<String, dynamic>();
513 properties.forEach((PropertyPath path, value) { 497 properties.forEach((PropertyPath path, value) {
514 map['$path'.toLowerCase()] = value; 498 map['$path'.toLowerCase()] = value;
515 }); 499 });
516 return map; 500 return map;
(...skipping 24 matching lines...) Expand all
541 } 525 }
542 } 526 }
543 } 527 }
544 528
545 /// track document.register'ed tag names and their declarations 529 /// track document.register'ed tag names and their declarations
546 final Map _declarations = new Map<String, PolymerDeclaration>(); 530 final Map _declarations = new Map<String, PolymerDeclaration>();
547 531
548 bool _isRegistered(String name) => _declarations.containsKey(name); 532 bool _isRegistered(String name) => _declarations.containsKey(name);
549 PolymerDeclaration _getDeclaration(String name) => _declarations[name]; 533 PolymerDeclaration _getDeclaration(String name) => _declarations[name];
550 534
551 final _objectType = reflectClass(Object); 535 Map<PropertyPath, smoke.Declaration> _getPublishedProperties(
552 final _htmlElementType = reflectClass(HtmlElement); 536 Type type, Map<PropertyPath, smoke.Declaration> props) {
553 537 var options = const smoke.QueryOptions(includeInherited: true,
554 Map _getPublishedProperties(ClassMirror cls, Map props) { 538 withAnnotations: const [PublishedProperty]);
555 if (cls == _htmlElementType) return props; 539 for (var decl in smoke.query(type, options)) {
556 props = _getPublishedProperties(cls.superclass, props); 540 if (decl.isFinal) continue;
557 for (var member in cls.declarations.values) { 541 if (props == null) props = {};
558 if (member.isStatic || member.isPrivate) continue; 542 props[new PropertyPath([decl.name])] = decl;
559
560 if (member is VariableMirror && !member.isFinal
561 || member is MethodMirror && member.isGetter) {
562
563 for (var meta in member.metadata) {
564 if (meta.reflectee is PublishedProperty) {
565 // Note: we delay the setter check until we find @published because
566 // it's a tad expensive.
567 if (member is! MethodMirror || _hasSetter(cls, member)) {
568 if (props == null) props = {};
569 props[new PropertyPath([member.simpleName])] = member;
570 }
571 break;
572 }
573 }
574 }
575 } 543 }
576
577 return props; 544 return props;
578 } 545 }
579 546
580 DeclarationMirror _getProperty(ClassMirror cls, Symbol property) {
581 do {
582 var mirror = cls.declarations[property];
583 if (mirror is MethodMirror && mirror.isGetter && _hasSetter(cls, mirror)
584 || mirror is VariableMirror) {
585 return mirror;
586 }
587 cls = cls.superclass;
588
589 // It's generally a good idea to stop at Object, since we know it doesn't
590 // have what we want.
591 // TODO(jmesserly): This is also a workaround for what appears to be a V8
592 // bug introduced between Chrome 31 and 32. After 32
593 // JsClassMirror.declarations on Object calls
594 // JsClassMirror.typeVariables, which tries to get the _jsConstructor's
595 // .prototype["<>"]. This ends up getting the "" property instead, maybe
596 // because "<>" doesn't exist, and gets ";" which then blows up because
597 // the code later on expects a List of ints.
598 } while (cls != _objectType);
599 return null;
600 }
601
602 bool _hasSetter(ClassMirror cls, MethodMirror getter) {
603 var setterName = new Symbol('${MirrorSystem.getName(getter.simpleName)}=');
604 var mirror = cls.declarations[setterName];
605 return mirror is MethodMirror && mirror.isSetter;
606 }
607
608
609 /** Attribute prefix used for declarative event handlers. */ 547 /** Attribute prefix used for declarative event handlers. */
610 const _EVENT_PREFIX = 'on-'; 548 const _EVENT_PREFIX = 'on-';
611 549
612 /** Whether an attribute declares an event. */ 550 /** Whether an attribute declares an event. */
613 bool _hasEventPrefix(String attr) => attr.startsWith(_EVENT_PREFIX); 551 bool _hasEventPrefix(String attr) => attr.startsWith(_EVENT_PREFIX);
614 552
615 String _removeEventPrefix(String name) => name.substring(_EVENT_PREFIX.length); 553 String _removeEventPrefix(String name) => name.substring(_EVENT_PREFIX.length);
616 554
617 /** 555 /**
618 * Using Polymer's platform/src/ShadowCSS.js passing the style tag's content. 556 * Using Polymer's platform/src/ShadowCSS.js passing the style tag's content.
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
706 644
707 // Dart note: we need this function because we have additional renames JS does 645 // Dart note: we need this function because we have additional renames JS does
708 // not have. The JS renames are simply case differences, whereas we have ones 646 // not have. The JS renames are simply case differences, whereas we have ones
709 // like doubleclick -> dblclick and stripping the webkit prefix. 647 // like doubleclick -> dblclick and stripping the webkit prefix.
710 String _eventNameFromType(String eventType) { 648 String _eventNameFromType(String eventType) {
711 final result = _reverseEventTranslations[eventType]; 649 final result = _reverseEventTranslations[eventType];
712 return result != null ? result : eventType; 650 return result != null ? result : eventType;
713 } 651 }
714 652
715 final _ATTRIBUTES_REGEX = new RegExp(r'\s|,'); 653 final _ATTRIBUTES_REGEX = new RegExp(r'\s|,');
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698