| Index: pkg/analyzer/lib/src/generated/html.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
|
| index 5b4c6ac0578cc85412a18e8bcecf2af3a1c4c560..1e1b7b31bf2ed77bf6a6f98ffe585afd69ca3ef8 100644
|
| --- a/pkg/analyzer/lib/src/generated/html.dart
|
| +++ b/pkg/analyzer/lib/src/generated/html.dart
|
| @@ -8,15 +8,17 @@
|
| library engine.html;
|
|
|
| import 'dart:collection';
|
| +
|
| +import 'ast.dart';
|
| +import 'element.dart';
|
| +import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver,
|
| + ExpressionVisitor;
|
| +import 'error.dart' show AnalysisErrorListener;
|
| import 'java_core.dart';
|
| import 'java_engine.dart';
|
| -import 'source.dart';
|
| -import 'error.dart' show AnalysisErrorListener;
|
| -import 'scanner.dart' as sc show Scanner, SubSequenceReader, Token;
|
| import 'parser.dart' show Parser;
|
| -import 'ast.dart';
|
| -import 'element.dart';
|
| -import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver, ExpressionVisitor;
|
| +import 'scanner.dart' as sc show Scanner, SubSequenceReader, Token;
|
| +import 'source.dart';
|
|
|
| /**
|
| * The abstract class `AbstractScanner` implements a scanner for HTML code. Subclasses are
|
| @@ -82,18 +84,8 @@ abstract class AbstractScanner {
|
| * Set array of element tags for which the content between tags should be consider a single token.
|
| */
|
| void set passThroughElements(List<String> passThroughElements) {
|
| - this._passThroughElements = passThroughElements != null ? passThroughElements : _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();
|
| + this._passThroughElements =
|
| + passThroughElements != null ? passThroughElements : _NO_PASS_THROUGH_ELEMENTS;
|
| }
|
|
|
| /**
|
| @@ -129,9 +121,21 @@ abstract class AbstractScanner {
|
| _lineStarts.add(offset);
|
| }
|
|
|
| + /**
|
| + * 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();
|
| + }
|
| +
|
| void _appendEofToken() {
|
| Token eofToken = new Token.con1(TokenType.EOF, offset);
|
| - // The EOF token points to itself so that there is always infinite look-ahead.
|
| + // The EOF token points to itself so that there is always infinite
|
| + // look-ahead.
|
| eofToken.setNext(eofToken);
|
| _tail = _tail.setNext(eofToken);
|
| }
|
| @@ -142,9 +146,11 @@ abstract class AbstractScanner {
|
| return token;
|
| }
|
|
|
| - Token _emitWithOffset(TokenType type, int start) => _emit(new Token.con1(type, start));
|
| + Token _emitWithOffset(TokenType type, int start) =>
|
| + _emit(new Token.con1(type, start));
|
|
|
| - Token _emitWithOffsetAndLength(TokenType type, int start, int count) => _emit(new Token.con2(type, start, getString(start, count)));
|
| + Token _emitWithOffsetAndLength(TokenType type, int start, int count) =>
|
| + _emit(new Token.con2(type, start, getString(start, count)));
|
|
|
| Token _firstToken() => _tokens.next;
|
|
|
| @@ -362,16 +368,6 @@ class ExpressionVisitor_HtmlUnitUtils_getExpression extends ExpressionVisitor {
|
| * of [XmlNode]s.
|
| */
|
| class HtmlParser extends XmlParser {
|
| - /**
|
| - * The line information associated with the source being parsed.
|
| - */
|
| - LineInfo _lineInfo;
|
| -
|
| - /**
|
| - * The error listener to which errors will be reported.
|
| - */
|
| - final AnalysisErrorListener _errorListener;
|
| -
|
| static String _APPLICATION_DART_IN_DOUBLE_QUOTES = "\"application/dart\"";
|
|
|
| static String _APPLICATION_DART_IN_SINGLE_QUOTES = "'application/dart'";
|
| @@ -383,49 +379,31 @@ class HtmlParser extends XmlParser {
|
| /**
|
| * A set containing the names of tags that do not have a closing tag.
|
| */
|
| - static Set<String> SELF_CLOSING = new HashSet<String>.from(<String>[
|
| - "area",
|
| - "base",
|
| - "basefont",
|
| - "br",
|
| - "col",
|
| - "frame",
|
| - "hr",
|
| - "img",
|
| - "input",
|
| - "link",
|
| - "meta",
|
| - "param",
|
| - "!"]);
|
| + static Set<String> SELF_CLOSING = new HashSet<String>.from(
|
| + <String>[
|
| + "area",
|
| + "base",
|
| + "basefont",
|
| + "br",
|
| + "col",
|
| + "frame",
|
| + "hr",
|
| + "img",
|
| + "input",
|
| + "link",
|
| + "meta",
|
| + "param",
|
| + "!"]);
|
|
|
| /**
|
| - * Given the contents of an embedded expression that occurs at the given offset, parse it as a
|
| - * Dart expression. The contents should not include the expression's delimiters.
|
| - *
|
| - * @param source the source that contains that given token
|
| - * @param token the token to start parsing from
|
| - * @return the Dart expression that was parsed
|
| + * The line information associated with the source being parsed.
|
| */
|
| - static Expression parseEmbeddedExpression(Source source, sc.Token token, AnalysisErrorListener errorListener) {
|
| - Parser parser = new Parser(source, errorListener);
|
| - return parser.parseExpression(token);
|
| - }
|
| + LineInfo _lineInfo;
|
|
|
| /**
|
| - * Given the contents of an embedded expression that occurs at the given offset, scans it as a
|
| - * Dart code.
|
| - *
|
| - * @param source the source of that contains the given contents
|
| - * @param contents the contents to scan
|
| - * @param contentOffset the offset of the contents in the larger file
|
| - * @return the first Dart token
|
| + * The error listener to which errors will be reported.
|
| */
|
| - static sc.Token scanDartSource(Source source, LineInfo lineInfo, String contents, int contentOffset, AnalysisErrorListener errorListener) {
|
| - LineInfo_Location location = lineInfo.getLocation(contentOffset);
|
| - sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(contents, contentOffset), errorListener);
|
| - scanner.setSourceStart(location.lineNumber, location.columnNumber);
|
| - return scanner.tokenize();
|
| - }
|
| + final AnalysisErrorListener _errorListener;
|
|
|
| /**
|
| * Construct a parser for the specified source.
|
| @@ -435,30 +413,31 @@ class HtmlParser extends XmlParser {
|
| */
|
| HtmlParser(Source source, this._errorListener) : super(source);
|
|
|
| - /**
|
| - * Parse the given tokens.
|
| - *
|
| - * @param token the first token in the stream of tokens to be parsed
|
| - * @param lineInfo the line information created by the scanner
|
| - * @return the parse result (not `null`)
|
| - */
|
| - HtmlUnit parse(Token token, LineInfo lineInfo) {
|
| - this._lineInfo = lineInfo;
|
| - List<XmlTagNode> tagNodes = parseTopTagNodes(token);
|
| - return new HtmlUnit(token, tagNodes, currentToken);
|
| - }
|
| -
|
| @override
|
| - XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) => new XmlAttributeNode(name, equals, value);
|
| + XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) =>
|
| + new XmlAttributeNode(name, equals, value);
|
|
|
| @override
|
| - XmlTagNode createTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) {
|
| + XmlTagNode createTagNode(Token nodeStart, Token tag,
|
| + List<XmlAttributeNode> attributes, Token attributeEnd,
|
| + List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) {
|
| if (_isScriptNode(tag, attributes, tagNodes)) {
|
| - HtmlScriptTagNode tagNode = new HtmlScriptTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
|
| + HtmlScriptTagNode tagNode = new HtmlScriptTagNode(
|
| + nodeStart,
|
| + tag,
|
| + attributes,
|
| + attributeEnd,
|
| + tagNodes,
|
| + contentEnd,
|
| + closingTag,
|
| + nodeEnd);
|
| String contents = tagNode.content;
|
| int contentOffset = attributeEnd.end;
|
| LineInfo_Location location = _lineInfo.getLocation(contentOffset);
|
| - sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(contents, contentOffset), _errorListener);
|
| + sc.Scanner scanner = new sc.Scanner(
|
| + source,
|
| + new sc.SubSequenceReader(contents, contentOffset),
|
| + _errorListener);
|
| scanner.setSourceStart(location.lineNumber, location.columnNumber);
|
| sc.Token firstToken = scanner.tokenize();
|
| Parser parser = new Parser(source, _errorListener);
|
| @@ -467,19 +446,41 @@ class HtmlParser extends XmlParser {
|
| tagNode.script = unit;
|
| return tagNode;
|
| }
|
| - return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
|
| + return new XmlTagNode(
|
| + nodeStart,
|
| + tag,
|
| + attributes,
|
| + attributeEnd,
|
| + tagNodes,
|
| + contentEnd,
|
| + closingTag,
|
| + nodeEnd);
|
| }
|
|
|
| @override
|
| bool isSelfClosing(Token tag) => SELF_CLOSING.contains(tag.lexeme);
|
|
|
| /**
|
| + * Parse the given tokens.
|
| + *
|
| + * @param token the first token in the stream of tokens to be parsed
|
| + * @param lineInfo the line information created by the scanner
|
| + * @return the parse result (not `null`)
|
| + */
|
| + HtmlUnit parse(Token token, LineInfo lineInfo) {
|
| + this._lineInfo = lineInfo;
|
| + List<XmlTagNode> tagNodes = parseTopTagNodes(token);
|
| + return new HtmlUnit(token, tagNodes, currentToken);
|
| + }
|
| +
|
| + /**
|
| * Determine if the specified node is a Dart script.
|
| *
|
| * @param node the node to be tested (not `null`)
|
| * @return `true` if the node is a Dart script
|
| */
|
| - bool _isScriptNode(Token tag, List<XmlAttributeNode> attributes, List<XmlTagNode> tagNodes) {
|
| + bool _isScriptNode(Token tag, List<XmlAttributeNode> attributes,
|
| + List<XmlTagNode> tagNodes) {
|
| if (tagNodes.length != 0 || tag.lexeme != _SCRIPT) {
|
| return false;
|
| }
|
| @@ -488,7 +489,8 @@ class HtmlParser extends XmlParser {
|
| Token valueToken = attribute.valueToken;
|
| if (valueToken != null) {
|
| String value = valueToken.lexeme;
|
| - if (value == _APPLICATION_DART_IN_DOUBLE_QUOTES || value == _APPLICATION_DART_IN_SINGLE_QUOTES) {
|
| + if (value == _APPLICATION_DART_IN_DOUBLE_QUOTES ||
|
| + value == _APPLICATION_DART_IN_SINGLE_QUOTES) {
|
| return true;
|
| }
|
| }
|
| @@ -496,6 +498,40 @@ class HtmlParser extends XmlParser {
|
| }
|
| return false;
|
| }
|
| +
|
| + /**
|
| + * Given the contents of an embedded expression that occurs at the given offset, parse it as a
|
| + * Dart expression. The contents should not include the expression's delimiters.
|
| + *
|
| + * @param source the source that contains that given token
|
| + * @param token the token to start parsing from
|
| + * @return the Dart expression that was parsed
|
| + */
|
| + static Expression parseEmbeddedExpression(Source source, sc.Token token,
|
| + AnalysisErrorListener errorListener) {
|
| + Parser parser = new Parser(source, errorListener);
|
| + return parser.parseExpression(token);
|
| + }
|
| +
|
| + /**
|
| + * Given the contents of an embedded expression that occurs at the given offset, scans it as a
|
| + * Dart code.
|
| + *
|
| + * @param source the source of that contains the given contents
|
| + * @param contents the contents to scan
|
| + * @param contentOffset the offset of the contents in the larger file
|
| + * @return the first Dart token
|
| + */
|
| + static sc.Token scanDartSource(Source source, LineInfo lineInfo,
|
| + String contents, int contentOffset, AnalysisErrorListener errorListener) {
|
| + LineInfo_Location location = lineInfo.getLocation(contentOffset);
|
| + sc.Scanner scanner = new sc.Scanner(
|
| + source,
|
| + new sc.SubSequenceReader(contents, contentOffset),
|
| + errorListener);
|
| + scanner.setSourceStart(location.lineNumber, location.columnNumber);
|
| + return scanner.tokenize();
|
| + }
|
| }
|
|
|
| /**
|
| @@ -526,10 +562,18 @@ class HtmlScriptTagNode extends XmlTagNode {
|
| * @param closingTag the name of the tag that occurs in the closing tag
|
| * @param nodeEnd the last token in the tag
|
| */
|
| - HtmlScriptTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
|
| -
|
| - @override
|
| - accept(XmlVisitor visitor) => visitor.visitHtmlScriptTagNode(this);
|
| + HtmlScriptTagNode(Token nodeStart, Token tag,
|
| + List<XmlAttributeNode> attributes, Token attributeEnd,
|
| + List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd)
|
| + : super(
|
| + nodeStart,
|
| + tag,
|
| + attributes,
|
| + attributeEnd,
|
| + tagNodes,
|
| + contentEnd,
|
| + closingTag,
|
| + nodeEnd);
|
|
|
| /**
|
| * Return the AST structure representing the Dart code within this tag, or `null` if this
|
| @@ -547,6 +591,9 @@ class HtmlScriptTagNode extends XmlTagNode {
|
| void set script(CompilationUnit unit) {
|
| _script = unit;
|
| }
|
| +
|
| + @override
|
| + accept(XmlVisitor visitor) => visitor.visitHtmlScriptTagNode(this);
|
| }
|
|
|
| /**
|
| @@ -581,9 +628,6 @@ class HtmlUnit extends XmlNode {
|
| this._tagNodes = becomeParentOfAll(tagNodes);
|
| }
|
|
|
| - @override
|
| - accept(XmlVisitor visitor) => visitor.visitHtmlUnit(this);
|
| -
|
| /**
|
| * Return the element associated with this HTML unit.
|
| *
|
| @@ -592,6 +636,15 @@ class HtmlUnit extends XmlNode {
|
| @override
|
| HtmlElement get element => super.element as HtmlElement;
|
|
|
| + @override
|
| + void set element(Element element) {
|
| + if (element != null && element is! HtmlElement) {
|
| + throw new IllegalArgumentException(
|
| + "HtmlElement expected, but ${element.runtimeType} given");
|
| + }
|
| + super.element = element;
|
| + }
|
| +
|
| /**
|
| * Answer the tag nodes contained in the receiver. Callers should not manipulate the returned list
|
| * to edit the AST structure.
|
| @@ -601,12 +654,7 @@ class HtmlUnit extends XmlNode {
|
| List<XmlTagNode> get tagNodes => _tagNodes;
|
|
|
| @override
|
| - void set element(Element element) {
|
| - if (element != null && element is! HtmlElement) {
|
| - throw new IllegalArgumentException("HtmlElement expected, but ${element.runtimeType} given");
|
| - }
|
| - super.element = element;
|
| - }
|
| + accept(XmlVisitor visitor) => visitor.visitHtmlUnit(this);
|
|
|
| @override
|
| void visitChildren(XmlVisitor visitor) {
|
| @@ -628,8 +676,8 @@ class HtmlUnitUtils {
|
| if (htmlUnit == null) {
|
| return null;
|
| }
|
| - RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode visitor
|
| - = new RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode(offset);
|
| + RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode visitor =
|
| + new RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode(offset);
|
| try {
|
| htmlUnit.accept(visitor);
|
| } on HtmlUnitUtils_FoundAttributeNodeError catch (e) {
|
| @@ -663,7 +711,8 @@ class HtmlUnitUtils {
|
| static Element getElementToOpen(HtmlUnit htmlUnit, Expression expression) {
|
| Element element = getElement(expression);
|
| {
|
| - AngularElement angularElement = AngularHtmlUnitResolver.getAngularElement(element);
|
| + AngularElement angularElement =
|
| + AngularHtmlUnitResolver.getAngularElement(element);
|
| if (angularElement != null) {
|
| return angularElement;
|
| }
|
| @@ -679,8 +728,8 @@ class HtmlUnitUtils {
|
| if (htmlUnit == null) {
|
| return null;
|
| }
|
| - RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode visitor
|
| - = new RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode(offset);
|
| + RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode visitor =
|
| + new RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode(offset);
|
| try {
|
| htmlUnit.accept(visitor);
|
| } on HtmlUnitUtils_FoundTagNodeError catch (e) {
|
| @@ -697,8 +746,8 @@ class HtmlUnitUtils {
|
| if (htmlUnit == null) {
|
| return null;
|
| }
|
| - ExpressionVisitor_HtmlUnitUtils_getExpression visitor
|
| - = new ExpressionVisitor_HtmlUnitUtils_getExpression(offset);
|
| + ExpressionVisitor_HtmlUnitUtils_getExpression visitor =
|
| + new ExpressionVisitor_HtmlUnitUtils_getExpression(offset);
|
| try {
|
| // TODO(scheglov) this code is very Angular specific
|
| htmlUnit.accept(visitor);
|
| @@ -725,7 +774,9 @@ class HtmlUnitUtils {
|
| }
|
| // is "offset" in the open tag?
|
| Token closeTag = node.closingTag;
|
| - if (closeTag != null && closeTag.offset <= offset && offset <= closeTag.end) {
|
| + if (closeTag != null &&
|
| + closeTag.offset <= offset &&
|
| + offset <= closeTag.end) {
|
| return node;
|
| }
|
| // not on a tag name
|
| @@ -821,7 +872,8 @@ class RecursiveXmlVisitor<R> implements XmlVisitor<R> {
|
| }
|
| }
|
|
|
| -class RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode extends RecursiveXmlVisitor<Object> {
|
| +class RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode extends
|
| + RecursiveXmlVisitor<Object> {
|
| final int offset;
|
|
|
| XmlAttributeNode result;
|
| @@ -839,7 +891,8 @@ class RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode extends RecursiveXmlVis
|
| }
|
| }
|
|
|
| -class RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode extends RecursiveXmlVisitor<Object> {
|
| +class RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode extends
|
| + RecursiveXmlVisitor<Object> {
|
| final int offset;
|
|
|
| XmlTagNode result;
|
| @@ -925,7 +978,8 @@ class StringScanner extends AbstractScanner {
|
| }
|
|
|
| @override
|
| - String getString(int start, int endDelta) => _string.substring(start, _charOffset + 1 + endDelta).toString();
|
| + String getString(int start, int endDelta) =>
|
| + _string.substring(start, _charOffset + 1 + endDelta).toString();
|
|
|
| @override
|
| int peek() {
|
| @@ -937,86 +991,6 @@ class StringScanner extends AbstractScanner {
|
| }
|
|
|
| /**
|
| - * Instances of the class `ToSourceVisitor` write a source representation of a visited XML
|
| - * node (and all of it's children) to a writer.
|
| - */
|
| -class ToSourceVisitor implements XmlVisitor<Object> {
|
| - /**
|
| - * The writer to which the source is to be written.
|
| - */
|
| - final 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(this._writer);
|
| -
|
| - @override
|
| - Object visitHtmlScriptTagNode(HtmlScriptTagNode node) => visitXmlTagNode(node);
|
| -
|
| - @override
|
| - Object visitHtmlUnit(HtmlUnit node) {
|
| - for (XmlTagNode child in node.tagNodes) {
|
| - _visit(child);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @override
|
| - Object visitXmlAttributeNode(XmlAttributeNode node) {
|
| - String name = node.name;
|
| - Token value = node.valueToken;
|
| - if (name.length == 0) {
|
| - _writer.print("__");
|
| - } else {
|
| - _writer.print(name);
|
| - }
|
| - _writer.print("=");
|
| - if (value == null) {
|
| - _writer.print("__");
|
| - } else {
|
| - _writer.print(value.lexeme);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @override
|
| - Object visitXmlTagNode(XmlTagNode node) {
|
| - _writer.print("<");
|
| - String tagName = node.tag;
|
| - _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);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| * Instances of the class `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.
|
| */
|
| @@ -1075,6 +1049,15 @@ class Token {
|
| int get end => offset + length;
|
|
|
| /**
|
| + * Return `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 (`0`).
|
| + *
|
| + * @return `true` if this token is a synthetic token
|
| + */
|
| + bool get isSynthetic => length == 0;
|
| +
|
| + /**
|
| * Return the number of characters in the node's source range.
|
| *
|
| * @return the number of characters in the node's source range
|
| @@ -1096,15 +1079,6 @@ class Token {
|
| Token get next => _next;
|
|
|
| /**
|
| - * Return `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 (`0`).
|
| - *
|
| - * @return `true` if this token is a synthetic token
|
| - */
|
| - bool get 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.
|
| *
|
| @@ -1177,16 +1151,103 @@ class TokenType extends Enum<TokenType> {
|
| }
|
|
|
| class TokenType_EOF extends TokenType {
|
| - const TokenType_EOF(String name, int ordinal, String arg0) : super(name, ordinal, arg0);
|
| + const TokenType_EOF(String name, int ordinal, String arg0)
|
| + : super(name, ordinal, arg0);
|
|
|
| @override
|
| String toString() => "-eof-";
|
| }
|
|
|
| /**
|
| + * Instances of the class `ToSourceVisitor` write a source representation of a visited XML
|
| + * node (and all of it's children) to a writer.
|
| + */
|
| +class ToSourceVisitor implements XmlVisitor<Object> {
|
| + /**
|
| + * The writer to which the source is to be written.
|
| + */
|
| + final 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(this._writer);
|
| +
|
| + @override
|
| + Object visitHtmlScriptTagNode(HtmlScriptTagNode node) =>
|
| + visitXmlTagNode(node);
|
| +
|
| + @override
|
| + Object visitHtmlUnit(HtmlUnit node) {
|
| + for (XmlTagNode child in node.tagNodes) {
|
| + _visit(child);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitXmlAttributeNode(XmlAttributeNode node) {
|
| + String name = node.name;
|
| + Token value = node.valueToken;
|
| + if (name.length == 0) {
|
| + _writer.print("__");
|
| + } else {
|
| + _writer.print(name);
|
| + }
|
| + _writer.print("=");
|
| + if (value == null) {
|
| + _writer.print("__");
|
| + } else {
|
| + _writer.print(value.lexeme);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitXmlTagNode(XmlTagNode node) {
|
| + _writer.print("<");
|
| + String tagName = node.tag;
|
| + _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);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| * Instances of `XmlAttributeNode` represent name/value pairs owned by an [XmlTagNode].
|
| */
|
| class XmlAttributeNode extends XmlNode {
|
| + /**
|
| + * An empty list of XML attribute nodes.
|
| + */
|
| + static const List<XmlAttributeNode> EMPTY_LIST = const <XmlAttributeNode>[];
|
| +
|
| final Token _name;
|
|
|
| final Token equals;
|
| @@ -1196,11 +1257,6 @@ class XmlAttributeNode extends XmlNode {
|
| List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
|
|
|
| /**
|
| - * An empty list of XML attribute nodes.
|
| - */
|
| - static const List<XmlAttributeNode> EMPTY_LIST = const <XmlAttributeNode>[];
|
| -
|
| - /**
|
| * Construct a new instance representing an XML attribute.
|
| *
|
| * @param name the name token (not `null`). This may be a zero length token if the attribute
|
| @@ -1211,9 +1267,6 @@ class XmlAttributeNode extends XmlNode {
|
| XmlAttributeNode(this._name, this.equals, this._value);
|
|
|
| @override
|
| - accept(XmlVisitor visitor) => visitor.visitXmlAttributeNode(this);
|
| -
|
| - @override
|
| Token get beginToken => _name;
|
|
|
| @override
|
| @@ -1243,7 +1296,8 @@ class XmlAttributeNode extends XmlNode {
|
| if (_value == null) {
|
| return null;
|
| }
|
| - //TODO (danrubel): replace HTML character encodings with the actual characters
|
| + //TODO (danrubel): replace HTML character encodings with the actual
|
| + // characters
|
| String text = _value.lexeme;
|
| int len = text.length;
|
| if (len > 0) {
|
| @@ -1274,7 +1328,8 @@ class XmlAttributeNode extends XmlNode {
|
| return -1;
|
| }
|
| String text = _value.lexeme;
|
| - if (StringUtilities.startsWithChar(text, 0x22) || StringUtilities.startsWithChar(text, 0x27)) {
|
| + if (StringUtilities.startsWithChar(text, 0x22) ||
|
| + StringUtilities.startsWithChar(text, 0x27)) {
|
| return _value.offset + 1;
|
| }
|
| return _value.offset;
|
| @@ -1289,6 +1344,9 @@ class XmlAttributeNode extends XmlNode {
|
| Token get valueToken => _value;
|
|
|
| @override
|
| + accept(XmlVisitor visitor) => visitor.visitXmlAttributeNode(this);
|
| +
|
| + @override
|
| void visitChildren(XmlVisitor visitor) {
|
| // no children to visit
|
| }
|
| @@ -1305,11 +1363,6 @@ abstract class XmlExpression {
|
| static const List<XmlExpression> EMPTY_ARRAY = const <XmlExpression>[];
|
|
|
| /**
|
| - * Check if the given offset belongs to the expression's source range.
|
| - */
|
| - bool contains(int offset) => this.offset <= offset && offset < end;
|
| -
|
| - /**
|
| * Return the offset of the character immediately following the last character of this
|
| * expression's source range. This is equivalent to `getOffset() + getLength()`.
|
| *
|
| @@ -1328,6 +1381,11 @@ abstract class XmlExpression {
|
| int get offset;
|
|
|
| /**
|
| + * Check if the given offset belongs to the expression's source range.
|
| + */
|
| + bool contains(int offset) => this.offset <= offset && offset < end;
|
| +
|
| + /**
|
| * Return the [Reference] at the given offset.
|
| *
|
| * @param offset the offset from the beginning of the file
|
| @@ -1368,14 +1426,6 @@ abstract class XmlNode {
|
| Element _element;
|
|
|
| /**
|
| - * 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 `null` if none
|
| @@ -1390,6 +1440,15 @@ abstract class XmlNode {
|
| Element get element => _element;
|
|
|
| /**
|
| + * Set the element associated with this node.
|
| + *
|
| + * @param element the element
|
| + */
|
| + void set element(Element element) {
|
| + this._element = element;
|
| + }
|
| +
|
| + /**
|
| * Return the offset of the character immediately following the last character of this node's
|
| * source range. This is equivalent to `node.getOffset() + node.getLength()`. For an html
|
| * unit this will be equal to the length of the unit's source.
|
| @@ -1445,28 +1504,33 @@ abstract class XmlNode {
|
| XmlNode get parent => _parent;
|
|
|
| /**
|
| - * Set the element associated with this node.
|
| + * Set the parent of this node to the given node.
|
| *
|
| - * @param element the element
|
| + * @param newParent the node that is to be made the parent of this node
|
| */
|
| - void set element(Element element) {
|
| - this._element = element;
|
| - }
|
| -
|
| - @override
|
| - String toString() {
|
| - PrintStringWriter writer = new PrintStringWriter();
|
| - accept(new ToSourceVisitor(writer));
|
| - return writer.toString();
|
| + void set parent(XmlNode newParent) {
|
| + XmlNode current = newParent;
|
| + while (current != null) {
|
| + if (identical(current, this)) {
|
| + AnalysisEngine.instance.logger.logError(
|
| + "Circular structure while setting an XML node's parent",
|
| + new CaughtException(
|
| + new ArgumentError(_buildRecursiveStructureMessage(newParent)),
|
| + null));
|
| + return;
|
| + }
|
| + current = current.parent;
|
| + }
|
| + _parent = newParent;
|
| }
|
|
|
| /**
|
| - * Use the given visitor to visit all of the children of this node. The children will be visited
|
| - * in source order.
|
| + * Use the given visitor to visit this node.
|
| *
|
| - * @param visitor the visitor that will be used to visit the children of 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
|
| */
|
| - void visitChildren(XmlVisitor visitor);
|
| + accept(XmlVisitor visitor);
|
|
|
| /**
|
| * Make this node the parent of the given child node.
|
| @@ -1503,6 +1567,21 @@ abstract class XmlNode {
|
| return children;
|
| }
|
|
|
| + @override
|
| + 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 visitor);
|
| +
|
| /**
|
| * This method exists for debugging purposes only.
|
| */
|
| @@ -1538,27 +1617,6 @@ abstract class XmlNode {
|
| }
|
| return buffer.toString();
|
| }
|
| -
|
| - /**
|
| - * 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) {
|
| - XmlNode current = newParent;
|
| - while (current != null) {
|
| - if (identical(current, this)) {
|
| - AnalysisEngine.instance.logger.logError(
|
| - "Circular structure while setting an XML node's parent",
|
| - new CaughtException(
|
| - new ArgumentError(_buildRecursiveStructureMessage(newParent)),
|
| - null));
|
| - return;
|
| - }
|
| - current = current.parent;
|
| - }
|
| - _parent = newParent;
|
| - }
|
| }
|
|
|
| /**
|
| @@ -1584,6 +1642,13 @@ class XmlParser {
|
| XmlParser(this.source);
|
|
|
| /**
|
| + * Answer the current token.
|
| + *
|
| + * @return the current token
|
| + */
|
| + Token get currentToken => _currentToken;
|
| +
|
| + /**
|
| * Create a node representing an attribute.
|
| *
|
| * @param name the name of the attribute
|
| @@ -1591,7 +1656,8 @@ class XmlParser {
|
| * @param value the value of the attribute
|
| * @return the node that was created
|
| */
|
| - XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) => new XmlAttributeNode(name, equals, value);
|
| + XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) =>
|
| + new XmlAttributeNode(name, equals, value);
|
|
|
| /**
|
| * Create a node representing a tag.
|
| @@ -1606,7 +1672,18 @@ class XmlParser {
|
| * @param nodeEnd the last token in the tag
|
| * @return the node that was created
|
| */
|
| - XmlTagNode createTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) => new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
|
| + XmlTagNode createTagNode(Token nodeStart, Token tag,
|
| + List<XmlAttributeNode> attributes, Token attributeEnd,
|
| + List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) =>
|
| + new XmlTagNode(
|
| + nodeStart,
|
| + tag,
|
| + attributes,
|
| + attributeEnd,
|
| + tagNodes,
|
| + contentEnd,
|
| + closingTag,
|
| + nodeEnd);
|
|
|
| /**
|
| * Answer `true` if the specified tag is self closing and thus should never have content or
|
| @@ -1630,7 +1707,9 @@ class XmlParser {
|
| while (type != TokenType.EOF) {
|
| if (type == TokenType.LT) {
|
| tagNodes.add(_parseTagNode());
|
| - } else if (type == TokenType.DECLARATION || type == TokenType.DIRECTIVE || type == TokenType.COMMENT) {
|
| + } else if (type == TokenType.DECLARATION ||
|
| + type == TokenType.DIRECTIVE ||
|
| + type == TokenType.COMMENT) {
|
| // ignored tokens
|
| _currentToken = _currentToken.next;
|
| } else {
|
| @@ -1643,13 +1722,6 @@ class XmlParser {
|
| }
|
|
|
| /**
|
| - * 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 `null`)
|
| @@ -1701,11 +1773,15 @@ class XmlParser {
|
| */
|
| List<XmlAttributeNode> _parseAttributes() {
|
| TokenType type = _currentToken.type;
|
| - if (type == TokenType.GT || type == TokenType.SLASH_GT || type == TokenType.EOF) {
|
| + if (type == TokenType.GT ||
|
| + type == TokenType.SLASH_GT ||
|
| + type == TokenType.EOF) {
|
| return XmlTagNode.NO_ATTRIBUTES;
|
| }
|
| List<XmlAttributeNode> attributes = new List<XmlAttributeNode>();
|
| - while (type != TokenType.GT && type != TokenType.SLASH_GT && type != TokenType.EOF) {
|
| + while (type != TokenType.GT &&
|
| + type != TokenType.SLASH_GT &&
|
| + type != TokenType.EOF) {
|
| if (type == TokenType.TAG) {
|
| attributes.add(_parseAttribute());
|
| } else {
|
| @@ -1767,7 +1843,8 @@ class XmlParser {
|
| List<XmlAttributeNode> attributes = _parseAttributes();
|
| // Token ending attribute list
|
| Token attributeEnd;
|
| - if (_currentToken.type == TokenType.GT || _currentToken.type == TokenType.SLASH_GT) {
|
| + if (_currentToken.type == TokenType.GT ||
|
| + _currentToken.type == TokenType.SLASH_GT) {
|
| attributeEnd = _currentToken;
|
| _currentToken = _currentToken.next;
|
| } else {
|
| @@ -1776,7 +1853,15 @@ class XmlParser {
|
| }
|
| // If the node has no children, then return the node
|
| if (attributeEnd.type == TokenType.SLASH_GT || isSelfClosing(tag)) {
|
| - return createTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.NO_TAG_NODES, _currentToken, null, attributeEnd);
|
| + return createTagNode(
|
| + nodeStart,
|
| + tag,
|
| + attributes,
|
| + attributeEnd,
|
| + XmlTagNode.NO_TAG_NODES,
|
| + _currentToken,
|
| + null,
|
| + attributeEnd);
|
| }
|
| // Parse the child tag nodes
|
| List<XmlTagNode> tagNodes = _parseChildTagNodes();
|
| @@ -1786,8 +1871,8 @@ class XmlParser {
|
| contentEnd = _currentToken;
|
| _currentToken = _currentToken.next;
|
| } else {
|
| - // TODO (danrubel): handle self closing HTML elements by inserting synthetic tokens
|
| - // but not reporting an error
|
| + // TODO (danrubel): handle self closing HTML elements by inserting
|
| + // synthetic tokens but not reporting an error
|
| _reportUnexpectedToken();
|
| contentEnd = _insertSyntheticToken(TokenType.LT_SLASH);
|
| }
|
| @@ -1809,7 +1894,15 @@ class XmlParser {
|
| _reportUnexpectedToken();
|
| nodeEnd = _insertSyntheticToken(TokenType.GT);
|
| }
|
| - return createTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
|
| + return createTagNode(
|
| + nodeStart,
|
| + tag,
|
| + attributes,
|
| + attributeEnd,
|
| + tagNodes,
|
| + contentEnd,
|
| + closingTag,
|
| + nodeEnd);
|
| }
|
|
|
| /**
|
| @@ -1828,12 +1921,14 @@ class XmlTagNode extends XmlNode {
|
| /**
|
| * Constant representing empty list of attributes.
|
| */
|
| - static List<XmlAttributeNode> NO_ATTRIBUTES = new UnmodifiableListView(new List<XmlAttributeNode>());
|
| + 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>());
|
| + static List<XmlTagNode> NO_TAG_NODES =
|
| + new UnmodifiableListView(new List<XmlTagNode>());
|
|
|
| /**
|
| * The starting [TokenType.LT] token (not `null`).
|
| @@ -1913,29 +2008,13 @@ class XmlTagNode extends XmlNode {
|
| * @param nodeEnd the ending [TokenType.GT] or [TokenType.SLASH_GT] token (not
|
| * `null`)
|
| */
|
| - XmlTagNode(this.nodeStart, this._tag, List<XmlAttributeNode> attributes, this.attributeEnd, List<XmlTagNode> tagNodes, this.contentEnd, this.closingTag, this.nodeEnd) {
|
| + XmlTagNode(this.nodeStart, this._tag, List<XmlAttributeNode> attributes,
|
| + this.attributeEnd, List<XmlTagNode> tagNodes, this.contentEnd, this.closingTag,
|
| + this.nodeEnd) {
|
| this._attributes = becomeParentOfAll(attributes, ifEmpty: NO_ATTRIBUTES);
|
| this._tagNodes = becomeParentOfAll(tagNodes, ifEmpty: NO_TAG_NODES);
|
| }
|
|
|
| - @override
|
| - accept(XmlVisitor visitor) => visitor.visitXmlTagNode(this);
|
| -
|
| - /**
|
| - * Answer the attribute with the specified name.
|
| - *
|
| - * @param name the attribute name
|
| - * @return the attribute or `null` if no matching attribute is found
|
| - */
|
| - XmlAttributeNode getAttribute(String name) {
|
| - for (XmlAttributeNode attribute in _attributes) {
|
| - if (attribute.name == name) {
|
| - return attribute;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| /**
|
| * Answer the receiver's attributes. Callers should not manipulate the returned list to edit the
|
| * AST structure.
|
| @@ -1944,19 +2023,6 @@ class XmlTagNode extends XmlNode {
|
| */
|
| List<XmlAttributeNode> get attributes => _attributes;
|
|
|
| - /**
|
| - * Find the attribute with the given name (see [getAttribute] and answer the lexeme
|
| - * for the attribute's value token without the leading and trailing quotes (see
|
| - * [XmlAttributeNode.getText]).
|
| - *
|
| - * @param name the attribute name
|
| - * @return the attribute text or `null` if no matching attribute is found
|
| - */
|
| - String getAttributeText(String name) {
|
| - XmlAttributeNode attribute = getAttribute(name);
|
| - return attribute != null ? attribute.text : null;
|
| - }
|
| -
|
| @override
|
| Token get beginToken => nodeStart;
|
|
|
| @@ -2033,6 +2099,37 @@ class XmlTagNode extends XmlNode {
|
| Token get tagToken => _tag;
|
|
|
| @override
|
| + accept(XmlVisitor visitor) => visitor.visitXmlTagNode(this);
|
| +
|
| + /**
|
| + * Answer the attribute with the specified name.
|
| + *
|
| + * @param name the attribute name
|
| + * @return the attribute or `null` if no matching attribute is found
|
| + */
|
| + XmlAttributeNode getAttribute(String name) {
|
| + for (XmlAttributeNode attribute in _attributes) {
|
| + if (attribute.name == name) {
|
| + return attribute;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Find the attribute with the given name (see [getAttribute] and answer the lexeme
|
| + * for the attribute's value token without the leading and trailing quotes (see
|
| + * [XmlAttributeNode.getText]).
|
| + *
|
| + * @param name the attribute name
|
| + * @return the attribute text or `null` if no matching attribute is found
|
| + */
|
| + String getAttributeText(String name) {
|
| + XmlAttributeNode attribute = getAttribute(name);
|
| + return attribute != null ? attribute.text : null;
|
| + }
|
| +
|
| + @override
|
| void visitChildren(XmlVisitor visitor) {
|
| for (XmlAttributeNode node in _attributes) {
|
| node.accept(visitor);
|
| @@ -2055,4 +2152,4 @@ abstract class XmlVisitor<R> {
|
| R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode);
|
|
|
| R visitXmlTagNode(XmlTagNode xmlTagNode);
|
| -}
|
| +}
|
|
|