| // This code was auto-generated, is not intended to be edited, and is subject to |
| // significant change. Please see the README file for more information. |
| |
| library engine.html; |
| |
| import 'dart:collection'; |
| import 'java_core.dart'; |
| import 'java_engine.dart'; |
| import 'source.dart'; |
| import 'error.dart'; |
| import 'instrumentation.dart'; |
| import 'element.dart' show HtmlElementImpl; |
| |
| /** |
| * Instances of the class {@code Token} represent a token that was scanned from the input. Each |
| * token knows which token follows it, acting as the head of a linked list of tokens. |
| * @coverage dart.engine.html |
| */ |
| class Token { |
| /** |
| * The offset from the beginning of the file to the first character in the token. |
| */ |
| int _offset = 0; |
| /** |
| * The previous token in the token stream. |
| */ |
| Token _previous; |
| /** |
| * The next token in the token stream. |
| */ |
| Token _next; |
| /** |
| * The type of the token. |
| */ |
| TokenType _type; |
| /** |
| * The lexeme represented by this token. |
| */ |
| String _value; |
| /** |
| * Initialize a newly created token. |
| * @param type the token type (not {@code null}) |
| * @param offset the offset from the beginning of the file to the first character in the token |
| */ |
| Token.con1(TokenType type, int offset) { |
| _jtd_constructor_150_impl(type, offset); |
| } |
| _jtd_constructor_150_impl(TokenType type, int offset) { |
| _jtd_constructor_151_impl(type, offset, type.lexeme); |
| } |
| /** |
| * Initialize a newly created token. |
| * @param type the token type (not {@code null}) |
| * @param offset the offset from the beginning of the file to the first character in the token |
| * @param value the lexeme represented by this token (not {@code null}) |
| */ |
| Token.con2(TokenType type2, int offset2, String value2) { |
| _jtd_constructor_151_impl(type2, offset2, value2); |
| } |
| _jtd_constructor_151_impl(TokenType type2, int offset2, String value2) { |
| this._type = type2; |
| this._value = StringUtilities.intern(value2); |
| this._offset = offset2; |
| } |
| /** |
| * Return the offset from the beginning of the file to the character after last character of the |
| * token. |
| * @return the offset from the beginning of the file to the first character after last character |
| * of the token |
| */ |
| int get end => _offset + length; |
| /** |
| * Return the number of characters in the node's source range. |
| * @return the number of characters in the node's source range |
| */ |
| int get length => lexeme.length; |
| /** |
| * Return the lexeme that represents this token. |
| * @return the lexeme (not {@code null}) |
| */ |
| String get lexeme => _value; |
| /** |
| * Return the next token in the token stream. |
| * @return the next token in the token stream |
| */ |
| Token get next => _next; |
| /** |
| * Return the offset from the beginning of the file to the first character in the token. |
| * @return the offset from the beginning of the file to the first character in the token |
| */ |
| int get offset => _offset; |
| /** |
| * Return the previous token in the token stream. |
| * @return the previous token in the token stream |
| */ |
| Token get previous => _previous; |
| /** |
| * Answer the token type for the receiver. |
| * @return the token type (not {@code null}) |
| */ |
| TokenType get type => _type; |
| /** |
| * Return {@code true} if this token is a synthetic token. A synthetic token is a token that was |
| * introduced by the parser in order to recover from an error in the code. Synthetic tokens always |
| * have a length of zero ({@code 0}). |
| * @return {@code true} if this token is a synthetic token |
| */ |
| bool isSynthetic() => length == 0; |
| /** |
| * Set the next token in the token stream to the given token. This has the side-effect of setting |
| * this token to be the previous token for the given token. |
| * @param token the next token in the token stream |
| * @return the token that was passed in |
| */ |
| Token setNext(Token token) { |
| _next = token; |
| token.previous = this; |
| return token; |
| } |
| String toString() => lexeme; |
| /** |
| * Set the previous token in the token stream to the given token. |
| * @param previous the previous token in the token stream |
| */ |
| void set previous(Token previous2) { |
| this._previous = previous2; |
| } |
| } |
| /** |
| * Instances of {@code HtmlParseResult} hold the result of parsing an HTML file. |
| * @coverage dart.engine.html |
| */ |
| class HtmlParseResult extends HtmlScanResult { |
| /** |
| * The unit containing the parsed information (not {@code null}). |
| */ |
| HtmlUnit _unit; |
| HtmlParseResult(int modificationTime, Token token, List<int> lineStarts, HtmlUnit unit) : super(modificationTime, token, lineStarts) { |
| this._unit = unit; |
| } |
| /** |
| * Answer the unit generated by parsing the source |
| * @return the unit (not {@code null}) |
| */ |
| HtmlUnit get htmlUnit => _unit; |
| } |
| /** |
| * Instances of the class {@code RecursiveXmlVisitor} implement an XML visitor that will recursively |
| * visit all of the nodes in an XML structure. For example, using an instance of this class to visit |
| * a {@link XmlTagNode} will also cause all of the contained {@link XmlAttributeNode}s and{@link XmlTagNode}s to be visited. |
| * <p> |
| * Subclasses that override a visit method must either invoke the overridden visit method or must |
| * explicitly ask the visited node to visit its children. Failure to do so will cause the children |
| * of the visited node to not be visited. |
| * @coverage dart.engine.html |
| */ |
| class RecursiveXmlVisitor<R> implements XmlVisitor<R> { |
| R visitHtmlUnit(HtmlUnit node) { |
| node.visitChildren(this); |
| return null; |
| } |
| R visitXmlAttributeNode(XmlAttributeNode node) { |
| node.visitChildren(this); |
| return null; |
| } |
| R visitXmlTagNode(XmlTagNode node) { |
| node.visitChildren(this); |
| return null; |
| } |
| } |
| /** |
| * The abstract class {@code XmlNode} defines behavior common to all XML/HTML nodes. |
| * @coverage dart.engine.html |
| */ |
| abstract class XmlNode { |
| /** |
| * The parent of the node, or {@code null} if the node is the root of an AST structure. |
| */ |
| XmlNode _parent; |
| /** |
| * Use the given visitor to visit this node. |
| * @param visitor the visitor that will visit this node |
| * @return the value returned by the visitor as a result of visiting this node |
| */ |
| accept(XmlVisitor visitor); |
| /** |
| * Return the first token included in this node's source range. |
| * @return the first token or {@code null} if none |
| */ |
| Token get beginToken; |
| /** |
| * Return the offset of the character immediately following the last character of this node's |
| * source range. This is equivalent to {@code node.getOffset() + node.getLength()}. For an html |
| * unit this will be equal to the length of the unit's source. |
| * @return the offset of the character just past the node's source range |
| */ |
| int get end => offset + length; |
| /** |
| * Return the last token included in this node's source range. |
| * @return the last token or {@code null} if none |
| */ |
| Token get endToken; |
| /** |
| * Return the number of characters in the node's source range. |
| * @return the number of characters in the node's source range |
| */ |
| int get length { |
| Token beginToken2 = beginToken; |
| Token endToken2 = endToken; |
| if (beginToken2 == null || endToken2 == null) { |
| return -1; |
| } |
| return endToken2.offset + endToken2.length - beginToken2.offset; |
| } |
| /** |
| * Return the offset from the beginning of the file to the first character in the node's source |
| * range. |
| * @return the offset from the beginning of the file to the first character in the node's source |
| * range |
| */ |
| int get offset { |
| Token beginToken2 = beginToken; |
| if (beginToken2 == null) { |
| return -1; |
| } |
| return beginToken.offset; |
| } |
| /** |
| * Return this node's parent node, or {@code null} if this node is the root of an AST structure. |
| * <p> |
| * Note that the relationship between an AST node and its parent node may change over the lifetime |
| * of a node. |
| * @return the parent of this node, or {@code null} if none |
| */ |
| XmlNode get parent => _parent; |
| String toString() { |
| PrintStringWriter writer = new PrintStringWriter(); |
| accept(new ToSourceVisitor(writer)); |
| return writer.toString(); |
| } |
| /** |
| * Use the given visitor to visit all of the children of this node. The children will be visited |
| * in source order. |
| * @param visitor the visitor that will be used to visit the children of this node |
| */ |
| void visitChildren(XmlVisitor<Object> visitor); |
| /** |
| * Make this node the parent of the given child nodes. |
| * @param children the nodes that will become the children of this node |
| * @return the nodes that were made children of this node |
| */ |
| List becomeParentOf(List children) { |
| if (children != null) { |
| for (JavaIterator iter = new JavaIterator(children); iter.hasNext;) { |
| XmlNode node = iter.next(); |
| node.parent = this; |
| } |
| return new List.from(children); |
| } |
| return children; |
| } |
| /** |
| * Make this node the parent of the given child node. |
| * @param child the node that will become a child of this node |
| * @return the node that was made a child of this node |
| */ |
| XmlNode becomeParentOf2(XmlNode child) { |
| if (child != null) { |
| XmlNode node = child; |
| node.parent = this; |
| } |
| return child; |
| } |
| /** |
| * Set the parent of this node to the given node. |
| * @param newParent the node that is to be made the parent of this node |
| */ |
| void set parent(XmlNode newParent) { |
| _parent = newParent; |
| } |
| } |
| /** |
| * Instances of the class {@code SimpleXmlVisitor} implement an AST visitor that will do nothing |
| * when visiting an AST node. It is intended to be a superclass for classes that use the visitor |
| * pattern primarily as a dispatch mechanism (and hence don't need to recursively visit a whole |
| * structure) and that only need to visit a small number of node types. |
| */ |
| class SimpleXmlVisitor<R> implements XmlVisitor<R> { |
| R visitHtmlUnit(HtmlUnit htmlUnit) => null; |
| R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode) => null; |
| R visitXmlTagNode(XmlTagNode xmlTagNode) => null; |
| } |
| /** |
| * The abstract class {@code AbstractScanner} implements a scanner for HTML code. Subclasses are |
| * required to implement the interface used to access the characters being scanned. |
| * @coverage dart.engine.html |
| */ |
| abstract class AbstractScanner { |
| static List<String> _NO_PASS_THROUGH_ELEMENTS = <String> []; |
| /** |
| * The source being scanned. |
| */ |
| Source _source; |
| /** |
| * The token pointing to the head of the linked list of tokens. |
| */ |
| Token _tokens; |
| /** |
| * The last token that was scanned. |
| */ |
| Token _tail; |
| /** |
| * A list containing the offsets of the first character of each line in the source code. |
| */ |
| List<int> _lineStarts = new List<int>(); |
| /** |
| * An array of element tags for which the content between tags should be consider a single token. |
| */ |
| List<String> _passThroughElements = _NO_PASS_THROUGH_ELEMENTS; |
| /** |
| * Initialize a newly created scanner. |
| * @param source the source being scanned |
| */ |
| AbstractScanner(Source source) { |
| this._source = source; |
| _tokens = new Token.con1(TokenType.EOF, -1); |
| _tokens.setNext(_tokens); |
| _tail = _tokens; |
| recordStartOfLine(); |
| } |
| /** |
| * Return an array containing the offsets of the first character of each line in the source code. |
| * @return an array containing the offsets of the first character of each line in the source code |
| */ |
| List<int> get lineStarts => _lineStarts; |
| /** |
| * Return the current offset relative to the beginning of the file. Return the initial offset if |
| * the scanner has not yet scanned the source code, and one (1) past the end of the source code if |
| * the source code has been scanned. |
| * @return the current offset of the scanner in the source |
| */ |
| int get offset; |
| /** |
| * Answer the source being scanned. |
| * @return the source or {@code null} if undefined |
| */ |
| Source get source => _source; |
| /** |
| * Set array of element tags for which the content between tags should be consider a single token. |
| */ |
| void set passThroughElements(List<String> passThroughElements2) { |
| this._passThroughElements = passThroughElements2 != null ? passThroughElements2 : _NO_PASS_THROUGH_ELEMENTS; |
| } |
| /** |
| * Scan the source code to produce a list of tokens representing the source. |
| * @return the first token in the list of tokens that were produced |
| */ |
| Token tokenize() { |
| scan(); |
| appendEofToken(); |
| return firstToken(); |
| } |
| /** |
| * Advance the current position and return the character at the new current position. |
| * @return the character at the new current position |
| */ |
| int advance(); |
| /** |
| * Return the substring of the source code between the start offset and the modified current |
| * position. The current position is modified by adding the end delta. |
| * @param start the offset to the beginning of the string, relative to the start of the file |
| * @param endDelta the number of character after the current location to be included in the |
| * string, or the number of characters before the current location to be excluded if the |
| * offset is negative |
| * @return the specified substring of the source code |
| */ |
| String getString(int start, int endDelta); |
| /** |
| * Return the character at the current position without changing the current position. |
| * @return the character at the current position |
| */ |
| int peek(); |
| /** |
| * Record the fact that we are at the beginning of a new line in the source. |
| */ |
| void recordStartOfLine() { |
| _lineStarts.add(offset); |
| } |
| void appendEofToken() { |
| Token eofToken = new Token.con1(TokenType.EOF, offset); |
| eofToken.setNext(eofToken); |
| _tail = _tail.setNext(eofToken); |
| } |
| Token emit(Token token) { |
| _tail.setNext(token); |
| _tail = token; |
| return token; |
| } |
| Token emit2(TokenType type, int start) => emit(new Token.con1(type, start)); |
| Token emit3(TokenType type, int start, int count) => emit(new Token.con2(type, start, getString(start, count))); |
| Token firstToken() => _tokens.next; |
| int recordStartOfLineAndAdvance(int c) { |
| if (c == 0xD) { |
| c = advance(); |
| if (c == 0xA) { |
| c = advance(); |
| } |
| recordStartOfLine(); |
| } else if (c == 0xA) { |
| c = advance(); |
| recordStartOfLine(); |
| } else { |
| c = advance(); |
| } |
| return c; |
| } |
| void scan() { |
| bool inBrackets = false; |
| bool passThrough = false; |
| int c = advance(); |
| while (c >= 0) { |
| int start = offset; |
| if (c == 0x3C) { |
| c = advance(); |
| if (c == 0x21) { |
| c = advance(); |
| if (c == 0x2D && peek() == 0x2D) { |
| c = advance(); |
| int dashCount = 1; |
| while (c >= 0) { |
| if (c == 0x2D) { |
| dashCount++; |
| } else if (c == 0x3E && dashCount >= 2) { |
| c = advance(); |
| break; |
| } else { |
| dashCount = 0; |
| } |
| c = recordStartOfLineAndAdvance(c); |
| } |
| emit3(TokenType.COMMENT, start, -1); |
| if (_tail.length < 7) { |
| } |
| } else { |
| while (c >= 0) { |
| if (c == 0x3E) { |
| c = advance(); |
| break; |
| } |
| c = recordStartOfLineAndAdvance(c); |
| } |
| emit3(TokenType.DECLARATION, start, -1); |
| if (!_tail.lexeme.endsWith(">")) { |
| } |
| } |
| } else if (c == 0x3F) { |
| while (c >= 0) { |
| if (c == 0x3F) { |
| c = advance(); |
| if (c == 0x3E) { |
| c = advance(); |
| break; |
| } |
| } else { |
| c = recordStartOfLineAndAdvance(c); |
| } |
| } |
| emit3(TokenType.DIRECTIVE, start, -1); |
| if (_tail.length < 4) { |
| } |
| } else if (c == 0x2F) { |
| emit2(TokenType.LT_SLASH, start); |
| inBrackets = true; |
| c = advance(); |
| } else { |
| inBrackets = true; |
| emit2(TokenType.LT, start); |
| while (Character.isWhitespace(c)) { |
| c = recordStartOfLineAndAdvance(c); |
| } |
| if (Character.isLetterOrDigit(c)) { |
| int tagStart = offset; |
| c = advance(); |
| while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) { |
| c = advance(); |
| } |
| emit3(TokenType.TAG, tagStart, -1); |
| String tag = _tail.lexeme; |
| for (String str in _passThroughElements) { |
| if (str == tag) { |
| passThrough = true; |
| break; |
| } |
| } |
| } |
| } |
| } else if (c == 0x3E) { |
| emit2(TokenType.GT, start); |
| inBrackets = false; |
| c = advance(); |
| if (passThrough) { |
| while (c >= 0 && (c != 0x3C || peek() != 0x2F)) { |
| c = recordStartOfLineAndAdvance(c); |
| } |
| if (start + 1 < offset) { |
| emit3(TokenType.TEXT, start + 1, -1); |
| } |
| passThrough = false; |
| } |
| } else if (c == 0x2F && peek() == 0x3E) { |
| advance(); |
| emit2(TokenType.SLASH_GT, start); |
| inBrackets = false; |
| c = advance(); |
| } else if (!inBrackets) { |
| c = recordStartOfLineAndAdvance(c); |
| while (c != 0x3C && c >= 0) { |
| c = recordStartOfLineAndAdvance(c); |
| } |
| emit3(TokenType.TEXT, start, -1); |
| } else if (c == 0x22 || c == 0x27) { |
| int endQuote = c; |
| c = advance(); |
| while (c >= 0) { |
| if (c == endQuote) { |
| c = advance(); |
| break; |
| } |
| c = recordStartOfLineAndAdvance(c); |
| } |
| emit3(TokenType.STRING, start, -1); |
| } else if (c == 0x3D) { |
| emit2(TokenType.EQ, start); |
| c = advance(); |
| } else if (Character.isWhitespace(c)) { |
| do { |
| c = recordStartOfLineAndAdvance(c); |
| } while (Character.isWhitespace(c)); |
| } else if (Character.isLetterOrDigit(c)) { |
| c = advance(); |
| while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) { |
| c = advance(); |
| } |
| emit3(TokenType.TAG, start, -1); |
| } else { |
| emit3(TokenType.TEXT, start, 0); |
| c = advance(); |
| } |
| } |
| } |
| } |
| /** |
| * Instances of {@code HtmlScanResult} hold the result of scanning an HTML file. |
| * @coverage dart.engine.html |
| */ |
| class HtmlScanResult { |
| /** |
| * The time at which the contents of the source were last set. |
| */ |
| int _modificationTime = 0; |
| /** |
| * The first token in the token stream (not {@code null}). |
| */ |
| Token _token; |
| /** |
| * The line start information that was produced. |
| */ |
| List<int> _lineStarts; |
| HtmlScanResult(int modificationTime, Token token, List<int> lineStarts) { |
| this._modificationTime = modificationTime; |
| this._token = token; |
| this._lineStarts = lineStarts; |
| } |
| /** |
| * Answer the line start information that was produced. |
| * @return an array of line starts (not {@code null}) |
| */ |
| List<int> get lineStarts => _lineStarts; |
| /** |
| * Return the time at which the contents of the source were last set. |
| * @return the time at which the contents of the source were last set |
| */ |
| int get modificationTime => _modificationTime; |
| /** |
| * Answer the first token in the token stream. |
| * @return the token (not {@code null}) |
| */ |
| Token get token => _token; |
| } |
| /** |
| * Instances of the class {@code StringScanner} implement a scanner that reads from a string. The |
| * scanning logic is in the superclass. |
| * @coverage dart.engine.html |
| */ |
| class StringScanner extends AbstractScanner { |
| /** |
| * The string from which characters will be read. |
| */ |
| String _string; |
| /** |
| * The number of characters in the string. |
| */ |
| int _stringLength = 0; |
| /** |
| * The index, relative to the string, of the last character that was read. |
| */ |
| int _charOffset = 0; |
| /** |
| * Initialize a newly created scanner to scan the characters in the given string. |
| * @param source the source being scanned |
| * @param string the string from which characters will be read |
| */ |
| StringScanner(Source source, String string) : super(source) { |
| this._string = string; |
| this._stringLength = string.length; |
| this._charOffset = -1; |
| } |
| int get offset => _charOffset; |
| void set offset(int offset2) { |
| _charOffset = offset2; |
| } |
| int advance() { |
| if (++_charOffset < _stringLength) { |
| return _string.codeUnitAt(_charOffset); |
| } |
| _charOffset = _stringLength; |
| return -1; |
| } |
| String getString(int start, int endDelta) => _string.substring(start, _charOffset + 1 + endDelta); |
| int peek() { |
| if (_charOffset + 1 < _stringLength) { |
| return _string.codeUnitAt(_charOffset + 1); |
| } |
| return -1; |
| } |
| } |
| /** |
| * Instances of the class {@code CharBufferScanner} implement a scanner that reads from a character |
| * buffer. The scanning logic is in the superclass. |
| * @coverage dart.engine.html |
| */ |
| class CharBufferScanner extends AbstractScanner { |
| /** |
| * The buffer from which characters will be read. |
| */ |
| CharSequence _buffer; |
| /** |
| * The number of characters in the buffer. |
| */ |
| int _bufferLength = 0; |
| /** |
| * The index of the last character that was read. |
| */ |
| int _charOffset = 0; |
| /** |
| * Initialize a newly created scanner to scan the characters in the given character buffer. |
| * @param source the source being scanned |
| * @param buffer the buffer from which characters will be read |
| */ |
| CharBufferScanner(Source source, CharSequence buffer) : super(source) { |
| this._buffer = buffer; |
| this._bufferLength = buffer.length(); |
| this._charOffset = -1; |
| } |
| int get offset => _charOffset; |
| int advance() { |
| if (++_charOffset < _bufferLength) { |
| return _buffer.charAt(_charOffset); |
| } |
| _charOffset = _bufferLength; |
| return -1; |
| } |
| String getString(int start, int endDelta) => _buffer.subSequence(start, _charOffset + 1 + endDelta).toString(); |
| int peek() { |
| if (_charOffset + 1 < _bufferLength) { |
| return _buffer.charAt(_charOffset + 1); |
| } |
| return -1; |
| } |
| } |
| /** |
| * Instances of the class {@code ToSourceVisitor} write a source representation of a visited XML |
| * node (and all of it's children) to a writer. |
| * @coverage dart.engine.html |
| */ |
| class ToSourceVisitor implements XmlVisitor<Object> { |
| /** |
| * The writer to which the source is to be written. |
| */ |
| PrintWriter _writer; |
| /** |
| * Initialize a newly created visitor to write source code representing the visited nodes to the |
| * given writer. |
| * @param writer the writer to which the source is to be written |
| */ |
| ToSourceVisitor(PrintWriter writer) { |
| this._writer = writer; |
| } |
| Object visitHtmlUnit(HtmlUnit node) { |
| for (XmlTagNode child in node.tagNodes) { |
| visit(child); |
| } |
| return null; |
| } |
| Object visitXmlAttributeNode(XmlAttributeNode node) { |
| String name2 = node.name.lexeme; |
| Token value2 = node.value; |
| if (name2.length == 0) { |
| _writer.print("__"); |
| } else { |
| _writer.print(name2); |
| } |
| _writer.print("="); |
| if (value2 == null) { |
| _writer.print("__"); |
| } else { |
| _writer.print(value2.lexeme); |
| } |
| return null; |
| } |
| Object visitXmlTagNode(XmlTagNode node) { |
| _writer.print("<"); |
| String tagName = node.tag.lexeme; |
| _writer.print(tagName); |
| for (XmlAttributeNode attribute in node.attributes) { |
| _writer.print(" "); |
| visit(attribute); |
| } |
| _writer.print(node.attributeEnd.lexeme); |
| if (node.closingTag != null) { |
| for (XmlTagNode child in node.tagNodes) { |
| visit(child); |
| } |
| _writer.print("</"); |
| _writer.print(tagName); |
| _writer.print(">"); |
| } |
| return null; |
| } |
| /** |
| * Safely visit the given node. |
| * @param node the node to be visited |
| */ |
| void visit(XmlNode node) { |
| if (node != null) { |
| node.accept(this); |
| } |
| } |
| } |
| /** |
| * The enumeration {@code TokenType} defines the types of tokens that can be returned by the |
| * scanner. |
| * @coverage dart.engine.html |
| */ |
| class TokenType implements Comparable<TokenType> { |
| /** |
| * The type of the token that marks the end of the input. |
| */ |
| static final TokenType EOF = new TokenType_EOF('EOF', 0, ""); |
| static final TokenType EQ = new TokenType('EQ', 1, "="); |
| static final TokenType GT = new TokenType('GT', 2, ">"); |
| static final TokenType LT_SLASH = new TokenType('LT_SLASH', 3, "</"); |
| static final TokenType LT = new TokenType('LT', 4, "<"); |
| static final TokenType SLASH_GT = new TokenType('SLASH_GT', 5, "/>"); |
| static final TokenType COMMENT = new TokenType('COMMENT', 6, null); |
| static final TokenType DECLARATION = new TokenType('DECLARATION', 7, null); |
| static final TokenType DIRECTIVE = new TokenType('DIRECTIVE', 8, null); |
| static final TokenType STRING = new TokenType('STRING', 9, null); |
| static final TokenType TAG = new TokenType('TAG', 10, null); |
| static final TokenType TEXT = new TokenType('TEXT', 11, null); |
| static final List<TokenType> values = [EOF, EQ, GT, LT_SLASH, LT, SLASH_GT, COMMENT, DECLARATION, DIRECTIVE, STRING, TAG, TEXT]; |
| final String __name; |
| final int __ordinal; |
| int get ordinal => __ordinal; |
| /** |
| * The lexeme that defines this type of token, or {@code null} if there is more than one possible |
| * lexeme for this type of token. |
| */ |
| String _lexeme; |
| TokenType(this.__name, this.__ordinal, String lexeme) { |
| this._lexeme = lexeme; |
| } |
| /** |
| * Return the lexeme that defines this type of token, or {@code null} if there is more than one |
| * possible lexeme for this type of token. |
| * @return the lexeme that defines this type of token |
| */ |
| String get lexeme => _lexeme; |
| int compareTo(TokenType other) => __ordinal - other.__ordinal; |
| String toString() => __name; |
| } |
| class TokenType_EOF extends TokenType { |
| TokenType_EOF(String ___name, int ___ordinal, String arg0) : super(___name, ___ordinal, arg0); |
| String toString() => "-eof-"; |
| } |
| /** |
| * Instances of {@code XmlAttributeNode} represent name/value pairs owned by an {@link XmlTagNode}. |
| * @coverage dart.engine.html |
| */ |
| class XmlAttributeNode extends XmlNode { |
| Token _name; |
| Token _equals; |
| Token _value; |
| /** |
| * Construct a new instance representing an XML attribute. |
| * @param name the name token (not {@code null}). This may be a zero length token if the attribute |
| * is badly formed. |
| * @param equals the equals sign or {@code null} if none |
| * @param value the value token (not {@code null}) |
| */ |
| XmlAttributeNode(Token name, Token equals, Token value) { |
| this._name = name; |
| this._equals = equals; |
| this._value = value; |
| } |
| accept(XmlVisitor visitor) => visitor.visitXmlAttributeNode(this); |
| Token get beginToken => _name; |
| Token get endToken => _value; |
| /** |
| * Answer the equals sign token that appears between the name and value tokens. This may be{@code null} if the attribute is badly formed. |
| * @return the token or {@code null} if there is no equals sign between the name and value |
| */ |
| Token get equals => _equals; |
| /** |
| * Answer the attribute name. This may be a zero length token if the attribute is badly formed. |
| * @return the name (not {@code null}) |
| */ |
| Token get name => _name; |
| /** |
| * Answer the lexeme for the value token without the leading and trailing quotes. |
| * @return the text or {@code null} if the value is not specified |
| */ |
| String get text { |
| if (_value == null) { |
| return null; |
| } |
| String text = _value.lexeme; |
| int len = text.length; |
| if (len > 0) { |
| if (text.codeUnitAt(0) == 0x22) { |
| if (len > 1 && text.codeUnitAt(len - 1) == 0x22) { |
| return text.substring(1, len - 1); |
| } else { |
| return text.substring(1); |
| } |
| } else if (text.codeUnitAt(0) == 0x27) { |
| if (len > 1 && text.codeUnitAt(len - 1) == 0x27) { |
| return text.substring(1, len - 1); |
| } else { |
| return text.substring(1); |
| } |
| } |
| } |
| return text; |
| } |
| /** |
| * Answer the attribute value. A properly formed value will start and end with matching quote |
| * characters, but the value returned may not be properly formed. |
| * @return the value or {@code null} if this represents a badly formed attribute |
| */ |
| Token get value => _value; |
| void visitChildren(XmlVisitor<Object> visitor) { |
| } |
| } |
| /** |
| * The interface {@code XmlVisitor} defines the behavior of objects that can be used to visit an{@link XmlNode} structure. |
| * @coverage dart.engine.html |
| */ |
| abstract class XmlVisitor<R> { |
| R visitHtmlUnit(HtmlUnit htmlUnit); |
| R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode); |
| R visitXmlTagNode(XmlTagNode xmlTagNode); |
| } |
| /** |
| * Instances of {@code HtmlScanner} receive and scan HTML content from a {@link Source}.<br/> |
| * For example, the following code scans HTML source and returns the result: |
| * <pre> |
| * HtmlScanner scanner = new HtmlScanner(source); |
| * source.getContents(scanner); |
| * return scanner.getResult(); |
| * </pre> |
| * @coverage dart.engine.html |
| */ |
| class HtmlScanner implements Source_ContentReceiver { |
| List<String> _SCRIPT_TAG = <String> ["script"]; |
| /** |
| * The source being scanned (not {@code null}) |
| */ |
| Source _source; |
| /** |
| * The time at which the contents of the source were last set. |
| */ |
| int _modificationTime = 0; |
| /** |
| * The scanner used to scan the source |
| */ |
| AbstractScanner _scanner; |
| /** |
| * The first token in the token stream. |
| */ |
| Token _token; |
| /** |
| * Construct a new instance to scan the specified source. |
| * @param source the source to be scanned (not {@code null}) |
| */ |
| HtmlScanner(Source source) { |
| this._source = source; |
| } |
| void accept(CharBuffer contents, int modificationTime2) { |
| this._modificationTime = modificationTime2; |
| _scanner = new CharBufferScanner(_source, contents); |
| _scanner.passThroughElements = _SCRIPT_TAG; |
| _token = _scanner.tokenize(); |
| } |
| void accept2(String contents, int modificationTime2) { |
| this._modificationTime = modificationTime2; |
| _scanner = new StringScanner(_source, contents); |
| _scanner.passThroughElements = _SCRIPT_TAG; |
| _token = _scanner.tokenize(); |
| } |
| /** |
| * Answer the result of scanning the source |
| * @return the result (not {@code null}) |
| */ |
| HtmlScanResult get result => new HtmlScanResult(_modificationTime, _token, _scanner.lineStarts); |
| } |
| /** |
| * Instances of the class {@code XmlParser} are used to parse tokens into a AST structure comprised |
| * of {@link XmlNode}s. |
| * @coverage dart.engine.html |
| */ |
| class XmlParser { |
| /** |
| * The source being parsed. |
| */ |
| Source _source; |
| /** |
| * The next token to be parsed. |
| */ |
| Token _currentToken; |
| /** |
| * Construct a parser for the specified source. |
| * @param source the source being parsed |
| */ |
| XmlParser(Source source) { |
| this._source = source; |
| } |
| /** |
| * Answer the source being parsed. |
| * @return the source |
| */ |
| Source get source => _source; |
| /** |
| * Answer {@code true} if the specified tag is self closing and thus should never have content or |
| * child tag nodes. |
| * @param tag the tag (not {@code null}) |
| * @return {@code true} if self closing |
| */ |
| bool isSelfClosing(Token tag) => false; |
| /** |
| * Parse the entire token stream and in the process, advance the current token to the end of the |
| * token stream. |
| * @return the list of tag nodes found (not {@code null}, contains no {@code null}) |
| */ |
| List<XmlTagNode> parseTopTagNodes(Token firstToken) { |
| _currentToken = firstToken; |
| List<XmlTagNode> tagNodes = new List<XmlTagNode>(); |
| while (true) { |
| while (true) { |
| if (_currentToken.type == TokenType.LT) { |
| tagNodes.add(parseTagNode()); |
| } else if (_currentToken.type == TokenType.DECLARATION || _currentToken.type == TokenType.DIRECTIVE || _currentToken.type == TokenType.COMMENT) { |
| _currentToken = _currentToken.next; |
| } else if (_currentToken.type == TokenType.EOF) { |
| return tagNodes; |
| } else { |
| reportUnexpectedToken(); |
| _currentToken = _currentToken.next; |
| } |
| break; |
| } |
| } |
| } |
| /** |
| * Answer the current token. |
| * @return the current token |
| */ |
| Token get currentToken => _currentToken; |
| /** |
| * Insert a synthetic token of the specified type before the current token |
| * @param type the type of token to be inserted (not {@code null}) |
| * @return the synthetic token that was inserted (not {@code null}) |
| */ |
| Token insertSyntheticToken(TokenType type) { |
| Token token = new Token.con2(type, _currentToken.offset, ""); |
| _currentToken.previous.setNext(token); |
| token.setNext(_currentToken); |
| return token; |
| } |
| /** |
| * Parse the token stream for an attribute. This method advances the current token over the |
| * attribute, but should not be called if the {@link #currentToken} is not {@link TokenType#TAG}. |
| * @return the attribute (not {@code null}) |
| */ |
| XmlAttributeNode parseAttribute() { |
| Token name = _currentToken; |
| _currentToken = _currentToken.next; |
| Token equals; |
| if (identical(_currentToken.type, TokenType.EQ)) { |
| equals = _currentToken; |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| equals = insertSyntheticToken(TokenType.EQ); |
| } |
| Token value; |
| if (identical(_currentToken.type, TokenType.STRING)) { |
| value = _currentToken; |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| value = insertSyntheticToken(TokenType.STRING); |
| } |
| return new XmlAttributeNode(name, equals, value); |
| } |
| /** |
| * Parse the stream for a sequence of attributes. This method advances the current token to the |
| * next {@link TokenType#GT}, {@link TokenType#SLASH_GT}, or {@link TokenType#EOF}. |
| * @return a collection of zero or more attributes (not {@code null}, contains no {@code null}s) |
| */ |
| List<XmlAttributeNode> parseAttributes() { |
| TokenType type2 = _currentToken.type; |
| if (identical(type2, TokenType.GT) || identical(type2, TokenType.SLASH_GT) || identical(type2, TokenType.EOF)) { |
| return XmlTagNode.NO_ATTRIBUTES; |
| } |
| List<XmlAttributeNode> attributes = new List<XmlAttributeNode>(); |
| while (true) { |
| while (true) { |
| if (_currentToken.type == TokenType.GT || _currentToken.type == TokenType.SLASH_GT || _currentToken.type == TokenType.EOF) { |
| return attributes; |
| } else if (_currentToken.type == TokenType.TAG) { |
| attributes.add(parseAttribute()); |
| } else { |
| reportUnexpectedToken(); |
| _currentToken = _currentToken.next; |
| } |
| break; |
| } |
| } |
| } |
| /** |
| * Parse the stream for a sequence of tag nodes existing within a parent tag node. This method |
| * advances the current token to the next {@link TokenType#LT_SLASH} or {@link TokenType#EOF}. |
| * @return a list of nodes (not {@code null}, contains no {@code null}s) |
| */ |
| List<XmlTagNode> parseChildTagNodes() { |
| TokenType type2 = _currentToken.type; |
| if (identical(type2, TokenType.LT_SLASH) || identical(type2, TokenType.EOF)) { |
| return XmlTagNode.NO_TAG_NODES; |
| } |
| List<XmlTagNode> nodes = new List<XmlTagNode>(); |
| while (true) { |
| while (true) { |
| if (_currentToken.type == TokenType.LT) { |
| nodes.add(parseTagNode()); |
| } else if (_currentToken.type == TokenType.LT_SLASH || _currentToken.type == TokenType.EOF) { |
| return nodes; |
| } else if (_currentToken.type == TokenType.COMMENT) { |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| _currentToken = _currentToken.next; |
| } |
| break; |
| } |
| } |
| } |
| /** |
| * Parse the token stream for the next tag node. This method advances current token over the |
| * parsed tag node, but should only be called if the current token is {@link TokenType#LT} |
| * @return the tag node or {@code null} if none found |
| */ |
| XmlTagNode parseTagNode() { |
| Token nodeStart = _currentToken; |
| _currentToken = _currentToken.next; |
| Token tag; |
| if (identical(_currentToken.type, TokenType.TAG)) { |
| tag = _currentToken; |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| tag = insertSyntheticToken(TokenType.TAG); |
| } |
| List<XmlAttributeNode> attributes = parseAttributes(); |
| Token attributeEnd; |
| if (identical(_currentToken.type, TokenType.GT) || identical(_currentToken.type, TokenType.SLASH_GT)) { |
| attributeEnd = _currentToken; |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| attributeEnd = insertSyntheticToken(TokenType.SLASH_GT); |
| } |
| if (identical(attributeEnd.type, TokenType.SLASH_GT) || isSelfClosing(tag)) { |
| return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.NO_TAG_NODES, _currentToken, null, attributeEnd); |
| } |
| List<XmlTagNode> tagNodes = parseChildTagNodes(); |
| Token contentEnd; |
| if (identical(_currentToken.type, TokenType.LT_SLASH)) { |
| contentEnd = _currentToken; |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| contentEnd = insertSyntheticToken(TokenType.LT_SLASH); |
| } |
| Token closingTag; |
| if (identical(_currentToken.type, TokenType.TAG)) { |
| closingTag = _currentToken; |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| closingTag = insertSyntheticToken(TokenType.TAG); |
| } |
| Token nodeEnd; |
| if (identical(_currentToken.type, TokenType.GT)) { |
| nodeEnd = _currentToken; |
| _currentToken = _currentToken.next; |
| } else { |
| reportUnexpectedToken(); |
| nodeEnd = insertSyntheticToken(TokenType.GT); |
| } |
| return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd); |
| } |
| /** |
| * Report the current token as unexpected |
| */ |
| void reportUnexpectedToken() { |
| } |
| } |
| /** |
| * Instances of {@code XmlTagNode} represent XML or HTML elements such as {@code <p>} and{@code <body foo="bar"> ... </body>}. |
| * @coverage dart.engine.html |
| */ |
| class XmlTagNode extends XmlNode { |
| /** |
| * Constant representing empty list of attributes. |
| */ |
| static List<XmlAttributeNode> NO_ATTRIBUTES = new UnmodifiableListView(new List<XmlAttributeNode>()); |
| /** |
| * Constant representing empty list of tag nodes. |
| */ |
| static List<XmlTagNode> NO_TAG_NODES = new UnmodifiableListView(new List<XmlTagNode>()); |
| /** |
| * The starting {@link TokenType#LT} token (not {@code null}). |
| */ |
| Token _nodeStart; |
| /** |
| * The {@link TokenType#TAG} token after the starting '<' (not {@code null}). |
| */ |
| Token _tag; |
| /** |
| * The attributes contained by the receiver (not {@code null}, contains no {@code null}s). |
| */ |
| List<XmlAttributeNode> _attributes; |
| /** |
| * The {@link TokenType#GT} or {@link TokenType#SLASH_GT} token after the attributes (not{@code null}). The token may be the same token as {@link #nodeEnd} if there are no child{@link #tagNodes}. |
| */ |
| Token _attributeEnd; |
| /** |
| * The tag nodes contained in the receiver (not {@code null}, contains no {@code null}s). |
| */ |
| List<XmlTagNode> _tagNodes; |
| /** |
| * The token (not {@code null}) after the content, which may be |
| * <ul> |
| * <li>(1) {@link TokenType#LT_SLASH} for nodes with open and close tags, or</li> |
| * <li>(2) the {@link TokenType#LT} nodeStart of the next sibling node if this node is self |
| * closing or the attributeEnd is {@link TokenType#SLASH_GT}, or</li> |
| * <li>(3) {@link TokenType#EOF} if the node does not have a closing tag and is the last node in |
| * the stream {@link TokenType#LT_SLASH} token after the content, or {@code null} if there is no |
| * content and the attributes ended with {@link TokenType#SLASH_GT}.</li> |
| * </ul> |
| */ |
| Token _contentEnd; |
| /** |
| * The closing {@link TokenType#TAG} after the child elements or {@code null} if there is no |
| * content and the attributes ended with {@link TokenType#SLASH_GT} |
| */ |
| Token _closingTag; |
| /** |
| * The ending {@link TokenType#GT} or {@link TokenType#SLASH_GT} token (not {@code null}). |
| */ |
| Token _nodeEnd; |
| /** |
| * Construct a new instance representing an XML or HTML element |
| * @param nodeStart the starting {@link TokenType#LT} token (not {@code null}) |
| * @param tag the {@link TokenType#TAG} token after the starting '<' (not {@code null}). |
| * @param attributes the attributes associated with this element or {@link #NO_ATTRIBUTES} (not{@code null}, contains no {@code null}s) |
| * @param attributeEnd The {@link TokenType#GT} or {@link TokenType#SLASH_GT} token after the |
| * attributes (not {@code null}). The token may be the same token as {@link #nodeEnd} if |
| * there are no child {@link #tagNodes}. |
| * @param tagNodes child tag nodes of the receiver or {@link #NO_TAG_NODES} (not {@code null}, |
| * contains no {@code null}s) |
| * @param contentEnd the token (not {@code null}) after the content, which may be |
| * <ul> |
| * <li>(1) {@link TokenType#LT_SLASH} for nodes with open and close tags, or</li> |
| * <li>(2) the {@link TokenType#LT} nodeStart of the next sibling node if this node is |
| * self closing or the attributeEnd is {@link TokenType#SLASH_GT}, or</li> |
| * <li>(3) {@link TokenType#EOF} if the node does not have a closing tag and is the last |
| * node in the stream {@link TokenType#LT_SLASH} token after the content, or {@code null}if there is no content and the attributes ended with {@link TokenType#SLASH_GT}.</li> |
| * </ul> |
| * @param closingTag the closing {@link TokenType#TAG} after the child elements or {@code null} if |
| * there is no content and the attributes ended with {@link TokenType#SLASH_GT} |
| * @param nodeEnd the ending {@link TokenType#GT} or {@link TokenType#SLASH_GT} token (not{@code null}) |
| */ |
| XmlTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) { |
| this._nodeStart = nodeStart; |
| this._tag = tag; |
| this._attributes = becomeParentOfEmpty(attributes, NO_ATTRIBUTES); |
| this._attributeEnd = attributeEnd; |
| this._tagNodes = becomeParentOfEmpty(tagNodes, NO_TAG_NODES); |
| this._contentEnd = contentEnd; |
| this._closingTag = closingTag; |
| this._nodeEnd = nodeEnd; |
| } |
| accept(XmlVisitor visitor) => visitor.visitXmlTagNode(this); |
| /** |
| * The {@link TokenType#GT} or {@link TokenType#SLASH_GT} token after the attributes (not{@code null}). The token may be the same token as {@link #nodeEnd} if there are no child{@link #tagNodes}. |
| * @return the token (not {@code null}) |
| */ |
| Token get attributeEnd => _attributeEnd; |
| /** |
| * Answer the receiver's attributes. Callers should not manipulate the returned list to edit the |
| * AST structure. |
| * @return the attributes (not {@code null}, contains no {@code null}s) |
| */ |
| List<XmlAttributeNode> get attributes => _attributes; |
| Token get beginToken => _nodeStart; |
| /** |
| * The the closing {@link TokenType#TAG} after the child elements or {@code null} if there is no |
| * content and the attributes ended with {@link TokenType#SLASH_GT} |
| * @return the closing tag or {@code null} |
| */ |
| Token get closingTag => _closingTag; |
| /** |
| * Answer a string representing the content contained in the receiver. This includes the textual |
| * representation of any child tag nodes ({@link #getTagNodes()}). Whitespace between '<', |
| * '</', and '>', '/>' is discarded, but all other whitespace is preserved. |
| * @return the content (not {@code null}) |
| */ |
| String get content { |
| Token token = _attributeEnd.next; |
| if (identical(token, _contentEnd)) { |
| return ""; |
| } |
| String content = token.lexeme; |
| token = token.next; |
| if (identical(token, _contentEnd)) { |
| return content; |
| } |
| JavaStringBuilder buffer = new JavaStringBuilder(); |
| while (token != _contentEnd) { |
| buffer.append(token.lexeme); |
| token = token.next; |
| } |
| return buffer.toString(); |
| } |
| /** |
| * Answer the token (not {@code null}) after the content, which may be |
| * <ul> |
| * <li>(1) {@link TokenType#LT_SLASH} for nodes with open and close tags, or</li> |
| * <li>(2) the {@link TokenType#LT} nodeStart of the next sibling node if this node is self |
| * closing or the attributeEnd is {@link TokenType#SLASH_GT}, or</li> |
| * <li>(3) {@link TokenType#EOF} if the node does not have a closing tag and is the last node in |
| * the stream {@link TokenType#LT_SLASH} token after the content, or {@code null} if there is no |
| * content and the attributes ended with {@link TokenType#SLASH_GT}.</li> |
| * </ul> |
| * @return the token (not {@code null}) |
| */ |
| Token get contentEnd => _contentEnd; |
| Token get endToken { |
| if (_nodeEnd != null) { |
| return _nodeEnd; |
| } |
| if (_closingTag != null) { |
| return _closingTag; |
| } |
| if (_contentEnd != null) { |
| return _contentEnd; |
| } |
| if (!_tagNodes.isEmpty) { |
| return _tagNodes[_tagNodes.length - 1].endToken; |
| } |
| if (_attributeEnd != null) { |
| return _attributeEnd; |
| } |
| if (!_attributes.isEmpty) { |
| return _attributes[_attributes.length - 1].endToken; |
| } |
| return _tag; |
| } |
| /** |
| * Answer the ending {@link TokenType#GT} or {@link TokenType#SLASH_GT} token. |
| * @return the token (not {@code null}) |
| */ |
| Token get nodeEnd => _nodeEnd; |
| /** |
| * Answer the starting {@link TokenType#LT} token. |
| * @return the token (not {@code null}) |
| */ |
| Token get nodeStart => _nodeStart; |
| /** |
| * Answer the {@link TokenType#TAG} token after the starting '<'. |
| * @return the token (not {@code null}) |
| */ |
| Token get tag => _tag; |
| /** |
| * Answer the tag nodes contained in the receiver. Callers should not manipulate the returned list |
| * to edit the AST structure. |
| * @return the children (not {@code null}, contains no {@code null}s) |
| */ |
| List<XmlTagNode> get tagNodes => _tagNodes; |
| void visitChildren(XmlVisitor<Object> visitor) { |
| for (XmlAttributeNode node in _attributes) { |
| node.accept(visitor); |
| } |
| for (XmlTagNode node in _tagNodes) { |
| node.accept(visitor); |
| } |
| } |
| /** |
| * Same as {@link #becomeParentOf(List)}, but returns given "ifEmpty" if "children" is empty |
| */ |
| List becomeParentOfEmpty(List children, List ifEmpty) { |
| if (children != null && children.isEmpty) { |
| return ifEmpty; |
| } |
| return becomeParentOf(children); |
| } |
| } |
| /** |
| * Instances of the class {@code HtmlParser} are used to parse tokens into a AST structure comprised |
| * of {@link XmlNode}s. |
| * @coverage dart.engine.html |
| */ |
| class HtmlParser extends XmlParser { |
| static Set<String> SELF_CLOSING = new Set<String>(); |
| /** |
| * Construct a parser for the specified source. |
| * @param source the source being parsed |
| */ |
| HtmlParser(Source source) : super(source) { |
| } |
| /** |
| * Parse the tokens specified by the given scan result. |
| * @param scanResult the result of scanning an HTML source (not {@code null}) |
| * @return the parse result (not {@code null}) |
| */ |
| HtmlParseResult parse(HtmlScanResult scanResult) { |
| Token firstToken = scanResult.token; |
| List<XmlTagNode> tagNodes = parseTopTagNodes(firstToken); |
| HtmlUnit unit = new HtmlUnit(firstToken, tagNodes, currentToken); |
| return new HtmlParseResult(scanResult.modificationTime, firstToken, scanResult.lineStarts, unit); |
| } |
| /** |
| * Scan then parse the specified source. |
| * @param source the source to be scanned and parsed (not {@code null}) |
| * @return the parse result (not {@code null}) |
| */ |
| HtmlParseResult parse2(Source source) { |
| HtmlScanner scanner = new HtmlScanner(source); |
| source.getContents(scanner); |
| return parse(scanner.result); |
| } |
| bool isSelfClosing(Token tag) => SELF_CLOSING.contains(tag.lexeme); |
| } |
| /** |
| * Instances of the class {@code HtmlUnit} represent the contents of an HTML file. |
| * @coverage dart.engine.html |
| */ |
| class HtmlUnit extends XmlNode { |
| /** |
| * The first token in the token stream that was parsed to form this HTML unit. |
| */ |
| Token _beginToken; |
| /** |
| * The last token in the token stream that was parsed to form this compilation unit. This token |
| * should always have a type of {@link TokenType.EOF}. |
| */ |
| Token _endToken; |
| /** |
| * The tag nodes contained in the receiver (not {@code null}, contains no {@code null}s). |
| */ |
| List<XmlTagNode> _tagNodes; |
| /** |
| * The element associated with this HTML unit or {@code null} if the receiver is not resolved. |
| */ |
| HtmlElementImpl _element; |
| /** |
| * Construct a new instance representing the content of an HTML file. |
| * @param beginToken the first token in the file (not {@code null}) |
| * @param tagNodes child tag nodes of the receiver (not {@code null}, contains no {@code null}s) |
| * @param endToken the last token in the token stream which should be of type{@link TokenType.EOF} |
| */ |
| HtmlUnit(Token beginToken, List<XmlTagNode> tagNodes, Token endToken) { |
| this._beginToken = beginToken; |
| this._tagNodes = becomeParentOf(tagNodes); |
| this._endToken = endToken; |
| } |
| accept(XmlVisitor visitor) => visitor.visitHtmlUnit(this); |
| Token get beginToken => _beginToken; |
| /** |
| * Return the element associated with this HTML unit. |
| * @return the element or {@code null} if the receiver is not resolved |
| */ |
| HtmlElementImpl get element => _element; |
| Token get endToken => _endToken; |
| /** |
| * Answer the tag nodes contained in the receiver. Callers should not manipulate the returned list |
| * to edit the AST structure. |
| * @return the children (not {@code null}, contains no {@code null}s) |
| */ |
| List<XmlTagNode> get tagNodes => _tagNodes; |
| /** |
| * Set the element associated with this HTML unit. |
| * @param element the element |
| */ |
| void set element(HtmlElementImpl element2) { |
| this._element = element2; |
| } |
| void visitChildren(XmlVisitor<Object> visitor) { |
| for (XmlTagNode node in _tagNodes) { |
| node.accept(visitor); |
| } |
| } |
| } |