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

Side by Side Diff: pkg/analyzer/tool/summary/generate.dart

Issue 2748803003: Change summary code generator to use Fasta parser. (Closed)
Patch Set: Created 3 years, 9 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 /** 5 /**
6 * This file contains code to generate serialization/deserialization logic for 6 * This file contains code to generate serialization/deserialization logic for
7 * summaries based on an "IDL" description of the summary format (written in 7 * summaries based on an "IDL" description of the summary format (written in
8 * stylized Dart). 8 * stylized Dart).
9 * 9 *
10 * For each class in the "IDL" input, two corresponding classes are generated: 10 * For each class in the "IDL" input, two corresponding classes are generated:
11 * - A class with the same name which represents deserialized summary data in 11 * - A class with the same name which represents deserialized summary data in
12 * memory. This class has read-only semantics. 12 * memory. This class has read-only semantics.
13 * - A "builder" class which can be used to generate serialized summary data. 13 * - A "builder" class which can be used to generate serialized summary data.
14 * This class has write-only semantics. 14 * This class has write-only semantics.
15 * 15 *
16 * Each of the "builder" classes has a single `finish` method which writes 16 * Each of the "builder" classes has a single `finish` method which writes
17 * the entity being built into the given FlatBuffer and returns the `Offset` 17 * the entity being built into the given FlatBuffer and returns the `Offset`
18 * reference to it. 18 * reference to it.
19 */ 19 */
20 library analyzer.tool.summary.generate; 20 library analyzer.tool.summary.generate;
21 21
22 import 'dart:convert'; 22 import 'dart:convert';
23 import 'dart:io' hide File; 23 import 'dart:io' hide File;
24 24
25 import 'package:analyzer/analyzer.dart';
26 import 'package:analyzer/dart/ast/token.dart';
27 import 'package:analyzer/error/listener.dart';
28 import 'package:analyzer/file_system/file_system.dart'; 25 import 'package:analyzer/file_system/file_system.dart';
29 import 'package:analyzer/file_system/physical_file_system.dart'; 26 import 'package:analyzer/file_system/physical_file_system.dart';
30 import 'package:analyzer/src/codegen/tools.dart'; 27 import 'package:analyzer/src/codegen/tools.dart';
31 import 'package:analyzer/src/dart/scanner/reader.dart'; 28 import 'package:front_end/src/fasta/scanner/string_scanner.dart';
32 import 'package:analyzer/src/dart/scanner/scanner.dart'; 29 import 'package:front_end/src/fasta/scanner/token.dart';
33 import 'package:analyzer/src/generated/parser.dart';
34 import 'package:analyzer/src/generated/source.dart';
35 import 'package:path/path.dart'; 30 import 'package:path/path.dart';
36 31
37 import 'idl_model.dart' as idlModel; 32 import 'idl_model.dart' as idlModel;
33 import 'mini_ast.dart';
38 34
39 main() { 35 main() {
40 String script = Platform.script.toFilePath(windows: Platform.isWindows); 36 String script = Platform.script.toFilePath(windows: Platform.isWindows);
41 String pkgPath = normalize(join(dirname(script), '..', '..')); 37 String pkgPath = normalize(join(dirname(script), '..', '..'));
42 GeneratedContent.generateAll(pkgPath, allTargets); 38 GeneratedContent.generateAll(pkgPath, allTargets);
43 } 39 }
44 40
45 final List<GeneratedContent> allTargets = <GeneratedContent>[ 41 final List<GeneratedContent> allTargets = <GeneratedContent>[
46 formatTarget, 42 formatTarget,
47 schemaTarget 43 schemaTarget
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 * Semantic model of the "IDL" input file. 77 * Semantic model of the "IDL" input file.
82 */ 78 */
83 idlModel.Idl _idl; 79 idlModel.Idl _idl;
84 80
85 _CodeGenerator(String pkgPath) { 81 _CodeGenerator(String pkgPath) {
86 // Parse the input "IDL" file. 82 // Parse the input "IDL" file.
87 PhysicalResourceProvider provider = new PhysicalResourceProvider( 83 PhysicalResourceProvider provider = new PhysicalResourceProvider(
88 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS); 84 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS);
89 String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart'); 85 String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart');
90 File idlFile = provider.getFile(idlPath); 86 File idlFile = provider.getFile(idlPath);
91 Source idlSource = provider.getFile(idlPath).createSource();
92 String idlText = idlFile.readAsStringSync(); 87 String idlText = idlFile.readAsStringSync();
93 BooleanErrorListener errorListener = new BooleanErrorListener();
94 CharacterReader idlReader = new CharSequenceReader(idlText);
95 Scanner scanner = new Scanner(idlSource, idlReader, errorListener);
96 Token tokenStream = scanner.tokenize();
97 LineInfo lineInfo = new LineInfo(scanner.lineStarts);
98 Parser parser = new Parser(idlSource, new BooleanErrorListener());
99 CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream);
100 // Extract a description of the IDL and make sure it is valid. 88 // Extract a description of the IDL and make sure it is valid.
101 extractIdl(lineInfo, idlParsed); 89 var scanner = new StringScanner(idlText, includeComments: true);
90 var startingToken = scanner.tokenize();
91 var listener = new MiniAstBuilder();
92 var parser = new MiniAstParser(listener);
93 parser.parseUnit(startingToken);
94 extractIdl(listener.compilationUnit);
102 checkIdl(); 95 checkIdl();
103 } 96 }
104 97
105 /** 98 /**
106 * Perform basic sanity checking of the IDL (over and above that done by 99 * Perform basic sanity checking of the IDL (over and above that done by
107 * [extractIdl]). 100 * [extractIdl]).
108 */ 101 */
109 void checkIdl() { 102 void checkIdl() {
110 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { 103 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) {
111 if (cls.fileIdentifier != null) { 104 if (cls.fileIdentifier != null) {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 return 'List<$typeStr>'; 206 return 'List<$typeStr>';
214 } else { 207 } else {
215 return typeStr; 208 return typeStr;
216 } 209 }
217 } 210 }
218 211
219 /** 212 /**
220 * Process the AST in [idlParsed] and store the resulting semantic model in 213 * Process the AST in [idlParsed] and store the resulting semantic model in
221 * [_idl]. Also perform some error checking. 214 * [_idl]. Also perform some error checking.
222 */ 215 */
223 void extractIdl(LineInfo lineInfo, CompilationUnit idlParsed) { 216 void extractIdl(CompilationUnit idlParsed) {
224 _idl = new idlModel.Idl(); 217 _idl = new idlModel.Idl();
225 for (CompilationUnitMember decl in idlParsed.declarations) { 218 for (CompilationUnitMember decl in idlParsed.declarations) {
226 if (decl is ClassDeclaration) { 219 if (decl is ClassDeclaration) {
227 bool isTopLevel = false; 220 bool isTopLevel = false;
228 String fileIdentifier; 221 String fileIdentifier;
229 String clsName = decl.name.name; 222 String clsName = decl.name;
230 for (Annotation annotation in decl.metadata) { 223 for (Annotation annotation in decl.metadata) {
231 if (annotation.arguments != null && 224 if (annotation.arguments != null &&
232 annotation.name.name == 'TopLevel' && 225 annotation.name == 'TopLevel' &&
233 annotation.constructorName == null) { 226 annotation.constructorName == null) {
234 isTopLevel = true; 227 isTopLevel = true;
235 if (annotation.arguments == null) { 228 if (annotation.arguments == null) {
236 throw new Exception( 229 throw new Exception(
237 'Class `$clsName`: TopLevel requires parenthesis'); 230 'Class `$clsName`: TopLevel requires parenthesis');
238 } 231 }
239 if (annotation.constructorName != null) { 232 if (annotation.constructorName != null) {
240 throw new Exception( 233 throw new Exception(
241 "Class `$clsName`: TopLevel doesn't have named constructors"); 234 "Class `$clsName`: TopLevel doesn't have named constructors");
242 } 235 }
243 if (annotation.arguments.arguments.length == 1) { 236 if (annotation.arguments.length == 1) {
244 Expression arg = annotation.arguments.arguments[0]; 237 Expression arg = annotation.arguments[0];
245 if (arg is StringLiteral) { 238 if (arg is StringLiteral) {
246 fileIdentifier = arg.stringValue; 239 fileIdentifier = arg.stringValue;
247 } else { 240 } else {
248 throw new Exception( 241 throw new Exception(
249 'Class `$clsName`: TopLevel argument must be a string' 242 'Class `$clsName`: TopLevel argument must be a string'
250 ' literal'); 243 ' literal');
251 } 244 }
252 } else if (annotation.arguments.arguments.length != 0) { 245 } else if (annotation.arguments.length != 0) {
253 throw new Exception( 246 throw new Exception(
254 'Class `$clsName`: TopLevel requires 0 or 1 arguments'); 247 'Class `$clsName`: TopLevel requires 0 or 1 arguments');
255 } 248 }
256 } 249 }
257 } 250 }
258 String doc = _getNodeDoc(lineInfo, decl); 251 String doc = _getNodeDoc(decl);
259 idlModel.ClassDeclaration cls = new idlModel.ClassDeclaration( 252 idlModel.ClassDeclaration cls = new idlModel.ClassDeclaration(
260 doc, clsName, isTopLevel, fileIdentifier); 253 doc, clsName, isTopLevel, fileIdentifier);
261 _idl.classes[clsName] = cls; 254 _idl.classes[clsName] = cls;
262 String expectedBase = 'base.SummaryClass'; 255 String expectedBase = 'base.SummaryClass';
263 if (decl.extendsClause == null || 256 if (decl.superclass == null || decl.superclass.name != expectedBase) {
264 decl.extendsClause.superclass.name.name != expectedBase) {
265 throw new Exception( 257 throw new Exception(
266 'Class `$clsName` needs to extend `$expectedBase`'); 258 'Class `$clsName` needs to extend `$expectedBase`');
267 } 259 }
268 for (ClassMember classMember in decl.members) { 260 for (ClassMember classMember in decl.members) {
269 if (classMember is MethodDeclaration && classMember.isGetter) { 261 if (classMember is MethodDeclaration && classMember.isGetter) {
270 String desc = '$clsName.${classMember.name.name}'; 262 String desc = '$clsName.${classMember.name}';
271 if (classMember.returnType is! TypeName) { 263 if (classMember.returnType == null) {
272 if (classMember.returnType == null) { 264 throw new Exception('Class member needs a type: $desc');
273 throw new Exception('Class member needs a type: $desc');
274 }
275 throw new Exception('Class member needs a class type: $desc');
276 } 265 }
277 TypeName type = classMember.returnType; 266 TypeName type = classMember.returnType;
278 bool isList = false; 267 bool isList = false;
279 if (type.name.name == 'List' && 268 if (type.name == 'List' &&
280 type.typeArguments != null && 269 type.typeArguments != null &&
281 type.typeArguments.arguments.length == 1) { 270 type.typeArguments.length == 1) {
282 isList = true; 271 isList = true;
283 type = type.typeArguments.arguments[0]; 272 type = type.typeArguments[0];
284 } 273 }
285 if (type.typeArguments != null) { 274 if (type.typeArguments != null) {
286 throw new Exception('Cannot handle type arguments in `$type`'); 275 throw new Exception('Cannot handle type arguments in `$type`');
287 } 276 }
288 int id; 277 int id;
289 bool isDeprecated = false; 278 bool isDeprecated = false;
290 bool isInformative = false; 279 bool isInformative = false;
291 for (Annotation annotation in classMember.metadata) { 280 for (Annotation annotation in classMember.metadata) {
292 if (annotation.name.name == 'Id') { 281 if (annotation.name == 'Id') {
293 if (id != null) { 282 if (id != null) {
294 throw new Exception( 283 throw new Exception(
295 'Duplicate @id annotation ($classMember)'); 284 'Duplicate @id annotation ($classMember)');
296 } 285 }
297 if (annotation.arguments.arguments.length != 1) { 286 if (annotation.arguments == null) {
287 throw new Exception('@Id must be passed an argument');
288 }
289 if (annotation.arguments.length != 1) {
298 throw new Exception( 290 throw new Exception(
299 '@Id must be passed exactly one argument ($desc)'); 291 '@Id must be passed exactly one argument ($desc)');
300 } 292 }
301 Expression expression = annotation.arguments.arguments[0]; 293 Expression expression = annotation.arguments[0];
302 if (expression is IntegerLiteral) { 294 if (expression is IntegerLiteral) {
303 id = expression.value; 295 id = expression.value;
304 } else { 296 } else {
305 throw new Exception( 297 throw new Exception(
306 '@Id parameter must be an integer literal ($desc)'); 298 '@Id parameter must be an integer literal ($desc)');
307 } 299 }
308 } else if (annotation.name.name == 'deprecated') { 300 } else if (annotation.name == 'deprecated') {
309 if (annotation.arguments != null) { 301 if (annotation.arguments != null) {
310 throw new Exception('@deprecated does not take args ($desc)'); 302 throw new Exception('@deprecated does not take args ($desc)');
311 } 303 }
312 isDeprecated = true; 304 isDeprecated = true;
313 } else if (annotation.name.name == 'informative') { 305 } else if (annotation.name == 'informative') {
314 isInformative = true; 306 isInformative = true;
315 } 307 }
316 } 308 }
317 if (id == null) { 309 if (id == null) {
318 throw new Exception('Missing @id annotation ($desc)'); 310 throw new Exception('Missing @id annotation ($desc)');
319 } 311 }
320 String doc = _getNodeDoc(lineInfo, classMember); 312 String doc = _getNodeDoc(classMember);
321 idlModel.FieldType fieldType = 313 idlModel.FieldType fieldType =
322 new idlModel.FieldType(type.name.name, isList); 314 new idlModel.FieldType(type.name, isList);
323 cls.allFields.add(new idlModel.FieldDeclaration( 315 cls.allFields.add(new idlModel.FieldDeclaration(doc,
324 doc, 316 classMember.name, fieldType, id, isDeprecated, isInformative));
325 classMember.name.name,
326 fieldType,
327 id,
328 isDeprecated,
329 isInformative));
330 } else if (classMember is ConstructorDeclaration && 317 } else if (classMember is ConstructorDeclaration &&
331 classMember.name.name == 'fromBuffer') { 318 classMember.name.name.endsWith('fromBuffer')) {
332 // Ignore `fromBuffer` declarations; they simply forward to the 319 // Ignore `fromBuffer` declarations; they simply forward to the
333 // read functions generated by [_generateReadFunction]. 320 // read functions generated by [_generateReadFunction].
334 } else { 321 } else {
335 throw new Exception('Unexpected class member `$classMember`'); 322 throw new Exception('Unexpected class member `$classMember`');
336 } 323 }
337 } 324 }
338 } else if (decl is EnumDeclaration) { 325 } else if (decl is EnumDeclaration) {
339 String doc = _getNodeDoc(lineInfo, decl); 326 String doc = _getNodeDoc(decl);
340 idlModel.EnumDeclaration enm = 327 idlModel.EnumDeclaration enm =
341 new idlModel.EnumDeclaration(doc, decl.name.name); 328 new idlModel.EnumDeclaration(doc, decl.name);
342 _idl.enums[enm.name] = enm; 329 _idl.enums[enm.name] = enm;
343 for (EnumConstantDeclaration constDecl in decl.constants) { 330 for (EnumConstantDeclaration constDecl in decl.constants) {
344 String doc = _getNodeDoc(lineInfo, constDecl); 331 String doc = _getNodeDoc(constDecl);
345 enm.values 332 enm.values
346 .add(new idlModel.EnumValueDeclaration(doc, constDecl.name.name)); 333 .add(new idlModel.EnumValueDeclaration(doc, constDecl.name));
347 } 334 }
348 } else if (decl is TopLevelVariableDeclaration) {
349 // Ignore top level variable declarations; they are present just to make
350 // the IDL analyze without warnings.
351 } else { 335 } else {
352 throw new Exception('Unexpected declaration `$decl`'); 336 throw new Exception('Unexpected declaration `$decl`');
353 } 337 }
354 } 338 }
355 } 339 }
356 340
357 /** 341 /**
358 * Generate a string representing the FlatBuffer schema type which should be 342 * Generate a string representing the FlatBuffer schema type which should be
359 * used to represent [type]. 343 * used to represent [type].
360 */ 344 */
(...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after
1008 default: 992 default:
1009 throw "Don't know how to generate signature call for $typeName"; 993 throw "Don't know how to generate signature call for $typeName";
1010 } 994 }
1011 } 995 }
1012 } 996 }
1013 997
1014 /** 998 /**
1015 * Return the documentation text of the given [node], or `null` if the [node] 999 * Return the documentation text of the given [node], or `null` if the [node]
1016 * does not have a comment. Each line is `\n` separated. 1000 * does not have a comment. Each line is `\n` separated.
1017 */ 1001 */
1018 String _getNodeDoc(LineInfo lineInfo, AnnotatedNode node) { 1002 String _getNodeDoc(AnnotatedNode node) {
1019 Comment comment = node.documentationComment; 1003 Comment comment = node.documentationComment;
1020 if (comment != null && 1004 if (comment != null &&
1021 comment.isDocumentation && 1005 comment.isDocumentation &&
1022 comment.tokens.length == 1 && 1006 comment.tokens.length == 1 &&
1023 comment.tokens.first.type == TokenType.MULTI_LINE_COMMENT) { 1007 comment.tokens.first.lexeme.startsWith('/*')) {
1024 Token token = comment.tokens.first; 1008 Token token = comment.tokens.first;
1025 int column = lineInfo.getLocation(token.offset).columnNumber;
1026 String indent = ' ' * (column - 1);
1027 return token.lexeme.split('\n').map((String line) { 1009 return token.lexeme.split('\n').map((String line) {
1028 if (line.startsWith(indent)) { 1010 line = line.trimLeft();
1029 line = line.substring(indent.length); 1011 if (line.startsWith('*')) line = ' ' + line;
1030 }
1031 return line; 1012 return line;
1032 }).join('\n'); 1013 }).join('\n');
1033 } 1014 }
1034 return null; 1015 return null;
1035 } 1016 }
1036 } 1017 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/tool/summary/mini_ast.dart » ('j') | pkg/analyzer/tool/summary/mini_ast.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698