| OLD | NEW |
| 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: |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 import 'package:analyzer/src/dart/scanner/scanner.dart'; | 31 import 'package:analyzer/src/dart/scanner/scanner.dart'; |
| 32 import 'package:analyzer/src/generated/parser.dart'; | 32 import 'package:analyzer/src/generated/parser.dart'; |
| 33 import 'package:analyzer/src/generated/source.dart'; | 33 import 'package:analyzer/src/generated/source.dart'; |
| 34 import 'package:path/path.dart'; | 34 import 'package:path/path.dart'; |
| 35 | 35 |
| 36 import 'idl_model.dart' as idlModel; | 36 import 'idl_model.dart' as idlModel; |
| 37 | 37 |
| 38 main() { | 38 main() { |
| 39 String script = Platform.script.toFilePath(windows: Platform.isWindows); | 39 String script = Platform.script.toFilePath(windows: Platform.isWindows); |
| 40 String pkgPath = normalize(join(dirname(script), '..', '..')); | 40 String pkgPath = normalize(join(dirname(script), '..', '..')); |
| 41 GeneratedContent.generateAll(pkgPath, <GeneratedContent>[target]); | 41 GeneratedContent.generateAll(pkgPath, allTargets); |
| 42 } | 42 } |
| 43 | 43 |
| 44 final GeneratedFile target = | 44 final List<GeneratedContent> allTargets = <GeneratedContent>[ |
| 45 formatTarget, |
| 46 schemaTarget |
| 47 ]; |
| 48 |
| 49 final GeneratedFile formatTarget = |
| 45 new GeneratedFile('lib/src/summary/format.dart', (String pkgPath) { | 50 new GeneratedFile('lib/src/summary/format.dart', (String pkgPath) { |
| 46 // Parse the input "IDL" file and pass it to the [_CodeGenerator]. | 51 _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath); |
| 47 PhysicalResourceProvider provider = new PhysicalResourceProvider( | 52 codeGenerator.generateFormatCode(); |
| 48 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS); | |
| 49 String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart'); | |
| 50 File idlFile = provider.getFile(idlPath); | |
| 51 Source idlSource = provider.getFile(idlPath).createSource(); | |
| 52 String idlText = idlFile.readAsStringSync(); | |
| 53 BooleanErrorListener errorListener = new BooleanErrorListener(); | |
| 54 CharacterReader idlReader = new CharSequenceReader(idlText); | |
| 55 Scanner scanner = new Scanner(idlSource, idlReader, errorListener); | |
| 56 Token tokenStream = scanner.tokenize(); | |
| 57 LineInfo lineInfo = new LineInfo(scanner.lineStarts); | |
| 58 Parser parser = new Parser(idlSource, new BooleanErrorListener()); | |
| 59 CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream); | |
| 60 _CodeGenerator codeGenerator = new _CodeGenerator(); | |
| 61 codeGenerator.processCompilationUnit(lineInfo, idlParsed); | |
| 62 return codeGenerator._outBuffer.toString(); | 53 return codeGenerator._outBuffer.toString(); |
| 63 }); | 54 }); |
| 64 | 55 |
| 56 final GeneratedFile schemaTarget = |
| 57 new GeneratedFile('lib/src/summary/format.fbs', (String pkgPath) { |
| 58 _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath); |
| 59 codeGenerator.generateFlatBufferSchema(); |
| 60 return codeGenerator._outBuffer.toString(); |
| 61 }); |
| 62 |
| 65 typedef String _StringToString(String s); | 63 typedef String _StringToString(String s); |
| 66 | 64 |
| 67 class _CodeGenerator { | 65 class _CodeGenerator { |
| 68 /** | 66 /** |
| 69 * Buffer in which generated code is accumulated. | 67 * Buffer in which generated code is accumulated. |
| 70 */ | 68 */ |
| 71 final StringBuffer _outBuffer = new StringBuffer(); | 69 final StringBuffer _outBuffer = new StringBuffer(); |
| 72 | 70 |
| 73 /** | 71 /** |
| 74 * Current indentation level. | 72 * Current indentation level. |
| 75 */ | 73 */ |
| 76 String _indentation = ''; | 74 String _indentation = ''; |
| 77 | 75 |
| 78 /** | 76 /** |
| 79 * Semantic model of the "IDL" input file. | 77 * Semantic model of the "IDL" input file. |
| 80 */ | 78 */ |
| 81 idlModel.Idl _idl; | 79 idlModel.Idl _idl; |
| 82 | 80 |
| 81 _CodeGenerator(String pkgPath) { |
| 82 // Parse the input "IDL" file. |
| 83 PhysicalResourceProvider provider = new PhysicalResourceProvider( |
| 84 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS); |
| 85 String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart'); |
| 86 File idlFile = provider.getFile(idlPath); |
| 87 Source idlSource = provider.getFile(idlPath).createSource(); |
| 88 String idlText = idlFile.readAsStringSync(); |
| 89 BooleanErrorListener errorListener = new BooleanErrorListener(); |
| 90 CharacterReader idlReader = new CharSequenceReader(idlText); |
| 91 Scanner scanner = new Scanner(idlSource, idlReader, errorListener); |
| 92 Token tokenStream = scanner.tokenize(); |
| 93 LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
| 94 Parser parser = new Parser(idlSource, new BooleanErrorListener()); |
| 95 CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream); |
| 96 // Extract a description of the IDL and make sure it is valid. |
| 97 extractIdl(lineInfo, idlParsed); |
| 98 checkIdl(); |
| 99 } |
| 100 |
| 83 /** | 101 /** |
| 84 * Perform basic sanity checking of the IDL (over and above that done by | 102 * Perform basic sanity checking of the IDL (over and above that done by |
| 85 * [extractIdl]). | 103 * [extractIdl]). |
| 86 */ | 104 */ |
| 87 void checkIdl() { | 105 void checkIdl() { |
| 88 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { | 106 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { |
| 89 if (cls.fileIdentifier != null) { | 107 if (cls.fileIdentifier != null) { |
| 90 if (cls.fileIdentifier.length != 4) { | 108 if (cls.fileIdentifier.length != 4) { |
| 91 throw new Exception('$name: file identifier must be 4 characters'); | 109 throw new Exception('$name: file identifier must be 4 characters'); |
| 92 } | 110 } |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 } else if (decl is TopLevelVariableDeclaration) { | 325 } else if (decl is TopLevelVariableDeclaration) { |
| 308 // Ignore top level variable declarations; they are present just to make | 326 // Ignore top level variable declarations; they are present just to make |
| 309 // the IDL analyze without warnings. | 327 // the IDL analyze without warnings. |
| 310 } else { | 328 } else { |
| 311 throw new Exception('Unexpected declaration `$decl`'); | 329 throw new Exception('Unexpected declaration `$decl`'); |
| 312 } | 330 } |
| 313 } | 331 } |
| 314 } | 332 } |
| 315 | 333 |
| 316 /** | 334 /** |
| 335 * Generate a string representing the FlatBuffer schema type which should be |
| 336 * used to represent [type]. |
| 337 */ |
| 338 String fbsType(idlModel.FieldType type) { |
| 339 String typeStr; |
| 340 switch (type.typeName) { |
| 341 case 'bool': |
| 342 typeStr = 'bool'; |
| 343 break; |
| 344 case 'double': |
| 345 typeStr = 'double'; |
| 346 break; |
| 347 case 'int': |
| 348 typeStr = 'uint'; |
| 349 break; |
| 350 case 'String': |
| 351 typeStr = 'string'; |
| 352 break; |
| 353 default: |
| 354 typeStr = type.typeName; |
| 355 break; |
| 356 } |
| 357 if (type.isList) { |
| 358 return '[$typeStr]'; |
| 359 } else { |
| 360 return typeStr; |
| 361 } |
| 362 } |
| 363 |
| 364 /** |
| 365 * Entry point to the code generator when generating the "format.fbs" file. |
| 366 */ |
| 367 void generateFlatBufferSchema() { |
| 368 outputHeader(); |
| 369 for (idlModel.EnumDeclaration enm in _idl.enums.values) { |
| 370 out(); |
| 371 outDoc(enm.documentation); |
| 372 out('enum ${enm.name} : byte {'); |
| 373 indent(() { |
| 374 for (int i = 0; i < enm.values.length; i++) { |
| 375 idlModel.EnumValueDeclaration value = enm.values[i]; |
| 376 if (i != 0) { |
| 377 out(); |
| 378 } |
| 379 String suffix = i < enm.values.length - 1 ? ',' : ''; |
| 380 outDoc(value.documentation); |
| 381 out('${value.name}$suffix'); |
| 382 } |
| 383 }); |
| 384 out('}'); |
| 385 } |
| 386 for (idlModel.ClassDeclaration cls in _idl.classes.values) { |
| 387 out(); |
| 388 outDoc(cls.documentation); |
| 389 out('table ${cls.name} {'); |
| 390 indent(() { |
| 391 for (int i = 0; i < cls.fields.length; i++) { |
| 392 idlModel.FieldDeclaration field = cls.fields[i]; |
| 393 if (i != 0) { |
| 394 out(); |
| 395 } |
| 396 outDoc(field.documentation); |
| 397 out('${field.name}:${fbsType(field.type)} (id: ${field.id});'); |
| 398 } |
| 399 }); |
| 400 out('}'); |
| 401 } |
| 402 out(); |
| 403 // Standard flatbuffers only support one root type. We support multiple |
| 404 // root types. For now work around this by forcing PackageBundle to be the |
| 405 // root type. TODO(paulberry): come up with a better solution. |
| 406 idlModel.ClassDeclaration rootType = _idl.classes['PackageBundle']; |
| 407 out('root_type ${rootType.name};'); |
| 408 if (rootType.fileIdentifier != null) { |
| 409 out(); |
| 410 out('file_identifier ${quoted(rootType.fileIdentifier)};'); |
| 411 } |
| 412 } |
| 413 |
| 414 /** |
| 415 * Entry point to the code generator when generating the "format.dart" file. |
| 416 */ |
| 417 void generateFormatCode() { |
| 418 outputHeader(); |
| 419 out('library analyzer.src.summary.format;'); |
| 420 out(); |
| 421 out("import 'flat_buffers.dart' as fb;"); |
| 422 out("import 'idl.dart' as idl;"); |
| 423 out("import 'dart:convert' as convert;"); |
| 424 out(); |
| 425 for (idlModel.EnumDeclaration enm in _idl.enums.values) { |
| 426 _generateEnumReader(enm); |
| 427 out(); |
| 428 } |
| 429 for (idlModel.ClassDeclaration cls in _idl.classes.values) { |
| 430 _generateBuilder(cls); |
| 431 out(); |
| 432 if (cls.isTopLevel) { |
| 433 _generateReadFunction(cls); |
| 434 out(); |
| 435 } |
| 436 _generateReader(cls); |
| 437 out(); |
| 438 _generateImpl(cls); |
| 439 out(); |
| 440 _generateMixin(cls); |
| 441 out(); |
| 442 } |
| 443 } |
| 444 |
| 445 /** |
| 317 * Add the prefix `idl.` to a type name, unless that type name is the name of | 446 * Add the prefix `idl.` to a type name, unless that type name is the name of |
| 318 * a built-in type. | 447 * a built-in type. |
| 319 */ | 448 */ |
| 320 String idlPrefix(String s) { | 449 String idlPrefix(String s) { |
| 321 switch (s) { | 450 switch (s) { |
| 322 case 'bool': | 451 case 'bool': |
| 323 case 'double': | 452 case 'double': |
| 324 case 'int': | 453 case 'int': |
| 325 case 'String': | 454 case 'String': |
| 326 return s; | 455 return s; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 353 _outBuffer.writeln('$_indentation$s'); | 482 _outBuffer.writeln('$_indentation$s'); |
| 354 } | 483 } |
| 355 } | 484 } |
| 356 | 485 |
| 357 void outDoc(String documentation) { | 486 void outDoc(String documentation) { |
| 358 if (documentation != null) { | 487 if (documentation != null) { |
| 359 documentation.split('\n').forEach(out); | 488 documentation.split('\n').forEach(out); |
| 360 } | 489 } |
| 361 } | 490 } |
| 362 | 491 |
| 363 /** | 492 void outputHeader() { |
| 364 * Entry point to the code generator. Interpret the AST in [idlParsed], | |
| 365 * generate code, and output it to [_outBuffer]. | |
| 366 */ | |
| 367 void processCompilationUnit(LineInfo lineInfo, CompilationUnit idlParsed) { | |
| 368 extractIdl(lineInfo, idlParsed); | |
| 369 checkIdl(); | |
| 370 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR
S file'); | 493 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR
S file'); |
| 371 out('// for details. All rights reserved. Use of this source code is governe
d by a'); | 494 out('// for details. All rights reserved. Use of this source code is governe
d by a'); |
| 372 out('// BSD-style license that can be found in the LICENSE file.'); | 495 out('// BSD-style license that can be found in the LICENSE file.'); |
| 373 out('//'); | 496 out('//'); |
| 374 out('// This file has been automatically generated. Please do not edit it m
anually.'); | 497 out('// This file has been automatically generated. Please do not edit it m
anually.'); |
| 375 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f
iles".'); | 498 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f
iles".'); |
| 376 out(); | 499 out(); |
| 377 out('library analyzer.src.summary.format;'); | |
| 378 out(); | |
| 379 out("import 'flat_buffers.dart' as fb;"); | |
| 380 out("import 'idl.dart' as idl;"); | |
| 381 out("import 'dart:convert' as convert;"); | |
| 382 out(); | |
| 383 for (idlModel.EnumDeclaration enm in _idl.enums.values) { | |
| 384 _generateEnumReader(enm); | |
| 385 out(); | |
| 386 } | |
| 387 for (idlModel.ClassDeclaration cls in _idl.classes.values) { | |
| 388 _generateBuilder(cls); | |
| 389 out(); | |
| 390 if (cls.isTopLevel) { | |
| 391 _generateReadFunction(cls); | |
| 392 out(); | |
| 393 } | |
| 394 _generateReader(cls); | |
| 395 out(); | |
| 396 _generateImpl(cls); | |
| 397 out(); | |
| 398 _generateMixin(cls); | |
| 399 out(); | |
| 400 } | |
| 401 } | 500 } |
| 402 | 501 |
| 403 /** | 502 /** |
| 404 * Enclose [s] in quotes, escaping as necessary. | 503 * Enclose [s] in quotes, escaping as necessary. |
| 405 */ | 504 */ |
| 406 String quoted(String s) { | 505 String quoted(String s) { |
| 407 return JSON.encode(s); | 506 return JSON.encode(s); |
| 408 } | 507 } |
| 409 | 508 |
| 410 void _generateBuilder(idlModel.ClassDeclaration cls) { | 509 void _generateBuilder(idlModel.ClassDeclaration cls) { |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 return token.lexeme.split('\n').map((String line) { | 868 return token.lexeme.split('\n').map((String line) { |
| 770 if (line.startsWith(indent)) { | 869 if (line.startsWith(indent)) { |
| 771 line = line.substring(indent.length); | 870 line = line.substring(indent.length); |
| 772 } | 871 } |
| 773 return line; | 872 return line; |
| 774 }).join('\n'); | 873 }).join('\n'); |
| 775 } | 874 } |
| 776 return null; | 875 return null; |
| 777 } | 876 } |
| 778 } | 877 } |
| OLD | NEW |