| Index: frog/leg/lib/native_helper.dart
|
| ===================================================================
|
| --- frog/leg/lib/native_helper.dart (revision 5925)
|
| +++ frog/leg/lib/native_helper.dart (working copy)
|
| @@ -1,263 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -String typeNameInChrome(obj) {
|
| - String name = JS('String', "#.constructor.name", obj);
|
| - if (name == 'Window') return 'DOMWindow';
|
| - return name;
|
| -}
|
| -
|
| -String typeNameInFirefox(obj) {
|
| - String name = constructorNameFallback(obj);
|
| - if (name == 'Window') return 'DOMWindow';
|
| - if (name == 'Document') return 'HTMLDocument';
|
| - if (name == 'XMLDocument') return 'Document';
|
| - return name;
|
| -}
|
| -
|
| -String typeNameInIE(obj) {
|
| - String name = constructorNameFallback(obj);
|
| - if (name == 'Window') return 'DOMWindow';
|
| - // IE calls both HTML and XML documents 'Document', so we check for the
|
| - // xmlVersion property, which is the empty string on HTML documents.
|
| - if (name == 'Document' && JS('bool', '!!#.xmlVersion', obj)) return 'Document';
|
| - if (name == 'Document') return 'HTMLDocument';
|
| - return name;
|
| -}
|
| -
|
| -String constructorNameFallback(obj) {
|
| - var constructor = JS('var', "#.constructor", obj);
|
| - if (JS('String', "typeof(#)", constructor) === 'function') {
|
| - // The constructor isn't null or undefined at this point. Try
|
| - // to grab hold of its name.
|
| - var name = JS('var', '#.name', constructor);
|
| - // If the name is a non-empty string, we use that as the type
|
| - // name of this object. On Firefox, we often get 'Object' as
|
| - // the constructor name even for more specialized objects so
|
| - // we have to fall through to the toString() based implementation
|
| - // below in that case.
|
| - if (JS('String', "typeof(#)", name) === 'string'
|
| - && !name.isEmpty()
|
| - && name !== 'Object') {
|
| - return name;
|
| - }
|
| - }
|
| - String string = JS('String', 'Object.prototype.toString.call(#)', obj);
|
| - return string.substring(8, string.length - 1);
|
| -}
|
| -
|
| -
|
| -/**
|
| - * Returns the function to use to get the type name of an object.
|
| - */
|
| -Function getTypeNameOfFunction() {
|
| - // If we're not in the browser, we're almost certainly running on v8.
|
| - if (JS('String', 'typeof(navigator)') !== 'object') return typeNameInChrome;
|
| -
|
| - String userAgent = JS('String', "navigator.userAgent");
|
| - if (userAgent.contains(const RegExp('Chrome|DumpRenderTree'))) {
|
| - return typeNameInChrome;
|
| - } else if (userAgent.contains('Firefox')) {
|
| - return typeNameInFirefox;
|
| - } else if (userAgent.contains('MSIE')) {
|
| - return typeNameInIE;
|
| - } else {
|
| - return constructorNameFallback;
|
| - }
|
| -}
|
| -
|
| -
|
| -/**
|
| - * Cached value for the function to use to get the type name of an
|
| - * object.
|
| - */
|
| -Function _getTypeNameOf;
|
| -
|
| -/**
|
| - * Returns the type name of [obj].
|
| - */
|
| -String getTypeNameOf(var obj) {
|
| - if (_getTypeNameOf === null) _getTypeNameOf = getTypeNameOfFunction();
|
| - return _getTypeNameOf(obj);
|
| -}
|
| -
|
| -String toStringForNativeObject(var obj) {
|
| - return 'Instance of ${getTypeNameOf(obj)}';
|
| -}
|
| -
|
| -/**
|
| - * Sets a JavaScript property on an object.
|
| - */
|
| -void defineProperty(var obj, String property, var value) {
|
| - JS('void', """Object.defineProperty(#, #,
|
| - {value: #, enumerable: false, writable: false, configurable: true});""",
|
| - obj,
|
| - property,
|
| - value);
|
| -}
|
| -
|
| -/**
|
| - * Helper method to throw a [NoSuchMethodException] for a invalid call
|
| - * on a native object.
|
| - */
|
| -void throwNoSuchMethod(obj, name, arguments) {
|
| - throw new NoSuchMethodException(obj, name, arguments);
|
| -}
|
| -
|
| -/**
|
| - * This method looks up the type name of [obj] in [methods]. If it
|
| - * cannot find it, it looks into the [_dynamicMetadata] array. If the
|
| - * method can still not be found, it creates a method that will throw
|
| - * a [NoSuchMethodException].
|
| - *
|
| - * Once it has a method, the prototype of [obj] is patched with that
|
| - * method, on the property [name]. The method is then invoked.
|
| - *
|
| - * This method returns the result of invoking the found method.
|
| - */
|
| -dynamicBind(var obj,
|
| - String name,
|
| - var methods,
|
| - List arguments) {
|
| - String tag = getTypeNameOf(obj);
|
| - var method = JS('var', '#[#]', methods, tag);
|
| -
|
| - if (method === null && _dynamicMetadata !== null) {
|
| - for (int i = 0; i < _dynamicMetadata.length; i++) {
|
| - MetaInfo entry = _dynamicMetadata[i];
|
| - if (entry.set.contains(tag)) {
|
| - method = JS('var', '#[#]', methods, entry.tag);
|
| - if (method !== null) break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (method === null) {
|
| - method = JS('var', "#['Object']", methods);
|
| - }
|
| -
|
| - if (method === null) {
|
| - method = JS('var',
|
| - 'function () {'
|
| - '#(#, #, Array.prototype.slice.call(arguments));'
|
| - '}',
|
| - DART_CLOSURE_TO_JS(throwNoSuchMethod), obj, name);
|
| - }
|
| -
|
| - var nullCheckMethod = JS('var',
|
| - 'function() {'
|
| - 'var res = #.apply(this, Array.prototype.slice.call(arguments));'
|
| - 'return res === null ? (void 0) : res;'
|
| - '}',
|
| - method);
|
| -
|
| - var proto = JS('var', 'Object.getPrototypeOf(#)', obj);
|
| - if (JS('bool', '!#.hasOwnProperty(#)', proto, name)) {
|
| - defineProperty(proto, name, nullCheckMethod);
|
| - }
|
| -
|
| - return JS('var', '#.apply(#, #)', nullCheckMethod, obj, arguments);
|
| -}
|
| -
|
| -/**
|
| - * Code for doing the dynamic dispatch on JavaScript prototypes that are not
|
| - * available at compile-time. Each property of a native Dart class
|
| - * is registered through this function, which is called with the
|
| - * following pattern:
|
| - *
|
| - * dynamicFunction('propertyName').prototypeName = // JS code
|
| - *
|
| - * What this function does is:
|
| - * - Creates a map of { prototypeName: JS code }.
|
| - * - Attaches 'propertyName' to the JS Object prototype that will
|
| - * intercept at runtime all calls to propertyName.
|
| - * - Sets the value of 'propertyName' to the returned method from
|
| - * [dynamicBind].
|
| - *
|
| - */
|
| -dynamicFunction(name) {
|
| - var f = JS('var', 'Object.prototype[#]', name);
|
| - if (f !== null && JS('bool', '!!#.methods', f)) {
|
| - return JS('var', '#.methods', f);
|
| - }
|
| -
|
| - // TODO(ngeoffray): We could make this a map if the code we
|
| - // generate plays well with a Dart map.
|
| - var methods = JS('var', '{}');
|
| - // If there is a method attached to the Dart Object class, use it as
|
| - // the method to call in case no method is registered for that type.
|
| - var dartMethod = JS('var', 'Object.getPrototypeOf(#)[#]', new Object(), name);
|
| - if (dartMethod !== null) JS('void', "#['Object'] = #", methods, dartMethod);
|
| -
|
| - var bind = JS('var',
|
| - 'function() {'
|
| - 'return #(this, #, #, Array.prototype.slice.call(arguments));'
|
| - '}',
|
| - DART_CLOSURE_TO_JS(dynamicBind), name, methods);
|
| -
|
| - JS('void', '#.methods = #', bind, methods);
|
| - defineProperty(JS('var', 'Object.prototype'), name, bind);
|
| - return methods;
|
| -}
|
| -
|
| -/**
|
| - * This class encodes the class hierarchy when we need it for dynamic
|
| - * dispatch.
|
| - */
|
| -class MetaInfo {
|
| - /**
|
| - * The type name this [MetaInfo] relates to.
|
| - */
|
| - String tag;
|
| -
|
| - /**
|
| - * A string containing the names of subtypes of [tag], separated by
|
| - * '|'.
|
| - */
|
| - String tags;
|
| -
|
| - /**
|
| - * A list of names of subtypes of [tag].
|
| - */
|
| - Set<String> set;
|
| -
|
| - MetaInfo(this.tag, this.tags, this.set);
|
| -}
|
| -
|
| -List<MetaInfo> get _dynamicMetadata() {
|
| - if (JS('var', 'typeof(\$dynamicMetadata)') === 'undefined') {
|
| - _dynamicMetadata = <MetaInfo>[];
|
| - }
|
| - return JS('var', '\$dynamicMetadata');
|
| -}
|
| -
|
| -void set _dynamicMetadata(List<String> table) {
|
| - JS('void', '\$dynamicMetadata = #', table);
|
| -}
|
| -
|
| -/**
|
| - * Builds the metadata used for encoding the class hierarchy of native
|
| - * classes. The following example:
|
| - *
|
| - * class A native "*A" {}
|
| - * class B native "*B" {}
|
| - *
|
| - * Will generate:
|
| - * ['A', 'A|B']
|
| - *
|
| - * This method turns the array into a list of [MetaInfo] objects.
|
| - */
|
| -void dynamicSetMetadata(List<List<String>> inputTable) {
|
| - _dynamicMetadata = <MetaInfo>[];
|
| - for (int i = 0; i < inputTable.length; i++) {
|
| - String tag = inputTable[i][0];
|
| - String tags = inputTable[i][1];
|
| - Set<String> set = new Set<String>();
|
| - List<String> tagNames = tags.split('|');
|
| - for (int j = 0; j < tagNames.length; j++) {
|
| - set.add(tagNames[j]);
|
| - }
|
| - _dynamicMetadata.add(new MetaInfo(tag, tags, set));
|
| - }
|
| -}
|
|
|