OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 library services.src.completion.statement; | 5 library services.src.completion.statement; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:analysis_server/plugin/protocol/protocol.dart'; | 9 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
10 import 'package:analysis_server/src/protocol_server.dart' hide Element; | 10 import 'package:analysis_server/src/protocol_server.dart' hide Element; |
(...skipping 19 matching lines...) Expand all Loading... |
30 static const NO_COMPLETION = | 30 static const NO_COMPLETION = |
31 const StatementCompletionKind('No_COMPLETION', 'No completion available'); | 31 const StatementCompletionKind('No_COMPLETION', 'No completion available'); |
32 static const SIMPLE_ENTER = const StatementCompletionKind( | 32 static const SIMPLE_ENTER = const StatementCompletionKind( |
33 'SIMPLE_ENTER', "Insert a newline at the end of the current line"); | 33 'SIMPLE_ENTER', "Insert a newline at the end of the current line"); |
34 static const SIMPLE_SEMICOLON = const StatementCompletionKind( | 34 static const SIMPLE_SEMICOLON = const StatementCompletionKind( |
35 'SIMPLE_SEMICOLON', "Add a semicolon and newline"); | 35 'SIMPLE_SEMICOLON', "Add a semicolon and newline"); |
36 static const COMPLETE_DO_STMT = const StatementCompletionKind( | 36 static const COMPLETE_DO_STMT = const StatementCompletionKind( |
37 'COMPLETE_DO_STMT', "Complete do-statement"); | 37 'COMPLETE_DO_STMT', "Complete do-statement"); |
38 static const COMPLETE_IF_STMT = const StatementCompletionKind( | 38 static const COMPLETE_IF_STMT = const StatementCompletionKind( |
39 'COMPLETE_IF_STMT', "Complete if-statement"); | 39 'COMPLETE_IF_STMT', "Complete if-statement"); |
| 40 static const COMPLETE_FOR_STMT = const StatementCompletionKind( |
| 41 'COMPLETE_FOR_STMT', "Complete for-statement"); |
40 static const COMPLETE_WHILE_STMT = const StatementCompletionKind( | 42 static const COMPLETE_WHILE_STMT = const StatementCompletionKind( |
41 'COMPLETE_WHILE_STMT', "Complete while-statement"); | 43 'COMPLETE_WHILE_STMT', "Complete while-statement"); |
42 } | 44 } |
43 | 45 |
44 /** | 46 /** |
45 * A description of a statement completion. | 47 * A description of a statement completion. |
46 * | 48 * |
47 * Clients may not extend, implement or mix-in this class. | 49 * Clients may not extend, implement or mix-in this class. |
48 */ | 50 */ |
49 class StatementCompletion { | 51 class StatementCompletion { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 error.offset <= node.offset + node.length) { | 174 error.offset <= node.offset + node.length) { |
173 if (error.errorCode is! HintCode) { | 175 if (error.errorCode is! HintCode) { |
174 errors.add(error); | 176 errors.add(error); |
175 } | 177 } |
176 } | 178 } |
177 } | 179 } |
178 | 180 |
179 // TODO(messick) Consider changing (some of) this to a visitor. | 181 // TODO(messick) Consider changing (some of) this to a visitor. |
180 if (_complete_ifStatement() || | 182 if (_complete_ifStatement() || |
181 _complete_doStatement() || | 183 _complete_doStatement() || |
| 184 _complete_forStatement() || |
| 185 _complete_forEachStatement() || |
| 186 _complete_switchStatement() || |
| 187 _complete_tryStatement() || |
182 _complete_whileStatement() || | 188 _complete_whileStatement() || |
183 _complete_simpleSemicolon() || | 189 _complete_simpleSemicolon() || |
184 _complete_simpleEnter()) { | 190 _complete_simpleEnter()) { |
185 return completion; | 191 return completion; |
186 } | 192 } |
187 return NO_COMPLETION; | 193 return NO_COMPLETION; |
188 } | 194 } |
189 | 195 |
190 void _addIndentEdit(SourceRange range, String oldIndent, String newIndent) { | |
191 SourceEdit edit = utils.createIndentEdit(range, oldIndent, newIndent); | |
192 doSourceChange_addElementEdit(change, unitElement, edit); | |
193 } | |
194 | |
195 void _addInsertEdit(int offset, String text) { | 196 void _addInsertEdit(int offset, String text) { |
196 SourceEdit edit = new SourceEdit(offset, 0, text); | 197 SourceEdit edit = new SourceEdit(offset, 0, text); |
197 doSourceChange_addElementEdit(change, unitElement, edit); | 198 doSourceChange_addElementEdit(change, unitElement, edit); |
198 } | 199 } |
199 | 200 |
200 void _addReplaceEdit(SourceRange range, String text) { | 201 void _addReplaceEdit(SourceRange range, String text) { |
201 SourceEdit edit = new SourceEdit(range.offset, range.length, text); | 202 SourceEdit edit = new SourceEdit(range.offset, range.length, text); |
202 doSourceChange_addElementEdit(change, unitElement, edit); | 203 doSourceChange_addElementEdit(change, unitElement, edit); |
203 } | 204 } |
204 | 205 |
(...skipping 26 matching lines...) Expand all Loading... |
231 text = text.substring(0, text.length - eol.length); | 232 text = text.substring(0, text.length - eol.length); |
232 } | 233 } |
233 return text; | 234 return text; |
234 } | 235 } |
235 | 236 |
236 bool _complete_doStatement() { | 237 bool _complete_doStatement() { |
237 if (errors.isEmpty || node is! DoStatement) { | 238 if (errors.isEmpty || node is! DoStatement) { |
238 return false; | 239 return false; |
239 } | 240 } |
240 DoStatement statement = node; | 241 DoStatement statement = node; |
241 var stmt = new _DoIfWhileStructure( | |
242 statement.whileKeyword, | |
243 statement.leftParenthesis, | |
244 statement.condition, | |
245 statement.rightParenthesis, | |
246 null); | |
247 SourceBuilder sb = _sourceBuilderAfterKeyword(statement.doKeyword); | 242 SourceBuilder sb = _sourceBuilderAfterKeyword(statement.doKeyword); |
248 bool hasWhileKeyword = statement.whileKeyword.lexeme == "while"; | 243 bool hasWhileKeyword = statement.whileKeyword.lexeme == "while"; |
249 int exitDelta = 0; | 244 int exitDelta = 0; |
250 if (statement.body is EmptyStatement) { | 245 if (statement.body is EmptyStatement) { |
251 String text = utils.getNodeText(statement.body); | 246 String text = utils.getNodeText(statement.body); |
252 int delta = 0; | 247 int delta = 0; |
253 if (text.startsWith(';')) { | 248 if (text.startsWith(';')) { |
254 delta = 1; | 249 delta = 1; |
255 _addReplaceEdit(rangeStartLength(statement.body.offset, delta), ''); | 250 _addReplaceEdit(rangeStartLength(statement.body.offset, delta), ''); |
256 if (hasWhileKeyword) { | 251 if (hasWhileKeyword) { |
257 text = utils.getNodeText(statement); | 252 text = utils.getNodeText(statement); |
258 if (text.indexOf(new RegExp(r'do\s*;\s*while')) == 0) { | 253 if (text.indexOf(new RegExp(r'do\s*;\s*while')) == 0) { |
259 int end = text.indexOf('while'); | 254 int end = text.indexOf('while'); |
260 int start = text.indexOf(';') + 1; | 255 int start = text.indexOf(';') + 1; |
261 delta += end - start - 1; | 256 delta += end - start - 1; |
262 _addReplaceEdit( | 257 _addReplaceEdit( |
263 rangeStartLength(start + statement.offset, end - start), ' '); | 258 rangeStartLength(start + statement.offset, end - start), ' '); |
264 } | 259 } |
265 } | 260 } |
266 sb = new SourceBuilder(file, sb.offset + delta); | 261 sb = new SourceBuilder(file, sb.offset + delta); |
267 sb.append(' '); | 262 sb.append(' '); |
268 } | 263 } |
269 _appendEmptyBraces( | 264 _appendEmptyBraces(sb, |
270 sb, !(hasWhileKeyword && _isEmptyExpression(statement.condition))); | 265 !(hasWhileKeyword && _isSyntheticExpression(statement.condition))); |
271 if (delta != 0) { | 266 if (delta != 0) { |
272 exitDelta = sb.length - delta; | 267 exitDelta = sb.length - delta; |
273 } | 268 } |
274 } else if (_isEmptyBlock(statement.body)) { | 269 } else if (_isEmptyBlock(statement.body)) { |
275 sb = new SourceBuilder(sb.file, statement.body.end); | 270 sb = new SourceBuilder(sb.file, statement.body.end); |
276 } | 271 } |
277 SourceBuilder sb2; | 272 SourceBuilder sb2; |
278 if (hasWhileKeyword) { | 273 if (hasWhileKeyword) { |
| 274 var stmt = new _KeywordConditionBlockStructure( |
| 275 statement.whileKeyword, |
| 276 statement.leftParenthesis, |
| 277 statement.condition, |
| 278 statement.rightParenthesis, |
| 279 null); |
279 sb2 = _complete_keywordCondition(stmt); | 280 sb2 = _complete_keywordCondition(stmt); |
280 if (sb2.length == 0) { | 281 if (sb2.length == 0) { |
281 // true if condition is '()' | 282 // true if condition is '()' |
282 if (exitPosition != null) { | 283 if (exitPosition != null) { |
283 if (statement.semicolon.lexeme.isEmpty) { | 284 if (statement.semicolon.isSynthetic) { |
284 _insertBuilder(sb); | 285 _insertBuilder(sb); |
285 sb = new SourceBuilder(file, exitPosition.offset + 1); | 286 sb = new SourceBuilder(file, exitPosition.offset + 1); |
286 sb.append(';'); | 287 sb.append(';'); |
287 } | 288 } |
288 } | 289 } |
289 } else { | 290 } else { |
290 if (sb.exitOffset == null && sb2?.exitOffset != null) { | 291 if (sb.exitOffset == null && sb2?.exitOffset != null) { |
291 _insertBuilder(sb); | 292 _insertBuilder(sb); |
292 sb = sb2; | 293 sb = sb2; |
293 sb.append(';'); | 294 sb.append(';'); |
294 } else { | 295 } else { |
295 sb.append(sb2.toString()); | 296 sb.append(sb2.toString()); |
296 } | 297 } |
297 } | 298 } |
298 } else { | 299 } else { |
299 sb.append(" while ("); | 300 sb.append(" while ("); |
300 sb.setExitOffset(); | 301 sb.setExitOffset(); |
301 sb.append(");"); | 302 sb.append(");"); |
302 } | 303 } |
303 _insertBuilder(sb); | 304 _insertBuilder(sb); |
304 if (exitDelta != 0) { | 305 if (exitDelta != 0) { |
305 exitPosition = | 306 exitPosition = |
306 new Position(exitPosition.file, exitPosition.offset + exitDelta); | 307 new Position(exitPosition.file, exitPosition.offset + exitDelta); |
307 } | 308 } |
308 _setCompletion(DartStatementCompletion.COMPLETE_DO_STMT); | 309 _setCompletion(DartStatementCompletion.COMPLETE_DO_STMT); |
309 return true; | 310 return true; |
310 } | 311 } |
311 | 312 |
| 313 bool _complete_forEachStatement() { |
| 314 // TODO(messick) Implement _complete_forEachStatement |
| 315 return false; |
| 316 } |
| 317 |
| 318 bool _complete_forStatement() { |
| 319 if (errors.isEmpty || node is! ForStatement) { |
| 320 return false; |
| 321 } |
| 322 ForStatement forNode = node; |
| 323 SourceBuilder sb; |
| 324 int delta = 0; |
| 325 if (forNode.leftParenthesis.isSynthetic) { |
| 326 if (!forNode.rightParenthesis.isSynthetic) { |
| 327 return false; |
| 328 } |
| 329 // keywordOnly (unit test name suffix that exercises this branch) |
| 330 sb = _sourceBuilderAfterKeyword(forNode.forKeyword); |
| 331 sb.append('('); |
| 332 sb.setExitOffset(); |
| 333 sb.append(')'); |
| 334 } else { |
| 335 if (!forNode.rightSeparator.isSynthetic) { |
| 336 // Fully-defined init, cond, updaters so nothing more needed here. |
| 337 // emptyParts |
| 338 sb = new SourceBuilder(file, forNode.rightParenthesis.offset + 1); |
| 339 } else if (!forNode.leftSeparator.isSynthetic) { |
| 340 if (_isSyntheticExpression(forNode.condition)) { |
| 341 exitPosition = _newPosition(forNode.leftSeparator.offset + 1); |
| 342 String text = utils |
| 343 .getNodeText(forNode) |
| 344 .substring(forNode.leftSeparator.offset - forNode.offset); |
| 345 if (text.startsWith(new RegExp(r';\s*\)'))) { |
| 346 // emptyCondition |
| 347 int end = text.indexOf(')'); |
| 348 sb = new SourceBuilder(file, forNode.leftSeparator.offset); |
| 349 // TODO(messick) Consider adding two semicolons here. |
| 350 _addReplaceEdit(rangeStartLength(sb.offset, end), '; '); |
| 351 delta = end - '; '.length; |
| 352 } else { |
| 353 // emptyInitializersEmptyCondition |
| 354 exitPosition = _newPosition(forNode.rightParenthesis.offset); |
| 355 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); |
| 356 } |
| 357 } else { |
| 358 // emptyUpdaters |
| 359 exitPosition = _newPosition(forNode.rightSeparator.offset); |
| 360 sb = new SourceBuilder(file, forNode.rightSeparator.offset); |
| 361 _addReplaceEdit(rangeStartLength(sb.offset, 0), '; '); |
| 362 delta = -'; '.length; |
| 363 } |
| 364 } else if (_isSyntheticExpression(forNode.initialization)) { |
| 365 // emptyInitializers |
| 366 exitPosition = _newPosition(forNode.rightParenthesis.offset); |
| 367 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); |
| 368 } else { |
| 369 int start = forNode.condition.offset + forNode.condition.length; |
| 370 String text = |
| 371 utils.getNodeText(forNode).substring(start - forNode.offset); |
| 372 if (text.startsWith(new RegExp(r'\s*\)'))) { |
| 373 // missingLeftSeparator |
| 374 int end = text.indexOf(')'); |
| 375 sb = new SourceBuilder(file, start); |
| 376 _addReplaceEdit(rangeStartLength(start, end), '; '); |
| 377 delta = end - '; '.length; |
| 378 exitPosition = new Position(file, start); |
| 379 } else { |
| 380 // Not possible; any comment following init is attached to init. |
| 381 exitPosition = _newPosition(forNode.rightParenthesis.offset); |
| 382 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); |
| 383 } |
| 384 } |
| 385 } |
| 386 if (forNode.body is EmptyStatement) { |
| 387 // keywordOnly |
| 388 sb.append(' '); |
| 389 _appendEmptyBraces(sb, exitPosition == null); |
| 390 } |
| 391 if (delta != 0 && exitPosition != null) { |
| 392 // missingLeftSeparator |
| 393 exitPosition = new Position(file, exitPosition.offset - delta); |
| 394 } |
| 395 _insertBuilder(sb); |
| 396 _setCompletion(DartStatementCompletion.COMPLETE_FOR_STMT); |
| 397 return true; |
| 398 } |
| 399 |
312 bool _complete_ifOrWhileStatement( | 400 bool _complete_ifOrWhileStatement( |
313 _DoIfWhileStructure statement, StatementCompletionKind kind) { | 401 _KeywordConditionBlockStructure statement, StatementCompletionKind kind) { |
314 SourceBuilder sb = _complete_keywordCondition(statement); | 402 SourceBuilder sb = _complete_keywordCondition(statement); |
315 if (statement.block is EmptyStatement) { | 403 if (statement.block is EmptyStatement) { |
316 sb.append(' '); | 404 sb.append(' '); |
317 _appendEmptyBraces(sb, exitPosition == null); | 405 _appendEmptyBraces(sb, exitPosition == null); |
318 } | 406 } |
319 _insertBuilder(sb); | 407 _insertBuilder(sb); |
320 _setCompletion(kind); | 408 _setCompletion(kind); |
321 return true; | 409 return true; |
322 } | 410 } |
323 | 411 |
324 bool _complete_ifStatement() { | 412 bool _complete_ifStatement() { |
325 if (errors.isEmpty || node is! IfStatement) { | 413 if (errors.isEmpty || node is! IfStatement) { |
326 return false; | 414 return false; |
327 } | 415 } |
328 IfStatement ifNode = node; | 416 IfStatement ifNode = node; |
329 if (ifNode != null) { | 417 if (ifNode != null) { |
330 if (ifNode.elseKeyword != null) { | 418 if (ifNode.elseKeyword != null) { |
331 return false; | 419 return false; |
332 } | 420 } |
333 var stmt = new _DoIfWhileStructure( | 421 var stmt = new _KeywordConditionBlockStructure( |
334 ifNode.ifKeyword, | 422 ifNode.ifKeyword, |
335 ifNode.leftParenthesis, | 423 ifNode.leftParenthesis, |
336 ifNode.condition, | 424 ifNode.condition, |
337 ifNode.rightParenthesis, | 425 ifNode.rightParenthesis, |
338 ifNode.thenStatement); | 426 ifNode.thenStatement); |
339 return _complete_ifOrWhileStatement( | 427 return _complete_ifOrWhileStatement( |
340 stmt, DartStatementCompletion.COMPLETE_IF_STMT); | 428 stmt, DartStatementCompletion.COMPLETE_IF_STMT); |
341 } | 429 } |
342 return false; | 430 return false; |
343 } | 431 } |
344 | 432 |
345 SourceBuilder _complete_keywordCondition(_DoIfWhileStructure statement) { | 433 SourceBuilder _complete_keywordCondition( |
| 434 _KeywordConditionBlockStructure statement) { |
346 SourceBuilder sb; | 435 SourceBuilder sb; |
347 String text = _baseNodeText(node); | 436 if (statement.leftParenthesis.isSynthetic) { |
348 if (statement.leftParenthesis.lexeme.isEmpty) { | 437 if (!statement.rightParenthesis.isSynthetic) { |
349 if (!statement.rightParenthesis.lexeme.isEmpty) { | |
350 // Quite unlikely to see this so don't try to fix it. | 438 // Quite unlikely to see this so don't try to fix it. |
351 return null; | 439 return null; |
352 } | 440 } |
353 sb = _sourceBuilderAfterKeyword(statement.keyword); | 441 sb = _sourceBuilderAfterKeyword(statement.keyword); |
354 sb.append('('); | 442 sb.append('('); |
355 sb.setExitOffset(); | 443 sb.setExitOffset(); |
356 sb.append(')'); | 444 sb.append(')'); |
357 } else { | 445 } else { |
358 if (_isEmptyExpression(statement.condition)) { | 446 if (_isSyntheticExpression(statement.condition)) { |
359 exitPosition = _newPosition(statement.leftParenthesis.offset + 1); | 447 exitPosition = _newPosition(statement.leftParenthesis.offset + 1); |
360 sb = new SourceBuilder(file, statement.rightParenthesis.offset + 1); | 448 sb = new SourceBuilder(file, statement.rightParenthesis.offset + 1); |
361 } else { | 449 } else { |
362 sb = new SourceBuilder(file, statement.rightParenthesis.offset + 1); | 450 sb = new SourceBuilder(file, statement.rightParenthesis.offset + 1); |
363 } | 451 } |
364 } | 452 } |
365 return sb; | 453 return sb; |
366 } | 454 } |
367 | 455 |
368 bool _complete_simpleEnter() { | 456 bool _complete_simpleEnter() { |
(...skipping 18 matching lines...) Expand all Loading... |
387 if (error != null) { | 475 if (error != null) { |
388 int insertOffset = error.offset + error.length; | 476 int insertOffset = error.offset + error.length; |
389 _addInsertEdit(insertOffset, ';'); | 477 _addInsertEdit(insertOffset, ';'); |
390 int offset = _appendNewlinePlusIndent() + 1 /* ';' */; | 478 int offset = _appendNewlinePlusIndent() + 1 /* ';' */; |
391 _setCompletionAt(DartStatementCompletion.SIMPLE_SEMICOLON, offset); | 479 _setCompletionAt(DartStatementCompletion.SIMPLE_SEMICOLON, offset); |
392 return true; | 480 return true; |
393 } | 481 } |
394 return false; | 482 return false; |
395 } | 483 } |
396 | 484 |
| 485 bool _complete_switchStatement() { |
| 486 // TODO(messick) Implement _complete_switchStatement |
| 487 return false; |
| 488 } |
| 489 |
| 490 bool _complete_tryStatement() { |
| 491 // TODO(messick) Implement _complete_tryStatement |
| 492 return false; |
| 493 } |
| 494 |
397 bool _complete_whileStatement() { | 495 bool _complete_whileStatement() { |
398 if (errors.isEmpty || node is! WhileStatement) { | 496 if (errors.isEmpty || node is! WhileStatement) { |
399 return false; | 497 return false; |
400 } | 498 } |
401 WhileStatement whileNode = node; | 499 WhileStatement whileNode = node; |
402 if (whileNode != null) { | 500 if (whileNode != null) { |
403 var stmt = new _DoIfWhileStructure( | 501 var stmt = new _KeywordConditionBlockStructure( |
404 whileNode.whileKeyword, | 502 whileNode.whileKeyword, |
405 whileNode.leftParenthesis, | 503 whileNode.leftParenthesis, |
406 whileNode.condition, | 504 whileNode.condition, |
407 whileNode.rightParenthesis, | 505 whileNode.rightParenthesis, |
408 whileNode.body); | 506 whileNode.body); |
409 return _complete_ifOrWhileStatement( | 507 return _complete_ifOrWhileStatement( |
410 stmt, DartStatementCompletion.COMPLETE_WHILE_STMT); | 508 stmt, DartStatementCompletion.COMPLETE_WHILE_STMT); |
411 } | 509 } |
412 return false; | 510 return false; |
413 } | 511 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 if (exitOffset != null) { | 553 if (exitOffset != null) { |
456 exitPosition = _newPosition(exitOffset); | 554 exitPosition = _newPosition(exitOffset); |
457 } | 555 } |
458 } | 556 } |
459 } | 557 } |
460 | 558 |
461 bool _isEmptyBlock(AstNode stmt) { | 559 bool _isEmptyBlock(AstNode stmt) { |
462 return stmt is Block && stmt.statements.isEmpty; | 560 return stmt is Block && stmt.statements.isEmpty; |
463 } | 561 } |
464 | 562 |
465 bool _isEmptyExpression(Expression expr) { | 563 bool _isSyntheticExpression(Expression expr) { |
466 if (expr is! SimpleIdentifier) { | 564 return expr is SimpleIdentifier && expr.isSynthetic; |
467 return false; | |
468 } | |
469 SimpleIdentifier id = expr as SimpleIdentifier; | |
470 return id.length == 0; | |
471 } | 565 } |
472 | 566 |
473 bool _isEmptyStatement(AstNode stmt) { | 567 bool _isEmptyStatement(AstNode stmt) { |
474 return stmt is EmptyStatement || _isEmptyBlock(stmt); | 568 return stmt is EmptyStatement || _isEmptyBlock(stmt); |
475 } | 569 } |
476 | 570 |
477 Position _newPosition(int offset) { | 571 Position _newPosition(int offset) { |
478 return new Position(file, offset); | 572 return new Position(file, offset); |
479 } | 573 } |
480 | 574 |
(...skipping 21 matching lines...) Expand all Loading... |
502 sb = new SourceBuilder(file, keyword.offset + len); | 596 sb = new SourceBuilder(file, keyword.offset + len); |
503 sb.append(' '); | 597 sb.append(' '); |
504 } else { | 598 } else { |
505 sb = new SourceBuilder(file, keyword.offset + len + 1); | 599 sb = new SourceBuilder(file, keyword.offset + len + 1); |
506 } | 600 } |
507 return sb; | 601 return sb; |
508 } | 602 } |
509 } | 603 } |
510 | 604 |
511 // Encapsulate common structure of if-statement and while-statement. | 605 // Encapsulate common structure of if-statement and while-statement. |
512 class _DoIfWhileStructure { | 606 class _KeywordConditionBlockStructure { |
513 final Token keyword; | 607 final Token keyword; |
514 final Token leftParenthesis, rightParenthesis; | 608 final Token leftParenthesis, rightParenthesis; |
515 final Expression condition; | 609 final Expression condition; |
516 final Statement block; | 610 final Statement block; |
517 | 611 |
518 _DoIfWhileStructure(this.keyword, this.leftParenthesis, this.condition, | 612 _KeywordConditionBlockStructure(this.keyword, this.leftParenthesis, |
519 this.rightParenthesis, this.block); | 613 this.condition, this.rightParenthesis, this.block); |
520 | 614 |
521 int get offset => keyword.offset; | 615 int get offset => keyword.offset; |
522 } | 616 } |
OLD | NEW |