| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 // This code was auto-generated, is not intended to be edited, and is subject to | 5 // This code was auto-generated, is not intended to be edited, and is subject to |
| 6 // significant change. Please see the README file for more information. | 6 // significant change. Please see the README file for more information. |
| 7 | 7 |
| 8 library engine.html; | 8 library engine.html; |
| 9 | 9 |
| 10 import 'dart:collection'; | 10 import 'dart:collection'; |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 static Element getElement2(HtmlUnit htmlUnit, int offset) { | 270 static Element getElement2(HtmlUnit htmlUnit, int offset) { |
| 271 Expression expression = getExpression(htmlUnit, offset); | 271 Expression expression = getExpression(htmlUnit, offset); |
| 272 return getElement(expression); | 272 return getElement(expression); |
| 273 } | 273 } |
| 274 | 274 |
| 275 /** | 275 /** |
| 276 * Returns the [Element] to open when requested at the given [Expression]. | 276 * Returns the [Element] to open when requested at the given [Expression]. |
| 277 */ | 277 */ |
| 278 static Element getElementToOpen(HtmlUnit htmlUnit, Expression expression) { | 278 static Element getElementToOpen(HtmlUnit htmlUnit, Expression expression) { |
| 279 Element element = getElement(expression); | 279 Element element = getElement(expression); |
| 280 // special cases for Angular |
| 280 if (isAngular(htmlUnit)) { | 281 if (isAngular(htmlUnit)) { |
| 282 // replace artificial controller variable Element with controller ClassEle
ment |
| 281 if (element is VariableElement) { | 283 if (element is VariableElement) { |
| 282 VariableElement variable = element as VariableElement; | 284 VariableElement variable = element as VariableElement; |
| 283 Type2 type = variable.type; | 285 Type2 type = variable.type; |
| 284 if (variable.nameOffset == 0 && type is InterfaceType) { | 286 if (variable.nameOffset == 0 && type is InterfaceType) { |
| 285 element = type.element; | 287 element = type.element; |
| 286 } | 288 } |
| 287 } | 289 } |
| 288 } | 290 } |
| 291 // done |
| 289 return element; | 292 return element; |
| 290 } | 293 } |
| 291 | 294 |
| 292 /** | 295 /** |
| 293 * Returns the [Expression] that is part of the given [HtmlUnit] and encloses
the | 296 * Returns the [Expression] that is part of the given [HtmlUnit] and encloses
the |
| 294 * given offset. | 297 * given offset. |
| 295 */ | 298 */ |
| 296 static Expression getExpression(HtmlUnit htmlUnit, int offset) { | 299 static Expression getExpression(HtmlUnit htmlUnit, int offset) { |
| 297 if (htmlUnit == null) { | 300 if (htmlUnit == null) { |
| 298 return null; | 301 return null; |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 * | 590 * |
| 588 * @param children the nodes that will become the children of this node | 591 * @param children the nodes that will become the children of this node |
| 589 * @return the nodes that were made children of this node | 592 * @return the nodes that were made children of this node |
| 590 */ | 593 */ |
| 591 List becomeParentOf(List children) { | 594 List becomeParentOf(List children) { |
| 592 if (children != null) { | 595 if (children != null) { |
| 593 for (JavaIterator iter = new JavaIterator(children); iter.hasNext;) { | 596 for (JavaIterator iter = new JavaIterator(children); iter.hasNext;) { |
| 594 XmlNode node = iter.next(); | 597 XmlNode node = iter.next(); |
| 595 node.parent = this; | 598 node.parent = this; |
| 596 } | 599 } |
| 600 // This will create ArrayList for exactly given number of elements. |
| 597 return new List.from(children); | 601 return new List.from(children); |
| 598 } | 602 } |
| 599 return children; | 603 return children; |
| 600 } | 604 } |
| 601 | 605 |
| 602 /** | 606 /** |
| 603 * Make this node the parent of the given child node. | 607 * Make this node the parent of the given child node. |
| 604 * | 608 * |
| 605 * @param child the node that will become a child of this node | 609 * @param child the node that will become a child of this node |
| 606 * @return the node that was made a child of this node | 610 * @return the node that was made a child of this node |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 791 | 795 |
| 792 /** | 796 /** |
| 793 * Record the fact that we are at the beginning of a new line in the source. | 797 * Record the fact that we are at the beginning of a new line in the source. |
| 794 */ | 798 */ |
| 795 void recordStartOfLine() { | 799 void recordStartOfLine() { |
| 796 _lineStarts.add(offset); | 800 _lineStarts.add(offset); |
| 797 } | 801 } |
| 798 | 802 |
| 799 void appendEofToken() { | 803 void appendEofToken() { |
| 800 Token eofToken = new Token.con1(TokenType.EOF, offset); | 804 Token eofToken = new Token.con1(TokenType.EOF, offset); |
| 805 // The EOF token points to itself so that there is always infinite look-ahea
d. |
| 801 eofToken.setNext(eofToken); | 806 eofToken.setNext(eofToken); |
| 802 _tail = _tail.setNext(eofToken); | 807 _tail = _tail.setNext(eofToken); |
| 803 } | 808 } |
| 804 | 809 |
| 805 Token emit(Token token) { | 810 Token emit(Token token) { |
| 806 _tail.setNext(token); | 811 _tail.setNext(token); |
| 807 _tail = token; | 812 _tail = token; |
| 808 return token; | 813 return token; |
| 809 } | 814 } |
| 810 | 815 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 834 bool inBrackets = false; | 839 bool inBrackets = false; |
| 835 String endPassThrough = null; | 840 String endPassThrough = null; |
| 836 int c = advance(); | 841 int c = advance(); |
| 837 while (c >= 0) { | 842 while (c >= 0) { |
| 838 int start = offset; | 843 int start = offset; |
| 839 if (c == 0x3C) { | 844 if (c == 0x3C) { |
| 840 c = advance(); | 845 c = advance(); |
| 841 if (c == 0x21) { | 846 if (c == 0x21) { |
| 842 c = advance(); | 847 c = advance(); |
| 843 if (c == 0x2D && peek() == 0x2D) { | 848 if (c == 0x2D && peek() == 0x2D) { |
| 849 // handle a comment |
| 844 c = advance(); | 850 c = advance(); |
| 845 int dashCount = 1; | 851 int dashCount = 1; |
| 846 while (c >= 0) { | 852 while (c >= 0) { |
| 847 if (c == 0x2D) { | 853 if (c == 0x2D) { |
| 848 dashCount++; | 854 dashCount++; |
| 849 } else if (c == 0x3E && dashCount >= 2) { | 855 } else if (c == 0x3E && dashCount >= 2) { |
| 850 c = advance(); | 856 c = advance(); |
| 851 break; | 857 break; |
| 852 } else { | 858 } else { |
| 853 dashCount = 0; | 859 dashCount = 0; |
| 854 } | 860 } |
| 855 c = recordStartOfLineAndAdvance(c); | 861 c = recordStartOfLineAndAdvance(c); |
| 856 } | 862 } |
| 857 emit3(TokenType.COMMENT, start, -1); | 863 emit3(TokenType.COMMENT, start, -1); |
| 864 // Capture <!--> and <!---> as tokens but report an error |
| 858 if (_tail.length < 7) { | 865 if (_tail.length < 7) { |
| 859 } | 866 } |
| 860 } else { | 867 } else { |
| 868 // handle a declaration |
| 861 while (c >= 0) { | 869 while (c >= 0) { |
| 862 if (c == 0x3E) { | 870 if (c == 0x3E) { |
| 863 c = advance(); | 871 c = advance(); |
| 864 break; | 872 break; |
| 865 } | 873 } |
| 866 c = recordStartOfLineAndAdvance(c); | 874 c = recordStartOfLineAndAdvance(c); |
| 867 } | 875 } |
| 868 emit3(TokenType.DECLARATION, start, -1); | 876 emit3(TokenType.DECLARATION, start, -1); |
| 869 if (!_tail.lexeme.endsWith(">")) { | 877 if (!_tail.lexeme.endsWith(">")) { |
| 870 } | 878 } |
| 871 } | 879 } |
| 872 } else if (c == 0x3F) { | 880 } else if (c == 0x3F) { |
| 881 // handle a directive |
| 873 while (c >= 0) { | 882 while (c >= 0) { |
| 874 if (c == 0x3F) { | 883 if (c == 0x3F) { |
| 875 c = advance(); | 884 c = advance(); |
| 876 if (c == 0x3E) { | 885 if (c == 0x3E) { |
| 877 c = advance(); | 886 c = advance(); |
| 878 break; | 887 break; |
| 879 } | 888 } |
| 880 } else { | 889 } else { |
| 881 c = recordStartOfLineAndAdvance(c); | 890 c = recordStartOfLineAndAdvance(c); |
| 882 } | 891 } |
| 883 } | 892 } |
| 884 emit3(TokenType.DIRECTIVE, start, -1); | 893 emit3(TokenType.DIRECTIVE, start, -1); |
| 885 if (_tail.length < 4) { | 894 if (_tail.length < 4) { |
| 886 } | 895 } |
| 887 } else if (c == 0x2F) { | 896 } else if (c == 0x2F) { |
| 888 emit2(TokenType.LT_SLASH, start); | 897 emit2(TokenType.LT_SLASH, start); |
| 889 inBrackets = true; | 898 inBrackets = true; |
| 890 c = advance(); | 899 c = advance(); |
| 891 } else { | 900 } else { |
| 892 inBrackets = true; | 901 inBrackets = true; |
| 893 emit2(TokenType.LT, start); | 902 emit2(TokenType.LT, start); |
| 903 // ignore whitespace in braces |
| 894 while (Character.isWhitespace(c)) { | 904 while (Character.isWhitespace(c)) { |
| 895 c = recordStartOfLineAndAdvance(c); | 905 c = recordStartOfLineAndAdvance(c); |
| 896 } | 906 } |
| 907 // get tag |
| 897 if (Character.isLetterOrDigit(c)) { | 908 if (Character.isLetterOrDigit(c)) { |
| 898 int tagStart = offset; | 909 int tagStart = offset; |
| 899 c = advance(); | 910 c = advance(); |
| 900 while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) { | 911 while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) { |
| 901 c = advance(); | 912 c = advance(); |
| 902 } | 913 } |
| 903 emit3(TokenType.TAG, tagStart, -1); | 914 emit3(TokenType.TAG, tagStart, -1); |
| 915 // check tag against passThrough elements |
| 904 String tag = _tail.lexeme; | 916 String tag = _tail.lexeme; |
| 905 for (String str in _passThroughElements) { | 917 for (String str in _passThroughElements) { |
| 906 if (str == tag) { | 918 if (str == tag) { |
| 907 endPassThrough = "</${str}>"; | 919 endPassThrough = "</${str}>"; |
| 908 break; | 920 break; |
| 909 } | 921 } |
| 910 } | 922 } |
| 911 } | 923 } |
| 912 } | 924 } |
| 913 } else if (c == 0x3E) { | 925 } else if (c == 0x3E) { |
| 914 emit2(TokenType.GT, start); | 926 emit2(TokenType.GT, start); |
| 915 inBrackets = false; | 927 inBrackets = false; |
| 916 c = advance(); | 928 c = advance(); |
| 929 // if passThrough != null, read until we match it |
| 917 if (endPassThrough != null) { | 930 if (endPassThrough != null) { |
| 918 bool endFound = false; | 931 bool endFound = false; |
| 919 int len = endPassThrough.length; | 932 int len = endPassThrough.length; |
| 920 int firstC = endPassThrough.codeUnitAt(0); | 933 int firstC = endPassThrough.codeUnitAt(0); |
| 921 int index = 0; | 934 int index = 0; |
| 922 int nextC = firstC; | 935 int nextC = firstC; |
| 923 while (c >= 0) { | 936 while (c >= 0) { |
| 924 if (c == nextC) { | 937 if (c == nextC) { |
| 925 index++; | 938 index++; |
| 926 if (index == len) { | 939 if (index == len) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 953 emit2(TokenType.SLASH_GT, start); | 966 emit2(TokenType.SLASH_GT, start); |
| 954 inBrackets = false; | 967 inBrackets = false; |
| 955 c = advance(); | 968 c = advance(); |
| 956 } else if (!inBrackets) { | 969 } else if (!inBrackets) { |
| 957 c = recordStartOfLineAndAdvance(c); | 970 c = recordStartOfLineAndAdvance(c); |
| 958 while (c != 0x3C && c >= 0) { | 971 while (c != 0x3C && c >= 0) { |
| 959 c = recordStartOfLineAndAdvance(c); | 972 c = recordStartOfLineAndAdvance(c); |
| 960 } | 973 } |
| 961 emit3(TokenType.TEXT, start, -1); | 974 emit3(TokenType.TEXT, start, -1); |
| 962 } else if (c == 0x22 || c == 0x27) { | 975 } else if (c == 0x22 || c == 0x27) { |
| 976 // read a string |
| 963 int endQuote = c; | 977 int endQuote = c; |
| 964 c = advance(); | 978 c = advance(); |
| 965 while (c >= 0) { | 979 while (c >= 0) { |
| 966 if (c == endQuote) { | 980 if (c == endQuote) { |
| 967 c = advance(); | 981 c = advance(); |
| 968 break; | 982 break; |
| 969 } | 983 } |
| 970 c = recordStartOfLineAndAdvance(c); | 984 c = recordStartOfLineAndAdvance(c); |
| 971 } | 985 } |
| 972 emit3(TokenType.STRING, start, -1); | 986 emit3(TokenType.STRING, start, -1); |
| 973 } else if (c == 0x3D) { | 987 } else if (c == 0x3D) { |
| 988 // a non-char token |
| 974 emit2(TokenType.EQ, start); | 989 emit2(TokenType.EQ, start); |
| 975 c = advance(); | 990 c = advance(); |
| 976 } else if (Character.isWhitespace(c)) { | 991 } else if (Character.isWhitespace(c)) { |
| 992 // ignore whitespace in braces |
| 977 do { | 993 do { |
| 978 c = recordStartOfLineAndAdvance(c); | 994 c = recordStartOfLineAndAdvance(c); |
| 979 } while (Character.isWhitespace(c)); | 995 } while (Character.isWhitespace(c)); |
| 980 } else if (Character.isLetterOrDigit(c)) { | 996 } else if (Character.isLetterOrDigit(c)) { |
| 981 c = advance(); | 997 c = advance(); |
| 982 while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) { | 998 while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) { |
| 983 c = advance(); | 999 c = advance(); |
| 984 } | 1000 } |
| 985 emit3(TokenType.TAG, start, -1); | 1001 emit3(TokenType.TAG, start, -1); |
| 986 } else { | 1002 } else { |
| 1003 // a non-char token |
| 987 emit3(TokenType.TEXT, start, 0); | 1004 emit3(TokenType.TEXT, start, 0); |
| 988 c = advance(); | 1005 c = advance(); |
| 989 } | 1006 } |
| 990 } | 1007 } |
| 991 } | 1008 } |
| 992 } | 1009 } |
| 993 | 1010 |
| 994 /** | 1011 /** |
| 995 * Instances of `HtmlScanResult` hold the result of scanning an HTML file. | 1012 * Instances of `HtmlScanResult` hold the result of scanning an HTML file. |
| 996 * | 1013 * |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 | 1337 |
| 1321 /** | 1338 /** |
| 1322 * Answer the lexeme for the value token without the leading and trailing quot
es. | 1339 * Answer the lexeme for the value token without the leading and trailing quot
es. |
| 1323 * | 1340 * |
| 1324 * @return the text or `null` if the value is not specified | 1341 * @return the text or `null` if the value is not specified |
| 1325 */ | 1342 */ |
| 1326 String get text { | 1343 String get text { |
| 1327 if (_value == null) { | 1344 if (_value == null) { |
| 1328 return null; | 1345 return null; |
| 1329 } | 1346 } |
| 1347 //TODO (danrubel): replace HTML character encodings with the actual characte
rs |
| 1330 String text = _value.lexeme; | 1348 String text = _value.lexeme; |
| 1331 int len = text.length; | 1349 int len = text.length; |
| 1332 if (len > 0) { | 1350 if (len > 0) { |
| 1333 if (text.codeUnitAt(0) == 0x22) { | 1351 if (text.codeUnitAt(0) == 0x22) { |
| 1334 if (len > 1 && text.codeUnitAt(len - 1) == 0x22) { | 1352 if (len > 1 && text.codeUnitAt(len - 1) == 0x22) { |
| 1335 return text.substring(1, len - 1); | 1353 return text.substring(1, len - 1); |
| 1336 } else { | 1354 } else { |
| 1337 return text.substring(1); | 1355 return text.substring(1); |
| 1338 } | 1356 } |
| 1339 } else if (text.codeUnitAt(0) == 0x27) { | 1357 } else if (text.codeUnitAt(0) == 0x27) { |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1557 * @return the list of tag nodes found (not `null`, contains no `null`) | 1575 * @return the list of tag nodes found (not `null`, contains no `null`) |
| 1558 */ | 1576 */ |
| 1559 List<XmlTagNode> parseTopTagNodes(Token firstToken) { | 1577 List<XmlTagNode> parseTopTagNodes(Token firstToken) { |
| 1560 _currentToken = firstToken; | 1578 _currentToken = firstToken; |
| 1561 List<XmlTagNode> tagNodes = new List<XmlTagNode>(); | 1579 List<XmlTagNode> tagNodes = new List<XmlTagNode>(); |
| 1562 while (true) { | 1580 while (true) { |
| 1563 while (true) { | 1581 while (true) { |
| 1564 if (_currentToken.type == TokenType.LT) { | 1582 if (_currentToken.type == TokenType.LT) { |
| 1565 tagNodes.add(parseTagNode()); | 1583 tagNodes.add(parseTagNode()); |
| 1566 } else if (_currentToken.type == TokenType.DECLARATION || _currentToken.
type == TokenType.DIRECTIVE || _currentToken.type == TokenType.COMMENT) { | 1584 } else if (_currentToken.type == TokenType.DECLARATION || _currentToken.
type == TokenType.DIRECTIVE || _currentToken.type == TokenType.COMMENT) { |
| 1585 // ignored tokens |
| 1567 _currentToken = _currentToken.next; | 1586 _currentToken = _currentToken.next; |
| 1568 } else if (_currentToken.type == TokenType.EOF) { | 1587 } else if (_currentToken.type == TokenType.EOF) { |
| 1569 return tagNodes; | 1588 return tagNodes; |
| 1570 } else { | 1589 } else { |
| 1571 reportUnexpectedToken(); | 1590 reportUnexpectedToken(); |
| 1572 _currentToken = _currentToken.next; | 1591 _currentToken = _currentToken.next; |
| 1573 } | 1592 } |
| 1574 break; | 1593 break; |
| 1575 } | 1594 } |
| 1576 } | 1595 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1596 return token; | 1615 return token; |
| 1597 } | 1616 } |
| 1598 | 1617 |
| 1599 /** | 1618 /** |
| 1600 * Parse the token stream for an attribute. This method advances the current t
oken over the | 1619 * Parse the token stream for an attribute. This method advances the current t
oken over the |
| 1601 * attribute, but should not be called if the [currentToken] is not [TokenType
#TAG]. | 1620 * attribute, but should not be called if the [currentToken] is not [TokenType
#TAG]. |
| 1602 * | 1621 * |
| 1603 * @return the attribute (not `null`) | 1622 * @return the attribute (not `null`) |
| 1604 */ | 1623 */ |
| 1605 XmlAttributeNode parseAttribute() { | 1624 XmlAttributeNode parseAttribute() { |
| 1625 // Assume the current token is a tag |
| 1606 Token name = _currentToken; | 1626 Token name = _currentToken; |
| 1607 _currentToken = _currentToken.next; | 1627 _currentToken = _currentToken.next; |
| 1628 // Equals sign |
| 1608 Token equals; | 1629 Token equals; |
| 1609 if (identical(_currentToken.type, TokenType.EQ)) { | 1630 if (identical(_currentToken.type, TokenType.EQ)) { |
| 1610 equals = _currentToken; | 1631 equals = _currentToken; |
| 1611 _currentToken = _currentToken.next; | 1632 _currentToken = _currentToken.next; |
| 1612 } else { | 1633 } else { |
| 1613 reportUnexpectedToken(); | 1634 reportUnexpectedToken(); |
| 1614 equals = insertSyntheticToken(TokenType.EQ); | 1635 equals = insertSyntheticToken(TokenType.EQ); |
| 1615 } | 1636 } |
| 1637 // String value |
| 1616 Token value; | 1638 Token value; |
| 1617 if (identical(_currentToken.type, TokenType.STRING)) { | 1639 if (identical(_currentToken.type, TokenType.STRING)) { |
| 1618 value = _currentToken; | 1640 value = _currentToken; |
| 1619 _currentToken = _currentToken.next; | 1641 _currentToken = _currentToken.next; |
| 1620 } else { | 1642 } else { |
| 1621 reportUnexpectedToken(); | 1643 reportUnexpectedToken(); |
| 1622 value = insertSyntheticToken(TokenType.STRING); | 1644 value = insertSyntheticToken(TokenType.STRING); |
| 1623 } | 1645 } |
| 1624 return createAttributeNode(name, equals, value); | 1646 return createAttributeNode(name, equals, value); |
| 1625 } | 1647 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1663 return XmlTagNode.NO_TAG_NODES; | 1685 return XmlTagNode.NO_TAG_NODES; |
| 1664 } | 1686 } |
| 1665 List<XmlTagNode> nodes = new List<XmlTagNode>(); | 1687 List<XmlTagNode> nodes = new List<XmlTagNode>(); |
| 1666 while (true) { | 1688 while (true) { |
| 1667 while (true) { | 1689 while (true) { |
| 1668 if (_currentToken.type == TokenType.LT) { | 1690 if (_currentToken.type == TokenType.LT) { |
| 1669 nodes.add(parseTagNode()); | 1691 nodes.add(parseTagNode()); |
| 1670 } else if (_currentToken.type == TokenType.LT_SLASH || _currentToken.typ
e == TokenType.EOF) { | 1692 } else if (_currentToken.type == TokenType.LT_SLASH || _currentToken.typ
e == TokenType.EOF) { |
| 1671 return nodes; | 1693 return nodes; |
| 1672 } else if (_currentToken.type == TokenType.COMMENT) { | 1694 } else if (_currentToken.type == TokenType.COMMENT) { |
| 1695 // ignored token |
| 1673 _currentToken = _currentToken.next; | 1696 _currentToken = _currentToken.next; |
| 1674 } else { | 1697 } else { |
| 1675 reportUnexpectedToken(); | 1698 reportUnexpectedToken(); |
| 1676 _currentToken = _currentToken.next; | 1699 _currentToken = _currentToken.next; |
| 1677 } | 1700 } |
| 1678 break; | 1701 break; |
| 1679 } | 1702 } |
| 1680 } | 1703 } |
| 1681 } | 1704 } |
| 1682 | 1705 |
| 1683 /** | 1706 /** |
| 1684 * Parse the token stream for the next tag node. This method advances current
token over the | 1707 * Parse the token stream for the next tag node. This method advances current
token over the |
| 1685 * parsed tag node, but should only be called if the current token is [TokenTy
pe#LT] | 1708 * parsed tag node, but should only be called if the current token is [TokenTy
pe#LT] |
| 1686 * | 1709 * |
| 1687 * @return the tag node or `null` if none found | 1710 * @return the tag node or `null` if none found |
| 1688 */ | 1711 */ |
| 1689 XmlTagNode parseTagNode() { | 1712 XmlTagNode parseTagNode() { |
| 1713 // Assume that the current node is a tag node start TokenType#LT |
| 1690 Token nodeStart = _currentToken; | 1714 Token nodeStart = _currentToken; |
| 1691 _currentToken = _currentToken.next; | 1715 _currentToken = _currentToken.next; |
| 1716 // Get the tag or create a synthetic tag and report an error |
| 1692 Token tag; | 1717 Token tag; |
| 1693 if (identical(_currentToken.type, TokenType.TAG)) { | 1718 if (identical(_currentToken.type, TokenType.TAG)) { |
| 1694 tag = _currentToken; | 1719 tag = _currentToken; |
| 1695 _currentToken = _currentToken.next; | 1720 _currentToken = _currentToken.next; |
| 1696 } else { | 1721 } else { |
| 1697 reportUnexpectedToken(); | 1722 reportUnexpectedToken(); |
| 1698 tag = insertSyntheticToken(TokenType.TAG); | 1723 tag = insertSyntheticToken(TokenType.TAG); |
| 1699 } | 1724 } |
| 1725 // Parse the attributes |
| 1700 List<XmlAttributeNode> attributes = parseAttributes(); | 1726 List<XmlAttributeNode> attributes = parseAttributes(); |
| 1727 // Token ending attribute list |
| 1701 Token attributeEnd; | 1728 Token attributeEnd; |
| 1702 if (identical(_currentToken.type, TokenType.GT) || identical(_currentToken.t
ype, TokenType.SLASH_GT)) { | 1729 if (identical(_currentToken.type, TokenType.GT) || identical(_currentToken.t
ype, TokenType.SLASH_GT)) { |
| 1703 attributeEnd = _currentToken; | 1730 attributeEnd = _currentToken; |
| 1704 _currentToken = _currentToken.next; | 1731 _currentToken = _currentToken.next; |
| 1705 } else { | 1732 } else { |
| 1706 reportUnexpectedToken(); | 1733 reportUnexpectedToken(); |
| 1707 attributeEnd = insertSyntheticToken(TokenType.SLASH_GT); | 1734 attributeEnd = insertSyntheticToken(TokenType.SLASH_GT); |
| 1708 } | 1735 } |
| 1736 // If the node has no children, then return the node |
| 1709 if (identical(attributeEnd.type, TokenType.SLASH_GT) || isSelfClosing(tag))
{ | 1737 if (identical(attributeEnd.type, TokenType.SLASH_GT) || isSelfClosing(tag))
{ |
| 1710 return createTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.
NO_TAG_NODES, _currentToken, null, attributeEnd); | 1738 return createTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.
NO_TAG_NODES, _currentToken, null, attributeEnd); |
| 1711 } | 1739 } |
| 1740 // Parse the child tag nodes |
| 1712 List<XmlTagNode> tagNodes = parseChildTagNodes(); | 1741 List<XmlTagNode> tagNodes = parseChildTagNodes(); |
| 1742 // Token ending child tag nodes |
| 1713 Token contentEnd; | 1743 Token contentEnd; |
| 1714 if (identical(_currentToken.type, TokenType.LT_SLASH)) { | 1744 if (identical(_currentToken.type, TokenType.LT_SLASH)) { |
| 1715 contentEnd = _currentToken; | 1745 contentEnd = _currentToken; |
| 1716 _currentToken = _currentToken.next; | 1746 _currentToken = _currentToken.next; |
| 1717 } else { | 1747 } else { |
| 1748 // TODO (danrubel): handle self closing HTML elements by inserting synthet
ic tokens |
| 1749 // but not reporting an error |
| 1718 reportUnexpectedToken(); | 1750 reportUnexpectedToken(); |
| 1719 contentEnd = insertSyntheticToken(TokenType.LT_SLASH); | 1751 contentEnd = insertSyntheticToken(TokenType.LT_SLASH); |
| 1720 } | 1752 } |
| 1753 // Closing tag |
| 1721 Token closingTag; | 1754 Token closingTag; |
| 1722 if (identical(_currentToken.type, TokenType.TAG)) { | 1755 if (identical(_currentToken.type, TokenType.TAG)) { |
| 1723 closingTag = _currentToken; | 1756 closingTag = _currentToken; |
| 1724 _currentToken = _currentToken.next; | 1757 _currentToken = _currentToken.next; |
| 1725 } else { | 1758 } else { |
| 1726 reportUnexpectedToken(); | 1759 reportUnexpectedToken(); |
| 1727 closingTag = insertSyntheticToken(TokenType.TAG); | 1760 closingTag = insertSyntheticToken(TokenType.TAG); |
| 1728 } | 1761 } |
| 1762 // Token ending node |
| 1729 Token nodeEnd; | 1763 Token nodeEnd; |
| 1730 if (identical(_currentToken.type, TokenType.GT)) { | 1764 if (identical(_currentToken.type, TokenType.GT)) { |
| 1731 nodeEnd = _currentToken; | 1765 nodeEnd = _currentToken; |
| 1732 _currentToken = _currentToken.next; | 1766 _currentToken = _currentToken.next; |
| 1733 } else { | 1767 } else { |
| 1734 reportUnexpectedToken(); | 1768 reportUnexpectedToken(); |
| 1735 nodeEnd = insertSyntheticToken(TokenType.GT); | 1769 nodeEnd = insertSyntheticToken(TokenType.GT); |
| 1736 } | 1770 } |
| 1737 return createTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, con
tentEnd, closingTag, nodeEnd); | 1771 return createTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, con
tentEnd, closingTag, nodeEnd); |
| 1738 } | 1772 } |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1894 * representation of any child tag nodes ([getTagNodes]). Whitespace between '
<', | 1928 * representation of any child tag nodes ([getTagNodes]). Whitespace between '
<', |
| 1895 * '</', and '>', '/>' is discarded, but all other whitespace is preserved. | 1929 * '</', and '>', '/>' is discarded, but all other whitespace is preserved. |
| 1896 * | 1930 * |
| 1897 * @return the content (not `null`) | 1931 * @return the content (not `null`) |
| 1898 */ | 1932 */ |
| 1899 String get content { | 1933 String get content { |
| 1900 Token token = attributeEnd.next; | 1934 Token token = attributeEnd.next; |
| 1901 if (identical(token, contentEnd)) { | 1935 if (identical(token, contentEnd)) { |
| 1902 return ""; | 1936 return ""; |
| 1903 } | 1937 } |
| 1938 //TODO (danrubel): handle CDATA and replace HTML character encodings with th
e actual characters |
| 1904 String content = token.lexeme; | 1939 String content = token.lexeme; |
| 1905 token = token.next; | 1940 token = token.next; |
| 1906 if (identical(token, contentEnd)) { | 1941 if (identical(token, contentEnd)) { |
| 1907 return content; | 1942 return content; |
| 1908 } | 1943 } |
| 1909 JavaStringBuilder buffer = new JavaStringBuilder(); | 1944 JavaStringBuilder buffer = new JavaStringBuilder(); |
| 1910 while (token != contentEnd) { | 1945 while (token != contentEnd) { |
| 1911 buffer.append(token.lexeme); | 1946 buffer.append(token.lexeme); |
| 1912 token = token.next; | 1947 token = token.next; |
| 1913 } | 1948 } |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2184 } | 2219 } |
| 2185 super.element = element; | 2220 super.element = element; |
| 2186 } | 2221 } |
| 2187 | 2222 |
| 2188 void visitChildren(XmlVisitor visitor) { | 2223 void visitChildren(XmlVisitor visitor) { |
| 2189 for (XmlTagNode node in _tagNodes) { | 2224 for (XmlTagNode node in _tagNodes) { |
| 2190 node.accept(visitor); | 2225 node.accept(visitor); |
| 2191 } | 2226 } |
| 2192 } | 2227 } |
| 2193 } | 2228 } |
| OLD | NEW |