| 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 /** | |
| 6 * Traverses the entire code of a function to find whether it contains awaits, | |
| 7 * ensuring they occur only in valid locations. This visitor will *not* recurse | |
| 8 * inside nested function declarations. | |
| 9 */ | |
| 10 class AwaitChecker implements TreeVisitor { | |
| 11 | |
| 12 /** Functions found within the body of the entry function. */ | |
| 13 List<FunctionDefinition> nestedFunctions; | |
| 14 | |
| 15 /** Helper bool to ensure that only the top-level function is analyzed. */ | |
| 16 bool _entryFunction = true; | |
| 17 | |
| 18 /** AST nodes that contain await expressions. */ | |
| 19 NodeSet haveAwait; | |
| 20 | |
| 21 // TODO: track haveExit (return/throw) and haveBreak (break/continue) to | |
| 22 // property transform nodes that don't contain await, but may be affected | |
| 23 AwaitChecker() : nestedFunctions = [], haveAwait = new NodeSet(); | |
| 24 | |
| 25 visitVariableDefinition(VariableDefinition node) { | |
| 26 bool awaitSeen = _visitList(node.values); | |
| 27 if (awaitSeen) haveAwait.add(node); | |
| 28 return awaitSeen; | |
| 29 } | |
| 30 | |
| 31 visitFunctionDefinition(FunctionDefinition node) { | |
| 32 if (_entryFunction) { | |
| 33 _entryFunction = false; | |
| 34 if (node.initializers != null) { | |
| 35 for (Expression e in node.initializers) { | |
| 36 if (e.visit(this)) { | |
| 37 world.error('Await expressions are not allowed in initializers.', | |
| 38 e.span); | |
| 39 } | |
| 40 } | |
| 41 } | |
| 42 if (_visit(node.body)) { | |
| 43 haveAwait.add(node); | |
| 44 // TODO(sigmund) check that return type is Dynamic or a future. | |
| 45 return true; | |
| 46 } | |
| 47 return false; | |
| 48 } else { | |
| 49 // Do not analyze nested functions now, use a separate checker for that. | |
| 50 nestedFunctions.add(node); | |
| 51 return false; | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 _notSupportedStmt(name, node) { | |
| 56 world.error("Await is not supported in '$name' statements yet.", node.span); | |
| 57 } | |
| 58 | |
| 59 _notSupported(name, node) { | |
| 60 world.error( | |
| 61 "Await is not supported in $name yet, try pulling into a tmp var.", | |
| 62 node.span); | |
| 63 } | |
| 64 | |
| 65 visitReturnStatement(ReturnStatement node) { | |
| 66 bool awaitSeen = _visit(node.value); | |
| 67 if (awaitSeen) haveAwait.add(node); | |
| 68 return awaitSeen; | |
| 69 } | |
| 70 | |
| 71 visitThrowStatement(ThrowStatement node) { | |
| 72 bool awaitSeen = _visit(node.value); | |
| 73 if (awaitSeen) haveAwait.add(node); | |
| 74 return awaitSeen; | |
| 75 } | |
| 76 | |
| 77 visitAssertStatement(AssertStatement node) { | |
| 78 bool awaitSeen = node.test.visit(this); | |
| 79 if (awaitSeen) { | |
| 80 haveAwait.add(node); | |
| 81 _notSupportedStmt("assert", node); | |
| 82 } | |
| 83 return awaitSeen; | |
| 84 } | |
| 85 | |
| 86 visitBreakStatement(BreakStatement node) { | |
| 87 return false; | |
| 88 } | |
| 89 | |
| 90 visitContinueStatement(ContinueStatement node) { | |
| 91 return false; | |
| 92 } | |
| 93 | |
| 94 visitIfStatement(IfStatement node) { | |
| 95 bool awaitSeen = node.test.visit(this); | |
| 96 if (node.trueBranch.visit(this)) { | |
| 97 awaitSeen = true; | |
| 98 } | |
| 99 if (_visit(node.falseBranch)) { | |
| 100 awaitSeen = true; | |
| 101 } | |
| 102 if (awaitSeen) haveAwait.add(node); | |
| 103 return awaitSeen; | |
| 104 } | |
| 105 | |
| 106 visitWhileStatement(WhileStatement node) { | |
| 107 bool awaitSeen = node.test.visit(this); | |
| 108 if (_visit(node.body)) awaitSeen = true; | |
| 109 if (awaitSeen) haveAwait.add(node); | |
| 110 return awaitSeen; | |
| 111 } | |
| 112 | |
| 113 visitDoStatement(DoStatement node) { | |
| 114 bool awaitSeen = node.test.visit(this); | |
| 115 if (_visit(node.body)) awaitSeen = true; | |
| 116 if (awaitSeen) { | |
| 117 haveAwait.add(node); | |
| 118 _notSupportedStmt("do while", node); | |
| 119 } | |
| 120 return awaitSeen; | |
| 121 } | |
| 122 | |
| 123 visitForStatement(ForStatement node) { | |
| 124 bool awaitSeen = node.test.visit(this); | |
| 125 if (_visit(node.body)) awaitSeen = true; | |
| 126 if (_visit(node.init)) awaitSeen = true; | |
| 127 if (_visitList(node.step)) awaitSeen = true; | |
| 128 if (awaitSeen) { | |
| 129 haveAwait.add(node); | |
| 130 _notSupportedStmt("for", node); | |
| 131 } | |
| 132 return awaitSeen; | |
| 133 } | |
| 134 | |
| 135 visitForInStatement(ForInStatement node) { | |
| 136 bool awaitSeen = node.list.visit(this); | |
| 137 if (_visit(node.body)) awaitSeen = true; | |
| 138 if (awaitSeen) { | |
| 139 haveAwait.add(node); | |
| 140 _notSupportedStmt("for-in", node); | |
| 141 } | |
| 142 return awaitSeen; | |
| 143 } | |
| 144 | |
| 145 visitTryStatement(TryStatement node) { | |
| 146 bool awaitSeen = (_visit(node.body)); | |
| 147 if (_visitList(node.catches)) awaitSeen = true; | |
| 148 if (_visit(node.finallyBlock)) { | |
| 149 awaitSeen = true; | |
| 150 } | |
| 151 if (awaitSeen) haveAwait.add(node); | |
| 152 return awaitSeen; | |
| 153 } | |
| 154 | |
| 155 visitSwitchStatement(SwitchStatement node) { | |
| 156 bool awaitSeen = node.test.visit(this); | |
| 157 if (_visitList(node.cases)) awaitSeen = true; | |
| 158 if (awaitSeen) { | |
| 159 haveAwait.add(node); | |
| 160 _notSupportedStmt("switch", node); | |
| 161 } | |
| 162 return awaitSeen; | |
| 163 } | |
| 164 | |
| 165 visitBlockStatement(BlockStatement node) { | |
| 166 bool awaitSeen = _visitList(node.body); | |
| 167 if (awaitSeen) haveAwait.add(node); | |
| 168 return awaitSeen; | |
| 169 } | |
| 170 | |
| 171 visitLabeledStatement(LabeledStatement node) { | |
| 172 bool awaitSeen = node.body.visit(this); | |
| 173 if (awaitSeen) haveAwait.add(node); | |
| 174 return awaitSeen; | |
| 175 } | |
| 176 | |
| 177 visitExpressionStatement(ExpressionStatement node) { | |
| 178 bool awaitSeen = node.body.visit(this); | |
| 179 if (awaitSeen) haveAwait.add(node); | |
| 180 return awaitSeen; | |
| 181 } | |
| 182 | |
| 183 visitEmptyStatement(EmptyStatement node) { | |
| 184 return false; | |
| 185 } | |
| 186 | |
| 187 visitLambdaExpression(LambdaExpression node) { | |
| 188 _entryFunction = false; | |
| 189 return node.func.visit(this); | |
| 190 } | |
| 191 | |
| 192 visitCallExpression(CallExpression node) { | |
| 193 bool awaitSeen = node.target.visit(this); | |
| 194 if (_visitList(node.arguments)) awaitSeen = true; | |
| 195 if (awaitSeen) haveAwait.add(node); | |
| 196 return awaitSeen; | |
| 197 } | |
| 198 | |
| 199 visitIndexExpression(IndexExpression node) { | |
| 200 bool awaitSeen = node.target.visit(this); | |
| 201 if (node.index.visit(this)) awaitSeen = true; | |
| 202 if (awaitSeen) haveAwait.add(node); | |
| 203 return awaitSeen; | |
| 204 } | |
| 205 | |
| 206 visitBinaryExpression(BinaryExpression node) { | |
| 207 bool awaitSeen = node.x.visit(this); | |
| 208 if (node.y.visit(this)) awaitSeen = true; | |
| 209 if (awaitSeen) haveAwait.add(node); | |
| 210 return awaitSeen; | |
| 211 } | |
| 212 | |
| 213 visitUnaryExpression(UnaryExpression node) { | |
| 214 // TODO(sigmund): issue errors for ++/-- cases where we expect an l-value. | |
| 215 bool awaitSeen = node.self.visit(this); | |
| 216 if (awaitSeen) { | |
| 217 haveAwait.add(node); | |
| 218 _notSupported("unary expressions", node); | |
| 219 } | |
| 220 return awaitSeen; | |
| 221 } | |
| 222 | |
| 223 visitPostfixExpression(PostfixExpression node) { | |
| 224 // TODO(sigmund): issue errors for ++/-- cases where we expect an l-value. | |
| 225 bool awaitSeen = node.body.visit(this); | |
| 226 if (awaitSeen) { | |
| 227 haveAwait.add(node); | |
| 228 _notSupported("postfix expressions", node); | |
| 229 } | |
| 230 return awaitSeen; | |
| 231 } | |
| 232 | |
| 233 visitNewExpression(NewExpression node) { | |
| 234 bool awaitSeen = _visitList(node.arguments); | |
| 235 if (awaitSeen) { | |
| 236 haveAwait.add(node); | |
| 237 _notSupported("new expressions", node); | |
| 238 } | |
| 239 return awaitSeen; | |
| 240 } | |
| 241 | |
| 242 visitListExpression(ListExpression node) { | |
| 243 bool awaitSeen = _visitList(node.values); | |
| 244 if (awaitSeen) { | |
| 245 haveAwait.add(node); | |
| 246 _notSupported("list literals", node); | |
| 247 } | |
| 248 return awaitSeen; | |
| 249 } | |
| 250 | |
| 251 visitMapExpression(MapExpression node) { | |
| 252 bool awaitSeen = _visitList(node.items); | |
| 253 if (awaitSeen) { | |
| 254 haveAwait.add(node); | |
| 255 _notSupported("map literals", node); | |
| 256 } | |
| 257 return awaitSeen; | |
| 258 } | |
| 259 | |
| 260 visitConditionalExpression(ConditionalExpression node) { | |
| 261 bool awaitSeen = node.test.visit(this); | |
| 262 if (node.trueBranch.visit(this)) awaitSeen = true; | |
| 263 if (node.falseBranch.visit(this)) awaitSeen = true; | |
| 264 if (awaitSeen) { | |
| 265 haveAwait.add(node); | |
| 266 _notSupported("ternary expressions", node); | |
| 267 } | |
| 268 return awaitSeen; | |
| 269 } | |
| 270 | |
| 271 visitIsExpression(IsExpression node) { | |
| 272 bool awaitSeen = node.x.visit(this); | |
| 273 if (awaitSeen) { | |
| 274 haveAwait.add(node); | |
| 275 _notSupported("'is' checks", node); | |
| 276 } | |
| 277 return awaitSeen; | |
| 278 } | |
| 279 | |
| 280 visitParenExpression(ParenExpression node) { | |
| 281 bool awaitSeen = node.body.visit(this); | |
| 282 if (awaitSeen) haveAwait.add(node); | |
| 283 return awaitSeen; | |
| 284 } | |
| 285 | |
| 286 visitAwaitExpression(AwaitExpression node) { | |
| 287 haveAwait.add(node); | |
| 288 return true; | |
| 289 } | |
| 290 | |
| 291 visitDotExpression(DotExpression node) { | |
| 292 bool awaitSeen = node.self.visit(this); | |
| 293 if (awaitSeen) haveAwait.add(node); | |
| 294 return awaitSeen; | |
| 295 } | |
| 296 | |
| 297 visitVarExpression(VarExpression node) { | |
| 298 return false; | |
| 299 } | |
| 300 | |
| 301 visitThisExpression(ThisExpression node) { | |
| 302 return false; | |
| 303 } | |
| 304 | |
| 305 visitSuperExpression(SuperExpression node) { | |
| 306 return false; | |
| 307 } | |
| 308 | |
| 309 visitStringInterpExpression(StringInterpExpression node) { | |
| 310 return false; | |
| 311 } | |
| 312 | |
| 313 visitLiteralExpression(LiteralExpression node) { | |
| 314 return false; | |
| 315 } | |
| 316 | |
| 317 visitArgumentNode(ArgumentNode node) { | |
| 318 bool awaitSeen = node.value.visit(this); | |
| 319 if (awaitSeen) haveAwait.add(node); | |
| 320 return awaitSeen; | |
| 321 } | |
| 322 | |
| 323 visitCatchNode(CatchNode node) { | |
| 324 bool awaitSeen = false; | |
| 325 if (_visit(node.body)) awaitSeen = true; | |
| 326 if (awaitSeen) { | |
| 327 haveAwait.add(node); | |
| 328 _notSupported("catch blocks", node); | |
| 329 } | |
| 330 return awaitSeen; | |
| 331 } | |
| 332 | |
| 333 visitCaseNode(CaseNode node) { | |
| 334 bool awaitSeen = false; | |
| 335 for (Expression e in node.cases) { | |
| 336 if (_visit(e)) { | |
| 337 world.error( | |
| 338 'Await is not allowed in case expressions of switch statements.', | |
| 339 e.span); | |
| 340 awaitSeen = true; | |
| 341 } | |
| 342 } | |
| 343 if (_visitList(node.statements)) awaitSeen = true; | |
| 344 if (awaitSeen) { | |
| 345 haveAwait.add(node); | |
| 346 _notSupported("case blocks", node); | |
| 347 } | |
| 348 return awaitSeen; | |
| 349 } | |
| 350 | |
| 351 /** | |
| 352 * Recurses on every element in the list, returns whether any of them has an | |
| 353 * await. | |
| 354 */ | |
| 355 _visitList(List nodes) { | |
| 356 bool awaitSeen = false; | |
| 357 if (nodes != null) { | |
| 358 for (final n in nodes) { | |
| 359 if (_visit(n)) awaitSeen = true; | |
| 360 } | |
| 361 } | |
| 362 return awaitSeen; | |
| 363 } | |
| 364 | |
| 365 _visit(node) { | |
| 366 if (node == null) return false; | |
| 367 return node.visit(this); | |
| 368 } | |
| 369 } | |
| OLD | NEW |