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

Side by Side Diff: pkg/analyzer/lib/src/dart/ast/utilities.dart

Issue 1660873003: Clone and link all tokens in AstCloner. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 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
« no previous file with comments | « pkg/analyzer/lib/src/dart/ast/ast.dart ('k') | pkg/analyzer/lib/src/generated/scanner.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 library analyzer.src.dart.ast.utilities; 5 library analyzer.src.dart.ast.utilities;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/visitor.dart'; 10 import 'package:analyzer/dart/ast/visitor.dart';
(...skipping 11 matching lines...) Expand all
22 * properties associated with the nodes. 22 * properties associated with the nodes.
23 */ 23 */
24 class AstCloner implements AstVisitor<AstNode> { 24 class AstCloner implements AstVisitor<AstNode> {
25 /** 25 /**
26 * A flag indicating whether tokens should be cloned while cloning an AST 26 * A flag indicating whether tokens should be cloned while cloning an AST
27 * structure. 27 * structure.
28 */ 28 */
29 final bool cloneTokens; 29 final bool cloneTokens;
30 30
31 /** 31 /**
32 * Mapping from original tokes to cloned.
33 */
34 final Map<Token, Token> _clonedTokens = new Map<Token, Token>.identity();
35
36 /**
37 * The next original token to clone.
38 */
39 Token _nextToClone;
40
41 /**
42 * The last cloned token.
43 */
44 Token _lastCloned;
45
46 /**
47 * The offset of the last cloned token.
48 */
49 int _lastClonedOffset = -1;
50
51 /**
32 * Initialize a newly created AST cloner to optionally clone tokens while 52 * Initialize a newly created AST cloner to optionally clone tokens while
33 * cloning AST nodes if [cloneTokens] is `true`. 53 * cloning AST nodes if [cloneTokens] is `true`.
54 *
55 * TODO(brianwilkerson) Change this to be a named parameter.
34 */ 56 */
35 AstCloner( 57 AstCloner([this.cloneTokens = false]);
36 [this.cloneTokens =
37 false]); // TODO(brianwilkerson) Change this to be a named parameter.
38 58
39 /** 59 /**
40 * Return a clone of the given [node]. 60 * Return a clone of the given [node].
41 */ 61 */
42 AstNode cloneNode(AstNode node) { 62 AstNode cloneNode(AstNode node) {
43 if (node == null) { 63 if (node == null) {
44 return null; 64 return null;
45 } 65 }
46 return node.accept(this) as AstNode; 66 return node.accept(this) as AstNode;
47 } 67 }
48 68
49 /** 69 /**
50 * Return a list containing cloned versions of the nodes in the given list of 70 * Return a list containing cloned versions of the nodes in the given list of
51 * [nodes]. 71 * [nodes].
52 */ 72 */
53 List<AstNode> cloneNodeList(NodeList nodes) { 73 List<AstNode> cloneNodeList(NodeList nodes) {
54 int count = nodes.length; 74 int count = nodes.length;
55 List clonedNodes = new List(); 75 List clonedNodes = new List();
56 for (int i = 0; i < count; i++) { 76 for (int i = 0; i < count; i++) {
57 clonedNodes.add((nodes[i]).accept(this) as AstNode); 77 clonedNodes.add((nodes[i]).accept(this) as AstNode);
58 } 78 }
59 return clonedNodes; 79 return clonedNodes;
60 } 80 }
61 81
62 /** 82 /**
63 * Clone the given [token] if tokens are supposed to be cloned. 83 * Clone the given [token] if tokens are supposed to be cloned.
64 */ 84 */
65 Token cloneToken(Token token) { 85 Token cloneToken(Token token) {
66 if (cloneTokens) { 86 if (cloneTokens) {
67 return (token == null ? null : token.copy()); 87 if (token == null) {
88 return null;
89 }
90 if (_lastClonedOffset <= token.offset) {
91 _cloneTokens(_nextToClone ?? token, token.offset);
92 }
93 Token clone = _clonedTokens[token];
94 assert(clone != null);
95 return clone;
68 } else { 96 } else {
69 return token; 97 return token;
70 } 98 }
71 } 99 }
72 100
73 /** 101 /**
74 * Clone the given [tokens] if tokens are supposed to be cloned. 102 * Clone the given [tokens] if tokens are supposed to be cloned.
75 */ 103 */
76 List<Token> cloneTokenList(List<Token> tokens) { 104 List<Token> cloneTokenList(List<Token> tokens) {
77 if (cloneTokens) { 105 if (cloneTokens) {
78 return tokens.map((Token token) => token.copy()).toList(); 106 return tokens.map(cloneToken).toList();
79 } 107 }
80 return tokens; 108 return tokens;
81 } 109 }
82 110
83 @override 111 @override
84 AdjacentStrings visitAdjacentStrings(AdjacentStrings node) => 112 AdjacentStrings visitAdjacentStrings(AdjacentStrings node) =>
85 new AdjacentStrings(cloneNodeList(node.strings)); 113 new AdjacentStrings(cloneNodeList(node.strings));
86 114
87 @override 115 @override
88 Annotation visitAnnotation(Annotation node) => new Annotation( 116 Annotation visitAnnotation(Annotation node) => new Annotation(
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 cloneNode(node.withClause), 206 cloneNode(node.withClause),
179 cloneNode(node.implementsClause), 207 cloneNode(node.implementsClause),
180 cloneToken(node.leftBracket), 208 cloneToken(node.leftBracket),
181 cloneNodeList(node.members), 209 cloneNodeList(node.members),
182 cloneToken(node.rightBracket)); 210 cloneToken(node.rightBracket));
183 copy.nativeClause = cloneNode(node.nativeClause); 211 copy.nativeClause = cloneNode(node.nativeClause);
184 return copy; 212 return copy;
185 } 213 }
186 214
187 @override 215 @override
188 ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) => new ClassTypeAlias( 216 ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) {
217 cloneToken(node.abstractKeyword);
218 return new ClassTypeAlias(
189 cloneNode(node.documentationComment), 219 cloneNode(node.documentationComment),
190 cloneNodeList(node.metadata), 220 cloneNodeList(node.metadata),
191 cloneToken(node.typedefKeyword), 221 cloneToken(node.typedefKeyword),
192 cloneNode(node.name), 222 cloneNode(node.name),
193 cloneNode(node.typeParameters), 223 cloneNode(node.typeParameters),
194 cloneToken(node.equals), 224 cloneToken(node.equals),
195 cloneToken(node.abstractKeyword), 225 cloneToken(node.abstractKeyword),
196 cloneNode(node.superclass), 226 cloneNode(node.superclass),
197 cloneNode(node.withClause), 227 cloneNode(node.withClause),
198 cloneNode(node.implementsClause), 228 cloneNode(node.implementsClause),
199 cloneToken(node.semicolon)); 229 cloneToken(node.semicolon));
230 }
200 231
201 @override 232 @override
202 Comment visitComment(Comment node) { 233 Comment visitComment(Comment node) {
203 if (node.isDocumentation) { 234 if (node.isDocumentation) {
204 return Comment.createDocumentationCommentWithReferences( 235 return Comment.createDocumentationCommentWithReferences(
205 cloneTokenList(node.tokens), cloneNodeList(node.references)); 236 cloneTokenList(node.tokens), cloneNodeList(node.references));
206 } else if (node.isBlock) { 237 } else if (node.isBlock) {
207 return Comment.createBlockComment(cloneTokenList(node.tokens)); 238 return Comment.createBlockComment(cloneTokenList(node.tokens));
208 } 239 }
209 return Comment.createEndOfLineComment(cloneTokenList(node.tokens)); 240 return Comment.createEndOfLineComment(cloneTokenList(node.tokens));
210 } 241 }
211 242
212 @override 243 @override
213 CommentReference visitCommentReference(CommentReference node) => 244 CommentReference visitCommentReference(CommentReference node) =>
214 new CommentReference( 245 new CommentReference(
215 cloneToken(node.newKeyword), cloneNode(node.identifier)); 246 cloneToken(node.newKeyword), cloneNode(node.identifier));
216 247
217 @override 248 @override
218 CompilationUnit visitCompilationUnit(CompilationUnit node) { 249 CompilationUnit visitCompilationUnit(CompilationUnit node) {
250 ScriptTag scriptTag = cloneNode(node.scriptTag);
251 List<Directive> directives = cloneNodeList(node.directives);
252 List<CompilationUnitMember> declarations = cloneNodeList(node.declarations);
253 Token endToken = cloneToken(node.endToken);
254 Token beginToken = scriptTag?.beginToken ??
255 (directives.isEmpty ? null : directives.first.beginToken) ??
256 (declarations.isEmpty ? null : declarations.first.beginToken) ??
257 endToken;
219 CompilationUnit clone = new CompilationUnit( 258 CompilationUnit clone = new CompilationUnit(
220 cloneToken(node.beginToken), 259 beginToken, scriptTag, directives, declarations, endToken);
221 cloneNode(node.scriptTag),
222 cloneNodeList(node.directives),
223 cloneNodeList(node.declarations),
224 cloneToken(node.endToken));
225 clone.lineInfo = node.lineInfo; 260 clone.lineInfo = node.lineInfo;
226 return clone; 261 return clone;
227 } 262 }
228 263
229 @override 264 @override
230 ConditionalExpression visitConditionalExpression( 265 ConditionalExpression visitConditionalExpression(
231 ConditionalExpression node) => 266 ConditionalExpression node) =>
232 new ConditionalExpression( 267 new ConditionalExpression(
233 cloneNode(node.condition), 268 cloneNode(node.condition),
234 cloneToken(node.question), 269 cloneToken(node.question),
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after
880 cloneToken(node.withKeyword), cloneNodeList(node.mixinTypes)); 915 cloneToken(node.withKeyword), cloneNodeList(node.mixinTypes));
881 916
882 @override 917 @override
883 YieldStatement visitYieldStatement(YieldStatement node) => new YieldStatement( 918 YieldStatement visitYieldStatement(YieldStatement node) => new YieldStatement(
884 cloneToken(node.yieldKeyword), 919 cloneToken(node.yieldKeyword),
885 cloneToken(node.star), 920 cloneToken(node.star),
886 cloneNode(node.expression), 921 cloneNode(node.expression),
887 cloneToken(node.semicolon)); 922 cloneToken(node.semicolon));
888 923
889 /** 924 /**
925 * Clone all token starting from the given [token] up to a token that has
926 * offset greater then [stopAfter], and put mapping from originals to clones
927 * into [_clonedTokens].
928 *
929 * We cannot clone tokens as we visit nodes because not every token is a part
930 * of a node, E.g. commas in argument lists are not represented in AST. But
931 * we need to the sequence of tokens that is identical to the original one.
932 */
933 void _cloneTokens(Token token, int stopAfter) {
934 if (token == null) {
935 return;
936 }
937 if (token is CommentToken) {
938 token = (token as CommentToken).parent;
939 }
940 while (token != null) {
941 Token clone = token.copy();
942 {
943 CommentToken c1 = token.precedingComments;
944 CommentToken c2 = clone.precedingComments;
945 while (c1 != null && c2 != null) {
946 _clonedTokens[c1] = c2;
947 if (c1 is DocumentationCommentToken &&
948 c2 is DocumentationCommentToken) {
949 for (int i = 0; i < c1.references.length; i++) {
950 _clonedTokens[c1.references[i]] = c2.references[i];
951 }
952 }
953 c1 = c1.next;
954 c2 = c2.next;
955 }
956 }
957 _clonedTokens[token] = clone;
958 _lastCloned?.setNext(clone);
959 _lastCloned = clone;
960 if (token.type == TokenType.EOF) {
961 break;
962 }
963 if (token.offset > stopAfter) {
964 _nextToClone = token.next;
965 _lastClonedOffset = token.offset;
966 break;
967 }
968 token = token.next;
969 }
970 }
971
972 /**
890 * Return a clone of the given [node]. 973 * Return a clone of the given [node].
891 */ 974 */
892 static AstNode clone(AstNode node) { 975 static AstNode clone(AstNode node) {
893 return node.accept(new AstCloner()); 976 return node.accept(new AstCloner());
894 } 977 }
895 } 978 }
896 979
897 /** 980 /**
898 * An AstVisitor that compares the structure of two AstNodes to see whether they 981 * An AstVisitor that compares the structure of two AstNodes to see whether they
899 * are equal. 982 * are equal.
(...skipping 5363 matching lines...) Expand 10 before | Expand all | Expand 10 after
6263 * Safely visit the given [token], printing the [suffix] after the token if it 6346 * Safely visit the given [token], printing the [suffix] after the token if it
6264 * is non-`null`. 6347 * is non-`null`.
6265 */ 6348 */
6266 void _visitTokenWithSuffix(Token token, String suffix) { 6349 void _visitTokenWithSuffix(Token token, String suffix) {
6267 if (token != null) { 6350 if (token != null) {
6268 _writer.print(token.lexeme); 6351 _writer.print(token.lexeme);
6269 _writer.print(suffix); 6352 _writer.print(suffix);
6270 } 6353 }
6271 } 6354 }
6272 } 6355 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/dart/ast/ast.dart ('k') | pkg/analyzer/lib/src/generated/scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698