addon-sdk/source/lib/method/core.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 "use strict";
     3 var defineProperty = Object.defineProperty || function(object, name, property) {
     4   object[name] = property.value
     5   return object
     6 }
     8 // Shortcut for `Object.prototype.toString` for faster access.
     9 var typefy = Object.prototype.toString
    11 // Map to for jumping from typeof(value) to associated type prefix used
    12 // as a hash in the map of builtin implementations.
    13 var types = { "function": "Object", "object": "Object" }
    15 // Array is used to save method implementations for the host objects in order
    16 // to avoid extending them with non-primitive values that could cause leaks.
    17 var host = []
    18 // Hash map is used to save method implementations for builtin types in order
    19 // to avoid extending their prototypes. This also allows to share method
    20 // implementations for types across diff contexts / frames / compartments.
    21 var builtin = {}
    23 function Primitive() {}
    24 function ObjectType() {}
    25 ObjectType.prototype = new Primitive()
    26 function ErrorType() {}
    27 ErrorType.prototype = new ObjectType()
    29 var Default = builtin.Default = Primitive.prototype
    30 var Null = builtin.Null = new Primitive()
    31 var Void = builtin.Void = new Primitive()
    32 builtin.String = new Primitive()
    33 builtin.Number = new Primitive()
    34 builtin.Boolean = new Primitive()
    36 builtin.Object = ObjectType.prototype
    37 builtin.Error = ErrorType.prototype
    39 builtin.EvalError = new ErrorType()
    40 builtin.InternalError = new ErrorType()
    41 builtin.RangeError = new ErrorType()
    42 builtin.ReferenceError = new ErrorType()
    43 builtin.StopIteration = new ErrorType()
    44 builtin.SyntaxError = new ErrorType()
    45 builtin.TypeError = new ErrorType()
    46 builtin.URIError = new ErrorType()
    49 function Method(hint) {
    50   /**
    51   Private Method is a callable private name that dispatches on the first
    52   arguments same named Method:
    54       method(object, ...rest) => object[method](...rest)
    56   Optionally hint string may be provided that will be used in generated names
    57   to ease debugging.
    59   ## Example
    61       var foo = Method()
    63       // Implementation for any types
    64       foo.define(function(value, arg1, arg2) {
    65         // ...
    66       })
    68       // Implementation for a specific type
    69       foo.define(BarType, function(bar, arg1, arg2) {
    70         // ...
    71       })
    72   **/
    74   // Create an internal unique name if `hint` is provided it is used to
    75   // prefix name to ease debugging.
    76   var name = (hint || "") + "#" + Math.random().toString(32).substr(2)
    78   function dispatch(value) {
    79     // Method dispatches on type of the first argument.
    80     // If first argument is `null` or `void` associated implementation is
    81     // looked up in the `builtin` hash where implementations for built-ins
    82     // are stored.
    83     var type = null
    84     var method = value === null ? Null[name] :
    85                  value === void(0) ? Void[name] :
    86                  // Otherwise attempt to use method with a generated private
    87                  // `name` that is supposedly in the prototype chain of the
    88                  // `target`.
    89                  value[name] ||
    90                  // Otherwise assume it's one of the built-in type instances,
    91                  // in which case implementation is stored in a `builtin` hash.
    92                  // Attempt to find a implementation for the given built-in
    93                  // via constructor name and method name.
    94                  ((type = builtin[(value.constructor || "").name]) &&
    95                   type[name]) ||
    96                  // Otherwise assume it's a host object. For host objects
    97                  // actual method implementations are stored in the `host`
    98                  // array and only index for the implementation is stored
    99                  // in the host object's prototype chain. This avoids memory
   100                  // leaks that otherwise could happen when saving JS objects
   101                  // on host object.
   102                  host[value["!" + name] || void(0)] ||
   103                  // Otherwise attempt to lookup implementation for builtins by
   104                  // a type of the value. This basically makes sure that all
   105                  // non primitive values will delegate to an `Object`.
   106                  ((type = builtin[types[typeof(value)]]) && type[name])
   109     // If method implementation for the type is still not found then
   110     // just fallback for default implementation.
   111     method = method || Default[name]
   114     // If implementation is still not found (which also means there is no
   115     // default) just throw an error with a descriptive message.
   116     if (!method) throw TypeError("Type does not implements method: " + name)
   118     // If implementation was found then just delegate.
   119     return method.apply(method, arguments)
   120   }
   122   // Make `toString` of the dispatch return a private name, this enables
   123   // method definition without sugar:
   124   //
   125   //    var method = Method()
   126   //    object[method] = function() { /***/ }
   127   dispatch.toString = function toString() { return name }
   129   // Copy utility methods for convenient API.
   130   dispatch.implement = implementMethod
   131   dispatch.define = defineMethod
   133   return dispatch
   134 }
   136 // Create method shortcuts form functions.
   137 var defineMethod = function defineMethod(Type, lambda) {
   138   return define(this, Type, lambda)
   139 }
   140 var implementMethod = function implementMethod(object, lambda) {
   141   return implement(this, object, lambda)
   142 }
   144 // Define `implement` and `define` polymorphic methods to allow definitions
   145 // and implementations through them.
   146 var implement = Method("implement")
   147 var define = Method("define")
   150 function _implement(method, object, lambda) {
   151   /**
   152   Implements `Method` for the given `object` with a provided `implementation`.
   153   Calling `Method` with `object` as a first argument will dispatch on provided
   154   implementation.
   155   **/
   156   return defineProperty(object, method.toString(), {
   157     enumerable: false,
   158     configurable: false,
   159     writable: false,
   160     value: lambda
   161   })
   162 }
   164 function _define(method, Type, lambda) {
   165   /**
   166   Defines `Method` for the given `Type` with a provided `implementation`.
   167   Calling `Method` with a first argument of this `Type` will dispatch on
   168   provided `implementation`. If `Type` is a `Method` default implementation
   169   is defined. If `Type` is a `null` or `undefined` `Method` is implemented
   170   for that value type.
   171   **/
   173   // Attempt to guess a type via `Object.prototype.toString.call` hack.
   174   var type = Type && typefy.call(Type.prototype)
   176   // If only two arguments are passed then `Type` is actually an implementation
   177   // for a default type.
   178   if (!lambda) Default[method] = Type
   179   // If `Type` is `null` or `void` store implementation accordingly.
   180   else if (Type === null) Null[method] = lambda
   181   else if (Type === void(0)) Void[method] = lambda
   182   // If `type` hack indicates built-in type and type has a name us it to
   183   // store a implementation into associated hash. If hash for this type does
   184   // not exists yet create one.
   185   else if (type !== "[object Object]" && Type.name) {
   186     var Bulitin = builtin[Type.name] || (builtin[Type.name] = new ObjectType())
   187     Bulitin[method] = lambda
   188   }
   189   // If `type` hack indicates an object, that may be either object or any
   190   // JS defined "Class". If name of the constructor is `Object`, assume it's
   191   // built-in `Object` and store implementation accordingly.
   192   else if (Type.name === "Object")
   193     builtin.Object[method] = lambda
   194   // Host objects are pain!!! Every browser does some crazy stuff for them
   195   // So far all browser seem to not implement `call` method for host object
   196   // constructors. If that is a case here, assume it's a host object and
   197   // store implementation in a `host` array and store `index` in the array
   198   // in a `Type.prototype` itself. This avoids memory leaks that could be
   199   // caused by storing JS objects on a host objects.
   200   else if (Type.call === void(0)) {
   201     var index = host.indexOf(lambda)
   202     if (index < 0) index = host.push(lambda) - 1
   203     // Prefix private name with `!` so it can be dispatched from the method
   204     // without type checks.
   205     implement("!" + method, Type.prototype, index)
   206   }
   207   // If Got that far `Type` is user defined JS `Class`. Define private name
   208   // as hidden property on it's prototype.
   209   else
   210     implement(method, Type.prototype, lambda)
   211 }
   213 // And provided implementations for a polymorphic equivalents.
   214 _define(define, _define)
   215 _define(implement, _implement)
   217 // Define exports on `Method` as it's only thing being exported.
   218 Method.implement = implement
   219 Method.define = define
   220 Method.Method = Method
   221 Method.method = Method
   222 Method.builtin = builtin
   223 Method.host = host
   225 module.exports = Method

mercurial