| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 /// Exception thrown when a function receives the wrong number of arguments at | |
| 6 /// runtime. Overridden to provide a more informative error message. | |
| 7 // TODO(jmesserly): should the base class support a message? | |
| 8 class _ArgumentMismatchException extends ClosureArgumentMismatchException { | |
| 9 final String _message; | |
| 10 const _ArgumentMismatchException(this._message); | |
| 11 String toString() => "Closure argument mismatch: $_message"; | |
| 12 } | |
| 13 | |
| 14 /// Implementation details for [Function] | |
| 15 /// Note: we don't expose this because it has no useful API. It's just some | |
| 16 /// helpers for our dynamic calling convention. Maybe in the future there will | |
| 17 /// be more stuff here, though. | |
| 18 class _FunctionImplementation implements Function native "Function" { | |
| 19 /** | |
| 20 * Generates a dynamic call stub for a function. | |
| 21 * Our goal is to create a stub method like this on-the-fly: | |
| 22 * function($0, $1, capture) { return this($0, $1, true, capture); } | |
| 23 * | |
| 24 * This stub then replaces the dynamic one on Function, with one that is | |
| 25 * specialized for that particular function, taking into account its default | |
| 26 * arguments. | |
| 27 */ | |
| 28 _genStub(argsLength, [names]) native @''' | |
| 29 // Fast path #1: if no named arguments and arg count matches. | |
| 30 var thisLength = this.$length || this.length; | |
| 31 if (thisLength == argsLength && !names) { | |
| 32 return this; | |
| 33 } | |
| 34 | |
| 35 var paramsNamed = this.$optional ? (this.$optional.length / 2) : 0; | |
| 36 var paramsBare = thisLength - paramsNamed; | |
| 37 var argsNamed = names ? names.length : 0; | |
| 38 var argsBare = argsLength - argsNamed; | |
| 39 | |
| 40 // Check we got the right number of arguments | |
| 41 if (argsBare < paramsBare || argsLength > thisLength || | |
| 42 argsNamed > paramsNamed) { | |
| 43 return function() { | |
| 44 $throw(new _ArgumentMismatchException( | |
| 45 'Wrong number of arguments to function. Expected ' + paramsBare + | |
| 46 ' positional arguments and at most ' + paramsNamed + | |
| 47 ' named arguments, but got ' + argsBare + | |
| 48 ' positional arguments and ' + argsNamed + ' named arguments.')); | |
| 49 }; | |
| 50 } | |
| 51 | |
| 52 // First, fill in all of the default values | |
| 53 var p = new Array(paramsBare); | |
| 54 if (paramsNamed) { | |
| 55 p = p.concat(this.$optional.slice(paramsNamed)); | |
| 56 } | |
| 57 // Fill in positional args | |
| 58 var a = new Array(argsLength); | |
| 59 for (var i = 0; i < argsBare; i++) { | |
| 60 p[i] = a[i] = '$' + i; | |
| 61 } | |
| 62 // Then overwrite with supplied values for optional args | |
| 63 var lastParameterIndex; | |
| 64 var namesInOrder = true; | |
| 65 for (var i = 0; i < argsNamed; i++) { | |
| 66 var name = names[i]; | |
| 67 a[i + argsBare] = name; | |
| 68 var j = this.$optional.indexOf(name); | |
| 69 if (j < 0 || j >= paramsNamed) { | |
| 70 return function() { | |
| 71 $throw(new _ArgumentMismatchException( | |
| 72 'Named argument "' + name + '" was not expected by function.' + | |
| 73 ' Did you forget to mark the function parameter [optional]?')); | |
| 74 }; | |
| 75 } else if (lastParameterIndex && lastParameterIndex > j) { | |
| 76 namesInOrder = false; | |
| 77 } | |
| 78 p[j + paramsBare] = name; | |
| 79 lastParameterIndex = j; | |
| 80 } | |
| 81 | |
| 82 if (thisLength == argsLength && namesInOrder) { | |
| 83 // Fast path #2: named arguments, but they're in order and all supplied. | |
| 84 return this; | |
| 85 } | |
| 86 | |
| 87 // Note: using Function instead of 'eval' to get a clean scope. | |
| 88 // TODO(jmesserly): evaluate the performance of these stubs. | |
| 89 var f = 'function(' + a.join(',') + '){return $f(' + p.join(',') + ');}'; | |
| 90 return new Function('$f', 'return ' + f + '').call(null, this); | |
| 91 ''' { | |
| 92 throw new _ArgumentMismatchException(''); | |
| 93 } | |
| 94 } | |
| OLD | NEW |