Chromium Code Reviews| Index: pkg/compiler/lib/src/js_emitter/native_generator.dart |
| diff --git a/pkg/compiler/lib/src/js_emitter/native_generator.dart b/pkg/compiler/lib/src/js_emitter/native_generator.dart |
| index 60f6c3d17fffebd90f416752cf3adf54095e94f2..dcd9a9113a78e4d2ca9c7f254be1911679305e32 100644 |
| --- a/pkg/compiler/lib/src/js_emitter/native_generator.dart |
| +++ b/pkg/compiler/lib/src/js_emitter/native_generator.dart |
| @@ -73,4 +73,141 @@ class NativeGenerator { |
| // TODO(sra): MD5 of contributing source code or URIs? |
| return 'ZxYxX'; |
| } |
| + |
| + /// Encodes the collected native information so that it can be treated by |
| + /// the native info-handler below. |
| + /// |
| + /// The encoded information has the form: |
| + /// |
| + // "%": "leafTag1|leafTag2|...;nonleafTag1|...;Class1|Class2|...", |
| + // |
| + // If there is no data following a semicolon, the semicolon can be omitted. |
| + jsAst.Expression encodeNativeInfo(Class cls) { |
|
floitsch
2015/07/06 13:08:17
copy/paste except that it returns the encoded resu
herhut
2015/07/06 13:16:54
Why is this not static like the others? NativeGene
floitsch
2015/07/06 16:04:53
Done.
|
| + List<String> leafTags = cls.nativeLeafTags; |
| + List<String> nonLeafTags = cls.nativeNonLeafTags; |
| + List<Class> extensions = cls.nativeExtensions; |
| + |
| + String formatTags(Iterable<String> tags) { |
| + if (tags == null) return ''; |
| + return (tags.toList() |
| + ..sort()).join('|'); |
| + } |
| + |
| + String leafStr = formatTags(leafTags); |
| + String nonLeafStr = formatTags(nonLeafTags); |
| + |
| + StringBuffer sb = new StringBuffer(leafStr); |
| + if (nonLeafStr != '') { |
| + sb |
| + ..write(';') |
| + ..write(nonLeafStr); |
| + } |
| + |
| + String encoding = sb.toString(); |
| + |
| + if (cls.isNative || encoding != '' || extensions != null) { |
| + List<jsAst.Literal> parts = <jsAst.Literal>[js.stringPart(encoding)]; |
| + if (extensions != null) { |
| + parts |
| + ..add(js.stringPart(';')) |
| + ..addAll( |
| + js.joinLiterals(extensions.map((Class cls) => cls.name), |
| + js.stringPart('|'))); |
| + } |
| + return jsAst.concatenateStrings(parts, addQuotes: true); |
| + } |
| + return null; |
| + } |
| + |
| + /// Returns a JavaScript template that fills the embedded globals referenced |
| + /// by [interceptorsByTagAccess] and [leafTagsAccess]. |
| + /// |
| + /// This code must be invoked for every class that has a native info before |
| + /// the program starts. |
| + /// |
| + /// The [infoAccess] parameter must evaluate to an expression that contains |
| + /// the info (as a JavaScript string). |
| + /// |
| + /// The [constructorAccess] parameter must evaluate to an expression that |
| + /// contains the constructor of the class. The constructor's prototype must |
| + /// be set up. |
| + /// |
| + /// The [subclassReadGenerator] function must evaluate to a JS expression |
| + /// that returns a reference to the constructor (with evaluated prototype) |
| + /// of the given JS expression. |
| + /// |
| + /// The [interceptorsByTagAccess] must point to the embedded global |
| + /// [embeddedNames.INTERCEPTORS_BY_TAG] and must be initialized with an empty |
| + /// JS Object (used as a map). |
| + /// |
| + /// Similarly, the [leafTagsAccess] must point to the embedded global |
| + /// [embeddedNames.LEAF_TAGS] and must be initialized with an empty JS Object |
| + /// (used as a map). |
| + /// |
| + /// Both variables are passed in (instead of creating the access here) to |
| + /// make sure the caller is aware of these globals. |
| + jsAst.Statement buildNativeInfoHandler( |
|
floitsch
2015/07/06 13:08:18
verbatim copy/paste.
herhut
2015/07/06 13:16:54
Same here...
floitsch
2015/07/06 16:04:53
Done.
|
| + jsAst.Expression infoAccess, |
| + jsAst.Expression constructorAccess, |
| + jsAst.Expression subclassReadGenerator(jsAst.Expression subclass), |
| + jsAst.Expression interceptorsByTagAccess, |
| + jsAst.Expression leafTagsAccess) { |
| + jsAst.Expression subclassRead = |
| + subclassReadGenerator(js('subclasses[i]', [])); |
|
herhut
2015/07/06 13:16:53
indentation...
floitsch
2015/07/06 16:04:53
Done.
|
| + return js.statement(''' |
| + // The native info looks like this: |
| + // |
| + // HtmlElement: { |
| + // "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton" |
| + // |
| + // The first two semicolon-separated parts contain dispatch tags, the |
| + // third contains the JavaScript names for classes. |
| + // |
| + // The tags indicate that JavaScript objects with the dispatch tags |
| + // (usually constructor names) HTMLDivElement, HTMLAnchorElement and |
| + // HTMLElement all map to the Dart native class named HtmlElement. |
| + // The first set is for effective leaf nodes in the hierarchy, the |
| + // second set is non-leaf nodes. |
| + // |
| + // The third part contains the JavaScript names of Dart classes that |
| + // extend the native class. Here, FancyButton extends HtmlElement, so |
| + // the runtime needs to know that window.HTMLElement.prototype is the |
| + // prototype that needs to be extended in creating the custom element. |
| + // |
| + // The information is used to build tables referenced by |
| + // getNativeInterceptor and custom element support. |
| + { |
| + var nativeSpec = #info.split(";"); |
| + if (nativeSpec[0]) { |
| + var tags = nativeSpec[0].split("|"); |
| + for (var i = 0; i < tags.length; i++) { |
| + #interceptorsByTagAccess[tags[i]] = #constructor; |
| + #leafTagsAccess[tags[i]] = true; |
| + } |
| + } |
| + if (nativeSpec[1]) { |
| + tags = nativeSpec[1].split("|"); |
| + if (#allowNativesSubclassing) { |
| + if (nativeSpec[2]) { |
| + var subclasses = nativeSpec[2].split("|"); |
| + for (var i = 0; i < subclasses.length; i++) { |
| + var subclass = #subclassRead; |
| + subclass.#nativeSuperclassTagName = tags[0]; |
| + } |
| + } |
| + for (i = 0; i < tags.length; i++) { |
| + #interceptorsByTagAccess[tags[i]] = #constructor; |
| + #leafTagsAccess[tags[i]] = false; |
| + } |
| + } |
| + } |
| + } |
| + ''', {'info': infoAccess, |
| + 'constructor': constructorAccess, |
| + 'subclassRead': subclassRead, |
| + 'interceptorsByTagAccess': interceptorsByTagAccess, |
| + 'leafTagsAccess': leafTagsAccess, |
| + 'nativeSuperclassTagName': embeddedNames.NATIVE_SUPERCLASS_TAG_NAME, |
| + 'allowNativesSubclassing': true}); |
| + } |
| } |