Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(116)

Side by Side Diff: pkg/analyzer/lib/src/generated/html.dart

Issue 257773008: New analyzer snapshot, based on r35422. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update pubspec.yaml Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 // This code was auto-generated, is not intended to be edited, and is subject to 5 // This code was auto-generated, is not intended to be edited, and is subject to
6 // significant change. Please see the README file for more information. 6 // significant change. Please see the README file for more information.
7 7
8 library engine.html; 8 library engine.html;
9 9
10 import 'dart:collection'; 10 import 'dart:collection';
11 import 'java_core.dart'; 11 import 'java_core.dart';
12 import 'java_engine.dart'; 12 import 'java_engine.dart';
13 import 'source.dart'; 13 import 'source.dart';
14 import 'error.dart' show AnalysisErrorListener; 14 import 'error.dart' show AnalysisErrorListener;
15 import 'scanner.dart' as sc show Scanner, SubSequenceReader, Token; 15 import 'scanner.dart' as sc show Scanner, SubSequenceReader, Token;
16 import 'parser.dart' show Parser; 16 import 'parser.dart' show Parser;
17 import 'ast.dart'; 17 import 'ast.dart';
18 import 'element.dart'; 18 import 'element.dart';
19 import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver, ExpressionVis itor; 19 import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver, ExpressionVis itor;
20 20
21 /** 21 /**
22 * Instances of the class `Token` represent a token that was scanned from the in put. Each 22 * Instances of the class `XmlExpression` represent an abstract expression embed ded into
23 * token knows which token follows it, acting as the head of a linked list of to kens. 23 * [XmlNode].
24 */ 24 */
25 class Token { 25 abstract class XmlExpression {
26 /** 26 /**
27 * The offset from the beginning of the file to the first character in the tok en. 27 * An empty array of expressions.
28 */ 28 */
29 final int offset; 29 static List<XmlExpression> EMPTY_ARRAY = new List<XmlExpression>(0);
30 30
31 /** 31 /**
32 * The previous token in the token stream. 32 * Check if the given offset belongs to the expression's source range.
33 */ 33 */
34 Token previous; 34 bool contains(int offset) => this.offset <= offset && offset < end;
35 35
36 /** 36 /**
37 * The next token in the token stream. 37 * Return the offset of the character immediately following the last character of this
38 */ 38 * expression's source range. This is equivalent to `getOffset() + getLength() `.
39 Token _next; 39 *
40 40 * @return the offset of the character just past the expression's source range
41 /** 41 */
42 * The type of the token. 42 int get end;
43 */ 43
44 final TokenType type; 44 /**
45 45 * Return the number of characters in the expression's source range.
46 /** 46 */
47 * The lexeme represented by this token. 47 int get length;
48 */ 48
49 String _value; 49 /**
50 50 * Return the offset of the first character in the expression's source range.
51 /** 51 */
52 * Initialize a newly created token. 52 int get offset;
53 * 53
54 * @param type the token type (not `null`) 54 /**
55 * @param offset the offset from the beginning of the file to the first charac ter in the token 55 * Return the [Reference] at the given offset.
56 */ 56 *
57 Token.con1(TokenType type, int offset) : this.con2(type, offset, type.lexeme); 57 * @param offset the offset from the beginning of the file
58 58 * @return the [Reference] at the given offset, maybe `null`
59 /** 59 */
60 * Initialize a newly created token. 60 XmlExpression_Reference getReference(int offset);
61 *
62 * @param type the token type (not `null`)
63 * @param offset the offset from the beginning of the file to the first charac ter in the token
64 * @param value the lexeme represented by this token (not `null`)
65 */
66 Token.con2(this.type, this.offset, String value) {
67 this._value = StringUtilities.intern(value);
68 }
69
70 /**
71 * Return the offset from the beginning of the file to the character after las t character of the
72 * token.
73 *
74 * @return the offset from the beginning of the file to the first character af ter last character
75 * of the token
76 */
77 int get end => offset + length;
78
79 /**
80 * Return the number of characters in the node's source range.
81 *
82 * @return the number of characters in the node's source range
83 */
84 int get length => lexeme.length;
85
86 /**
87 * Return the lexeme that represents this token.
88 *
89 * @return the lexeme (not `null`)
90 */
91 String get lexeme => _value;
92
93 /**
94 * Return the next token in the token stream.
95 *
96 * @return the next token in the token stream
97 */
98 Token get next => _next;
99
100 /**
101 * Return `true` if this token is a synthetic token. A synthetic token is a to ken that was
102 * introduced by the parser in order to recover from an error in the code. Syn thetic tokens always
103 * have a length of zero (`0`).
104 *
105 * @return `true` if this token is a synthetic token
106 */
107 bool get isSynthetic => length == 0;
108
109 /**
110 * Set the next token in the token stream to the given token. This has the sid e-effect of setting
111 * this token to be the previous token for the given token.
112 *
113 * @param token the next token in the token stream
114 * @return the token that was passed in
115 */
116 Token setNext(Token token) {
117 _next = token;
118 token.previous = this;
119 return token;
120 }
121
122 @override
123 String toString() => lexeme;
124 } 61 }
125 62
126 /** 63 /**
127 * Implementation of [XmlExpression] for an [Expression] embedded without any wr apping 64 * The reference to the [Element].
128 * characters.
129 */ 65 */
130 class RawXmlExpression extends XmlExpression { 66 class XmlExpression_Reference {
131 final Expression expression; 67 Element element;
132 68
133 RawXmlExpression(this.expression);
134
135 @override
136 int get end => expression.end;
137
138 @override
139 int get length => expression.length;
140
141 @override
142 int get offset => expression.offset;
143
144 @override
145 XmlExpression_Reference getReference(int offset) {
146 AstNode node = new NodeLocator.con1(offset).searchWithin(expression);
147 if (node != null) {
148 Element element = ElementLocator.locate(node);
149 return new XmlExpression_Reference(element, node.offset, node.length);
150 }
151 return null;
152 }
153 }
154
155 /**
156 * Instances of the class `RecursiveXmlVisitor` implement an XML visitor that wi ll recursively
157 * visit all of the nodes in an XML structure. For example, using an instance of this class to visit
158 * a [XmlTagNode] will also cause all of the contained [XmlAttributeNode]s and
159 * [XmlTagNode]s to be visited.
160 *
161 * Subclasses that override a visit method must either invoke the overridden vis it method or must
162 * explicitly ask the visited node to visit its children. Failure to do so will cause the children
163 * of the visited node to not be visited.
164 */
165 class RecursiveXmlVisitor<R> implements XmlVisitor<R> {
166 @override
167 R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
168 node.visitChildren(this);
169 return null;
170 }
171
172 @override
173 R visitHtmlUnit(HtmlUnit node) {
174 node.visitChildren(this);
175 return null;
176 }
177
178 @override
179 R visitXmlAttributeNode(XmlAttributeNode node) {
180 node.visitChildren(this);
181 return null;
182 }
183
184 @override
185 R visitXmlTagNode(XmlTagNode node) {
186 node.visitChildren(this);
187 return null;
188 }
189 }
190
191 /**
192 * Utilities locating [Expression]s and [Element]s in [HtmlUnit].
193 */
194 class HtmlUnitUtils {
195 /**
196 * Returns the [XmlAttributeNode] that is part of the given [HtmlUnit] and enc loses
197 * the given offset.
198 */
199 static XmlAttributeNode getAttributeNode(HtmlUnit htmlUnit, int offset) {
200 if (htmlUnit == null) {
201 return null;
202 }
203 List<XmlAttributeNode> result = [null];
204 try {
205 htmlUnit.accept(new RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode(off set, result));
206 } on HtmlUnitUtils_FoundAttributeNodeError catch (e) {
207 return result[0];
208 }
209 return null;
210 }
211
212 /**
213 * Returns the best [Element] of the given [Expression].
214 */
215 static Element getElement(Expression expression) {
216 if (expression == null) {
217 return null;
218 }
219 return ElementLocator.locate(expression);
220 }
221
222 /**
223 * Returns the [Element] of the [Expression] in the given [HtmlUnit], enclosin g
224 * the given offset.
225 */
226 static Element getElementAtOffset(HtmlUnit htmlUnit, int offset) {
227 Expression expression = getExpression(htmlUnit, offset);
228 return getElement(expression);
229 }
230
231 /**
232 * Returns the [Element] to open when requested at the given [Expression].
233 */
234 static Element getElementToOpen(HtmlUnit htmlUnit, Expression expression) {
235 Element element = getElement(expression);
236 {
237 AngularElement angularElement = AngularHtmlUnitResolver.getAngularElement( element);
238 if (angularElement != null) {
239 return angularElement;
240 }
241 }
242 return element;
243 }
244
245 /**
246 * Returns the [XmlTagNode] that is part of the given [HtmlUnit] and encloses the
247 * given offset.
248 */
249 static XmlTagNode getEnclosingTagNode(HtmlUnit htmlUnit, int offset) {
250 if (htmlUnit == null) {
251 return null;
252 }
253 List<XmlTagNode> result = [null];
254 try {
255 htmlUnit.accept(new RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode( offset, result));
256 } on HtmlUnitUtils_FoundTagNodeError catch (e) {
257 return result[0];
258 }
259 return null;
260 }
261
262 /**
263 * Returns the [Expression] that is part of the given [HtmlUnit] and encloses the
264 * given offset.
265 */
266 static Expression getExpression(HtmlUnit htmlUnit, int offset) {
267 if (htmlUnit == null) {
268 return null;
269 }
270 List<Expression> result = [null];
271 try {
272 // TODO(scheglov) this code is very Angular specific
273 htmlUnit.accept(new ExpressionVisitor_HtmlUnitUtils_getExpression(offset, result));
274 } on HtmlUnitUtils_FoundExpressionError catch (e) {
275 return result[0];
276 }
277 return null;
278 }
279
280 /**
281 * Returns the [XmlTagNode] that is part of the given [HtmlUnit] and its open or
282 * closing tag name encloses the given offset.
283 */
284 static XmlTagNode getTagNode(HtmlUnit htmlUnit, int offset) {
285 XmlTagNode node = getEnclosingTagNode(htmlUnit, offset);
286 // do we have an enclosing tag at all?
287 if (node == null) {
288 return null;
289 }
290 // is "offset" in the open tag?
291 Token openTag = node.tagToken;
292 if (openTag.offset <= offset && offset <= openTag.end) {
293 return node;
294 }
295 // is "offset" in the open tag?
296 Token closeTag = node.closingTag;
297 if (closeTag != null && closeTag.offset <= offset && offset <= closeTag.end) {
298 return node;
299 }
300 // not on a tag name
301 return null;
302 }
303
304 /**
305 * Returns the [Expression] that is part of the given root [AstNode] and enclo ses the
306 * given offset.
307 */
308 static Expression _getExpressionAt(AstNode root, int offset) {
309 if (root.offset <= offset && offset <= root.end) {
310 AstNode dartNode = new NodeLocator.con1(offset).searchWithin(root);
311 if (dartNode is Expression) {
312 return dartNode;
313 }
314 }
315 return null;
316 }
317 }
318
319 class HtmlUnitUtils_FoundAttributeNodeError extends Error {
320 }
321
322 class HtmlUnitUtils_FoundExpressionError extends Error {
323 }
324
325 class HtmlUnitUtils_FoundTagNodeError extends Error {
326 }
327
328 class RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode extends RecursiveXmlVis itor<Object> {
329 int offset = 0; 69 int offset = 0;
330 70
331 List<XmlAttributeNode> result; 71 int length = 0;
332 72
333 RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode(this.offset, this.result) : super(); 73 XmlExpression_Reference(Element element, int offset, int length) {
334 74 this.element = element;
335 @override 75 this.offset = offset;
336 Object visitXmlAttributeNode(XmlAttributeNode node) { 76 this.length = length;
337 Token nameToken = node.nameToken;
338 if (nameToken.offset <= offset && offset <= nameToken.end) {
339 result[0] = node;
340 throw new HtmlUnitUtils_FoundAttributeNodeError();
341 }
342 return super.visitXmlAttributeNode(node);
343 }
344 }
345
346 class RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode extends RecursiveXml Visitor<Object> {
347 int offset = 0;
348
349 List<XmlTagNode> result;
350
351 RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode(this.offset, this.result ) : super();
352
353 @override
354 Object visitXmlTagNode(XmlTagNode node) {
355 if (node.offset <= offset && offset < node.end) {
356 result[0] = node;
357 super.visitXmlTagNode(node);
358 throw new HtmlUnitUtils_FoundTagNodeError();
359 }
360 return null;
361 }
362 }
363
364 class ExpressionVisitor_HtmlUnitUtils_getExpression extends ExpressionVisitor {
365 int offset = 0;
366
367 List<Expression> result;
368
369 ExpressionVisitor_HtmlUnitUtils_getExpression(this.offset, this.result) : supe r();
370
371 @override
372 void visitExpression(Expression expression) {
373 Expression at = HtmlUnitUtils._getExpressionAt(expression, offset);
374 if (at != null) {
375 result[0] = at;
376 throw new HtmlUnitUtils_FoundExpressionError();
377 }
378 }
379 }
380
381 /**
382 * Instances of the class `HtmlScriptTagNode` represent a script tag within an H TML file that
383 * references a Dart script.
384 */
385 class HtmlScriptTagNode extends XmlTagNode {
386 /**
387 * The AST structure representing the Dart code within this tag.
388 */
389 CompilationUnit _script;
390
391 /**
392 * The element representing this script.
393 */
394 HtmlScriptElement scriptElement;
395
396 /**
397 * Initialize a newly created node to represent a script tag within an HTML fi le that references a
398 * Dart script.
399 *
400 * @param nodeStart the token marking the beginning of the tag
401 * @param tag the name of the tag
402 * @param attributes the attributes in the tag
403 * @param attributeEnd the token terminating the region where attributes can b e
404 * @param tagNodes the children of the tag
405 * @param contentEnd the token that starts the closing tag
406 * @param closingTag the name of the tag that occurs in the closing tag
407 * @param nodeEnd the last token in the tag
408 */
409 HtmlScriptTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attribute s, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closin gTag, Token nodeEnd) : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
410
411 @override
412 accept(XmlVisitor visitor) => visitor.visitHtmlScriptTagNode(this);
413
414 /**
415 * Return the AST structure representing the Dart code within this tag, or `nu ll` if this
416 * tag references an external script.
417 *
418 * @return the AST structure representing the Dart code within this tag
419 */
420 CompilationUnit get script => _script;
421
422 /**
423 * Set the AST structure representing the Dart code within this tag to the giv en compilation unit.
424 *
425 * @param unit the AST structure representing the Dart code within this tag
426 */
427 void set script(CompilationUnit unit) {
428 _script = unit;
429 }
430 }
431
432 /**
433 * The abstract class `XmlNode` defines behavior common to all XML/HTML nodes.
434 */
435 abstract class XmlNode {
436 /**
437 * The parent of the node, or `null` if the node is the root of an AST structu re.
438 */
439 XmlNode _parent;
440
441 /**
442 * The element associated with this node or `null` if the receiver is not reso lved.
443 */
444 Element _element;
445
446 /**
447 * Use the given visitor to visit this node.
448 *
449 * @param visitor the visitor that will visit this node
450 * @return the value returned by the visitor as a result of visiting this node
451 */
452 accept(XmlVisitor visitor);
453
454 /**
455 * Return the first token included in this node's source range.
456 *
457 * @return the first token or `null` if none
458 */
459 Token get beginToken;
460
461 /**
462 * Return the element associated with this node.
463 *
464 * @return the element or `null` if the receiver is not resolved
465 */
466 Element get element => _element;
467
468 /**
469 * Return the offset of the character immediately following the last character of this node's
470 * source range. This is equivalent to `node.getOffset() + node.getLength()`. For an html
471 * unit this will be equal to the length of the unit's source.
472 *
473 * @return the offset of the character just past the node's source range
474 */
475 int get end => offset + length;
476
477 /**
478 * Return the last token included in this node's source range.
479 *
480 * @return the last token or `null` if none
481 */
482 Token get endToken;
483
484 /**
485 * Return the number of characters in the node's source range.
486 *
487 * @return the number of characters in the node's source range
488 */
489 int get length {
490 Token beginToken = this.beginToken;
491 Token endToken = this.endToken;
492 if (beginToken == null || endToken == null) {
493 return -1;
494 }
495 return endToken.offset + endToken.length - beginToken.offset;
496 }
497
498 /**
499 * Return the offset from the beginning of the file to the first character in the node's source
500 * range.
501 *
502 * @return the offset from the beginning of the file to the first character in the node's source
503 * range
504 */
505 int get offset {
506 Token beginToken = this.beginToken;
507 if (beginToken == null) {
508 return -1;
509 }
510 return this.beginToken.offset;
511 }
512
513 /**
514 * Return this node's parent node, or `null` if this node is the root of an AS T structure.
515 *
516 * Note that the relationship between an AST node and its parent node may chan ge over the lifetime
517 * of a node.
518 *
519 * @return the parent of this node, or `null` if none
520 */
521 XmlNode get parent => _parent;
522
523 /**
524 * Set the element associated with this node.
525 *
526 * @param element the element
527 */
528 void set element(Element element) {
529 this._element = element;
530 }
531
532 @override
533 String toString() {
534 PrintStringWriter writer = new PrintStringWriter();
535 accept(new ToSourceVisitor(writer));
536 return writer.toString();
537 }
538
539 /**
540 * Use the given visitor to visit all of the children of this node. The childr en will be visited
541 * in source order.
542 *
543 * @param visitor the visitor that will be used to visit the children of this node
544 */
545 void visitChildren(XmlVisitor visitor);
546
547 /**
548 * Make this node the parent of the given child node.
549 *
550 * @param child the node that will become a child of this node
551 * @return the node that was made a child of this node
552 */
553 XmlNode becomeParentOf(XmlNode child) {
554 if (child != null) {
555 XmlNode node = child;
556 node.parent = this;
557 }
558 return child;
559 }
560
561 /**
562 * Make this node the parent of the given child nodes.
563 *
564 * @param children the nodes that will become the children of this node
565 * @param ifEmpty the (empty) nodes to return if "children" is empty
566 * @return the nodes that were made children of this node
567 */
568 List becomeParentOfAll(List children, {List ifEmpty}) {
569 if (children == null || children.isEmpty) {
570 if (ifEmpty != null) {
571 return ifEmpty;
572 }
573 }
574 if (children != null) {
575 for (JavaIterator iter = new JavaIterator(children); iter.hasNext;) {
576 XmlNode node = iter.next();
577 node.parent = this;
578 }
579 // This will create ArrayList for exactly given number of elements.
580 return new List.from(children);
581 }
582 return children;
583 }
584
585 /**
586 * This method exists for debugging purposes only.
587 */
588 void _appendIdentifier(JavaStringBuilder builder, XmlNode node) {
589 if (node is XmlTagNode) {
590 builder.append(node.tag);
591 } else if (node is XmlAttributeNode) {
592 builder.append(node.name);
593 } else {
594 builder.append("htmlUnit");
595 }
596 }
597
598 /**
599 * This method exists for debugging purposes only.
600 */
601 String _buildRecursiveStructureMessage(XmlNode newParent) {
602 JavaStringBuilder builder = new JavaStringBuilder();
603 builder.append("Attempt to create recursive structure: ");
604 XmlNode current = newParent;
605 while (current != null) {
606 if (!identical(current, newParent)) {
607 builder.append(" -> ");
608 }
609 if (identical(current, this)) {
610 builder.appendChar(0x2A);
611 _appendIdentifier(builder, current);
612 builder.appendChar(0x2A);
613 } else {
614 _appendIdentifier(builder, current);
615 }
616 current = current.parent;
617 }
618 return builder.toString();
619 }
620
621 /**
622 * Set the parent of this node to the given node.
623 *
624 * @param newParent the node that is to be made the parent of this node
625 */
626 void set parent(XmlNode newParent) {
627 XmlNode current = newParent;
628 while (current != null) {
629 if (identical(current, this)) {
630 AnalysisEngine.instance.logger.logError2("Circular structure while setti ng an XML node's parent", new IllegalArgumentException(_buildRecursiveStructureM essage(newParent)));
631 return;
632 }
633 current = current.parent;
634 }
635 _parent = newParent;
636 } 77 }
637 } 78 }
638 79
639 /** 80 /**
640 * Instances of the class `SimpleXmlVisitor` implement an AST visitor that will do nothing 81 * Instances of the class `SimpleXmlVisitor` implement an AST visitor that will do nothing
641 * when visiting an AST node. It is intended to be a superclass for classes that use the visitor 82 * when visiting an AST node. It is intended to be a superclass for classes that use the visitor
642 * pattern primarily as a dispatch mechanism (and hence don't need to recursivel y visit a whole 83 * pattern primarily as a dispatch mechanism (and hence don't need to recursivel y visit a whole
643 * structure) and that only need to visit a small number of node types. 84 * structure) and that only need to visit a small number of node types.
644 */ 85 */
645 class SimpleXmlVisitor<R> implements XmlVisitor<R> { 86 class SimpleXmlVisitor<R> implements XmlVisitor<R> {
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 } else { 410 } else {
970 // a non-char token 411 // a non-char token
971 _emitWithOffsetAndLength(TokenType.TEXT, start, 0); 412 _emitWithOffsetAndLength(TokenType.TEXT, start, 0);
972 c = advance(); 413 c = advance();
973 } 414 }
974 } 415 }
975 } 416 }
976 } 417 }
977 418
978 /** 419 /**
979 * Instances of the class `StringScanner` implement a scanner that reads from a string. The 420 * Instances of the class `Token` represent a token that was scanned from the in put. Each
980 * scanning logic is in the superclass. 421 * token knows which token follows it, acting as the head of a linked list of to kens.
981 */ 422 */
982 class StringScanner extends AbstractScanner { 423 class Token {
983 /** 424 /**
984 * The string from which characters will be read. 425 * The offset from the beginning of the file to the first character in the tok en.
985 */ 426 */
986 final String _string; 427 final int offset;
987 428
988 /** 429 /**
989 * The number of characters in the string. 430 * The previous token in the token stream.
990 */ 431 */
991 int _stringLength = 0; 432 Token previous;
992 433
993 /** 434 /**
994 * The index, relative to the string, of the last character that was read. 435 * The next token in the token stream.
995 */ 436 */
996 int _charOffset = 0; 437 Token _next;
997 438
998 /** 439 /**
999 * Initialize a newly created scanner to scan the characters in the given stri ng. 440 * The type of the token.
1000 * 441 */
1001 * @param source the source being scanned 442 final TokenType type;
1002 * @param string the string from which characters will be read 443
1003 */ 444 /**
1004 StringScanner(Source source, this._string) : super(source) { 445 * The lexeme represented by this token.
1005 this._stringLength = _string.length; 446 */
1006 this._charOffset = -1; 447 String _value;
1007 } 448
1008 449 /**
1009 @override 450 * Initialize a newly created token.
1010 int get offset => _charOffset; 451 *
1011 452 * @param type the token type (not `null`)
1012 void set offset(int offset) { 453 * @param offset the offset from the beginning of the file to the first charac ter in the token
1013 _charOffset = offset; 454 */
1014 } 455 Token.con1(TokenType type, int offset) : this.con2(type, offset, type.lexeme);
1015 456
1016 @override 457 /**
1017 int advance() { 458 * Initialize a newly created token.
1018 if (++_charOffset < _stringLength) { 459 *
1019 return _string.codeUnitAt(_charOffset); 460 * @param type the token type (not `null`)
1020 } 461 * @param offset the offset from the beginning of the file to the first charac ter in the token
1021 _charOffset = _stringLength; 462 * @param value the lexeme represented by this token (not `null`)
1022 return -1; 463 */
1023 } 464 Token.con2(this.type, this.offset, String value) {
1024 465 this._value = StringUtilities.intern(value);
1025 @override 466 }
1026 String getString(int start, int endDelta) => _string.substring(start, _charOff set + 1 + endDelta).toString(); 467
1027 468 /**
1028 @override 469 * Return the offset from the beginning of the file to the character after las t character of the
1029 int peek() { 470 * token.
1030 if (_charOffset + 1 < _stringLength) { 471 *
1031 return _string.codeUnitAt(_charOffset + 1); 472 * @return the offset from the beginning of the file to the first character af ter last character
1032 } 473 * of the token
1033 return -1; 474 */
1034 } 475 int get end => offset + length;
476
477 /**
478 * Return the number of characters in the node's source range.
479 *
480 * @return the number of characters in the node's source range
481 */
482 int get length => lexeme.length;
483
484 /**
485 * Return the lexeme that represents this token.
486 *
487 * @return the lexeme (not `null`)
488 */
489 String get lexeme => _value;
490
491 /**
492 * Return the next token in the token stream.
493 *
494 * @return the next token in the token stream
495 */
496 Token get next => _next;
497
498 /**
499 * Return `true` if this token is a synthetic token. A synthetic token is a to ken that was
500 * introduced by the parser in order to recover from an error in the code. Syn thetic tokens always
501 * have a length of zero (`0`).
502 *
503 * @return `true` if this token is a synthetic token
504 */
505 bool get isSynthetic => length == 0;
506
507 /**
508 * Set the next token in the token stream to the given token. This has the sid e-effect of setting
509 * this token to be the previous token for the given token.
510 *
511 * @param token the next token in the token stream
512 * @return the token that was passed in
513 */
514 Token setNext(Token token) {
515 _next = token;
516 token.previous = this;
517 return token;
518 }
519
520 @override
521 String toString() => lexeme;
1035 } 522 }
1036 523
1037 /** 524 /**
1038 * Instances of the class `ToSourceVisitor` write a source representation of a v isited XML 525 * Instances of `XmlTagNode` represent XML or HTML elements such as `` and
1039 * node (and all of it's children) to a writer. 526 * `<body foo="bar"> ... </body>`.
1040 */ 527 */
1041 class ToSourceVisitor implements XmlVisitor<Object> { 528 class XmlTagNode extends XmlNode {
1042 /** 529 /**
1043 * The writer to which the source is to be written. 530 * Constant representing empty list of attributes.
1044 */ 531 */
1045 final PrintWriter _writer; 532 static List<XmlAttributeNode> NO_ATTRIBUTES = new UnmodifiableListView(new Lis t<XmlAttributeNode>());
1046 533
1047 /** 534 /**
1048 * Initialize a newly created visitor to write source code representing the vi sited nodes to the 535 * Constant representing empty list of tag nodes.
1049 * given writer. 536 */
1050 * 537 static List<XmlTagNode> NO_TAG_NODES = new UnmodifiableListView(new List<XmlTa gNode>());
1051 * @param writer the writer to which the source is to be written 538
1052 */ 539 /**
1053 ToSourceVisitor(this._writer); 540 * The starting [TokenType#LT] token (not `null`).
1054 541 */
1055 @override 542 final Token nodeStart;
1056 Object visitHtmlScriptTagNode(HtmlScriptTagNode node) => visitXmlTagNode(node) ; 543
1057 544 /**
1058 @override 545 * The [TokenType#TAG] token after the starting '&lt;' (not `null`).
1059 Object visitHtmlUnit(HtmlUnit node) { 546 */
1060 for (XmlTagNode child in node.tagNodes) { 547 final Token _tag;
1061 _visit(child); 548
549 /**
550 * The attributes contained by the receiver (not `null`, contains no `null`s).
551 */
552 List<XmlAttributeNode> _attributes;
553
554 /**
555 * The [TokenType#GT] or [TokenType#SLASH_GT] token after the attributes (not
556 * `null`). The token may be the same token as [nodeEnd] if there are no child
557 * [tagNodes].
558 */
559 final Token attributeEnd;
560
561 /**
562 * The tag nodes contained in the receiver (not `null`, contains no `null`s).
563 */
564 List<XmlTagNode> _tagNodes;
565
566 /**
567 * The token (not `null`) after the content, which may be
568 * * (1) [TokenType#LT_SLASH] for nodes with open and close tags, or
569 * * (2) the [TokenType#LT] nodeStart of the next sibling node if this node is self
570 * closing or the attributeEnd is [TokenType#SLASH_GT], or
571 * * (3) [TokenType#EOF] if the node does not have a closing tag and is the la st node in
572 * the stream [TokenType#LT_SLASH] token after the content, or `null` if there is no
573 * content and the attributes ended with [TokenType#SLASH_GT].
574 */
575 final Token contentEnd;
576
577 /**
578 * The closing [TokenType#TAG] after the child elements or `null` if there is no
579 * content and the attributes ended with [TokenType#SLASH_GT]
580 */
581 final Token closingTag;
582
583 /**
584 * The ending [TokenType#GT] or [TokenType#SLASH_GT] token (not `null`).
585 */
586 final Token nodeEnd;
587
588 /**
589 * The expressions that are embedded in the tag's content.
590 */
591 List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
592
593 /**
594 * Construct a new instance representing an XML or HTML element
595 *
596 * @param nodeStart the starting [TokenType#LT] token (not `null`)
597 * @param tag the [TokenType#TAG] token after the starting '&lt;' (not `null`) .
598 * @param attributes the attributes associated with this element or [NO_ATTRIB UTES] (not
599 * `null`, contains no `null`s)
600 * @param attributeEnd The [TokenType#GT] or [TokenType#SLASH_GT] token after the
601 * attributes (not `null`). The token may be the same token as [nodeE nd] if
602 * there are no child [tagNodes].
603 * @param tagNodes child tag nodes of the receiver or [NO_TAG_NODES] (not `nul l`,
604 * contains no `null`s)
605 * @param contentEnd the token (not `null`) after the content, which may be
606 * * (1) [TokenType#LT_SLASH] for nodes with open and close tags, or
607 * * (2) the [TokenType#LT] nodeStart of the next sibling node if thi s node is
608 * self closing or the attributeEnd is [TokenType#SLASH_GT], or
609 * * (3) [TokenType#EOF] if the node does not have a closing tag and is the last
610 * node in the stream [TokenType#LT_SLASH] token after the content, o r `null`
611 * if there is no content and the attributes ended with [TokenType#SL ASH_GT].
612 * @param closingTag the closing [TokenType#TAG] after the child elements or ` null` if
613 * there is no content and the attributes ended with [TokenType#SLASH _GT]
614 * @param nodeEnd the ending [TokenType#GT] or [TokenType#SLASH_GT] token (not
615 * `null`)
616 */
617 XmlTagNode(this.nodeStart, this._tag, List<XmlAttributeNode> attributes, this. attributeEnd, List<XmlTagNode> tagNodes, this.contentEnd, this.closingTag, this. nodeEnd) {
618 this._attributes = becomeParentOfAll(attributes, ifEmpty: NO_ATTRIBUTES);
619 this._tagNodes = becomeParentOfAll(tagNodes, ifEmpty: NO_TAG_NODES);
620 }
621
622 @override
623 accept(XmlVisitor visitor) => visitor.visitXmlTagNode(this);
624
625 /**
626 * Answer the attribute with the specified name.
627 *
628 * @param name the attribute name
629 * @return the attribute or `null` if no matching attribute is found
630 */
631 XmlAttributeNode getAttribute(String name) {
632 for (XmlAttributeNode attribute in _attributes) {
633 if (attribute.name == name) {
634 return attribute;
635 }
1062 } 636 }
1063 return null; 637 return null;
1064 } 638 }
1065 639
1066 @override 640 /**
1067 Object visitXmlAttributeNode(XmlAttributeNode node) { 641 * Answer the receiver's attributes. Callers should not manipulate the returne d list to edit the
1068 String name = node.name; 642 * AST structure.
1069 Token value = node.valueToken; 643 *
1070 if (name.length == 0) { 644 * @return the attributes (not `null`, contains no `null`s)
1071 _writer.print("__"); 645 */
1072 } else { 646 List<XmlAttributeNode> get attributes => _attributes;
1073 _writer.print(name); 647
1074 } 648 /**
1075 _writer.print("="); 649 * Find the attribute with the given name (see [getAttribute] and answer the l exeme
1076 if (value == null) { 650 * for the attribute's value token without the leading and trailing quotes (se e
1077 _writer.print("__"); 651 * [XmlAttributeNode#getText]).
1078 } else { 652 *
1079 _writer.print(value.lexeme); 653 * @param name the attribute name
1080 } 654 * @return the attribute text or `null` if no matching attribute is found
1081 return null; 655 */
1082 } 656 String getAttributeText(String name) {
1083 657 XmlAttributeNode attribute = getAttribute(name);
1084 @override 658 return attribute != null ? attribute.text : null;
1085 Object visitXmlTagNode(XmlTagNode node) { 659 }
1086 _writer.print("<"); 660
1087 String tagName = node.tag; 661 @override
1088 _writer.print(tagName); 662 Token get beginToken => nodeStart;
1089 for (XmlAttributeNode attribute in node.attributes) { 663
1090 _writer.print(" "); 664 /**
1091 _visit(attribute); 665 * Answer a string representing the content contained in the receiver. This in cludes the textual
1092 } 666 * representation of any child tag nodes ([getTagNodes]). Whitespace between ' &lt;',
1093 _writer.print(node.attributeEnd.lexeme); 667 * '&lt;/', and '>', '/>' is discarded, but all other whitespace is preserved.
1094 if (node.closingTag != null) { 668 *
1095 for (XmlTagNode child in node.tagNodes) { 669 * @return the content (not `null`)
1096 _visit(child); 670 */
1097 } 671 String get content {
1098 _writer.print("</"); 672 Token token = attributeEnd.next;
1099 _writer.print(tagName); 673 if (identical(token, contentEnd)) {
1100 _writer.print(">"); 674 return "";
1101 } 675 }
1102 return null; 676 //TODO (danrubel): handle CDATA and replace HTML character encodings with th e actual characters
1103 } 677 String content = token.lexeme;
1104 678 token = token.next;
1105 /** 679 if (identical(token, contentEnd)) {
1106 * Safely visit the given node. 680 return content;
1107 * 681 }
1108 * @param node the node to be visited 682 JavaStringBuilder buffer = new JavaStringBuilder();
1109 */ 683 while (!identical(token, contentEnd)) {
1110 void _visit(XmlNode node) { 684 buffer.append(token.lexeme);
1111 if (node != null) { 685 token = token.next;
1112 node.accept(this); 686 }
1113 } 687 return buffer.toString();
1114 } 688 }
1115 } 689
1116 690 @override
1117 /** 691 Token get endToken {
1118 * The enumeration `TokenType` defines the types of tokens that can be returned by the 692 if (nodeEnd != null) {
1119 * scanner. 693 return nodeEnd;
1120 */ 694 }
1121 class TokenType extends Enum<TokenType> { 695 if (closingTag != null) {
1122 /** 696 return closingTag;
1123 * The type of the token that marks the end of the input. 697 }
1124 */ 698 if (contentEnd != null) {
1125 static const TokenType EOF = const TokenType_EOF('EOF', 0, ""); 699 return contentEnd;
1126 700 }
1127 static const TokenType EQ = const TokenType('EQ', 1, "="); 701 if (!_tagNodes.isEmpty) {
1128 702 return _tagNodes[_tagNodes.length - 1].endToken;
1129 static const TokenType GT = const TokenType('GT', 2, ">"); 703 }
1130 704 if (attributeEnd != null) {
1131 static const TokenType LT_SLASH = const TokenType('LT_SLASH', 3, "</"); 705 return attributeEnd;
1132 706 }
1133 static const TokenType LT = const TokenType('LT', 4, "<"); 707 if (!_attributes.isEmpty) {
1134 708 return _attributes[_attributes.length - 1].endToken;
1135 static const TokenType SLASH_GT = const TokenType('SLASH_GT', 5, "/>"); 709 }
1136 710 return _tag;
1137 static const TokenType COMMENT = const TokenType('COMMENT', 6, null); 711 }
1138 712
1139 static const TokenType DECLARATION = const TokenType('DECLARATION', 7, null); 713 /**
1140 714 * Answer the tag name after the starting '&lt;'.
1141 static const TokenType DIRECTIVE = const TokenType('DIRECTIVE', 8, null); 715 *
1142 716 * @return the tag name (not `null`)
1143 static const TokenType STRING = const TokenType('STRING', 9, null); 717 */
1144 718 String get tag => _tag.lexeme;
1145 static const TokenType TAG = const TokenType('TAG', 10, null); 719
1146 720 /**
1147 static const TokenType TEXT = const TokenType('TEXT', 11, null); 721 * Answer the tag nodes contained in the receiver. Callers should not manipula te the returned list
1148 722 * to edit the AST structure.
1149 static const List<TokenType> values = const [ 723 *
1150 EOF, 724 * @return the children (not `null`, contains no `null`s)
1151 EQ, 725 */
1152 GT, 726 List<XmlTagNode> get tagNodes => _tagNodes;
1153 LT_SLASH, 727
1154 LT, 728 /**
1155 SLASH_GT, 729 * Answer the [TokenType#TAG] token after the starting '&lt;'.
1156 COMMENT, 730 *
1157 DECLARATION, 731 * @return the token (not `null`)
1158 DIRECTIVE, 732 */
1159 STRING, 733 Token get tagToken => _tag;
1160 TAG,
1161 TEXT];
1162
1163 /**
1164 * The lexeme that defines this type of token, or `null` if there is more than one possible
1165 * lexeme for this type of token.
1166 */
1167 final String lexeme;
1168
1169 const TokenType(String name, int ordinal, this.lexeme) : super(name, ordinal);
1170 }
1171
1172 class TokenType_EOF extends TokenType {
1173 const TokenType_EOF(String name, int ordinal, String arg0) : super(name, ordin al, arg0);
1174
1175 @override
1176 String toString() => "-eof-";
1177 }
1178
1179 /**
1180 * Instances of `XmlAttributeNode` represent name/value pairs owned by an [XmlTa gNode].
1181 */
1182 class XmlAttributeNode extends XmlNode {
1183 final Token _name;
1184
1185 final Token equals;
1186
1187 final Token _value;
1188
1189 List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
1190
1191 /**
1192 * Construct a new instance representing an XML attribute.
1193 *
1194 * @param name the name token (not `null`). This may be a zero length token if the attribute
1195 * is badly formed.
1196 * @param equals the equals sign or `null` if none
1197 * @param value the value token (not `null`)
1198 */
1199 XmlAttributeNode(this._name, this.equals, this._value);
1200
1201 @override
1202 accept(XmlVisitor visitor) => visitor.visitXmlAttributeNode(this);
1203
1204 @override
1205 Token get beginToken => _name;
1206
1207 @override
1208 Token get endToken => _value;
1209
1210 /**
1211 * Answer the attribute name. This may be a zero length string if the attribut e is badly formed.
1212 *
1213 * @return the name (not `null`)
1214 */
1215 String get name => _name.lexeme;
1216
1217 /**
1218 * Answer the attribute name token. This may be a zero length token if the att ribute is badly
1219 * formed.
1220 *
1221 * @return the name token (not `null`)
1222 */
1223 Token get nameToken => _name;
1224
1225 /**
1226 * Answer the lexeme for the value token without the leading and trailing quot es.
1227 *
1228 * @return the text or `null` if the value is not specified
1229 */
1230 String get text {
1231 if (_value == null) {
1232 return null;
1233 }
1234 //TODO (danrubel): replace HTML character encodings with the actual characte rs
1235 String text = _value.lexeme;
1236 int len = text.length;
1237 if (len > 0) {
1238 if (text.codeUnitAt(0) == 0x22) {
1239 if (len > 1 && text.codeUnitAt(len - 1) == 0x22) {
1240 return text.substring(1, len - 1);
1241 } else {
1242 return text.substring(1);
1243 }
1244 } else if (text.codeUnitAt(0) == 0x27) {
1245 if (len > 1 && text.codeUnitAt(len - 1) == 0x27) {
1246 return text.substring(1, len - 1);
1247 } else {
1248 return text.substring(1);
1249 }
1250 }
1251 }
1252 return text;
1253 }
1254
1255 /**
1256 * Answer the offset of the value after the leading quote.
1257 *
1258 * @return the offset of the value, or `-1` if the value is not specified
1259 */
1260 int get textOffset {
1261 if (_value == null) {
1262 return -1;
1263 }
1264 String text = _value.lexeme;
1265 if (StringUtilities.startsWithChar(text, 0x22) || StringUtilities.startsWith Char(text, 0x27)) {
1266 return _value.offset + 1;
1267 }
1268 return _value.offset;
1269 }
1270
1271 /**
1272 * Answer the attribute value token. A properly formed value will start and en d with matching
1273 * quote characters, but the value returned may not be properly formed.
1274 *
1275 * @return the value token or `null` if this represents a badly formed attribu te
1276 */
1277 Token get valueToken => _value;
1278 734
1279 @override 735 @override
1280 void visitChildren(XmlVisitor visitor) { 736 void visitChildren(XmlVisitor visitor) {
1281 } 737 for (XmlAttributeNode node in _attributes) {
1282 } 738 node.accept(visitor);
1283 739 }
1284 /** 740 for (XmlTagNode node in _tagNodes) {
1285 * The interface `XmlVisitor` defines the behavior of objects that can be used t o visit an 741 node.accept(visitor);
1286 * [XmlNode] structure. 742 }
1287 */
1288 abstract class XmlVisitor<R> {
1289 R visitHtmlScriptTagNode(HtmlScriptTagNode node);
1290
1291 R visitHtmlUnit(HtmlUnit htmlUnit);
1292
1293 R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode);
1294
1295 R visitXmlTagNode(XmlTagNode xmlTagNode);
1296 }
1297
1298 /**
1299 * Instances of the class `XmlExpression` represent an abstract expression embed ded into
1300 * [XmlNode].
1301 */
1302 abstract class XmlExpression {
1303 /**
1304 * An empty array of expressions.
1305 */
1306 static List<XmlExpression> EMPTY_ARRAY = new List<XmlExpression>(0);
1307
1308 /**
1309 * Check if the given offset belongs to the expression's source range.
1310 */
1311 bool contains(int offset) => this.offset <= offset && offset < end;
1312
1313 /**
1314 * Return the offset of the character immediately following the last character of this
1315 * expression's source range. This is equivalent to `getOffset() + getLength() `.
1316 *
1317 * @return the offset of the character just past the expression's source range
1318 */
1319 int get end;
1320
1321 /**
1322 * Return the number of characters in the expression's source range.
1323 */
1324 int get length;
1325
1326 /**
1327 * Return the offset of the first character in the expression's source range.
1328 */
1329 int get offset;
1330
1331 /**
1332 * Return the [Reference] at the given offset.
1333 *
1334 * @param offset the offset from the beginning of the file
1335 * @return the [Reference] at the given offset, maybe `null`
1336 */
1337 XmlExpression_Reference getReference(int offset);
1338 }
1339
1340 /**
1341 * The reference to the [Element].
1342 */
1343 class XmlExpression_Reference {
1344 Element element;
1345
1346 int offset = 0;
1347
1348 int length = 0;
1349
1350 XmlExpression_Reference(Element element, int offset, int length) {
1351 this.element = element;
1352 this.offset = offset;
1353 this.length = length;
1354 } 743 }
1355 } 744 }
1356 745
1357 /** 746 /**
1358 * Instances of the class `XmlParser` are used to parse tokens into a AST struct ure comprised 747 * Instances of the class `XmlParser` are used to parse tokens into a AST struct ure comprised
1359 * of [XmlNode]s. 748 * of [XmlNode]s.
1360 */ 749 */
1361 class XmlParser { 750 class XmlParser {
1362 /** 751 /**
1363 * The source being parsed. 752 * The source being parsed.
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
1606 } 995 }
1607 996
1608 /** 997 /**
1609 * Report the current token as unexpected 998 * Report the current token as unexpected
1610 */ 999 */
1611 void _reportUnexpectedToken() { 1000 void _reportUnexpectedToken() {
1612 } 1001 }
1613 } 1002 }
1614 1003
1615 /** 1004 /**
1616 * Instances of `XmlTagNode` represent XML or HTML elements such as `` and 1005 * The abstract class `XmlNode` defines behavior common to all XML/HTML nodes.
1617 * `<body foo="bar"> ... </body>`.
1618 */ 1006 */
1619 class XmlTagNode extends XmlNode { 1007 abstract class XmlNode {
1620 /** 1008 /**
1621 * Constant representing empty list of attributes. 1009 * The parent of the node, or `null` if the node is the root of an AST structu re.
1622 */ 1010 */
1623 static List<XmlAttributeNode> NO_ATTRIBUTES = new UnmodifiableListView(new Lis t<XmlAttributeNode>()); 1011 XmlNode _parent;
1624 1012
1625 /** 1013 /**
1626 * Constant representing empty list of tag nodes. 1014 * The element associated with this node or `null` if the receiver is not reso lved.
1627 */ 1015 */
1628 static List<XmlTagNode> NO_TAG_NODES = new UnmodifiableListView(new List<XmlTa gNode>()); 1016 Element _element;
1629 1017
1630 /** 1018 /**
1631 * The starting [TokenType#LT] token (not `null`). 1019 * Use the given visitor to visit this node.
1632 */ 1020 *
1633 final Token nodeStart; 1021 * @param visitor the visitor that will visit this node
1634 1022 * @return the value returned by the visitor as a result of visiting this node
1635 /** 1023 */
1636 * The [TokenType#TAG] token after the starting '&lt;' (not `null`). 1024 accept(XmlVisitor visitor);
1637 */ 1025
1638 final Token _tag; 1026 /**
1639 1027 * Return the first token included in this node's source range.
1640 /** 1028 *
1641 * The attributes contained by the receiver (not `null`, contains no `null`s). 1029 * @return the first token or `null` if none
1642 */ 1030 */
1643 List<XmlAttributeNode> _attributes; 1031 Token get beginToken;
1644 1032
1645 /** 1033 /**
1646 * The [TokenType#GT] or [TokenType#SLASH_GT] token after the attributes (not 1034 * Return the element associated with this node.
1647 * `null`). The token may be the same token as [nodeEnd] if there are no child 1035 *
1648 * [tagNodes]. 1036 * @return the element or `null` if the receiver is not resolved
1649 */ 1037 */
1650 final Token attributeEnd; 1038 Element get element => _element;
1039
1040 /**
1041 * Return the offset of the character immediately following the last character of this node's
1042 * source range. This is equivalent to `node.getOffset() + node.getLength()`. For an html
1043 * unit this will be equal to the length of the unit's source.
1044 *
1045 * @return the offset of the character just past the node's source range
1046 */
1047 int get end => offset + length;
1048
1049 /**
1050 * Return the last token included in this node's source range.
1051 *
1052 * @return the last token or `null` if none
1053 */
1054 Token get endToken;
1055
1056 /**
1057 * Return the number of characters in the node's source range.
1058 *
1059 * @return the number of characters in the node's source range
1060 */
1061 int get length {
1062 Token beginToken = this.beginToken;
1063 Token endToken = this.endToken;
1064 if (beginToken == null || endToken == null) {
1065 return -1;
1066 }
1067 return endToken.offset + endToken.length - beginToken.offset;
1068 }
1069
1070 /**
1071 * Return the offset from the beginning of the file to the first character in the node's source
1072 * range.
1073 *
1074 * @return the offset from the beginning of the file to the first character in the node's source
1075 * range
1076 */
1077 int get offset {
1078 Token beginToken = this.beginToken;
1079 if (beginToken == null) {
1080 return -1;
1081 }
1082 return this.beginToken.offset;
1083 }
1084
1085 /**
1086 * Return this node's parent node, or `null` if this node is the root of an AS T structure.
1087 *
1088 * Note that the relationship between an AST node and its parent node may chan ge over the lifetime
1089 * of a node.
1090 *
1091 * @return the parent of this node, or `null` if none
1092 */
1093 XmlNode get parent => _parent;
1094
1095 /**
1096 * Set the element associated with this node.
1097 *
1098 * @param element the element
1099 */
1100 void set element(Element element) {
1101 this._element = element;
1102 }
1103
1104 @override
1105 String toString() {
1106 PrintStringWriter writer = new PrintStringWriter();
1107 accept(new ToSourceVisitor(writer));
1108 return writer.toString();
1109 }
1110
1111 /**
1112 * Use the given visitor to visit all of the children of this node. The childr en will be visited
1113 * in source order.
1114 *
1115 * @param visitor the visitor that will be used to visit the children of this node
1116 */
1117 void visitChildren(XmlVisitor visitor);
1118
1119 /**
1120 * Make this node the parent of the given child node.
1121 *
1122 * @param child the node that will become a child of this node
1123 * @return the node that was made a child of this node
1124 */
1125 XmlNode becomeParentOf(XmlNode child) {
1126 if (child != null) {
1127 XmlNode node = child;
1128 node.parent = this;
1129 }
1130 return child;
1131 }
1132
1133 /**
1134 * Make this node the parent of the given child nodes.
1135 *
1136 * @param children the nodes that will become the children of this node
1137 * @param ifEmpty the (empty) nodes to return if "children" is empty
1138 * @return the nodes that were made children of this node
1139 */
1140 List becomeParentOfAll(List children, {List ifEmpty}) {
1141 if (children == null || children.isEmpty) {
1142 if (ifEmpty != null) {
1143 return ifEmpty;
1144 }
1145 }
1146 if (children != null) {
1147 for (JavaIterator iter = new JavaIterator(children); iter.hasNext;) {
1148 XmlNode node = iter.next();
1149 node.parent = this;
1150 }
1151 // This will create ArrayList for exactly given number of elements.
1152 return new List.from(children);
1153 }
1154 return children;
1155 }
1156
1157 /**
1158 * This method exists for debugging purposes only.
1159 */
1160 void _appendIdentifier(JavaStringBuilder builder, XmlNode node) {
1161 if (node is XmlTagNode) {
1162 builder.append(node.tag);
1163 } else if (node is XmlAttributeNode) {
1164 builder.append(node.name);
1165 } else {
1166 builder.append("htmlUnit");
1167 }
1168 }
1169
1170 /**
1171 * This method exists for debugging purposes only.
1172 */
1173 String _buildRecursiveStructureMessage(XmlNode newParent) {
1174 JavaStringBuilder builder = new JavaStringBuilder();
1175 builder.append("Attempt to create recursive structure: ");
1176 XmlNode current = newParent;
1177 while (current != null) {
1178 if (!identical(current, newParent)) {
1179 builder.append(" -> ");
1180 }
1181 if (identical(current, this)) {
1182 builder.appendChar(0x2A);
1183 _appendIdentifier(builder, current);
1184 builder.appendChar(0x2A);
1185 } else {
1186 _appendIdentifier(builder, current);
1187 }
1188 current = current.parent;
1189 }
1190 return builder.toString();
1191 }
1192
1193 /**
1194 * Set the parent of this node to the given node.
1195 *
1196 * @param newParent the node that is to be made the parent of this node
1197 */
1198 void set parent(XmlNode newParent) {
1199 XmlNode current = newParent;
1200 while (current != null) {
1201 if (identical(current, this)) {
1202 AnalysisEngine.instance.logger.logError2("Circular structure while setti ng an XML node's parent", new IllegalArgumentException(_buildRecursiveStructureM essage(newParent)));
1203 return;
1204 }
1205 current = current.parent;
1206 }
1207 _parent = newParent;
1208 }
1209 }
1210
1211 /**
1212 * Implementation of [XmlExpression] for an [Expression] embedded without any wr apping
1213 * characters.
1214 */
1215 class RawXmlExpression extends XmlExpression {
1216 final Expression expression;
1217
1218 RawXmlExpression(this.expression);
1219
1220 @override
1221 int get end => expression.end;
1222
1223 @override
1224 int get length => expression.length;
1225
1226 @override
1227 int get offset => expression.offset;
1228
1229 @override
1230 XmlExpression_Reference getReference(int offset) {
1231 AstNode node = new NodeLocator.con1(offset).searchWithin(expression);
1232 if (node != null) {
1233 Element element = ElementLocator.locate(node);
1234 return new XmlExpression_Reference(element, node.offset, node.length);
1235 }
1236 return null;
1237 }
1238 }
1239
1240 /**
1241 * Utilities locating [Expression]s and [Element]s in [HtmlUnit].
1242 */
1243 class HtmlUnitUtils {
1244 /**
1245 * Returns the [XmlAttributeNode] that is part of the given [HtmlUnit] and enc loses
1246 * the given offset.
1247 */
1248 static XmlAttributeNode getAttributeNode(HtmlUnit htmlUnit, int offset) {
1249 if (htmlUnit == null) {
1250 return null;
1251 }
1252 List<XmlAttributeNode> result = [null];
1253 try {
1254 htmlUnit.accept(new RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode(off set, result));
1255 } on HtmlUnitUtils_FoundAttributeNodeError catch (e) {
1256 return result[0];
1257 }
1258 return null;
1259 }
1260
1261 /**
1262 * Returns the best [Element] of the given [Expression].
1263 */
1264 static Element getElement(Expression expression) {
1265 if (expression == null) {
1266 return null;
1267 }
1268 return ElementLocator.locate(expression);
1269 }
1270
1271 /**
1272 * Returns the [Element] of the [Expression] in the given [HtmlUnit], enclosin g
1273 * the given offset.
1274 */
1275 static Element getElementAtOffset(HtmlUnit htmlUnit, int offset) {
1276 Expression expression = getExpression(htmlUnit, offset);
1277 return getElement(expression);
1278 }
1279
1280 /**
1281 * Returns the [Element] to open when requested at the given [Expression].
1282 */
1283 static Element getElementToOpen(HtmlUnit htmlUnit, Expression expression) {
1284 Element element = getElement(expression);
1285 {
1286 AngularElement angularElement = AngularHtmlUnitResolver.getAngularElement( element);
1287 if (angularElement != null) {
1288 return angularElement;
1289 }
1290 }
1291 return element;
1292 }
1293
1294 /**
1295 * Returns the [XmlTagNode] that is part of the given [HtmlUnit] and encloses the
1296 * given offset.
1297 */
1298 static XmlTagNode getEnclosingTagNode(HtmlUnit htmlUnit, int offset) {
1299 if (htmlUnit == null) {
1300 return null;
1301 }
1302 List<XmlTagNode> result = [null];
1303 try {
1304 htmlUnit.accept(new RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode( offset, result));
1305 } on HtmlUnitUtils_FoundTagNodeError catch (e) {
1306 return result[0];
1307 }
1308 return null;
1309 }
1310
1311 /**
1312 * Returns the [Expression] that is part of the given [HtmlUnit] and encloses the
1313 * given offset.
1314 */
1315 static Expression getExpression(HtmlUnit htmlUnit, int offset) {
1316 if (htmlUnit == null) {
1317 return null;
1318 }
1319 List<Expression> result = [null];
1320 try {
1321 // TODO(scheglov) this code is very Angular specific
1322 htmlUnit.accept(new ExpressionVisitor_HtmlUnitUtils_getExpression(offset, result));
1323 } on HtmlUnitUtils_FoundExpressionError catch (e) {
1324 return result[0];
1325 }
1326 return null;
1327 }
1328
1329 /**
1330 * Returns the [XmlTagNode] that is part of the given [HtmlUnit] and its open or
1331 * closing tag name encloses the given offset.
1332 */
1333 static XmlTagNode getTagNode(HtmlUnit htmlUnit, int offset) {
1334 XmlTagNode node = getEnclosingTagNode(htmlUnit, offset);
1335 // do we have an enclosing tag at all?
1336 if (node == null) {
1337 return null;
1338 }
1339 // is "offset" in the open tag?
1340 Token openTag = node.tagToken;
1341 if (openTag.offset <= offset && offset <= openTag.end) {
1342 return node;
1343 }
1344 // is "offset" in the open tag?
1345 Token closeTag = node.closingTag;
1346 if (closeTag != null && closeTag.offset <= offset && offset <= closeTag.end) {
1347 return node;
1348 }
1349 // not on a tag name
1350 return null;
1351 }
1352
1353 /**
1354 * Returns the [Expression] that is part of the given root [AstNode] and enclo ses the
1355 * given offset.
1356 */
1357 static Expression _getExpressionAt(AstNode root, int offset) {
1358 if (root.offset <= offset && offset <= root.end) {
1359 AstNode dartNode = new NodeLocator.con1(offset).searchWithin(root);
1360 if (dartNode is Expression) {
1361 return dartNode;
1362 }
1363 }
1364 return null;
1365 }
1366 }
1367
1368 class HtmlUnitUtils_FoundAttributeNodeError extends Error {
1369 }
1370
1371 class HtmlUnitUtils_FoundExpressionError extends Error {
1372 }
1373
1374 class HtmlUnitUtils_FoundTagNodeError extends Error {
1375 }
1376
1377 class RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode extends RecursiveXmlVis itor<Object> {
1378 int offset = 0;
1379
1380 List<XmlAttributeNode> result;
1381
1382 RecursiveXmlVisitor_HtmlUnitUtils_getAttributeNode(this.offset, this.result) : super();
1383
1384 @override
1385 Object visitXmlAttributeNode(XmlAttributeNode node) {
1386 Token nameToken = node.nameToken;
1387 if (nameToken.offset <= offset && offset <= nameToken.end) {
1388 result[0] = node;
1389 throw new HtmlUnitUtils_FoundAttributeNodeError();
1390 }
1391 return super.visitXmlAttributeNode(node);
1392 }
1393 }
1394
1395 class RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode extends RecursiveXml Visitor<Object> {
1396 int offset = 0;
1397
1398 List<XmlTagNode> result;
1399
1400 RecursiveXmlVisitor_HtmlUnitUtils_getEnclosingTagNode(this.offset, this.result ) : super();
1401
1402 @override
1403 Object visitXmlTagNode(XmlTagNode node) {
1404 if (node.offset <= offset && offset < node.end) {
1405 result[0] = node;
1406 super.visitXmlTagNode(node);
1407 throw new HtmlUnitUtils_FoundTagNodeError();
1408 }
1409 return null;
1410 }
1411 }
1412
1413 class ExpressionVisitor_HtmlUnitUtils_getExpression extends ExpressionVisitor {
1414 int offset = 0;
1415
1416 List<Expression> result;
1417
1418 ExpressionVisitor_HtmlUnitUtils_getExpression(this.offset, this.result) : supe r();
1419
1420 @override
1421 void visitExpression(Expression expression) {
1422 Expression at = HtmlUnitUtils._getExpressionAt(expression, offset);
1423 if (at != null) {
1424 result[0] = at;
1425 throw new HtmlUnitUtils_FoundExpressionError();
1426 }
1427 }
1428 }
1429
1430 /**
1431 * The interface `XmlVisitor` defines the behavior of objects that can be used t o visit an
1432 * [XmlNode] structure.
1433 */
1434 abstract class XmlVisitor<R> {
1435 R visitHtmlScriptTagNode(HtmlScriptTagNode node);
1436
1437 R visitHtmlUnit(HtmlUnit htmlUnit);
1438
1439 R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode);
1440
1441 R visitXmlTagNode(XmlTagNode xmlTagNode);
1442 }
1443
1444 /**
1445 * Instances of the class `ToSourceVisitor` write a source representation of a v isited XML
1446 * node (and all of it's children) to a writer.
1447 */
1448 class ToSourceVisitor implements XmlVisitor<Object> {
1449 /**
1450 * The writer to which the source is to be written.
1451 */
1452 final PrintWriter _writer;
1453
1454 /**
1455 * Initialize a newly created visitor to write source code representing the vi sited nodes to the
1456 * given writer.
1457 *
1458 * @param writer the writer to which the source is to be written
1459 */
1460 ToSourceVisitor(this._writer);
1461
1462 @override
1463 Object visitHtmlScriptTagNode(HtmlScriptTagNode node) => visitXmlTagNode(node) ;
1464
1465 @override
1466 Object visitHtmlUnit(HtmlUnit node) {
1467 for (XmlTagNode child in node.tagNodes) {
1468 _visit(child);
1469 }
1470 return null;
1471 }
1472
1473 @override
1474 Object visitXmlAttributeNode(XmlAttributeNode node) {
1475 String name = node.name;
1476 Token value = node.valueToken;
1477 if (name.length == 0) {
1478 _writer.print("__");
1479 } else {
1480 _writer.print(name);
1481 }
1482 _writer.print("=");
1483 if (value == null) {
1484 _writer.print("__");
1485 } else {
1486 _writer.print(value.lexeme);
1487 }
1488 return null;
1489 }
1490
1491 @override
1492 Object visitXmlTagNode(XmlTagNode node) {
1493 _writer.print("<");
1494 String tagName = node.tag;
1495 _writer.print(tagName);
1496 for (XmlAttributeNode attribute in node.attributes) {
1497 _writer.print(" ");
1498 _visit(attribute);
1499 }
1500 _writer.print(node.attributeEnd.lexeme);
1501 if (node.closingTag != null) {
1502 for (XmlTagNode child in node.tagNodes) {
1503 _visit(child);
1504 }
1505 _writer.print("</");
1506 _writer.print(tagName);
1507 _writer.print(">");
1508 }
1509 return null;
1510 }
1511
1512 /**
1513 * Safely visit the given node.
1514 *
1515 * @param node the node to be visited
1516 */
1517 void _visit(XmlNode node) {
1518 if (node != null) {
1519 node.accept(this);
1520 }
1521 }
1522 }
1523
1524 /**
1525 * Instances of the class `HtmlUnit` represent the contents of an HTML file.
1526 */
1527 class HtmlUnit extends XmlNode {
1528 /**
1529 * The first token in the token stream that was parsed to form this HTML unit.
1530 */
1531 final Token beginToken;
1532
1533 /**
1534 * The last token in the token stream that was parsed to form this compilation unit. This token
1535 * should always have a type of [TokenType.EOF].
1536 */
1537 final Token endToken;
1651 1538
1652 /** 1539 /**
1653 * The tag nodes contained in the receiver (not `null`, contains no `null`s). 1540 * The tag nodes contained in the receiver (not `null`, contains no `null`s).
1654 */ 1541 */
1655 List<XmlTagNode> _tagNodes; 1542 List<XmlTagNode> _tagNodes;
1656 1543
1657 /** 1544 /**
1658 * The token (not `null`) after the content, which may be 1545 * Construct a new instance representing the content of an HTML file.
1659 * * (1) [TokenType#LT_SLASH] for nodes with open and close tags, or 1546 *
1660 * * (2) the [TokenType#LT] nodeStart of the next sibling node if this node is self 1547 * @param beginToken the first token in the file (not `null`)
1661 * closing or the attributeEnd is [TokenType#SLASH_GT], or 1548 * @param tagNodes child tag nodes of the receiver (not `null`, contains no `n ull`s)
1662 * * (3) [TokenType#EOF] if the node does not have a closing tag and is the la st node in 1549 * @param endToken the last token in the token stream which should be of type
1663 * the stream [TokenType#LT_SLASH] token after the content, or `null` if there is no 1550 * [TokenType.EOF]
1664 * content and the attributes ended with [TokenType#SLASH_GT].
1665 */ 1551 */
1666 final Token contentEnd; 1552 HtmlUnit(this.beginToken, List<XmlTagNode> tagNodes, this.endToken) {
1667 1553 this._tagNodes = becomeParentOfAll(tagNodes);
1668 /**
1669 * The closing [TokenType#TAG] after the child elements or `null` if there is no
1670 * content and the attributes ended with [TokenType#SLASH_GT]
1671 */
1672 final Token closingTag;
1673
1674 /**
1675 * The ending [TokenType#GT] or [TokenType#SLASH_GT] token (not `null`).
1676 */
1677 final Token nodeEnd;
1678
1679 /**
1680 * The expressions that are embedded in the tag's content.
1681 */
1682 List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
1683
1684 /**
1685 * Construct a new instance representing an XML or HTML element
1686 *
1687 * @param nodeStart the starting [TokenType#LT] token (not `null`)
1688 * @param tag the [TokenType#TAG] token after the starting '&lt;' (not `null`) .
1689 * @param attributes the attributes associated with this element or [NO_ATTRIB UTES] (not
1690 * `null`, contains no `null`s)
1691 * @param attributeEnd The [TokenType#GT] or [TokenType#SLASH_GT] token after the
1692 * attributes (not `null`). The token may be the same token as [nodeE nd] if
1693 * there are no child [tagNodes].
1694 * @param tagNodes child tag nodes of the receiver or [NO_TAG_NODES] (not `nul l`,
1695 * contains no `null`s)
1696 * @param contentEnd the token (not `null`) after the content, which may be
1697 * * (1) [TokenType#LT_SLASH] for nodes with open and close tags, or
1698 * * (2) the [TokenType#LT] nodeStart of the next sibling node if thi s node is
1699 * self closing or the attributeEnd is [TokenType#SLASH_GT], or
1700 * * (3) [TokenType#EOF] if the node does not have a closing tag and is the last
1701 * node in the stream [TokenType#LT_SLASH] token after the content, o r `null`
1702 * if there is no content and the attributes ended with [TokenType#SL ASH_GT].
1703 * @param closingTag the closing [TokenType#TAG] after the child elements or ` null` if
1704 * there is no content and the attributes ended with [TokenType#SLASH _GT]
1705 * @param nodeEnd the ending [TokenType#GT] or [TokenType#SLASH_GT] token (not
1706 * `null`)
1707 */
1708 XmlTagNode(this.nodeStart, this._tag, List<XmlAttributeNode> attributes, this. attributeEnd, List<XmlTagNode> tagNodes, this.contentEnd, this.closingTag, this. nodeEnd) {
1709 this._attributes = becomeParentOfAll(attributes, ifEmpty: NO_ATTRIBUTES);
1710 this._tagNodes = becomeParentOfAll(tagNodes, ifEmpty: NO_TAG_NODES);
1711 } 1554 }
1712 1555
1713 @override 1556 @override
1714 accept(XmlVisitor visitor) => visitor.visitXmlTagNode(this); 1557 accept(XmlVisitor visitor) => visitor.visitHtmlUnit(this);
1715 1558
1716 /** 1559 /**
1717 * Answer the attribute with the specified name. 1560 * Return the element associated with this HTML unit.
1718 * 1561 *
1719 * @param name the attribute name 1562 * @return the element or `null` if the receiver is not resolved
1720 * @return the attribute or `null` if no matching attribute is found
1721 */ 1563 */
1722 XmlAttributeNode getAttribute(String name) {
1723 for (XmlAttributeNode attribute in _attributes) {
1724 if (attribute.name == name) {
1725 return attribute;
1726 }
1727 }
1728 return null;
1729 }
1730
1731 /**
1732 * Answer the receiver's attributes. Callers should not manipulate the returne d list to edit the
1733 * AST structure.
1734 *
1735 * @return the attributes (not `null`, contains no `null`s)
1736 */
1737 List<XmlAttributeNode> get attributes => _attributes;
1738
1739 /**
1740 * Find the attribute with the given name (see [getAttribute] and answer the l exeme
1741 * for the attribute's value token without the leading and trailing quotes (se e
1742 * [XmlAttributeNode#getText]).
1743 *
1744 * @param name the attribute name
1745 * @return the attribute text or `null` if no matching attribute is found
1746 */
1747 String getAttributeText(String name) {
1748 XmlAttributeNode attribute = getAttribute(name);
1749 return attribute != null ? attribute.text : null;
1750 }
1751
1752 @override 1564 @override
1753 Token get beginToken => nodeStart; 1565 HtmlElement get element => super.element as HtmlElement;
1754
1755 /**
1756 * Answer a string representing the content contained in the receiver. This in cludes the textual
1757 * representation of any child tag nodes ([getTagNodes]). Whitespace between ' &lt;',
1758 * '&lt;/', and '>', '/>' is discarded, but all other whitespace is preserved.
1759 *
1760 * @return the content (not `null`)
1761 */
1762 String get content {
1763 Token token = attributeEnd.next;
1764 if (identical(token, contentEnd)) {
1765 return "";
1766 }
1767 //TODO (danrubel): handle CDATA and replace HTML character encodings with th e actual characters
1768 String content = token.lexeme;
1769 token = token.next;
1770 if (identical(token, contentEnd)) {
1771 return content;
1772 }
1773 JavaStringBuilder buffer = new JavaStringBuilder();
1774 while (!identical(token, contentEnd)) {
1775 buffer.append(token.lexeme);
1776 token = token.next;
1777 }
1778 return buffer.toString();
1779 }
1780
1781 @override
1782 Token get endToken {
1783 if (nodeEnd != null) {
1784 return nodeEnd;
1785 }
1786 if (closingTag != null) {
1787 return closingTag;
1788 }
1789 if (contentEnd != null) {
1790 return contentEnd;
1791 }
1792 if (!_tagNodes.isEmpty) {
1793 return _tagNodes[_tagNodes.length - 1].endToken;
1794 }
1795 if (attributeEnd != null) {
1796 return attributeEnd;
1797 }
1798 if (!_attributes.isEmpty) {
1799 return _attributes[_attributes.length - 1].endToken;
1800 }
1801 return _tag;
1802 }
1803
1804 /**
1805 * Answer the tag name after the starting '&lt;'.
1806 *
1807 * @return the tag name (not `null`)
1808 */
1809 String get tag => _tag.lexeme;
1810 1566
1811 /** 1567 /**
1812 * Answer the tag nodes contained in the receiver. Callers should not manipula te the returned list 1568 * Answer the tag nodes contained in the receiver. Callers should not manipula te the returned list
1813 * to edit the AST structure. 1569 * to edit the AST structure.
1814 * 1570 *
1815 * @return the children (not `null`, contains no `null`s) 1571 * @return the children (not `null`, contains no `null`s)
1816 */ 1572 */
1817 List<XmlTagNode> get tagNodes => _tagNodes; 1573 List<XmlTagNode> get tagNodes => _tagNodes;
1818 1574
1819 /** 1575 @override
1820 * Answer the [TokenType#TAG] token after the starting '&lt;'. 1576 void set element(Element element) {
1821 * 1577 if (element != null && element is! HtmlElement) {
1822 * @return the token (not `null`) 1578 throw new IllegalArgumentException("HtmlElement expected, but ${element.ru ntimeType} given");
1823 */ 1579 }
1824 Token get tagToken => _tag; 1580 super.element = element;
1581 }
1825 1582
1826 @override 1583 @override
1827 void visitChildren(XmlVisitor visitor) { 1584 void visitChildren(XmlVisitor visitor) {
1828 for (XmlAttributeNode node in _attributes) {
1829 node.accept(visitor);
1830 }
1831 for (XmlTagNode node in _tagNodes) { 1585 for (XmlTagNode node in _tagNodes) {
1832 node.accept(visitor); 1586 node.accept(visitor);
1833 } 1587 }
1834 } 1588 }
1835 } 1589 }
1836 1590
1591 /**
1592 * Instances of the class `StringScanner` implement a scanner that reads from a string. The
1593 * scanning logic is in the superclass.
1594 */
1595 class StringScanner extends AbstractScanner {
1596 /**
1597 * The string from which characters will be read.
1598 */
1599 final String _string;
1600
1601 /**
1602 * The number of characters in the string.
1603 */
1604 int _stringLength = 0;
1605
1606 /**
1607 * The index, relative to the string, of the last character that was read.
1608 */
1609 int _charOffset = 0;
1610
1611 /**
1612 * Initialize a newly created scanner to scan the characters in the given stri ng.
1613 *
1614 * @param source the source being scanned
1615 * @param string the string from which characters will be read
1616 */
1617 StringScanner(Source source, this._string) : super(source) {
1618 this._stringLength = _string.length;
1619 this._charOffset = -1;
1620 }
1621
1622 @override
1623 int get offset => _charOffset;
1624
1625 void set offset(int offset) {
1626 _charOffset = offset;
1627 }
1628
1629 @override
1630 int advance() {
1631 if (++_charOffset < _stringLength) {
1632 return _string.codeUnitAt(_charOffset);
1633 }
1634 _charOffset = _stringLength;
1635 return -1;
1636 }
1637
1638 @override
1639 String getString(int start, int endDelta) => _string.substring(start, _charOff set + 1 + endDelta).toString();
1640
1641 @override
1642 int peek() {
1643 if (_charOffset + 1 < _stringLength) {
1644 return _string.codeUnitAt(_charOffset + 1);
1645 }
1646 return -1;
1647 }
1648 }
1649
1837 /** 1650 /**
1838 * Instances of the class `HtmlParser` are used to parse tokens into a AST struc ture comprised 1651 * Instances of the class `HtmlParser` are used to parse tokens into a AST struc ture comprised
1839 * of [XmlNode]s. 1652 * of [XmlNode]s.
1840 */ 1653 */
1841 class HtmlParser extends XmlParser { 1654 class HtmlParser extends XmlParser {
1842 /** 1655 /**
1843 * The line information associated with the source being parsed. 1656 * The line information associated with the source being parsed.
1844 */ 1657 */
1845 LineInfo _lineInfo; 1658 LineInfo _lineInfo;
1846 1659
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1969 return true; 1782 return true;
1970 } 1783 }
1971 } 1784 }
1972 } 1785 }
1973 } 1786 }
1974 return false; 1787 return false;
1975 } 1788 }
1976 } 1789 }
1977 1790
1978 /** 1791 /**
1979 * Instances of the class `HtmlUnit` represent the contents of an HTML file. 1792 * Instances of the class `RecursiveXmlVisitor` implement an XML visitor that wi ll recursively
1980 */ 1793 * visit all of the nodes in an XML structure. For example, using an instance of this class to visit
1981 class HtmlUnit extends XmlNode { 1794 * a [XmlTagNode] will also cause all of the contained [XmlAttributeNode]s and
1982 /** 1795 * [XmlTagNode]s to be visited.
1983 * The first token in the token stream that was parsed to form this HTML unit. 1796 *
1984 */ 1797 * Subclasses that override a visit method must either invoke the overridden vis it method or must
1985 final Token beginToken; 1798 * explicitly ask the visited node to visit its children. Failure to do so will cause the children
1986 1799 * of the visited node to not be visited.
1987 /** 1800 */
1988 * The last token in the token stream that was parsed to form this compilation unit. This token 1801 class RecursiveXmlVisitor<R> implements XmlVisitor<R> {
1989 * should always have a type of [TokenType.EOF]. 1802 @override
1990 */ 1803 R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
1991 final Token endToken; 1804 node.visitChildren(this);
1992 1805 return null;
1993 /** 1806 }
1994 * The tag nodes contained in the receiver (not `null`, contains no `null`s). 1807
1995 */ 1808 @override
1996 List<XmlTagNode> _tagNodes; 1809 R visitHtmlUnit(HtmlUnit node) {
1997 1810 node.visitChildren(this);
1998 /** 1811 return null;
1999 * Construct a new instance representing the content of an HTML file. 1812 }
2000 * 1813
2001 * @param beginToken the first token in the file (not `null`) 1814 @override
2002 * @param tagNodes child tag nodes of the receiver (not `null`, contains no `n ull`s) 1815 R visitXmlAttributeNode(XmlAttributeNode node) {
2003 * @param endToken the last token in the token stream which should be of type 1816 node.visitChildren(this);
2004 * [TokenType.EOF] 1817 return null;
2005 */ 1818 }
2006 HtmlUnit(this.beginToken, List<XmlTagNode> tagNodes, this.endToken) { 1819
2007 this._tagNodes = becomeParentOfAll(tagNodes); 1820 @override
2008 } 1821 R visitXmlTagNode(XmlTagNode node) {
2009 1822 node.visitChildren(this);
2010 @override 1823 return null;
2011 accept(XmlVisitor visitor) => visitor.visitHtmlUnit(this); 1824 }
2012 1825 }
2013 /** 1826
2014 * Return the element associated with this HTML unit. 1827 /**
2015 * 1828 * Instances of the class `HtmlScriptTagNode` represent a script tag within an H TML file that
2016 * @return the element or `null` if the receiver is not resolved 1829 * references a Dart script.
2017 */ 1830 */
2018 @override 1831 class HtmlScriptTagNode extends XmlTagNode {
2019 HtmlElement get element => super.element as HtmlElement; 1832 /**
2020 1833 * The AST structure representing the Dart code within this tag.
2021 /** 1834 */
2022 * Answer the tag nodes contained in the receiver. Callers should not manipula te the returned list 1835 CompilationUnit _script;
2023 * to edit the AST structure. 1836
2024 * 1837 /**
2025 * @return the children (not `null`, contains no `null`s) 1838 * The element representing this script.
2026 */ 1839 */
2027 List<XmlTagNode> get tagNodes => _tagNodes; 1840 HtmlScriptElement scriptElement;
2028 1841
2029 @override 1842 /**
2030 void set element(Element element) { 1843 * Initialize a newly created node to represent a script tag within an HTML fi le that references a
2031 if (element != null && element is! HtmlElement) { 1844 * Dart script.
2032 throw new IllegalArgumentException("HtmlElement expected, but ${element.ru ntimeType} given"); 1845 *
2033 } 1846 * @param nodeStart the token marking the beginning of the tag
2034 super.element = element; 1847 * @param tag the name of the tag
2035 } 1848 * @param attributes the attributes in the tag
1849 * @param attributeEnd the token terminating the region where attributes can b e
1850 * @param tagNodes the children of the tag
1851 * @param contentEnd the token that starts the closing tag
1852 * @param closingTag the name of the tag that occurs in the closing tag
1853 * @param nodeEnd the last token in the tag
1854 */
1855 HtmlScriptTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attribute s, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closin gTag, Token nodeEnd) : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
1856
1857 @override
1858 accept(XmlVisitor visitor) => visitor.visitHtmlScriptTagNode(this);
1859
1860 /**
1861 * Return the AST structure representing the Dart code within this tag, or `nu ll` if this
1862 * tag references an external script.
1863 *
1864 * @return the AST structure representing the Dart code within this tag
1865 */
1866 CompilationUnit get script => _script;
1867
1868 /**
1869 * Set the AST structure representing the Dart code within this tag to the giv en compilation unit.
1870 *
1871 * @param unit the AST structure representing the Dart code within this tag
1872 */
1873 void set script(CompilationUnit unit) {
1874 _script = unit;
1875 }
1876 }
1877
1878 /**
1879 * The enumeration `TokenType` defines the types of tokens that can be returned by the
1880 * scanner.
1881 */
1882 class TokenType extends Enum<TokenType> {
1883 /**
1884 * The type of the token that marks the end of the input.
1885 */
1886 static const TokenType EOF = const TokenType_EOF('EOF', 0, "");
1887
1888 static const TokenType EQ = const TokenType('EQ', 1, "=");
1889
1890 static const TokenType GT = const TokenType('GT', 2, ">");
1891
1892 static const TokenType LT_SLASH = const TokenType('LT_SLASH', 3, "</");
1893
1894 static const TokenType LT = const TokenType('LT', 4, "<");
1895
1896 static const TokenType SLASH_GT = const TokenType('SLASH_GT', 5, "/>");
1897
1898 static const TokenType COMMENT = const TokenType('COMMENT', 6, null);
1899
1900 static const TokenType DECLARATION = const TokenType('DECLARATION', 7, null);
1901
1902 static const TokenType DIRECTIVE = const TokenType('DIRECTIVE', 8, null);
1903
1904 static const TokenType STRING = const TokenType('STRING', 9, null);
1905
1906 static const TokenType TAG = const TokenType('TAG', 10, null);
1907
1908 static const TokenType TEXT = const TokenType('TEXT', 11, null);
1909
1910 static const List<TokenType> values = const [
1911 EOF,
1912 EQ,
1913 GT,
1914 LT_SLASH,
1915 LT,
1916 SLASH_GT,
1917 COMMENT,
1918 DECLARATION,
1919 DIRECTIVE,
1920 STRING,
1921 TAG,
1922 TEXT];
1923
1924 /**
1925 * The lexeme that defines this type of token, or `null` if there is more than one possible
1926 * lexeme for this type of token.
1927 */
1928 final String lexeme;
1929
1930 const TokenType(String name, int ordinal, this.lexeme) : super(name, ordinal);
1931 }
1932
1933 class TokenType_EOF extends TokenType {
1934 const TokenType_EOF(String name, int ordinal, String arg0) : super(name, ordin al, arg0);
1935
1936 @override
1937 String toString() => "-eof-";
1938 }
1939
1940 /**
1941 * Instances of `XmlAttributeNode` represent name/value pairs owned by an [XmlTa gNode].
1942 */
1943 class XmlAttributeNode extends XmlNode {
1944 final Token _name;
1945
1946 final Token equals;
1947
1948 final Token _value;
1949
1950 List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
1951
1952 /**
1953 * Construct a new instance representing an XML attribute.
1954 *
1955 * @param name the name token (not `null`). This may be a zero length token if the attribute
1956 * is badly formed.
1957 * @param equals the equals sign or `null` if none
1958 * @param value the value token (not `null`)
1959 */
1960 XmlAttributeNode(this._name, this.equals, this._value);
1961
1962 @override
1963 accept(XmlVisitor visitor) => visitor.visitXmlAttributeNode(this);
1964
1965 @override
1966 Token get beginToken => _name;
1967
1968 @override
1969 Token get endToken => _value;
1970
1971 /**
1972 * Answer the attribute name. This may be a zero length string if the attribut e is badly formed.
1973 *
1974 * @return the name (not `null`)
1975 */
1976 String get name => _name.lexeme;
1977
1978 /**
1979 * Answer the attribute name token. This may be a zero length token if the att ribute is badly
1980 * formed.
1981 *
1982 * @return the name token (not `null`)
1983 */
1984 Token get nameToken => _name;
1985
1986 /**
1987 * Answer the lexeme for the value token without the leading and trailing quot es.
1988 *
1989 * @return the text or `null` if the value is not specified
1990 */
1991 String get text {
1992 if (_value == null) {
1993 return null;
1994 }
1995 //TODO (danrubel): replace HTML character encodings with the actual characte rs
1996 String text = _value.lexeme;
1997 int len = text.length;
1998 if (len > 0) {
1999 if (text.codeUnitAt(0) == 0x22) {
2000 if (len > 1 && text.codeUnitAt(len - 1) == 0x22) {
2001 return text.substring(1, len - 1);
2002 } else {
2003 return text.substring(1);
2004 }
2005 } else if (text.codeUnitAt(0) == 0x27) {
2006 if (len > 1 && text.codeUnitAt(len - 1) == 0x27) {
2007 return text.substring(1, len - 1);
2008 } else {
2009 return text.substring(1);
2010 }
2011 }
2012 }
2013 return text;
2014 }
2015
2016 /**
2017 * Answer the offset of the value after the leading quote.
2018 *
2019 * @return the offset of the value, or `-1` if the value is not specified
2020 */
2021 int get textOffset {
2022 if (_value == null) {
2023 return -1;
2024 }
2025 String text = _value.lexeme;
2026 if (StringUtilities.startsWithChar(text, 0x22) || StringUtilities.startsWith Char(text, 0x27)) {
2027 return _value.offset + 1;
2028 }
2029 return _value.offset;
2030 }
2031
2032 /**
2033 * Answer the attribute value token. A properly formed value will start and en d with matching
2034 * quote characters, but the value returned may not be properly formed.
2035 *
2036 * @return the value token or `null` if this represents a badly formed attribu te
2037 */
2038 Token get valueToken => _value;
2036 2039
2037 @override 2040 @override
2038 void visitChildren(XmlVisitor visitor) { 2041 void visitChildren(XmlVisitor visitor) {
2039 for (XmlTagNode node in _tagNodes) {
2040 node.accept(visitor);
2041 }
2042 } 2042 }
2043 } 2043 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698