| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of html; | 5 part of html; |
| 6 | 6 |
| 7 class _ConsoleVariables { | 7 class _ConsoleVariables { |
| 8 Map<String, Object> _data = new Map<String, Object>(); | 8 Map<String, Object> _data = new Map<String, Object>(); |
| 9 | 9 |
| 10 /** | 10 /** |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 */ | 133 */ |
| 134 static Map<String, dynamic> createLocalVariablesMap(List localVariables) { | 134 static Map<String, dynamic> createLocalVariablesMap(List localVariables) { |
| 135 var map = {}; | 135 var map = {}; |
| 136 for (int i = 0; i < localVariables.length; i+=2) { | 136 for (int i = 0; i < localVariables.length; i+=2) { |
| 137 map[stripMemberName(localVariables[i])] = localVariables[i+1]; | 137 map[stripMemberName(localVariables[i])] = localVariables[i+1]; |
| 138 } | 138 } |
| 139 return map; | 139 return map; |
| 140 } | 140 } |
| 141 | 141 |
| 142 static _ConsoleVariables _consoleTempVariables = new _ConsoleVariables(); | 142 static _ConsoleVariables _consoleTempVariables = new _ConsoleVariables(); |
| 143 |
| 144 /** |
| 145 * Header passed in from the Dartium Developer Tools when an expression is |
| 146 * evaluated in the console as opposed to the watch window or another context |
| 147 * that does not expect REPL support. |
| 148 */ |
| 149 static const _CONSOLE_API_SUPPORT_HEADER = |
| 150 'with ((this && this.console && this.console._commandLineAPI) || {}) {\n'; |
| 151 |
| 143 /** | 152 /** |
| 144 * Takes an [expression] and a list of [local] variable and returns an | 153 * Takes an [expression] and a list of [local] variable and returns an |
| 145 * expression for a closure with a body matching the original expression | 154 * expression for a closure with a body matching the original expression |
| 146 * where locals are passed in as arguments. Returns a list containing the | 155 * where locals are passed in as arguments. Returns a list containing the |
| 147 * String expression for the closure and the list of arguments that should | 156 * String expression for the closure and the list of arguments that should |
| 148 * be passed to it. The expression should then be evaluated using | 157 * be passed to it. The expression should then be evaluated using |
| 149 * Dart_EvaluateExpr which will generate a closure that should be invoked | 158 * Dart_EvaluateExpr which will generate a closure that should be invoked |
| 150 * with the list of arguments passed to this method. | 159 * with the list of arguments passed to this method. |
| 151 * | 160 * |
| 152 * For example: | 161 * For example: |
| 153 * <code>wrapExpressionAsClosure("foo + bar", ["bar", 40, "foo", 2])</code> | 162 * <code> |
| 163 * _consoleTempVariables = {'a' : someValue, 'b': someOtherValue} |
| 164 * wrapExpressionAsClosure("${_CONSOLE_API_SUPPORT_HEADER}foo + bar + a", |
| 165 * ["bar", 40, "foo", 2]) |
| 166 * </code> |
| 154 * will return: | 167 * will return: |
| 155 * <code>["(final $var, final bar, final foo) => foo + bar", [40, 2]]</code> | 168 * <code> |
| 169 * ["""(final $consoleVariables, final bar, final foo, final a, final b) => |
| 170 * (foo + bar + a |
| 171 * )""", |
| 172 * [_consoleTempVariables, 40, 2, someValue, someOtherValue]] |
| 173 * </code> |
| 156 */ | 174 */ |
| 157 static List wrapExpressionAsClosure(String expression, List locals) { | 175 static List wrapExpressionAsClosure(String expression, List locals) { |
| 176 // FIXME: dartbug.com/10434 find a less fragile way to determine whether |
| 177 // we need to strip off console API support added by InjectedScript. |
| 158 var args = {}; | 178 var args = {}; |
| 159 var sb = new StringBuffer("("); | 179 var sb = new StringBuffer("("); |
| 160 addArg(arg, value) { | 180 addArg(arg, value) { |
| 161 arg = stripMemberName(arg); | 181 arg = stripMemberName(arg); |
| 162 if (args.containsKey(arg)) return; | 182 if (args.containsKey(arg)) return; |
| 163 // We ignore arguments with the name 'this' rather than throwing an | 183 // We ignore arguments with the name 'this' rather than throwing an |
| 164 // exception because Dart_GetLocalVariables includes 'this' and it | 184 // exception because Dart_GetLocalVariables includes 'this' and it |
| 165 // is more convenient to filter it out here than from C++ code. | 185 // is more convenient to filter it out here than from C++ code. |
| 166 // 'this' needs to be handled by calling Dart_EvaluateExpr with | 186 // 'this' needs to be handled by calling Dart_EvaluateExpr with |
| 167 // 'this' as the target rather than by passing it as an argument. | 187 // 'this' as the target rather than by passing it as an argument. |
| 168 if (arg == 'this') return; | 188 if (arg == 'this') return; |
| 169 if (args.isNotEmpty) { | 189 if (args.isNotEmpty) { |
| 170 sb.write(", "); | 190 sb.write(", "); |
| 171 } | 191 } |
| 172 sb.write("final $arg"); | 192 sb.write("final $arg"); |
| 173 args[arg] = value; | 193 args[arg] = value; |
| 174 } | 194 } |
| 175 | 195 |
| 176 addArg("\$var", _consoleTempVariables); | 196 if (expression.indexOf(_CONSOLE_API_SUPPORT_HEADER) == 0) { |
| 197 expression = expression.substring(expression.indexOf('\n') + 1); |
| 198 expression = expression.substring(0, expression.lastIndexOf('\n')); |
| 177 | 199 |
| 178 for (int i = 0; i < locals.length; i+= 2) { | 200 addArg("\$consoleVariables", _consoleTempVariables); |
| 179 addArg(locals[i], locals[i+1]); | 201 |
| 202 // FIXME: use a real Dart tokenizer. The following regular expressions |
| 203 // only allow setting variables at the immediate start of the expression |
| 204 // to limit the number of edge cases we have to handle. |
| 205 |
| 206 // Match expressions that start with "var x" |
| 207 final _VARIABLE_DECLARATION = new RegExp("^(\\s*)var\\s+(\\w+)"); |
| 208 // Match expressions that start with "someExistingConsoleVar =" |
| 209 final _SET_VARIABLE = new RegExp("^(\\s*)(\\w+)(\\s*=)"); |
| 210 // Match trailing semicolons. |
| 211 final _ENDING_SEMICOLONS = new RegExp("(;\\s*)*\$"); |
| 212 expression = expression.replaceAllMapped(_VARIABLE_DECLARATION, |
| 213 (match) { |
| 214 var variableName = match[2]; |
| 215 // Set the console variable if it isn't already set. |
| 216 if (!_consoleTempVariables._data.containsKey(variableName)) { |
| 217 _consoleTempVariables._data[variableName] = null; |
| 218 } |
| 219 return "${match[1]}\$consoleVariables.${variableName}"; |
| 220 }); |
| 221 |
| 222 expression = expression.replaceAllMapped(_SET_VARIABLE, |
| 223 (match) { |
| 224 var variableName = match[2]; |
| 225 // Only rewrite if the name matches an existing console variable. |
| 226 if (_consoleTempVariables._data.containsKey(variableName)) { |
| 227 return "${match[1]}\$consoleVariables.${variableName}${match[3]}"; |
| 228 } else { |
| 229 return match[0]; |
| 230 } |
| 231 }); |
| 232 |
| 233 // We only allow dart expressions not Dart statements. Silently remove |
| 234 // trailing semicolons the user might have added by accident to reduce the |
| 235 // number of spurious compile errors. |
| 236 expression = expression.replaceFirst(_ENDING_SEMICOLONS, ""); |
| 180 } | 237 } |
| 181 sb..write(')=>\n$expression'); | 238 |
| 239 if (locals != null) { |
| 240 for (int i = 0; i < locals.length; i+= 2) { |
| 241 addArg(locals[i], locals[i+1]); |
| 242 } |
| 243 } |
| 244 // Inject all the already defined console variables. |
| 245 _consoleTempVariables._data.forEach(addArg); |
| 246 |
| 247 // TODO(jacobr): remove the parentheses around the expresson once |
| 248 // dartbug.com/13723 is fixed. Currently we wrap expression in parentheses |
| 249 // to ensure only valid Dart expressions are allowed. Otherwise the DartVM |
| 250 // quietly ignores trailing Dart statements resulting in user confusion |
| 251 // when part of an invalid expression they entered is ignored. |
| 252 sb..write(') => (\n$expression\n)'); |
| 182 return [sb.toString(), args.values.toList(growable: false)]; | 253 return [sb.toString(), args.values.toList(growable: false)]; |
| 183 } | 254 } |
| 184 | 255 |
| 185 /** | 256 /** |
| 257 * TODO(jacobr): this is a big hack to get around the fact that we are still |
| 258 * passing some JS expression to the evaluate method even when in a Dart |
| 259 * context. |
| 260 */ |
| 261 static bool isJsExpression(String expression) => |
| 262 expression.startsWith("(function getCompletions"); |
| 263 |
| 264 /** |
| 265 * Returns a list of completions to use if the receiver is o. |
| 266 */ |
| 267 static List<String> getCompletions(o) { |
| 268 MirrorSystem system = currentMirrorSystem(); |
| 269 var completions = new Set<String>(); |
| 270 addAll(Map<Symbol, dynamic> map, bool isStatic) { |
| 271 map.forEach((symbol, mirror) { |
| 272 if (mirror.isStatic == isStatic && !mirror.isPrivate) { |
| 273 var name = MirrorSystem.getName(symbol); |
| 274 if (mirror is MethodMirror && mirror.isSetter) |
| 275 name = name.substring(0, name.length - 1); |
| 276 completions.add(name); |
| 277 } |
| 278 }); |
| 279 } |
| 280 |
| 281 addForClass(ClassMirror mirror, bool isStatic) { |
| 282 if (mirror == null) |
| 283 return; |
| 284 addAll(mirror.members, isStatic); |
| 285 if (mirror.superclass != null) |
| 286 addForClass(mirror.superclass, isStatic); |
| 287 for (var interface in mirror.superinterfaces) { |
| 288 addForClass(interface, isStatic); |
| 289 } |
| 290 } |
| 291 |
| 292 if (o is Type) { |
| 293 addForClass(reflectClass(o), true); |
| 294 } else { |
| 295 addForClass(reflect(o).type, false); |
| 296 } |
| 297 return completions.toList(growable: false); |
| 298 } |
| 299 |
| 300 /** |
| 186 * Convenience helper to get the keys of a [Map] as a [List]. | 301 * Convenience helper to get the keys of a [Map] as a [List]. |
| 187 */ | 302 */ |
| 188 static List getMapKeyList(Map map) => map.keys.toList(); | 303 static List getMapKeyList(Map map) => map.keys.toList(); |
| 189 | 304 |
| 190 /** | 305 /** |
| 191 * Returns the keys of an arbitrary Dart Map encoded as unique Strings. | 306 * Returns the keys of an arbitrary Dart Map encoded as unique Strings. |
| 192 * Keys that are strings are left unchanged except that the prefix ":" is | 307 * Keys that are strings are left unchanged except that the prefix ":" is |
| 193 * added to disambiguate keys from other Dart members. | 308 * added to disambiguate keys from other Dart members. |
| 194 * Keys that are not strings have # followed by the index of the key in the ma
p | 309 * Keys that are not strings have # followed by the index of the key in the ma
p |
| 195 * prepended to disambuguate. This scheme is simplistic but easy to encode and | 310 * prepended to disambuguate. This scheme is simplistic but easy to encode and |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 _send(msg) { | 625 _send(msg) { |
| 511 _sendToHelperIsolate(msg, _sendPort); | 626 _sendToHelperIsolate(msg, _sendPort); |
| 512 } | 627 } |
| 513 | 628 |
| 514 bool get isActive => _isActive; | 629 bool get isActive => _isActive; |
| 515 } | 630 } |
| 516 | 631 |
| 517 get _pureIsolateTimerFactoryClosure => | 632 get _pureIsolateTimerFactoryClosure => |
| 518 ((int milliSeconds, void callback(Timer time), bool repeating) => | 633 ((int milliSeconds, void callback(Timer time), bool repeating) => |
| 519 new _PureIsolateTimer(milliSeconds, callback, repeating)); | 634 new _PureIsolateTimer(milliSeconds, callback, repeating)); |
| OLD | NEW |