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

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

Issue 45573002: Rename analyzer_experimental to analyzer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tweaks before publishing. Created 7 years, 1 month 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
(Empty)
1 // This code was auto-generated, is not intended to be edited, and is subject to
2 // significant change. Please see the README file for more information.
3 library engine.html;
4 import 'dart:collection';
5 import 'java_core.dart';
6 import 'java_engine.dart';
7 import 'source.dart';
8 import 'element.dart' show HtmlElementImpl;
9 import 'engine.dart' show AnalysisEngine;
10 /**
11 * Instances of the class `Token` represent a token that was scanned from the in put. Each
12 * token knows which token follows it, acting as the head of a linked list of to kens.
13 *
14 * @coverage dart.engine.html
15 */
16 class Token {
17
18 /**
19 * The offset from the beginning of the file to the first character in the tok en.
20 */
21 int offset = 0;
22
23 /**
24 * The previous token in the token stream.
25 */
26 Token previous;
27
28 /**
29 * The next token in the token stream.
30 */
31 Token next;
32
33 /**
34 * The type of the token.
35 */
36 TokenType type;
37
38 /**
39 * The lexeme represented by this token.
40 */
41 String lexeme;
42
43 /**
44 * Initialize a newly created token.
45 *
46 * @param type the token type (not `null`)
47 * @param offset the offset from the beginning of the file to the first charac ter in the token
48 */
49 Token.con1(TokenType type, int offset) : this.con2(type, offset, type.lexeme);
50
51 /**
52 * Initialize a newly created token.
53 *
54 * @param type the token type (not `null`)
55 * @param offset the offset from the beginning of the file to the first charac ter in the token
56 * @param value the lexeme represented by this token (not `null`)
57 */
58 Token.con2(TokenType type, int offset, String value) {
59 this.type = type;
60 this.lexeme = StringUtilities.intern(value);
61 this.offset = offset;
62 }
63
64 /**
65 * Return the offset from the beginning of the file to the character after las t character of the
66 * token.
67 *
68 * @return the offset from the beginning of the file to the first character af ter last character
69 * of the token
70 */
71 int get end => offset + length;
72
73 /**
74 * Return the number of characters in the node's source range.
75 *
76 * @return the number of characters in the node's source range
77 */
78 int get length => lexeme.length;
79
80 /**
81 * Return `true` if this token is a synthetic token. A synthetic token is a to ken that was
82 * introduced by the parser in order to recover from an error in the code. Syn thetic tokens always
83 * have a length of zero (`0`).
84 *
85 * @return `true` if this token is a synthetic token
86 */
87 bool get isSynthetic => length == 0;
88
89 /**
90 * Set the next token in the token stream to the given token. This has the sid e-effect of setting
91 * this token to be the previous token for the given token.
92 *
93 * @param token the next token in the token stream
94 * @return the token that was passed in
95 */
96 Token setNext(Token token) {
97 next = token;
98 token.previous = this;
99 return token;
100 }
101 String toString() => lexeme;
102 }
103 /**
104 * Instances of `HtmlParseResult` hold the result of parsing an HTML file.
105 *
106 * @coverage dart.engine.html
107 */
108 class HtmlParseResult extends HtmlScanResult {
109
110 /**
111 * The unit containing the parsed information (not `null`).
112 */
113 HtmlUnit htmlUnit;
114 HtmlParseResult(int modificationTime, Token token, List<int> lineStarts, HtmlU nit unit) : super(modificationTime, token, lineStarts) {
115 this.htmlUnit = unit;
116 }
117 }
118 /**
119 * Instances of the class `RecursiveXmlVisitor` implement an XML visitor that wi ll recursively
120 * visit all of the nodes in an XML structure. For example, using an instance of this class to visit
121 * a [XmlTagNode] will also cause all of the contained [XmlAttributeNode]s and
122 * [XmlTagNode]s to be visited.
123 *
124 * Subclasses that override a visit method must either invoke the overridden vis it method or must
125 * explicitly ask the visited node to visit its children. Failure to do so will cause the children
126 * of the visited node to not be visited.
127 *
128 * @coverage dart.engine.html
129 */
130 class RecursiveXmlVisitor<R> implements XmlVisitor<R> {
131 R visitHtmlUnit(HtmlUnit node) {
132 node.visitChildren(this);
133 return null;
134 }
135 R visitXmlAttributeNode(XmlAttributeNode node) {
136 node.visitChildren(this);
137 return null;
138 }
139 R visitXmlTagNode(XmlTagNode node) {
140 node.visitChildren(this);
141 return null;
142 }
143 }
144 /**
145 * The abstract class `XmlNode` defines behavior common to all XML/HTML nodes.
146 *
147 * @coverage dart.engine.html
148 */
149 abstract class XmlNode {
150
151 /**
152 * The parent of the node, or `null` if the node is the root of an AST structu re.
153 */
154 XmlNode _parent;
155
156 /**
157 * Use the given visitor to visit this node.
158 *
159 * @param visitor the visitor that will visit this node
160 * @return the value returned by the visitor as a result of visiting this node
161 */
162 accept(XmlVisitor visitor);
163
164 /**
165 * Return the first token included in this node's source range.
166 *
167 * @return the first token or `null` if none
168 */
169 Token get beginToken;
170
171 /**
172 * Return the offset of the character immediately following the last character of this node's
173 * source range. This is equivalent to `node.getOffset() + node.getLength()`. For an html
174 * unit this will be equal to the length of the unit's source.
175 *
176 * @return the offset of the character just past the node's source range
177 */
178 int get end => offset + length;
179
180 /**
181 * Return the last token included in this node's source range.
182 *
183 * @return the last token or `null` if none
184 */
185 Token get endToken;
186
187 /**
188 * Return the number of characters in the node's source range.
189 *
190 * @return the number of characters in the node's source range
191 */
192 int get length {
193 Token beginToken = this.beginToken;
194 Token endToken = this.endToken;
195 if (beginToken == null || endToken == null) {
196 return -1;
197 }
198 return endToken.offset + endToken.length - beginToken.offset;
199 }
200
201 /**
202 * Return the offset from the beginning of the file to the first character in the node's source
203 * range.
204 *
205 * @return the offset from the beginning of the file to the first character in the node's source
206 * range
207 */
208 int get offset {
209 Token beginToken = this.beginToken;
210 if (beginToken == null) {
211 return -1;
212 }
213 return this.beginToken.offset;
214 }
215
216 /**
217 * Return this node's parent node, or `null` if this node is the root of an AS T structure.
218 *
219 * Note that the relationship between an AST node and its parent node may chan ge over the lifetime
220 * of a node.
221 *
222 * @return the parent of this node, or `null` if none
223 */
224 XmlNode get parent => _parent;
225 String toString() {
226 PrintStringWriter writer = new PrintStringWriter();
227 accept(new ToSourceVisitor(writer));
228 return writer.toString();
229 }
230
231 /**
232 * Use the given visitor to visit all of the children of this node. The childr en will be visited
233 * in source order.
234 *
235 * @param visitor the visitor that will be used to visit the children of this node
236 */
237 void visitChildren(XmlVisitor visitor);
238
239 /**
240 * Make this node the parent of the given child nodes.
241 *
242 * @param children the nodes that will become the children of this node
243 * @return the nodes that were made children of this node
244 */
245 List becomeParentOf(List children) {
246 if (children != null) {
247 for (JavaIterator iter = new JavaIterator(children); iter.hasNext;) {
248 XmlNode node = iter.next();
249 node.parent = this;
250 }
251 return new List.from(children);
252 }
253 return children;
254 }
255
256 /**
257 * Make this node the parent of the given child node.
258 *
259 * @param child the node that will become a child of this node
260 * @return the node that was made a child of this node
261 */
262 XmlNode becomeParentOf2(XmlNode child) {
263 if (child != null) {
264 XmlNode node = child;
265 node.parent = this;
266 }
267 return child;
268 }
269
270 /**
271 * This method exists for debugging purposes only.
272 */
273 void appendIdentifier(JavaStringBuilder builder, XmlNode node) {
274 if (node is XmlTagNode) {
275 builder.append(((node as XmlTagNode)).tag.lexeme);
276 } else if (node is XmlAttributeNode) {
277 builder.append(((node as XmlAttributeNode)).name.lexeme);
278 } else {
279 builder.append("htmlUnit");
280 }
281 }
282
283 /**
284 * This method exists for debugging purposes only.
285 */
286 String buildRecursiveStructureMessage(XmlNode newParent) {
287 JavaStringBuilder builder = new JavaStringBuilder();
288 builder.append("Attempt to create recursive structure: ");
289 XmlNode current = newParent;
290 while (current != null) {
291 if (current != newParent) {
292 builder.append(" -> ");
293 }
294 if (identical(current, this)) {
295 builder.appendChar(0x2A);
296 appendIdentifier(builder, current);
297 builder.appendChar(0x2A);
298 } else {
299 appendIdentifier(builder, current);
300 }
301 current = current.parent;
302 }
303 return builder.toString();
304 }
305
306 /**
307 * Set the parent of this node to the given node.
308 *
309 * @param newParent the node that is to be made the parent of this node
310 */
311 void set parent(XmlNode newParent) {
312 XmlNode current = newParent;
313 while (current != null) {
314 if (identical(current, this)) {
315 AnalysisEngine.instance.logger.logError3(new IllegalArgumentException(bu ildRecursiveStructureMessage(newParent)));
316 return;
317 }
318 current = current.parent;
319 }
320 _parent = newParent;
321 }
322 }
323 /**
324 * Instances of the class `SimpleXmlVisitor` implement an AST visitor that will do nothing
325 * when visiting an AST node. It is intended to be a superclass for classes that use the visitor
326 * pattern primarily as a dispatch mechanism (and hence don't need to recursivel y visit a whole
327 * structure) and that only need to visit a small number of node types.
328 */
329 class SimpleXmlVisitor<R> implements XmlVisitor<R> {
330 R visitHtmlUnit(HtmlUnit htmlUnit) => null;
331 R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode) => null;
332 R visitXmlTagNode(XmlTagNode xmlTagNode) => null;
333 }
334 /**
335 * The abstract class `AbstractScanner` implements a scanner for HTML code. Subc lasses are
336 * required to implement the interface used to access the characters being scann ed.
337 *
338 * @coverage dart.engine.html
339 */
340 abstract class AbstractScanner {
341 static List<String> _NO_PASS_THROUGH_ELEMENTS = <String> [];
342
343 /**
344 * The source being scanned.
345 */
346 Source source;
347
348 /**
349 * The token pointing to the head of the linked list of tokens.
350 */
351 Token _tokens;
352
353 /**
354 * The last token that was scanned.
355 */
356 Token _tail;
357
358 /**
359 * A list containing the offsets of the first character of each line in the so urce code.
360 */
361 List<int> _lineStarts = new List<int>();
362
363 /**
364 * An array of element tags for which the content between tags should be consi der a single token.
365 */
366 List<String> _passThroughElements = _NO_PASS_THROUGH_ELEMENTS;
367
368 /**
369 * Initialize a newly created scanner.
370 *
371 * @param source the source being scanned
372 */
373 AbstractScanner(Source source) {
374 this.source = source;
375 _tokens = new Token.con1(TokenType.EOF, -1);
376 _tokens.setNext(_tokens);
377 _tail = _tokens;
378 recordStartOfLine();
379 }
380
381 /**
382 * Return an array containing the offsets of the first character of each line in the source code.
383 *
384 * @return an array containing the offsets of the first character of each line in the source code
385 */
386 List<int> get lineStarts => _lineStarts;
387
388 /**
389 * Return the current offset relative to the beginning of the file. Return the initial offset if
390 * the scanner has not yet scanned the source code, and one (1) past the end o f the source code if
391 * the source code has been scanned.
392 *
393 * @return the current offset of the scanner in the source
394 */
395 int get offset;
396
397 /**
398 * Set array of element tags for which the content between tags should be cons ider a single token.
399 */
400 void set passThroughElements(List<String> passThroughElements) {
401 this._passThroughElements = passThroughElements != null ? passThroughElement s : _NO_PASS_THROUGH_ELEMENTS;
402 }
403
404 /**
405 * Scan the source code to produce a list of tokens representing the source.
406 *
407 * @return the first token in the list of tokens that were produced
408 */
409 Token tokenize() {
410 scan();
411 appendEofToken();
412 return firstToken();
413 }
414
415 /**
416 * Advance the current position and return the character at the new current po sition.
417 *
418 * @return the character at the new current position
419 */
420 int advance();
421
422 /**
423 * Return the substring of the source code between the start offset and the mo dified current
424 * position. The current position is modified by adding the end delta.
425 *
426 * @param start the offset to the beginning of the string, relative to the sta rt of the file
427 * @param endDelta the number of character after the current location to be in cluded in the
428 * string, or the number of characters before the current location to be excluded if the
429 * offset is negative
430 * @return the specified substring of the source code
431 */
432 String getString(int start, int endDelta);
433
434 /**
435 * Return the character at the current position without changing the current p osition.
436 *
437 * @return the character at the current position
438 */
439 int peek();
440
441 /**
442 * Record the fact that we are at the beginning of a new line in the source.
443 */
444 void recordStartOfLine() {
445 _lineStarts.add(offset);
446 }
447 void appendEofToken() {
448 Token eofToken = new Token.con1(TokenType.EOF, offset);
449 eofToken.setNext(eofToken);
450 _tail = _tail.setNext(eofToken);
451 }
452 Token emit(Token token) {
453 _tail.setNext(token);
454 _tail = token;
455 return token;
456 }
457 Token emit2(TokenType type, int start) => emit(new Token.con1(type, start));
458 Token emit3(TokenType type, int start, int count) => emit(new Token.con2(type, start, getString(start, count)));
459 Token firstToken() => _tokens.next;
460 int recordStartOfLineAndAdvance(int c) {
461 if (c == 0xD) {
462 c = advance();
463 if (c == 0xA) {
464 c = advance();
465 }
466 recordStartOfLine();
467 } else if (c == 0xA) {
468 c = advance();
469 recordStartOfLine();
470 } else {
471 c = advance();
472 }
473 return c;
474 }
475 void scan() {
476 bool inBrackets = false;
477 String endPassThrough = null;
478 int c = advance();
479 while (c >= 0) {
480 int start = offset;
481 if (c == 0x3C) {
482 c = advance();
483 if (c == 0x21) {
484 c = advance();
485 if (c == 0x2D && peek() == 0x2D) {
486 c = advance();
487 int dashCount = 1;
488 while (c >= 0) {
489 if (c == 0x2D) {
490 dashCount++;
491 } else if (c == 0x3E && dashCount >= 2) {
492 c = advance();
493 break;
494 } else {
495 dashCount = 0;
496 }
497 c = recordStartOfLineAndAdvance(c);
498 }
499 emit3(TokenType.COMMENT, start, -1);
500 if (_tail.length < 7) {
501 }
502 } else {
503 while (c >= 0) {
504 if (c == 0x3E) {
505 c = advance();
506 break;
507 }
508 c = recordStartOfLineAndAdvance(c);
509 }
510 emit3(TokenType.DECLARATION, start, -1);
511 if (!_tail.lexeme.endsWith(">")) {
512 }
513 }
514 } else if (c == 0x3F) {
515 while (c >= 0) {
516 if (c == 0x3F) {
517 c = advance();
518 if (c == 0x3E) {
519 c = advance();
520 break;
521 }
522 } else {
523 c = recordStartOfLineAndAdvance(c);
524 }
525 }
526 emit3(TokenType.DIRECTIVE, start, -1);
527 if (_tail.length < 4) {
528 }
529 } else if (c == 0x2F) {
530 emit2(TokenType.LT_SLASH, start);
531 inBrackets = true;
532 c = advance();
533 } else {
534 inBrackets = true;
535 emit2(TokenType.LT, start);
536 while (Character.isWhitespace(c)) {
537 c = recordStartOfLineAndAdvance(c);
538 }
539 if (Character.isLetterOrDigit(c)) {
540 int tagStart = offset;
541 c = advance();
542 while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) {
543 c = advance();
544 }
545 emit3(TokenType.TAG, tagStart, -1);
546 String tag = _tail.lexeme;
547 for (String str in _passThroughElements) {
548 if (str == tag) {
549 endPassThrough = "</${str}>";
550 break;
551 }
552 }
553 }
554 }
555 } else if (c == 0x3E) {
556 emit2(TokenType.GT, start);
557 inBrackets = false;
558 c = advance();
559 if (endPassThrough != null) {
560 bool endFound = false;
561 int len = endPassThrough.length;
562 int firstC = endPassThrough.codeUnitAt(0);
563 int index = 0;
564 int nextC = firstC;
565 while (c >= 0) {
566 if (c == nextC) {
567 index++;
568 if (index == len) {
569 endFound = true;
570 break;
571 }
572 nextC = endPassThrough.codeUnitAt(index);
573 } else if (c == firstC) {
574 index = 1;
575 nextC = endPassThrough.codeUnitAt(1);
576 } else {
577 index = 0;
578 nextC = firstC;
579 }
580 c = recordStartOfLineAndAdvance(c);
581 }
582 if (start + 1 < offset) {
583 if (endFound) {
584 emit3(TokenType.TEXT, start + 1, -len);
585 emit2(TokenType.LT_SLASH, offset - len + 1);
586 emit3(TokenType.TAG, offset - len + 3, -1);
587 } else {
588 emit3(TokenType.TEXT, start + 1, -1);
589 }
590 }
591 endPassThrough = null;
592 }
593 } else if (c == 0x2F && peek() == 0x3E) {
594 advance();
595 emit2(TokenType.SLASH_GT, start);
596 inBrackets = false;
597 c = advance();
598 } else if (!inBrackets) {
599 c = recordStartOfLineAndAdvance(c);
600 while (c != 0x3C && c >= 0) {
601 c = recordStartOfLineAndAdvance(c);
602 }
603 emit3(TokenType.TEXT, start, -1);
604 } else if (c == 0x22 || c == 0x27) {
605 int endQuote = c;
606 c = advance();
607 while (c >= 0) {
608 if (c == endQuote) {
609 c = advance();
610 break;
611 }
612 c = recordStartOfLineAndAdvance(c);
613 }
614 emit3(TokenType.STRING, start, -1);
615 } else if (c == 0x3D) {
616 emit2(TokenType.EQ, start);
617 c = advance();
618 } else if (Character.isWhitespace(c)) {
619 do {
620 c = recordStartOfLineAndAdvance(c);
621 } while (Character.isWhitespace(c));
622 } else if (Character.isLetterOrDigit(c)) {
623 c = advance();
624 while (Character.isLetterOrDigit(c) || c == 0x2D || c == 0x5F) {
625 c = advance();
626 }
627 emit3(TokenType.TAG, start, -1);
628 } else {
629 emit3(TokenType.TEXT, start, 0);
630 c = advance();
631 }
632 }
633 }
634 }
635 /**
636 * Instances of `HtmlScanResult` hold the result of scanning an HTML file.
637 *
638 * @coverage dart.engine.html
639 */
640 class HtmlScanResult {
641
642 /**
643 * The time at which the contents of the source were last set.
644 */
645 int modificationTime = 0;
646
647 /**
648 * The first token in the token stream (not `null`).
649 */
650 Token token;
651
652 /**
653 * The line start information that was produced.
654 */
655 List<int> lineStarts;
656 HtmlScanResult(int modificationTime, Token token, List<int> lineStarts) {
657 this.modificationTime = modificationTime;
658 this.token = token;
659 this.lineStarts = lineStarts;
660 }
661 }
662 /**
663 * Instances of the class `StringScanner` implement a scanner that reads from a string. The
664 * scanning logic is in the superclass.
665 *
666 * @coverage dart.engine.html
667 */
668 class StringScanner extends AbstractScanner {
669
670 /**
671 * The string from which characters will be read.
672 */
673 String _string;
674
675 /**
676 * The number of characters in the string.
677 */
678 int _stringLength = 0;
679
680 /**
681 * The index, relative to the string, of the last character that was read.
682 */
683 int _charOffset = 0;
684
685 /**
686 * Initialize a newly created scanner to scan the characters in the given stri ng.
687 *
688 * @param source the source being scanned
689 * @param string the string from which characters will be read
690 */
691 StringScanner(Source source, String string) : super(source) {
692 this._string = string;
693 this._stringLength = string.length;
694 this._charOffset = -1;
695 }
696 int get offset => _charOffset;
697 void set offset(int offset) {
698 _charOffset = offset;
699 }
700 int advance() {
701 if (++_charOffset < _stringLength) {
702 return _string.codeUnitAt(_charOffset);
703 }
704 _charOffset = _stringLength;
705 return -1;
706 }
707 String getString(int start, int endDelta) => _string.substring(start, _charOff set + 1 + endDelta);
708 int peek() {
709 if (_charOffset + 1 < _stringLength) {
710 return _string.codeUnitAt(_charOffset + 1);
711 }
712 return -1;
713 }
714 }
715 /**
716 * Instances of the class `CharBufferScanner` implement a scanner that reads fro m a character
717 * buffer. The scanning logic is in the superclass.
718 *
719 * @coverage dart.engine.html
720 */
721 class CharBufferScanner extends AbstractScanner {
722
723 /**
724 * The buffer from which characters will be read.
725 */
726 CharSequence _buffer;
727
728 /**
729 * The number of characters in the buffer.
730 */
731 int _bufferLength = 0;
732
733 /**
734 * The index of the last character that was read.
735 */
736 int _charOffset = 0;
737
738 /**
739 * Initialize a newly created scanner to scan the characters in the given char acter buffer.
740 *
741 * @param source the source being scanned
742 * @param buffer the buffer from which characters will be read
743 */
744 CharBufferScanner(Source source, CharSequence buffer) : super(source) {
745 this._buffer = buffer;
746 this._bufferLength = buffer.length();
747 this._charOffset = -1;
748 }
749 int get offset => _charOffset;
750 int advance() {
751 if (++_charOffset < _bufferLength) {
752 return _buffer.charAt(_charOffset);
753 }
754 _charOffset = _bufferLength;
755 return -1;
756 }
757 String getString(int start, int endDelta) => _buffer.subSequence(start, _charO ffset + 1 + endDelta).toString();
758 int peek() {
759 if (_charOffset + 1 < _bufferLength) {
760 return _buffer.charAt(_charOffset + 1);
761 }
762 return -1;
763 }
764 }
765 /**
766 * Instances of the class `ToSourceVisitor` write a source representation of a v isited XML
767 * node (and all of it's children) to a writer.
768 *
769 * @coverage dart.engine.html
770 */
771 class ToSourceVisitor implements XmlVisitor<Object> {
772
773 /**
774 * The writer to which the source is to be written.
775 */
776 PrintWriter _writer;
777
778 /**
779 * Initialize a newly created visitor to write source code representing the vi sited nodes to the
780 * given writer.
781 *
782 * @param writer the writer to which the source is to be written
783 */
784 ToSourceVisitor(PrintWriter writer) {
785 this._writer = writer;
786 }
787 Object visitHtmlUnit(HtmlUnit node) {
788 for (XmlTagNode child in node.tagNodes) {
789 visit(child);
790 }
791 return null;
792 }
793 Object visitXmlAttributeNode(XmlAttributeNode node) {
794 String name = node.name.lexeme;
795 Token value = node.value;
796 if (name.length == 0) {
797 _writer.print("__");
798 } else {
799 _writer.print(name);
800 }
801 _writer.print("=");
802 if (value == null) {
803 _writer.print("__");
804 } else {
805 _writer.print(value.lexeme);
806 }
807 return null;
808 }
809 Object visitXmlTagNode(XmlTagNode node) {
810 _writer.print("<");
811 String tagName = node.tag.lexeme;
812 _writer.print(tagName);
813 for (XmlAttributeNode attribute in node.attributes) {
814 _writer.print(" ");
815 visit(attribute);
816 }
817 _writer.print(node.attributeEnd.lexeme);
818 if (node.closingTag != null) {
819 for (XmlTagNode child in node.tagNodes) {
820 visit(child);
821 }
822 _writer.print("</");
823 _writer.print(tagName);
824 _writer.print(">");
825 }
826 return null;
827 }
828
829 /**
830 * Safely visit the given node.
831 *
832 * @param node the node to be visited
833 */
834 void visit(XmlNode node) {
835 if (node != null) {
836 node.accept(this);
837 }
838 }
839 }
840 /**
841 * The enumeration `TokenType` defines the types of tokens that can be returned by the
842 * scanner.
843 *
844 * @coverage dart.engine.html
845 */
846 class TokenType extends Enum<TokenType> {
847
848 /**
849 * The type of the token that marks the end of the input.
850 */
851 static final TokenType EOF = new TokenType_EOF('EOF', 0, "");
852 static final TokenType EQ = new TokenType('EQ', 1, "=");
853 static final TokenType GT = new TokenType('GT', 2, ">");
854 static final TokenType LT_SLASH = new TokenType('LT_SLASH', 3, "</");
855 static final TokenType LT = new TokenType('LT', 4, "<");
856 static final TokenType SLASH_GT = new TokenType('SLASH_GT', 5, "/>");
857 static final TokenType COMMENT = new TokenType('COMMENT', 6, null);
858 static final TokenType DECLARATION = new TokenType('DECLARATION', 7, null);
859 static final TokenType DIRECTIVE = new TokenType('DIRECTIVE', 8, null);
860 static final TokenType STRING = new TokenType('STRING', 9, null);
861 static final TokenType TAG = new TokenType('TAG', 10, null);
862 static final TokenType TEXT = new TokenType('TEXT', 11, null);
863 static final List<TokenType> values = [
864 EOF,
865 EQ,
866 GT,
867 LT_SLASH,
868 LT,
869 SLASH_GT,
870 COMMENT,
871 DECLARATION,
872 DIRECTIVE,
873 STRING,
874 TAG,
875 TEXT];
876
877 /**
878 * The lexeme that defines this type of token, or `null` if there is more than one possible
879 * lexeme for this type of token.
880 */
881 String lexeme;
882 TokenType(String name, int ordinal, String lexeme) : super(name, ordinal) {
883 this.lexeme = lexeme;
884 }
885 }
886 class TokenType_EOF extends TokenType {
887 TokenType_EOF(String name, int ordinal, String arg0) : super(name, ordinal, ar g0);
888 String toString() => "-eof-";
889 }
890 /**
891 * Instances of `XmlAttributeNode` represent name/value pairs owned by an [XmlTa gNode].
892 *
893 * @coverage dart.engine.html
894 */
895 class XmlAttributeNode extends XmlNode {
896 Token name;
897 Token equals;
898 Token value;
899
900 /**
901 * Construct a new instance representing an XML attribute.
902 *
903 * @param name the name token (not `null`). This may be a zero length token if the attribute
904 * is badly formed.
905 * @param equals the equals sign or `null` if none
906 * @param value the value token (not `null`)
907 */
908 XmlAttributeNode(Token name, Token equals, Token value) {
909 this.name = name;
910 this.equals = equals;
911 this.value = value;
912 }
913 accept(XmlVisitor visitor) => visitor.visitXmlAttributeNode(this);
914 Token get beginToken => name;
915 Token get endToken => value;
916
917 /**
918 * Answer the lexeme for the value token without the leading and trailing quot es.
919 *
920 * @return the text or `null` if the value is not specified
921 */
922 String get text {
923 if (value == null) {
924 return null;
925 }
926 String text = value.lexeme;
927 int len = text.length;
928 if (len > 0) {
929 if (text.codeUnitAt(0) == 0x22) {
930 if (len > 1 && text.codeUnitAt(len - 1) == 0x22) {
931 return text.substring(1, len - 1);
932 } else {
933 return text.substring(1);
934 }
935 } else if (text.codeUnitAt(0) == 0x27) {
936 if (len > 1 && text.codeUnitAt(len - 1) == 0x27) {
937 return text.substring(1, len - 1);
938 } else {
939 return text.substring(1);
940 }
941 }
942 }
943 return text;
944 }
945 void visitChildren(XmlVisitor visitor) {
946 }
947 }
948 /**
949 * The interface `XmlVisitor` defines the behavior of objects that can be used t o visit an
950 * [XmlNode] structure.
951 *
952 * @coverage dart.engine.html
953 */
954 abstract class XmlVisitor<R> {
955 R visitHtmlUnit(HtmlUnit htmlUnit);
956 R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode);
957 R visitXmlTagNode(XmlTagNode xmlTagNode);
958 }
959 /**
960 * Instances of `HtmlScanner` receive and scan HTML content from a [Source].<br/ >
961 * For example, the following code scans HTML source and returns the result:
962 *
963 * <pre>
964 * HtmlScanner scanner = new HtmlScanner(source);
965 * source.getContents(scanner);
966 * return scanner.getResult();
967 * </pre>
968 *
969 * @coverage dart.engine.html
970 */
971 class HtmlScanner implements Source_ContentReceiver {
972 List<String> _SCRIPT_TAG = <String> ["script"];
973
974 /**
975 * The source being scanned (not `null`)
976 */
977 Source _source;
978
979 /**
980 * The time at which the contents of the source were last set.
981 */
982 int _modificationTime = 0;
983
984 /**
985 * The scanner used to scan the source
986 */
987 AbstractScanner _scanner;
988
989 /**
990 * The first token in the token stream.
991 */
992 Token _token;
993
994 /**
995 * Construct a new instance to scan the specified source.
996 *
997 * @param source the source to be scanned (not `null`)
998 */
999 HtmlScanner(Source source) {
1000 this._source = source;
1001 }
1002 void accept(CharBuffer contents, int modificationTime) {
1003 this._modificationTime = modificationTime;
1004 _scanner = new CharBufferScanner(_source, contents);
1005 _scanner.passThroughElements = _SCRIPT_TAG;
1006 _token = _scanner.tokenize();
1007 }
1008 void accept2(String contents, int modificationTime) {
1009 this._modificationTime = modificationTime;
1010 _scanner = new StringScanner(_source, contents);
1011 _scanner.passThroughElements = _SCRIPT_TAG;
1012 _token = _scanner.tokenize();
1013 }
1014
1015 /**
1016 * Answer the result of scanning the source
1017 *
1018 * @return the result (not `null`)
1019 */
1020 HtmlScanResult get result => new HtmlScanResult(_modificationTime, _token, _sc anner.lineStarts);
1021 }
1022 /**
1023 * Instances of the class `XmlParser` are used to parse tokens into a AST struct ure comprised
1024 * of [XmlNode]s.
1025 *
1026 * @coverage dart.engine.html
1027 */
1028 class XmlParser {
1029
1030 /**
1031 * The source being parsed.
1032 */
1033 Source source;
1034
1035 /**
1036 * The next token to be parsed.
1037 */
1038 Token currentToken;
1039
1040 /**
1041 * Construct a parser for the specified source.
1042 *
1043 * @param source the source being parsed
1044 */
1045 XmlParser(Source source) {
1046 this.source = source;
1047 }
1048
1049 /**
1050 * Answer `true` if the specified tag is self closing and thus should never ha ve content or
1051 * child tag nodes.
1052 *
1053 * @param tag the tag (not `null`)
1054 * @return `true` if self closing
1055 */
1056 bool isSelfClosing(Token tag) => false;
1057
1058 /**
1059 * Parse the entire token stream and in the process, advance the current token to the end of the
1060 * token stream.
1061 *
1062 * @return the list of tag nodes found (not `null`, contains no `null`)
1063 */
1064 List<XmlTagNode> parseTopTagNodes(Token firstToken) {
1065 currentToken = firstToken;
1066 List<XmlTagNode> tagNodes = new List<XmlTagNode>();
1067 while (true) {
1068 while (true) {
1069 if (currentToken.type == TokenType.LT) {
1070 tagNodes.add(parseTagNode());
1071 } else if (currentToken.type == TokenType.DECLARATION || currentToken.ty pe == TokenType.DIRECTIVE || currentToken.type == TokenType.COMMENT) {
1072 currentToken = currentToken.next;
1073 } else if (currentToken.type == TokenType.EOF) {
1074 return tagNodes;
1075 } else {
1076 reportUnexpectedToken();
1077 currentToken = currentToken.next;
1078 }
1079 break;
1080 }
1081 }
1082 }
1083
1084 /**
1085 * Insert a synthetic token of the specified type before the current token
1086 *
1087 * @param type the type of token to be inserted (not `null`)
1088 * @return the synthetic token that was inserted (not `null`)
1089 */
1090 Token insertSyntheticToken(TokenType type) {
1091 Token token = new Token.con2(type, currentToken.offset, "");
1092 currentToken.previous.setNext(token);
1093 token.setNext(currentToken);
1094 return token;
1095 }
1096
1097 /**
1098 * Parse the token stream for an attribute. This method advances the current t oken over the
1099 * attribute, but should not be called if the [currentToken] is not [TokenType #TAG].
1100 *
1101 * @return the attribute (not `null`)
1102 */
1103 XmlAttributeNode parseAttribute() {
1104 Token name = currentToken;
1105 currentToken = currentToken.next;
1106 Token equals;
1107 if (identical(currentToken.type, TokenType.EQ)) {
1108 equals = currentToken;
1109 currentToken = currentToken.next;
1110 } else {
1111 reportUnexpectedToken();
1112 equals = insertSyntheticToken(TokenType.EQ);
1113 }
1114 Token value;
1115 if (identical(currentToken.type, TokenType.STRING)) {
1116 value = currentToken;
1117 currentToken = currentToken.next;
1118 } else {
1119 reportUnexpectedToken();
1120 value = insertSyntheticToken(TokenType.STRING);
1121 }
1122 return new XmlAttributeNode(name, equals, value);
1123 }
1124
1125 /**
1126 * Parse the stream for a sequence of attributes. This method advances the cur rent token to the
1127 * next [TokenType#GT], [TokenType#SLASH_GT], or [TokenType#EOF].
1128 *
1129 * @return a collection of zero or more attributes (not `null`, contains no `n ull`s)
1130 */
1131 List<XmlAttributeNode> parseAttributes() {
1132 TokenType type = currentToken.type;
1133 if (identical(type, TokenType.GT) || identical(type, TokenType.SLASH_GT) || identical(type, TokenType.EOF)) {
1134 return XmlTagNode.NO_ATTRIBUTES;
1135 }
1136 List<XmlAttributeNode> attributes = new List<XmlAttributeNode>();
1137 while (true) {
1138 while (true) {
1139 if (currentToken.type == TokenType.GT || currentToken.type == TokenType. SLASH_GT || currentToken.type == TokenType.EOF) {
1140 return attributes;
1141 } else if (currentToken.type == TokenType.TAG) {
1142 attributes.add(parseAttribute());
1143 } else {
1144 reportUnexpectedToken();
1145 currentToken = currentToken.next;
1146 }
1147 break;
1148 }
1149 }
1150 }
1151
1152 /**
1153 * Parse the stream for a sequence of tag nodes existing within a parent tag n ode. This method
1154 * advances the current token to the next [TokenType#LT_SLASH] or [TokenType#E OF].
1155 *
1156 * @return a list of nodes (not `null`, contains no `null`s)
1157 */
1158 List<XmlTagNode> parseChildTagNodes() {
1159 TokenType type = currentToken.type;
1160 if (identical(type, TokenType.LT_SLASH) || identical(type, TokenType.EOF)) {
1161 return XmlTagNode.NO_TAG_NODES;
1162 }
1163 List<XmlTagNode> nodes = new List<XmlTagNode>();
1164 while (true) {
1165 while (true) {
1166 if (currentToken.type == TokenType.LT) {
1167 nodes.add(parseTagNode());
1168 } else if (currentToken.type == TokenType.LT_SLASH || currentToken.type == TokenType.EOF) {
1169 return nodes;
1170 } else if (currentToken.type == TokenType.COMMENT) {
1171 currentToken = currentToken.next;
1172 } else {
1173 reportUnexpectedToken();
1174 currentToken = currentToken.next;
1175 }
1176 break;
1177 }
1178 }
1179 }
1180
1181 /**
1182 * Parse the token stream for the next tag node. This method advances current token over the
1183 * parsed tag node, but should only be called if the current token is [TokenTy pe#LT]
1184 *
1185 * @return the tag node or `null` if none found
1186 */
1187 XmlTagNode parseTagNode() {
1188 Token nodeStart = currentToken;
1189 currentToken = currentToken.next;
1190 Token tag;
1191 if (identical(currentToken.type, TokenType.TAG)) {
1192 tag = currentToken;
1193 currentToken = currentToken.next;
1194 } else {
1195 reportUnexpectedToken();
1196 tag = insertSyntheticToken(TokenType.TAG);
1197 }
1198 List<XmlAttributeNode> attributes = parseAttributes();
1199 Token attributeEnd;
1200 if (identical(currentToken.type, TokenType.GT) || identical(currentToken.typ e, TokenType.SLASH_GT)) {
1201 attributeEnd = currentToken;
1202 currentToken = currentToken.next;
1203 } else {
1204 reportUnexpectedToken();
1205 attributeEnd = insertSyntheticToken(TokenType.SLASH_GT);
1206 }
1207 if (identical(attributeEnd.type, TokenType.SLASH_GT) || isSelfClosing(tag)) {
1208 return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode .NO_TAG_NODES, currentToken, null, attributeEnd);
1209 }
1210 List<XmlTagNode> tagNodes = parseChildTagNodes();
1211 Token contentEnd;
1212 if (identical(currentToken.type, TokenType.LT_SLASH)) {
1213 contentEnd = currentToken;
1214 currentToken = currentToken.next;
1215 } else {
1216 reportUnexpectedToken();
1217 contentEnd = insertSyntheticToken(TokenType.LT_SLASH);
1218 }
1219 Token closingTag;
1220 if (identical(currentToken.type, TokenType.TAG)) {
1221 closingTag = currentToken;
1222 currentToken = currentToken.next;
1223 } else {
1224 reportUnexpectedToken();
1225 closingTag = insertSyntheticToken(TokenType.TAG);
1226 }
1227 Token nodeEnd;
1228 if (identical(currentToken.type, TokenType.GT)) {
1229 nodeEnd = currentToken;
1230 currentToken = currentToken.next;
1231 } else {
1232 reportUnexpectedToken();
1233 nodeEnd = insertSyntheticToken(TokenType.GT);
1234 }
1235 return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, co ntentEnd, closingTag, nodeEnd);
1236 }
1237
1238 /**
1239 * Report the current token as unexpected
1240 */
1241 void reportUnexpectedToken() {
1242 }
1243 }
1244 /**
1245 * Instances of `XmlTagNode` represent XML or HTML elements such as `` and
1246 * `<body foo="bar"> ... </body>`.
1247 *
1248 * @coverage dart.engine.html
1249 */
1250 class XmlTagNode extends XmlNode {
1251
1252 /**
1253 * Constant representing empty list of attributes.
1254 */
1255 static List<XmlAttributeNode> NO_ATTRIBUTES = new UnmodifiableListView(new Lis t<XmlAttributeNode>());
1256
1257 /**
1258 * Constant representing empty list of tag nodes.
1259 */
1260 static List<XmlTagNode> NO_TAG_NODES = new UnmodifiableListView(new List<XmlTa gNode>());
1261
1262 /**
1263 * The starting [TokenType#LT] token (not `null`).
1264 */
1265 Token nodeStart;
1266
1267 /**
1268 * The [TokenType#TAG] token after the starting '&lt;' (not `null`).
1269 */
1270 Token tag;
1271
1272 /**
1273 * The attributes contained by the receiver (not `null`, contains no `null`s).
1274 */
1275 List<XmlAttributeNode> attributes;
1276
1277 /**
1278 * The [TokenType#GT] or [TokenType#SLASH_GT] token after the attributes (not
1279 * `null`). The token may be the same token as [nodeEnd] if there are no child
1280 * [tagNodes].
1281 */
1282 Token attributeEnd;
1283
1284 /**
1285 * The tag nodes contained in the receiver (not `null`, contains no `null`s).
1286 */
1287 List<XmlTagNode> tagNodes;
1288
1289 /**
1290 * The token (not `null`) after the content, which may be
1291 *
1292 * * (1) [TokenType#LT_SLASH] for nodes with open and close tags, or
1293 * * (2) the [TokenType#LT] nodeStart of the next sibling node if this node is self
1294 * closing or the attributeEnd is [TokenType#SLASH_GT], or
1295 * * (3) [TokenType#EOF] if the node does not have a closing tag and is the la st node in
1296 * the stream [TokenType#LT_SLASH] token after the content, or `null` if there is no
1297 * content and the attributes ended with [TokenType#SLASH_GT].
1298 *
1299 */
1300 Token contentEnd;
1301
1302 /**
1303 * The closing [TokenType#TAG] after the child elements or `null` if there is no
1304 * content and the attributes ended with [TokenType#SLASH_GT]
1305 */
1306 Token closingTag;
1307
1308 /**
1309 * The ending [TokenType#GT] or [TokenType#SLASH_GT] token (not `null`).
1310 */
1311 Token nodeEnd;
1312
1313 /**
1314 * Construct a new instance representing an XML or HTML element
1315 *
1316 * @param nodeStart the starting [TokenType#LT] token (not `null`)
1317 * @param tag the [TokenType#TAG] token after the starting '&lt;' (not `null`) .
1318 * @param attributes the attributes associated with this element or [NO_ATTRIB UTES] (not
1319 * `null`, contains no `null`s)
1320 * @param attributeEnd The [TokenType#GT] or [TokenType#SLASH_GT] token after the
1321 * attributes (not `null`). The token may be the same token as [nodeE nd] if
1322 * there are no child [tagNodes].
1323 * @param tagNodes child tag nodes of the receiver or [NO_TAG_NODES] (not `nul l`,
1324 * contains no `null`s)
1325 * @param contentEnd the token (not `null`) after the content, which may be
1326 *
1327 * * (1) [TokenType#LT_SLASH] for nodes with open and close tags, or
1328 * * (2) the [TokenType#LT] nodeStart of the next sibling node if thi s node is
1329 * self closing or the attributeEnd is [TokenType#SLASH_GT], or
1330 * * (3) [TokenType#EOF] if the node does not have a closing tag and is the last
1331 * node in the stream [TokenType#LT_SLASH] token after the content, o r `null`
1332 * if there is no content and the attributes ended with [TokenType#SL ASH_GT].
1333 *
1334 * @param closingTag the closing [TokenType#TAG] after the child elements or ` null` if
1335 * there is no content and the attributes ended with [TokenType#SLASH _GT]
1336 * @param nodeEnd the ending [TokenType#GT] or [TokenType#SLASH_GT] token (not
1337 * `null`)
1338 */
1339 XmlTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Toke n attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, T oken nodeEnd) {
1340 this.nodeStart = nodeStart;
1341 this.tag = tag;
1342 this.attributes = becomeParentOfEmpty(attributes, NO_ATTRIBUTES);
1343 this.attributeEnd = attributeEnd;
1344 this.tagNodes = becomeParentOfEmpty(tagNodes, NO_TAG_NODES);
1345 this.contentEnd = contentEnd;
1346 this.closingTag = closingTag;
1347 this.nodeEnd = nodeEnd;
1348 }
1349 accept(XmlVisitor visitor) => visitor.visitXmlTagNode(this);
1350
1351 /**
1352 * Answer the attribute with the specified name.
1353 *
1354 * @param name the attribute name
1355 * @return the attribute or `null` if no matching attribute is found
1356 */
1357 XmlAttributeNode getAttribute(String name) {
1358 for (XmlAttributeNode attribute in attributes) {
1359 if (attribute.name.lexeme == name) {
1360 return attribute;
1361 }
1362 }
1363 return null;
1364 }
1365
1366 /**
1367 * Find the attribute with the given name (see [getAttribute] and answer the l exeme
1368 * for the attribute's value token without the leading and trailing quotes (se e
1369 * [XmlAttributeNode#getText]).
1370 *
1371 * @param name the attribute name
1372 * @return the attribute text or `null` if no matching attribute is found
1373 */
1374 String getAttributeText(String name) {
1375 XmlAttributeNode attribute = getAttribute(name);
1376 return attribute != null ? attribute.text : null;
1377 }
1378 Token get beginToken => nodeStart;
1379
1380 /**
1381 * Answer a string representing the content contained in the receiver. This in cludes the textual
1382 * representation of any child tag nodes ([getTagNodes]). Whitespace between ' &lt;',
1383 * '&lt;/', and '>', '/>' is discarded, but all other whitespace is preserved.
1384 *
1385 * @return the content (not `null`)
1386 */
1387 String get content {
1388 Token token = attributeEnd.next;
1389 if (identical(token, contentEnd)) {
1390 return "";
1391 }
1392 String content = token.lexeme;
1393 token = token.next;
1394 if (identical(token, contentEnd)) {
1395 return content;
1396 }
1397 JavaStringBuilder buffer = new JavaStringBuilder();
1398 while (token != contentEnd) {
1399 buffer.append(token.lexeme);
1400 token = token.next;
1401 }
1402 return buffer.toString();
1403 }
1404 Token get endToken {
1405 if (nodeEnd != null) {
1406 return nodeEnd;
1407 }
1408 if (closingTag != null) {
1409 return closingTag;
1410 }
1411 if (contentEnd != null) {
1412 return contentEnd;
1413 }
1414 if (!tagNodes.isEmpty) {
1415 return tagNodes[tagNodes.length - 1].endToken;
1416 }
1417 if (attributeEnd != null) {
1418 return attributeEnd;
1419 }
1420 if (!attributes.isEmpty) {
1421 return attributes[attributes.length - 1].endToken;
1422 }
1423 return tag;
1424 }
1425 void visitChildren(XmlVisitor visitor) {
1426 for (XmlAttributeNode node in attributes) {
1427 node.accept(visitor);
1428 }
1429 for (XmlTagNode node in tagNodes) {
1430 node.accept(visitor);
1431 }
1432 }
1433
1434 /**
1435 * Same as [becomeParentOf], but returns given "ifEmpty" if "children" is empt y
1436 */
1437 List becomeParentOfEmpty(List children, List ifEmpty) {
1438 if (children != null && children.isEmpty) {
1439 return ifEmpty;
1440 }
1441 return becomeParentOf(children);
1442 }
1443 }
1444 /**
1445 * Instances of the class `HtmlParser` are used to parse tokens into a AST struc ture comprised
1446 * of [XmlNode]s.
1447 *
1448 * @coverage dart.engine.html
1449 */
1450 class HtmlParser extends XmlParser {
1451 static Set<String> SELF_CLOSING = new Set<String>();
1452
1453 /**
1454 * Construct a parser for the specified source.
1455 *
1456 * @param source the source being parsed
1457 */
1458 HtmlParser(Source source) : super(source);
1459
1460 /**
1461 * Parse the tokens specified by the given scan result.
1462 *
1463 * @param scanResult the result of scanning an HTML source (not `null`)
1464 * @return the parse result (not `null`)
1465 */
1466 HtmlParseResult parse(HtmlScanResult scanResult) {
1467 Token firstToken = scanResult.token;
1468 List<XmlTagNode> tagNodes = parseTopTagNodes(firstToken);
1469 HtmlUnit unit = new HtmlUnit(firstToken, tagNodes, currentToken);
1470 return new HtmlParseResult(scanResult.modificationTime, firstToken, scanResu lt.lineStarts, unit);
1471 }
1472
1473 /**
1474 * Scan then parse the specified source.
1475 *
1476 * @param source the source to be scanned and parsed (not `null`)
1477 * @return the parse result (not `null`)
1478 */
1479 HtmlParseResult parse2(Source source) {
1480 HtmlScanner scanner = new HtmlScanner(source);
1481 source.getContents(scanner);
1482 return parse(scanner.result);
1483 }
1484 bool isSelfClosing(Token tag) => SELF_CLOSING.contains(tag.lexeme);
1485 }
1486 /**
1487 * Instances of the class `HtmlUnit` represent the contents of an HTML file.
1488 *
1489 * @coverage dart.engine.html
1490 */
1491 class HtmlUnit extends XmlNode {
1492
1493 /**
1494 * The first token in the token stream that was parsed to form this HTML unit.
1495 */
1496 Token _beginToken;
1497
1498 /**
1499 * The last token in the token stream that was parsed to form this compilation unit. This token
1500 * should always have a type of [TokenType.EOF].
1501 */
1502 Token _endToken;
1503
1504 /**
1505 * The tag nodes contained in the receiver (not `null`, contains no `null`s).
1506 */
1507 List<XmlTagNode> tagNodes;
1508
1509 /**
1510 * The element associated with this HTML unit or `null` if the receiver is not resolved.
1511 */
1512 HtmlElementImpl element;
1513
1514 /**
1515 * Construct a new instance representing the content of an HTML file.
1516 *
1517 * @param beginToken the first token in the file (not `null`)
1518 * @param tagNodes child tag nodes of the receiver (not `null`, contains no `n ull`s)
1519 * @param endToken the last token in the token stream which should be of type
1520 * [TokenType.EOF]
1521 */
1522 HtmlUnit(Token beginToken, List<XmlTagNode> tagNodes, Token endToken) {
1523 this._beginToken = beginToken;
1524 this.tagNodes = becomeParentOf(tagNodes);
1525 this._endToken = endToken;
1526 }
1527 accept(XmlVisitor visitor) => visitor.visitHtmlUnit(this);
1528 Token get beginToken => _beginToken;
1529 Token get endToken => _endToken;
1530 void visitChildren(XmlVisitor visitor) {
1531 for (XmlTagNode node in tagNodes) {
1532 node.accept(visitor);
1533 }
1534 }
1535 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698