Specs: pass the current <script> to the module library init()

function, rename it _init(), plumb that through AutomaticMetadata, and
move @tagname and Element.tagname to a new frameworks.md file that has
stuff that wouldn't actually be part of core Sky

Review URL: https://codereview.chromium.org/946513006
This commit is contained in:
Hixie 2015-02-20 13:55:52 -08:00
parent 484c581d71
commit 01bec1736f
4 changed files with 45 additions and 30 deletions

View File

@ -184,19 +184,6 @@ class Attr {
final String value; // O(1)
}
// @tagname annotation for registering elements
// only useful when placed on classes that inherit from Element
class tagname extends AutomaticMetadata {
const tagname(this.name);
final String name;
void init(DeclarationMirror target, Module module) {
assert(target is ClassMirror);
if (!(target as ClassMirror).isSubclassOf(reflectClass(Element)))
throw new UnsupportedError('@tagname can only be used on descendants of Element');
module.registerElement(name, (target as ClassMirror).reflectedType);
}
}
// @hasShadow annotation for registering elements
class _HasShadow {
const _HasShadow();
@ -222,12 +209,6 @@ abstract class Element extends ParentNode {
// children must be Text or Element
// if needsShadow is true, creates a shadow tree
String get tagName { // O(N) in number of annotations on the class
// throws a StateError if the class doesn't have an @tagname annotation
var tagnameClass = reflectClass(tagname);
return (reflectClass(this.runtimeType).metadata.singleWhere((mirror) => mirror.type == tagnameClass).reflectee as tagname).name;
}
external bool hasAttribute(String name); // O(N) in number of attributes
external String getAttribute(String name); // O(N) in number of attributes
external void setAttribute(String name, [String value = '']); // O(N) in number of attributes

31
specs/frameworks.md Normal file
View File

@ -0,0 +1,31 @@
Frameworks
----------
Sky is intended to support multiple frameworks. Here is one way you
could register a custom element using Dart annotations:
```dart
// @tagname annotation for registering elements
// only useful when placed on classes that inherit from Element
class tagname extends AutomaticMetadata {
const tagname(this.name);
final String name;
void init(DeclarationMirror target, Module module, ScriptElement script) {
assert(target is ClassMirror);
if (!(target as ClassMirror).isSubclassOf(reflectClass(Element)))
throw new UnsupportedError('@tagname can only be used on descendants of Element');
module.registerElement(name, (target as ClassMirror).reflectedType);
}
}
```
A framework that used the above code could use the following code to
get the tag name of an element:
```dart
String getTagName(Element element) { // O(N) in number of annotations on the class
// throws a StateError if the class doesn't have an @tagname annotation
var tagnameClass = reflectClass(tagname);
return (reflectClass(element.runtimeType).metadata.singleWhere((mirror) => mirror.type == tagnameClass).reflectee as tagname).name;
}
```

View File

@ -71,15 +71,17 @@ the library itself):
```dart
class _ { }
void main() {
void main(ScriptElement script) {
LibraryMirror library = reflectClass(_).owner as LibraryMirror;
if (library.declarations.containsKey(#init) && library.declarations[#init] is MethodMirror)
init();
AutomaticMetadata.runLibrary(library, module);
if (library.declarations.containsKey(#_init) && library.declarations[#_init] is MethodMirror)
_init(script);
AutomaticMetadata.runLibrary(library, module, script);
}
```
Then, that ``main()`` function is called.
Then, that ``main(script)`` function is called, with ``script`` set to
the ``ScriptElement`` object representing the relevant ``<script>``
element.
TODO(ianh): decide what URL and name we should give the libraries, as
exposed in MirrorSystem.getName(libraryMirror.qualifiedName) etc

View File

@ -26,9 +26,9 @@ import 'dart:mirrors';
abstract class AutomaticMetadata {
const AutomaticMetadata();
void init(DeclarationMirror target, Module module);
void init(DeclarationMirror target, Module module, ScriptElement script);
static void runLibrary(LibraryMirror library, Module module) {
static void runLibrary(LibraryMirror library, Module module, ScriptElement script) {
library.declarations.values.toList() /* ..sort((DeclarationMirror a, DeclarationMirror b) {
bool aHasLocation;
try {
@ -55,7 +55,7 @@ abstract class AutomaticMetadata {
..forEach((DeclarationMirror d) {
d.metadata.forEach((InstanceMirror i) {
if (i.reflectee is AutomaticMetadata)
i.reflectee.run(d, module);
i.reflectee.run(d, module, script);
});
});
}
@ -63,16 +63,17 @@ abstract class AutomaticMetadata {
class AutomaticFunction extends AutomaticMetadata {
const AutomaticFunction();
void init(DeclarationMirror target, Module module) {
void init(DeclarationMirror target, Module module, ScriptElement script) {
assert(target is MethodMirror);
MethodMirror f = target as MethodMirror;
assert(!f.isAbstract);
assert(f.isRegularMethod);
assert(f.isTopLevel);
assert(f.isStatic);
assert(f.parameters.length == 0);
assert(f.parameters.length == 1);
assert(f.parameters[0].type == ScriptElement);
assert(f.returnType == currentMirrorSystem().voidType);
(f.owner as LibraryMirror).invoke(f.simpleName, []);
(f.owner as LibraryMirror).invoke(f.simpleName, [script]);
}
}
const autorun = const AutomaticFunction();