| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, 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 library _foreign_helper; | |
| 6 | |
| 7 /** | |
| 8 * Emits a JavaScript code fragment parameterized by arguments. | |
| 9 * | |
| 10 * Hash characters `#` in the [codeTemplate] are replaced in left-to-right order | |
| 11 * with expressions that contain the values of, or evaluate to, the arguments. | |
| 12 * The number of hash marks must match the number or arguments. Although | |
| 13 * declared with arguments [arg0] through [arg2], the form actually has no limit | |
| 14 * on the number of arguments. | |
| 15 * | |
| 16 * The [typeDescription] argument is interpreted as a description of the | |
| 17 * behavior of the JavaScript code. Currently it describes the types that may | |
| 18 * be returned by the expression, with the additional behavior that the returned | |
| 19 * values may be fresh instances of the types. The type information must be | |
| 20 * correct as it is trusted by the compiler in optimizations, and it must be | |
| 21 * precise as possible since it is used for native live type analysis to | |
| 22 * tree-shake large parts of the DOM libraries. If poorly written, the | |
| 23 * [typeDescription] will cause unnecessarily bloated programs. (You can check | |
| 24 * for this by compiling with `--verbose`; there is an info message describing | |
| 25 * the number of native (DOM) types that can be removed, which usually should be | |
| 26 * greater than zero.) | |
| 27 * | |
| 28 * The [typeDescription] is a [String] which contains a union of types separated | |
| 29 * by vertical bar `|` symbols, e.g. `"num|String"` describes the union of | |
| 30 * numbers and Strings. There is no type in Dart that is this precise. The | |
| 31 * Dart alternative would be `Object` or `dynamic`, but these types imply that | |
| 32 * the JS-code might also be creating instances of all the DOM types. If `null` | |
| 33 * is possible, it must be specified explicitly, e.g. `"String|Null"`. | |
| 34 * [typeDescription] has several extensions to help describe the behavior more | |
| 35 * accurately. In addition to the union type already described: | |
| 36 * | |
| 37 * + `=Object` is a plain JavaScript object. Some DOM methods return instances | |
| 38 * that have no corresponing Dart type (e.g. cross-frame documents), | |
| 39 * `=Object` can be used to describe these untyped' values. | |
| 40 * | |
| 41 * + `var` (or empty string). If the entire [typeDescription] is `var` (or | |
| 42 * empty string) then the type is `dynamic` but the code is known to not | |
| 43 * create any instances. | |
| 44 * | |
| 45 * Examples: | |
| 46 * | |
| 47 * // Parent window might be an opaque cross-frame window. | |
| 48 * var thing = JS('=Object|Window', '#.parent', myWindow); | |
| 49 * | |
| 50 * Guidelines: | |
| 51 * | |
| 52 * + Do not use any parameter, local, method or field names in the | |
| 53 * [codeTemplate]. These names are all subject to arbitrary renaming by the | |
| 54 * compiler. Pass the values in via `#` substition, and test with the | |
| 55 * `--minify` dart2js command-line option. | |
| 56 * | |
| 57 * + The substituted expressions are values, not locations. | |
| 58 * | |
| 59 * JS('void', '# += "x"', this.field); | |
| 60 * | |
| 61 * `this.field` might not be a substituted as a reference to the field. The | |
| 62 * generated code might accidentally work as intended, but it also might be | |
| 63 * | |
| 64 * var t1 = this.field; | |
| 65 * t1 += "x"; | |
| 66 * | |
| 67 * or | |
| 68 * | |
| 69 * this.get$field() += "x"; | |
| 70 * | |
| 71 * The remedy in this case is to expand the `+=` operator, leaving all | |
| 72 * references to the Dart field as Dart code: | |
| 73 * | |
| 74 * this.field = JS('String', '# + "x"', this.field); | |
| 75 * | |
| 76 * + Never use `#` in function bodies. | |
| 77 * | |
| 78 * This is a variation on the previous guideline. Since `#` is replaced with | |
| 79 * an *expression* and the expression is only valid in the immediate context, | |
| 80 * `#` should never appear in a function body. Doing so might defer the | |
| 81 * evaluation of the expression, and its side effects, until the function is | |
| 82 * called. | |
| 83 * | |
| 84 * For example, | |
| 85 * | |
| 86 * var value = foo(); | |
| 87 * var f = JS('', 'function(){return #}', value) | |
| 88 * | |
| 89 * might result in no immediate call to `foo` and a call to `foo` on every | |
| 90 * call to the JavaScript function bound to `f`. This is better: | |
| 91 * | |
| 92 * var f = JS('', | |
| 93 * '(function(val) { return function(){return val}; })(#)', value); | |
| 94 * | |
| 95 * Since `#` occurs in the immediately evaluated expression, the expression | |
| 96 * is immediately evaluated and bound to `val` in the immediate call. | |
| 97 * | |
| 98 * | |
| 99 * Additional notes. | |
| 100 * | |
| 101 * In the future we may extend [typeDescription] to include other aspects of the | |
| 102 * behavior, for example, separating the returned types from the instantiated | |
| 103 * types, or including effects to allow the compiler to perform more | |
| 104 * optimizations around the code. This might be an extension of [JS] or a new | |
| 105 * function similar to [JS] with additional arguments for the new information. | |
| 106 */ | |
| 107 // Add additional optional arguments if needed. The method is treated internally | |
| 108 // as a variable argument method. | |
| 109 JS(String typeDescription, String codeTemplate, | |
| 110 [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11]) | |
| 111 {} | |
| 112 | |
| 113 /** | |
| 114 * Returns the isolate in which this code is running. | |
| 115 */ | |
| 116 IsolateContext JS_CURRENT_ISOLATE_CONTEXT() {} | |
| 117 | |
| 118 abstract class IsolateContext { | |
| 119 /// Holds a (native) JavaScript instance of Isolate, see | |
| 120 /// finishIsolateConstructorFunction in emitter.dart. | |
| 121 get isolateStatics; | |
| 122 } | |
| 123 | |
| 124 /** | |
| 125 * Invokes [function] in the context of [isolate]. | |
| 126 */ | |
| 127 JS_CALL_IN_ISOLATE(isolate, Function function) {} | |
| 128 | |
| 129 /** | |
| 130 * Converts the Dart closure [function] into a JavaScript closure. | |
| 131 * | |
| 132 * Warning: This is no different from [RAW_DART_FUNCTION_REF] which means care | |
| 133 * must be taken to store the current isolate. | |
| 134 */ | |
| 135 DART_CLOSURE_TO_JS(Function function) {} | |
| 136 | |
| 137 /** | |
| 138 * Returns a raw reference to the JavaScript function which implements | |
| 139 * [function]. | |
| 140 * | |
| 141 * Warning: this is dangerous, you should probably use | |
| 142 * [DART_CLOSURE_TO_JS] instead. The returned object is not a valid | |
| 143 * Dart closure, does not store the isolate context or arity. | |
| 144 * | |
| 145 * A valid example of where this can be used is as the second argument | |
| 146 * to V8's Error.captureStackTrace. See | |
| 147 * https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi. | |
| 148 */ | |
| 149 RAW_DART_FUNCTION_REF(Function function) {} | |
| 150 | |
| 151 /** | |
| 152 * Sets the current isolate to [isolate]. | |
| 153 */ | |
| 154 void JS_SET_CURRENT_ISOLATE(isolate) {} | |
| 155 | |
| 156 /** | |
| 157 * Creates an isolate and returns it. | |
| 158 */ | |
| 159 JS_CREATE_ISOLATE() {} | |
| 160 | |
| 161 /** | |
| 162 * Returns the JavaScript constructor function for Dart's Object class. | |
| 163 * This can be used for type tests, as in | |
| 164 * | |
| 165 * if (JS('bool', '# instanceof #', obj, JS_DART_OBJECT_CONSTRUCTOR())) | |
| 166 * ... | |
| 167 */ | |
| 168 JS_DART_OBJECT_CONSTRUCTOR() {} | |
| 169 | |
| 170 /** | |
| 171 * Returns the interceptor for class [type]. The interceptor is the type's | |
| 172 * constructor's `prototype` property. [type] will typically be the class, not | |
| 173 * an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not | |
| 174 * `JS_INTERCEPTOR_CONSTANT(int)`. | |
| 175 */ | |
| 176 JS_INTERCEPTOR_CONSTANT(Type type) {} | |
| 177 | |
| 178 /** | |
| 179 * Returns the prefix used for generated is checks on classes. | |
| 180 */ | |
| 181 String JS_OPERATOR_IS_PREFIX() {} | |
| 182 | |
| 183 /** | |
| 184 * Returns the prefix used for generated type argument substitutions on classes. | |
| 185 */ | |
| 186 String JS_OPERATOR_AS_PREFIX() {} | |
| 187 | |
| 188 /// Returns the name of the class `Object` in the generated code. | |
| 189 String JS_OBJECT_CLASS_NAME() {} | |
| 190 | |
| 191 /// Returns the name of the class `Null` in the generated code. | |
| 192 String JS_NULL_CLASS_NAME() {} | |
| 193 | |
| 194 /// Returns the name of the class `Function` in the generated code. | |
| 195 String JS_FUNCTION_CLASS_NAME() {} | |
| 196 | |
| 197 /** | |
| 198 * Returns the field name used for determining if an object or its | |
| 199 * interceptor has JavaScript indexing behavior. | |
| 200 */ | |
| 201 String JS_IS_INDEXABLE_FIELD_NAME() {} | |
| 202 | |
| 203 /** | |
| 204 * Returns the object corresponding to Namer.CURRENT_ISOLATE. | |
| 205 */ | |
| 206 JS_CURRENT_ISOLATE() {} | |
| 207 | |
| 208 /// Returns the name used for generated function types on classes and methods. | |
| 209 String JS_SIGNATURE_NAME() {} | |
| 210 | |
| 211 /// Returns the name used to tag typedefs. | |
| 212 String JS_TYPEDEF_TAG() {} | |
| 213 | |
| 214 /// Returns the name used to tag function type representations in JavaScript. | |
| 215 String JS_FUNCTION_TYPE_TAG() {} | |
| 216 | |
| 217 /** | |
| 218 * Returns the name used to tag void return in function type representations | |
| 219 * in JavaScript. | |
| 220 */ | |
| 221 String JS_FUNCTION_TYPE_VOID_RETURN_TAG() {} | |
| 222 | |
| 223 /** | |
| 224 * Returns the name used to tag return types in function type representations | |
| 225 * in JavaScript. | |
| 226 */ | |
| 227 String JS_FUNCTION_TYPE_RETURN_TYPE_TAG() {} | |
| 228 | |
| 229 /** | |
| 230 * Returns the name used to tag required parameters in function type | |
| 231 * representations in JavaScript. | |
| 232 */ | |
| 233 String JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG() {} | |
| 234 | |
| 235 /** | |
| 236 * Returns the name used to tag optional parameters in function type | |
| 237 * representations in JavaScript. | |
| 238 */ | |
| 239 String JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG() {} | |
| 240 | |
| 241 /** | |
| 242 * Returns the name used to tag named parameters in function type | |
| 243 * representations in JavaScript. | |
| 244 */ | |
| 245 String JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG() {} | |
| 246 | |
| 247 /// Returns the JS name for [name] from the Namer. | |
| 248 String JS_GET_NAME(String name) {} | |
| 249 | |
| 250 /// Reads an embedded global. | |
| 251 /// | |
| 252 /// The [name] should be a constant defined in the `_embedded_names` library. | |
| 253 JS_EMBEDDED_GLOBAL(String typeDescription, String name) {} | |
| 254 | |
| 255 /// Returns the state of a flag that is determined by the state of the compiler | |
| 256 /// when the program has been analyzed. | |
| 257 bool JS_GET_FLAG(String name) {} | |
| 258 | |
| 259 /** | |
| 260 * Pretend [code] is executed. Generates no executable code. This is used to | |
| 261 * model effects at some other point in external code. For example, the | |
| 262 * following models an assignment to foo with an unknown value. | |
| 263 * | |
| 264 * var foo; | |
| 265 * | |
| 266 * main() { | |
| 267 * JS_EFFECT((_){ foo = _; }) | |
| 268 * } | |
| 269 * | |
| 270 * TODO(sra): Replace this hack with something to mark the volatile or | |
| 271 * externally initialized elements. | |
| 272 */ | |
| 273 void JS_EFFECT(Function code) { code(null); } | |
| 274 | |
| 275 /** | |
| 276 * Use this class for creating constants that hold JavaScript code. | |
| 277 * For example: | |
| 278 * | |
| 279 * const constant = JS_CONST('typeof window != "undefined"); | |
| 280 * | |
| 281 * This code will generate: | |
| 282 * $.JS_CONST_1 = typeof window != "undefined"; | |
| 283 */ | |
| 284 class JS_CONST { | |
| 285 final String code; | |
| 286 const JS_CONST(this.code); | |
| 287 } | |
| 288 | |
| 289 /** | |
| 290 * JavaScript string concatenation. Inputs must be Strings. Corresponds to the | |
| 291 * HStringConcat SSA instruction and may be constant-folded. | |
| 292 */ | |
| 293 String JS_STRING_CONCAT(String a, String b) { | |
| 294 // This body is unused, only here for type analysis. | |
| 295 return JS('String', '# + #', a, b); | |
| 296 } | |
| OLD | NEW |