| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 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 | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 | 3 |
| 4 class TagStack { | 4 class TagStack { |
| 5 List<ASTNode> _stack; | 5 List<ASTNode> _stack; |
| 6 | 6 |
| 7 TagStack(var elem) : _stack = [] { | 7 TagStack(var elem) : _stack = [] { |
| 8 _stack.add(elem); | 8 _stack.add(elem); |
| 9 } | 9 } |
| 10 | 10 |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 '</${TokenKind.tagNameFromTokenId(tagToken.kind)}>'); | 364 '</${TokenKind.tagNameFromTokenId(tagToken.kind)}>'); |
| 365 } | 365 } |
| 366 } else { | 366 } else { |
| 367 // Too many end tags. | 367 // Too many end tags. |
| 368 _error('Too many end tags at ' + | 368 _error('Too many end tags at ' + |
| 369 '</${TokenKind.tagNameFromTokenId(tagToken.kind)}>'); | 369 '</${TokenKind.tagNameFromTokenId(tagToken.kind)}>'); |
| 370 } | 370 } |
| 371 } | 371 } |
| 372 } | 372 } |
| 373 } else if (_maybeEat(TokenKind.START_COMMAND)) { | 373 } else if (_maybeEat(TokenKind.START_COMMAND)) { |
| 374 if (_peekIdentifier()) { | 374 Identifier commandName = processAsIdentifier(); |
| 375 var commandName = identifier(); | 375 if (commandName != null) { |
| 376 switch (commandName.name) { | 376 switch (commandName.name) { |
| 377 case "each": | 377 case "each": |
| 378 case "with": | 378 case "with": |
| 379 if (_peekIdentifier()) { | 379 var listName = processAsIdentifier(); |
| 380 var listName = identifier(); | 380 if (listName != null) { |
| 381 var loopItem = processAsIdentifier(); |
| 382 // Is the optional item name specified? |
| 383 // #each lists [item] |
| 384 // #with expression [item] |
| 381 | 385 |
| 382 _eat(TokenKind.RBRACE); | 386 _eat(TokenKind.RBRACE); |
| 383 | 387 |
| 384 var frag = new TemplateElement.fragment( | 388 var frag = new TemplateElement.fragment( |
| 385 _makeSpan(_peekToken.start)); | 389 _makeSpan(_peekToken.start)); |
| 386 TemplateDocument docFrag = processHTML(frag); | 390 TemplateDocument docFrag = processHTML(frag); |
| 387 | 391 |
| 388 if (docFrag != null) { | 392 if (docFrag != null) { |
| 389 var span = _makeSpan(start); | 393 var span = _makeSpan(start); |
| 390 var cmd; | 394 var cmd; |
| 391 if (commandName.name == "each") { | 395 if (commandName.name == "each") { |
| 392 cmd = new TemplateEachCommand(listName, docFrag, span); | 396 cmd = new TemplateEachCommand(listName, loopItem, docFrag, |
| 397 span); |
| 393 } else if (commandName.name == "with") { | 398 } else if (commandName.name == "with") { |
| 394 cmd = new TemplateWithCommand(listName, docFrag, span); | 399 cmd = new TemplateWithCommand(listName, loopItem, docFrag, |
| 400 span); |
| 395 } | 401 } |
| 396 | 402 |
| 397 stack.top().add(cmd); | 403 stack.top().add(cmd); |
| 398 stack.push(cmd); | 404 stack.push(cmd); |
| 399 } | 405 } |
| 400 | 406 |
| 401 // Process ${/commandName} | 407 // Process ${/commandName} |
| 402 _eat(TokenKind.END_COMMAND); | 408 _eat(TokenKind.END_COMMAND); |
| 403 | 409 |
| 404 // Close command ${/commandName} | 410 // Close command ${/commandName} |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 } | 443 } |
| 438 } else { | 444 } else { |
| 439 _error("Missing listname for #each command"); | 445 _error("Missing listname for #each command"); |
| 440 } | 446 } |
| 441 break; | 447 break; |
| 442 case "if": | 448 case "if": |
| 443 break; | 449 break; |
| 444 case "else": | 450 case "else": |
| 445 break; | 451 break; |
| 446 default: | 452 default: |
| 447 _error("Unknown template command"); | 453 // Calling another template. |
| 448 } | 454 int startPos = this._previousToken.end; |
| 455 // Gobble up everything until we hit } |
| 456 while (_peek() != TokenKind.RBRACE && |
| 457 _peek() != TokenKind.END_OF_FILE) { |
| 458 _next(false); |
| 459 } |
| 460 |
| 461 if (_peek() == TokenKind.RBRACE) { |
| 462 int endPos = this._previousToken.end; |
| 463 TemplateCall callNode = new TemplateCall(commandName.name, |
| 464 source.text.substring(startPos, endPos), _makeSpan(start)); |
| 465 stack.top().add(callNode); |
| 466 |
| 467 _next(false); |
| 468 } else { |
| 469 _error("Unknown template command"); |
| 470 } |
| 471 } // End of switch/case |
| 449 } | 472 } |
| 450 } else if (_peekKind(TokenKind.END_COMMAND)) { | 473 } else if (_peekKind(TokenKind.END_COMMAND)) { |
| 451 break; | 474 break; |
| 452 } else { | 475 } else { |
| 453 // Any text or expression nodes? | 476 // Any text or expression nodes? |
| 454 var nodes = processTextNodes(); | 477 var nodes = processTextNodes(); |
| 455 if (nodes.length > 0) { | 478 if (nodes.length > 0) { |
| 456 assert(stack.top() != null); | 479 assert(stack.top() != null); |
| 457 for (var node in nodes) { | 480 for (var node in nodes) { |
| 458 stack.top().add(node); | 481 stack.top().add(node); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 } | 541 } |
| 519 | 542 |
| 520 List<ASTNode> processTextNodes() { | 543 List<ASTNode> processTextNodes() { |
| 521 // May contain TemplateText and TemplateExpression. | 544 // May contain TemplateText and TemplateExpression. |
| 522 List<ASTNode> nodes = []; | 545 List<ASTNode> nodes = []; |
| 523 | 546 |
| 524 int start = _peekToken.start; | 547 int start = _peekToken.start; |
| 525 bool inExpression = false; | 548 bool inExpression = false; |
| 526 StringBuffer stringValue = new StringBuffer(); | 549 StringBuffer stringValue = new StringBuffer(); |
| 527 | 550 |
| 551 // Any text chars between close of tag and text node? |
| 552 if (_previousToken.kind == TokenKind.GREATER_THAN) { |
| 553 // If the next token is } could be the close template token. If user |
| 554 // needs } as token in text node use the entity &125; |
| 555 // TODO(terry): Probably need a &RCURLY entity instead of 125. |
| 556 if (_peek() == TokenKind.ERROR) { |
| 557 // Backup, just past previous token, & rescan we're outside of the tag. |
| 558 tokenizer.index = _previousToken.end; |
| 559 _next(false); |
| 560 } else if (_peek() != TokenKind.RBRACE) { |
| 561 // Yes, grab the chars after the > |
| 562 stringValue.add(_previousToken.source.text.substring( |
| 563 this._previousToken.end, this._peekToken.start)); |
| 564 } |
| 565 } |
| 566 |
| 528 // Gobble up everything until we hit < | 567 // Gobble up everything until we hit < |
| 529 int runningStart = _peekToken.start; | |
| 530 while (_peek() != TokenKind.LESS_THAN && | 568 while (_peek() != TokenKind.LESS_THAN && |
| 531 (_peek() != TokenKind.RBRACE || | 569 (_peek() != TokenKind.RBRACE || |
| 532 (_peek() == TokenKind.RBRACE && inExpression)) && | 570 (_peek() == TokenKind.RBRACE && inExpression)) && |
| 533 _peek() != TokenKind.END_OF_FILE) { | 571 _peek() != TokenKind.END_OF_FILE) { |
| 534 | 572 |
| 535 // Beginning of expression? | 573 // Beginning of expression? |
| 536 if (_peek() == TokenKind.START_EXPRESSION) { | 574 if (_peek() == TokenKind.START_EXPRESSION) { |
| 537 if (stringValue.length > 0) { | 575 if (stringValue.length > 0) { |
| 538 // We have a real text node create the text node. | 576 // We have a real text node create the text node. |
| 539 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start))); | 577 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start))); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 558 } | 596 } |
| 559 | 597 |
| 560 if (stringValue.length > 0) { | 598 if (stringValue.length > 0) { |
| 561 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start))); | 599 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start))); |
| 562 } | 600 } |
| 563 | 601 |
| 564 return nodes; | 602 return nodes; |
| 565 } | 603 } |
| 566 | 604 |
| 567 } | 605 } |
| OLD | NEW |