| Index: pkg/analyzer-experimental/lib/src/generated/html_scanner.dart
|
| diff --git a/pkg/analyzer-experimental/lib/src/generated/html_scanner.dart b/pkg/analyzer-experimental/lib/src/generated/html_scanner.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fa9a3c176ac20716c638e3cda36b48739a123c6f
|
| --- /dev/null
|
| +++ b/pkg/analyzer-experimental/lib/src/generated/html_scanner.dart
|
| @@ -0,0 +1,1261 @@
|
| +// 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.scanner;
|
| +
|
| +import 'dart:collection';
|
| +import 'java_core.dart';
|
| +import 'source.dart';
|
| +import 'error.dart';
|
| +import 'instrumentation.dart';
|
| +
|
| +/**
|
| + * 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.
|
| + */
|
| +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_143_impl(type, offset);
|
| + }
|
| + _jtd_constructor_143_impl(TokenType type, int offset) {
|
| + _jtd_constructor_144_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 type4, int offset3, String value7) {
|
| + _jtd_constructor_144_impl(type4, offset3, value7);
|
| + }
|
| + _jtd_constructor_144_impl(TokenType type4, int offset3, String value7) {
|
| + this._type = type4;
|
| + this._value = value7;
|
| + this._offset = offset3;
|
| + }
|
| + /**
|
| + * 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.
|
| + */
|
| +class HtmlParseResult extends HtmlScanResult {
|
| + /**
|
| + * The unit containing the parsed information (not {@code null}).
|
| + */
|
| + HtmlUnit _unit;
|
| + HtmlParseResult(Token token, List<int> lineStarts, HtmlUnit unit) : super(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.
|
| + */
|
| +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.
|
| + */
|
| +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 beginToken5 = beginToken;
|
| + Token endToken4 = endToken;
|
| + if (beginToken5 == null || endToken4 == null) {
|
| + return -1;
|
| + }
|
| + return endToken4.offset + endToken4.length - beginToken5.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 beginToken6 = beginToken;
|
| + if (beginToken6 == 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;
|
| + /**
|
| + * 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<XmlNode> becomeParentOf(List<XmlNode> children) {
|
| + if (children != null) {
|
| + for (JavaIterator<XmlNode> iter = new JavaIterator(children); iter.hasNext;) {
|
| + XmlNode node = iter.next();
|
| + node.parent = this;
|
| + }
|
| + }
|
| + 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;
|
| + }
|
| +}
|
| +/**
|
| + * 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.
|
| + */
|
| +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.
|
| + */
|
| +class HtmlScanResult {
|
| + /**
|
| + * The first token in the token stream (not {@code null}).
|
| + */
|
| + Token _token;
|
| + /**
|
| + * The line start information that was produced.
|
| + */
|
| + List<int> _lineStarts;
|
| + HtmlScanResult(Token token, List<int> lineStarts) {
|
| + 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;
|
| + /**
|
| + * 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.
|
| + */
|
| +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 offset12) {
|
| + _charOffset = offset12;
|
| + }
|
| + 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.
|
| + */
|
| +class CharBufferScanner extends AbstractScanner {
|
| + /**
|
| + * The buffer from which characters will be read.
|
| + */
|
| + CharBuffer _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, CharBuffer 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;
|
| + }
|
| +}
|
| +/**
|
| + * The enumeration {@code TokenType} defines the types of tokens that can be returned by the
|
| + * scanner.
|
| + */
|
| +class 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;
|
| + /**
|
| + * 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;
|
| + 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}.
|
| + */
|
| +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 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.
|
| + */
|
| +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>
|
| + */
|
| +class HtmlScanner implements Source_ContentReceiver {
|
| + List<String> _SCRIPT_TAG = <String> ["script"];
|
| + /**
|
| + * The source being scanned (not {@code null})
|
| + */
|
| + Source _source;
|
| + /**
|
| + * 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;
|
| + }
|
| + accept(CharBuffer contents) {
|
| + _scanner = new CharBufferScanner(_source, contents);
|
| + _scanner.passThroughElements = _SCRIPT_TAG;
|
| + _token = _scanner.tokenize();
|
| + }
|
| + void accept2(String contents) {
|
| + _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(_token, _scanner.lineStarts);
|
| +}
|
| +/**
|
| + * Instances of the class {@code XmlParser} are used to parse tokens into a AST structure comprised
|
| + * of {@link XmlNode}s.
|
| + */
|
| +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 type11 = _currentToken.type;
|
| + if (identical(type11, TokenType.GT) || identical(type11, TokenType.SLASH_GT) || identical(type11, 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 type12 = _currentToken.type;
|
| + if (identical(type12, TokenType.LT_SLASH) || identical(type12, 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>}.
|
| + */
|
| +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 = becomeParentOf(attributes);
|
| + this._attributeEnd = attributeEnd;
|
| + this._tagNodes = becomeParentOf(tagNodes);
|
| + 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;
|
| + }
|
| + StringBuffer buffer = new StringBuffer();
|
| + while (token != _contentEnd) {
|
| + buffer.write(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);
|
| + }
|
| + }
|
| +}
|
| +/**
|
| + * Instances of the class {@code HtmlParser} are used to parse tokens into a AST structure comprised
|
| + * of {@link XmlNode}s.
|
| + */
|
| +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(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.
|
| + */
|
| +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;
|
| + /**
|
| + * 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;
|
| + 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;
|
| + void visitChildren(XmlVisitor<Object> visitor) {
|
| + for (XmlTagNode node in _tagNodes) {
|
| + node.accept(visitor);
|
| + }
|
| + }
|
| +}
|
|
|