| 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 26 matching lines...) Expand all Loading... |
| 37 String script = Platform.script.toFilePath(windows: Platform.isWindows); | 37 String script = Platform.script.toFilePath(windows: Platform.isWindows); |
| 38 String pkgPath = normalize(join(dirname(script), '..', '..')); | 38 String pkgPath = normalize(join(dirname(script), '..', '..')); |
| 39 GeneratedContent.generateAll(pkgPath, <GeneratedContent>[target]); | 39 GeneratedContent.generateAll(pkgPath, <GeneratedContent>[target]); |
| 40 } | 40 } |
| 41 | 41 |
| 42 final GeneratedFile target = | 42 final GeneratedFile target = |
| 43 new GeneratedFile('lib/src/summary/format.dart', (String pkgPath) { | 43 new GeneratedFile('lib/src/summary/format.dart', (String pkgPath) { |
| 44 // Parse the input "IDL" file and pass it to the [_CodeGenerator]. | 44 // Parse the input "IDL" file and pass it to the [_CodeGenerator]. |
| 45 PhysicalResourceProvider provider = new PhysicalResourceProvider( | 45 PhysicalResourceProvider provider = new PhysicalResourceProvider( |
| 46 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS); | 46 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS); |
| 47 String idlPath = join(pkgPath, 'tool', 'summary', 'idl.dart'); | 47 String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart'); |
| 48 File idlFile = provider.getFile(idlPath); | 48 File idlFile = provider.getFile(idlPath); |
| 49 Source idlSource = provider.getFile(idlPath).createSource(); | 49 Source idlSource = provider.getFile(idlPath).createSource(); |
| 50 String idlText = idlFile.readAsStringSync(); | 50 String idlText = idlFile.readAsStringSync(); |
| 51 BooleanErrorListener errorListener = new BooleanErrorListener(); | 51 BooleanErrorListener errorListener = new BooleanErrorListener(); |
| 52 CharacterReader idlReader = new CharSequenceReader(idlText); | 52 CharacterReader idlReader = new CharSequenceReader(idlText); |
| 53 Scanner scanner = new Scanner(idlSource, idlReader, errorListener); | 53 Scanner scanner = new Scanner(idlSource, idlReader, errorListener); |
| 54 Token tokenStream = scanner.tokenize(); | 54 Token tokenStream = scanner.tokenize(); |
| 55 LineInfo lineInfo = new LineInfo(scanner.lineStarts); | 55 LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
| 56 Parser parser = new Parser(idlSource, new BooleanErrorListener()); | 56 Parser parser = new Parser(idlSource, new BooleanErrorListener()); |
| 57 CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream); | 57 CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 } | 103 } |
| 104 } | 104 } |
| 105 }); | 105 }); |
| 106 } | 106 } |
| 107 | 107 |
| 108 /** | 108 /** |
| 109 * Generate a string representing the Dart type which should be used to | 109 * Generate a string representing the Dart type which should be used to |
| 110 * represent [type] when deserialized. | 110 * represent [type] when deserialized. |
| 111 */ | 111 */ |
| 112 String dartType(idlModel.FieldType type) { | 112 String dartType(idlModel.FieldType type) { |
| 113 String baseType = idlPrefix(type.typeName); |
| 113 if (type.isList) { | 114 if (type.isList) { |
| 114 return 'List<${type.typeName}>'; | 115 return 'List<$baseType>'; |
| 115 } else { | 116 } else { |
| 116 return type.typeName; | 117 return baseType; |
| 117 } | 118 } |
| 118 } | 119 } |
| 119 | 120 |
| 120 /** | 121 /** |
| 121 * Generate a Dart expression representing the default value for a field | 122 * Generate a Dart expression representing the default value for a field |
| 122 * having the given [type], or `null` if there is no default value. | 123 * having the given [type], or `null` if there is no default value. |
| 123 * | 124 * |
| 124 * If [builder] is `true`, the returned type should be appropriate for use in | 125 * If [builder] is `true`, the returned type should be appropriate for use in |
| 125 * a builder class. | 126 * a builder class. |
| 126 */ | 127 */ |
| 127 String defaultValue(idlModel.FieldType type, bool builder) { | 128 String defaultValue(idlModel.FieldType type, bool builder) { |
| 128 if (type.isList) { | 129 if (type.isList) { |
| 129 if (builder) { | 130 if (builder) { |
| 130 idlModel.FieldType elementType = | 131 idlModel.FieldType elementType = |
| 131 new idlModel.FieldType(type.typeName, false); | 132 new idlModel.FieldType(type.typeName, false); |
| 132 return '<${encodedType(elementType)}>[]'; | 133 return '<${encodedType(elementType)}>[]'; |
| 133 } else { | 134 } else { |
| 134 return 'const <${type.typeName}>[]'; | 135 return 'const <${idlPrefix(type.typeName)}>[]'; |
| 135 } | 136 } |
| 136 } else if (_idl.enums.containsKey(type.typeName)) { | 137 } else if (_idl.enums.containsKey(type.typeName)) { |
| 137 return '${type.typeName}.${_idl.enums[type.typeName].values[0].name}'; | 138 return '${idlPrefix(type.typeName)}.' |
| 139 '${_idl.enums[type.typeName].values[0].name}'; |
| 138 } else if (type.typeName == 'int') { | 140 } else if (type.typeName == 'int') { |
| 139 return '0'; | 141 return '0'; |
| 140 } else if (type.typeName == 'String') { | 142 } else if (type.typeName == 'String') { |
| 141 return "''"; | 143 return "''"; |
| 142 } else if (type.typeName == 'bool') { | 144 } else if (type.typeName == 'bool') { |
| 143 return 'false'; | 145 return 'false'; |
| 144 } else { | 146 } else { |
| 145 return null; | 147 return null; |
| 146 } | 148 } |
| 147 } | 149 } |
| 148 | 150 |
| 149 /** | 151 /** |
| 150 * Generate a string representing the Dart type which should be used to | 152 * Generate a string representing the Dart type which should be used to |
| 151 * represent [type] while building a serialized data structure. | 153 * represent [type] while building a serialized data structure. |
| 152 */ | 154 */ |
| 153 String encodedType(idlModel.FieldType type) { | 155 String encodedType(idlModel.FieldType type) { |
| 154 String typeStr; | 156 String typeStr; |
| 155 if (_idl.classes.containsKey(type.typeName)) { | 157 if (_idl.classes.containsKey(type.typeName)) { |
| 156 typeStr = '${type.typeName}Builder'; | 158 typeStr = '${type.typeName}Builder'; |
| 157 } else { | 159 } else { |
| 158 typeStr = type.typeName; | 160 typeStr = idlPrefix(type.typeName); |
| 159 } | 161 } |
| 160 if (type.isList) { | 162 if (type.isList) { |
| 161 return 'List<$typeStr>'; | 163 return 'List<$typeStr>'; |
| 162 } else { | 164 } else { |
| 163 return typeStr; | 165 return typeStr; |
| 164 } | 166 } |
| 165 } | 167 } |
| 166 | 168 |
| 167 /** | 169 /** |
| 168 * Process the AST in [idlParsed] and store the resulting semantic model in | 170 * Process the AST in [idlParsed] and store the resulting semantic model in |
| 169 * [_idl]. Also perform some error checking. | 171 * [_idl]. Also perform some error checking. |
| 170 */ | 172 */ |
| 171 void extractIdl(LineInfo lineInfo, CompilationUnit idlParsed) { | 173 void extractIdl(LineInfo lineInfo, CompilationUnit idlParsed) { |
| 172 _idl = new idlModel.Idl(); | 174 _idl = new idlModel.Idl(); |
| 173 for (CompilationUnitMember decl in idlParsed.declarations) { | 175 for (CompilationUnitMember decl in idlParsed.declarations) { |
| 174 if (decl is ClassDeclaration) { | 176 if (decl is ClassDeclaration) { |
| 175 bool isTopLevel = false; | 177 bool isTopLevel = false; |
| 176 for (Annotation annotation in decl.metadata) { | 178 for (Annotation annotation in decl.metadata) { |
| 177 if (annotation.arguments == null && | 179 if (annotation.arguments == null && |
| 178 annotation.name.name == 'topLevel') { | 180 annotation.name.name == 'topLevel') { |
| 179 isTopLevel = true; | 181 isTopLevel = true; |
| 180 } | 182 } |
| 181 } | 183 } |
| 182 String doc = _getNodeDoc(lineInfo, decl); | 184 String doc = _getNodeDoc(lineInfo, decl); |
| 183 idlModel.ClassDeclaration cls = | 185 idlModel.ClassDeclaration cls = |
| 184 new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel); | 186 new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel); |
| 185 _idl.classes[cls.name] = cls; | 187 _idl.classes[cls.name] = cls; |
| 188 String expectedBase = 'base.SummaryClass'; |
| 189 if (decl.extendsClause == null || |
| 190 decl.extendsClause.superclass.name.name != expectedBase) { |
| 191 throw new Exception( |
| 192 'Class `${cls.name}` needs to extend `$expectedBase`'); |
| 193 } |
| 186 for (ClassMember classMember in decl.members) { | 194 for (ClassMember classMember in decl.members) { |
| 187 if (classMember is FieldDeclaration) { | 195 if (classMember is MethodDeclaration && classMember.isGetter) { |
| 188 TypeName type = classMember.fields.type; | 196 TypeName type = classMember.returnType; |
| 197 if (type == null) { |
| 198 throw new Exception('Class member needs a type: $classMember'); |
| 199 } |
| 189 bool isList = false; | 200 bool isList = false; |
| 190 if (type.name.name == 'List' && | 201 if (type.name.name == 'List' && |
| 191 type.typeArguments != null && | 202 type.typeArguments != null && |
| 192 type.typeArguments.arguments.length == 1) { | 203 type.typeArguments.arguments.length == 1) { |
| 193 isList = true; | 204 isList = true; |
| 194 type = type.typeArguments.arguments[0]; | 205 type = type.typeArguments.arguments[0]; |
| 195 } | 206 } |
| 196 if (type.typeArguments != null) { | 207 if (type.typeArguments != null) { |
| 197 throw new Exception('Cannot handle type arguments in `$type`'); | 208 throw new Exception('Cannot handle type arguments in `$type`'); |
| 198 } | 209 } |
| 199 String doc = _getNodeDoc(lineInfo, classMember); | 210 String doc = _getNodeDoc(lineInfo, classMember); |
| 200 idlModel.FieldType fieldType = | 211 idlModel.FieldType fieldType = |
| 201 new idlModel.FieldType(type.name.name, isList); | 212 new idlModel.FieldType(type.name.name, isList); |
| 202 for (VariableDeclaration field in classMember.fields.variables) { | 213 cls.fields.add(new idlModel.FieldDeclaration( |
| 203 cls.fields.add(new idlModel.FieldDeclaration( | 214 doc, classMember.name.name, fieldType)); |
| 204 doc, field.name.name, fieldType)); | 215 } else if (classMember is ConstructorDeclaration && |
| 205 } | 216 classMember.name.name == 'fromBuffer') { |
| 217 // Ignore `fromBuffer` declarations; they simply forward to the |
| 218 // read functions generated by [_generateReadFunction]. |
| 206 } else { | 219 } else { |
| 207 throw new Exception('Unexpected class member `$classMember`'); | 220 throw new Exception('Unexpected class member `$classMember`'); |
| 208 } | 221 } |
| 209 } | 222 } |
| 210 } else if (decl is EnumDeclaration) { | 223 } else if (decl is EnumDeclaration) { |
| 211 String doc = _getNodeDoc(lineInfo, decl); | 224 String doc = _getNodeDoc(lineInfo, decl); |
| 212 idlModel.EnumDeclaration enm = | 225 idlModel.EnumDeclaration enm = |
| 213 new idlModel.EnumDeclaration(doc, decl.name.name); | 226 new idlModel.EnumDeclaration(doc, decl.name.name); |
| 214 _idl.enums[enm.name] = enm; | 227 _idl.enums[enm.name] = enm; |
| 215 for (EnumConstantDeclaration constDecl in decl.constants) { | 228 for (EnumConstantDeclaration constDecl in decl.constants) { |
| 216 String doc = _getNodeDoc(lineInfo, constDecl); | 229 String doc = _getNodeDoc(lineInfo, constDecl); |
| 217 enm.values | 230 enm.values |
| 218 .add(new idlModel.EnumValueDeclaration(doc, constDecl.name.name)); | 231 .add(new idlModel.EnumValueDeclaration(doc, constDecl.name.name)); |
| 219 } | 232 } |
| 220 } else if (decl is TopLevelVariableDeclaration) { | 233 } else if (decl is TopLevelVariableDeclaration) { |
| 221 // Ignore top level variable declarations; they are present just to make | 234 // Ignore top level variable declarations; they are present just to make |
| 222 // the IDL analyze without warnings. | 235 // the IDL analyze without warnings. |
| 223 } else { | 236 } else { |
| 224 throw new Exception('Unexpected declaration `$decl`'); | 237 throw new Exception('Unexpected declaration `$decl`'); |
| 225 } | 238 } |
| 226 } | 239 } |
| 227 } | 240 } |
| 228 | 241 |
| 229 /** | 242 /** |
| 243 * Add the prefix `idl.` to a type name, unless that type name is the name of |
| 244 * a built-in type. |
| 245 */ |
| 246 String idlPrefix(String s) { |
| 247 switch (s) { |
| 248 case 'bool': |
| 249 case 'double': |
| 250 case 'int': |
| 251 case 'String': |
| 252 return s; |
| 253 default: |
| 254 return 'idl.$s'; |
| 255 } |
| 256 } |
| 257 |
| 258 /** |
| 230 * Execute [callback] with two spaces added to [_indentation]. | 259 * Execute [callback] with two spaces added to [_indentation]. |
| 231 */ | 260 */ |
| 232 void indent(void callback()) { | 261 void indent(void callback()) { |
| 233 String oldIndentation = _indentation; | 262 String oldIndentation = _indentation; |
| 234 try { | 263 try { |
| 235 _indentation += ' '; | 264 _indentation += ' '; |
| 236 callback(); | 265 callback(); |
| 237 } finally { | 266 } finally { |
| 238 _indentation = oldIndentation; | 267 _indentation = oldIndentation; |
| 239 } | 268 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 266 checkIdl(); | 295 checkIdl(); |
| 267 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR
S file'); | 296 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR
S file'); |
| 268 out('// for details. All rights reserved. Use of this source code is governe
d by a'); | 297 out('// for details. All rights reserved. Use of this source code is governe
d by a'); |
| 269 out('// BSD-style license that can be found in the LICENSE file.'); | 298 out('// BSD-style license that can be found in the LICENSE file.'); |
| 270 out('//'); | 299 out('//'); |
| 271 out('// This file has been automatically generated. Please do not edit it m
anually.'); | 300 out('// This file has been automatically generated. Please do not edit it m
anually.'); |
| 272 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f
iles".'); | 301 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f
iles".'); |
| 273 out(); | 302 out(); |
| 274 out('library analyzer.src.summary.format;'); | 303 out('library analyzer.src.summary.format;'); |
| 275 out(); | 304 out(); |
| 276 out("import 'base.dart' as base;"); | |
| 277 out("import 'flat_buffers.dart' as fb;"); | 305 out("import 'flat_buffers.dart' as fb;"); |
| 306 out("import 'idl.dart' as idl;"); |
| 278 out(); | 307 out(); |
| 279 for (idlModel.EnumDeclaration enm in _idl.enums.values) { | 308 for (idlModel.EnumDeclaration enm in _idl.enums.values) { |
| 280 _generateEnum(enm); | |
| 281 out(); | |
| 282 _generateEnumReader(enm); | 309 _generateEnumReader(enm); |
| 283 out(); | 310 out(); |
| 284 } | 311 } |
| 285 for (idlModel.ClassDeclaration cls in _idl.classes.values) { | 312 for (idlModel.ClassDeclaration cls in _idl.classes.values) { |
| 286 _generateBuilder(cls); | 313 _generateBuilder(cls); |
| 287 out(); | 314 out(); |
| 288 _generateInterface(cls); | 315 if (cls.isTopLevel) { |
| 289 out(); | 316 _generateReadFunction(cls); |
| 317 out(); |
| 318 } |
| 290 _generateReader(cls); | 319 _generateReader(cls); |
| 291 out(); | 320 out(); |
| 292 _generateImpl(cls); | 321 _generateImpl(cls); |
| 293 out(); | 322 out(); |
| 294 _generateMixin(cls); | 323 _generateMixin(cls); |
| 295 out(); | 324 out(); |
| 296 } | 325 } |
| 297 } | 326 } |
| 298 | 327 |
| 299 /** | 328 /** |
| 300 * Enclose [s] in quotes, escaping as necessary. | 329 * Enclose [s] in quotes, escaping as necessary. |
| 301 */ | 330 */ |
| 302 String quoted(String s) { | 331 String quoted(String s) { |
| 303 return JSON.encode(s); | 332 return JSON.encode(s); |
| 304 } | 333 } |
| 305 | 334 |
| 306 void _generateBuilder(idlModel.ClassDeclaration cls) { | 335 void _generateBuilder(idlModel.ClassDeclaration cls) { |
| 307 String name = cls.name; | 336 String name = cls.name; |
| 308 String builderName = name + 'Builder'; | 337 String builderName = name + 'Builder'; |
| 309 String mixinName = '_${name}Mixin'; | 338 String mixinName = '_${name}Mixin'; |
| 310 List<String> constructorParams = <String>[]; | 339 List<String> constructorParams = <String>[]; |
| 311 out('class $builderName extends Object with $mixinName ' | 340 out('class $builderName extends Object with $mixinName ' |
| 312 'implements $name {'); | 341 'implements ${idlPrefix(name)} {'); |
| 313 indent(() { | 342 indent(() { |
| 314 out('bool _finished = false;'); | 343 out('bool _finished = false;'); |
| 315 // Generate fields. | 344 // Generate fields. |
| 316 out(); | 345 out(); |
| 317 for (idlModel.FieldDeclaration field in cls.fields) { | 346 for (idlModel.FieldDeclaration field in cls.fields) { |
| 318 String fieldName = field.name; | 347 String fieldName = field.name; |
| 319 idlModel.FieldType type = field.type; | 348 idlModel.FieldType type = field.type; |
| 320 String typeStr = encodedType(type); | 349 String typeStr = encodedType(type); |
| 321 out('$typeStr _$fieldName;'); | 350 out('$typeStr _$fieldName;'); |
| 322 } | 351 } |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 }); | 490 }); |
| 462 out('}'); | 491 out('}'); |
| 463 }); | 492 }); |
| 464 out('return fbBuilder.endTable();'); | 493 out('return fbBuilder.endTable();'); |
| 465 }); | 494 }); |
| 466 out('}'); | 495 out('}'); |
| 467 }); | 496 }); |
| 468 out('}'); | 497 out('}'); |
| 469 } | 498 } |
| 470 | 499 |
| 471 void _generateEnum(idlModel.EnumDeclaration enm) { | |
| 472 String name = enm.name; | |
| 473 outDoc(enm.documentation); | |
| 474 out('enum $name {'); | |
| 475 indent(() { | |
| 476 for (idlModel.EnumValueDeclaration value in enm.values) { | |
| 477 outDoc(value.documentation); | |
| 478 if (enm.values.last == value) { | |
| 479 out('${value.name}'); | |
| 480 } else { | |
| 481 out('${value.name},'); | |
| 482 out(); | |
| 483 } | |
| 484 } | |
| 485 }); | |
| 486 out('}'); | |
| 487 } | |
| 488 | |
| 489 void _generateEnumReader(idlModel.EnumDeclaration enm) { | 500 void _generateEnumReader(idlModel.EnumDeclaration enm) { |
| 490 String name = enm.name; | 501 String name = enm.name; |
| 491 String readerName = '_${name}Reader'; | 502 String readerName = '_${name}Reader'; |
| 492 out('class $readerName extends fb.Reader<$name> {'); | 503 out('class $readerName extends fb.Reader<${idlPrefix(name)}> {'); |
| 493 indent(() { | 504 indent(() { |
| 494 out('const $readerName() : super();'); | 505 out('const $readerName() : super();'); |
| 495 out(); | 506 out(); |
| 496 out('@override'); | 507 out('@override'); |
| 497 out('int get size => 4;'); | 508 out('int get size => 4;'); |
| 498 out(); | 509 out(); |
| 499 out('@override'); | 510 out('@override'); |
| 500 out('$name read(fb.BufferPointer bp) {'); | 511 out('${idlPrefix(name)} read(fb.BufferPointer bp) {'); |
| 501 indent(() { | 512 indent(() { |
| 502 out('int index = const fb.Uint32Reader().read(bp);'); | 513 out('int index = const fb.Uint32Reader().read(bp);'); |
| 503 out('return $name.values[index];'); | 514 out('return ${idlPrefix(name)}.values[index];'); |
| 504 }); | 515 }); |
| 505 out('}'); | 516 out('}'); |
| 506 }); | 517 }); |
| 507 out('}'); | 518 out('}'); |
| 508 } | 519 } |
| 509 | 520 |
| 510 void _generateImpl(idlModel.ClassDeclaration cls) { | 521 void _generateImpl(idlModel.ClassDeclaration cls) { |
| 511 String name = cls.name; | 522 String name = cls.name; |
| 512 String implName = '_${name}Impl'; | 523 String implName = '_${name}Impl'; |
| 513 String mixinName = '_${name}Mixin'; | 524 String mixinName = '_${name}Mixin'; |
| 514 out('class $implName extends Object with $mixinName implements $name {'); | 525 out('class $implName extends Object with $mixinName' |
| 526 ' implements ${idlPrefix(name)} {'); |
| 515 indent(() { | 527 indent(() { |
| 516 out('final fb.BufferPointer _bp;'); | 528 out('final fb.BufferPointer _bp;'); |
| 517 out(); | 529 out(); |
| 518 out('$implName(this._bp);'); | 530 out('$implName(this._bp);'); |
| 519 out(); | 531 out(); |
| 520 // Write cache fields. | 532 // Write cache fields. |
| 521 for (idlModel.FieldDeclaration field in cls.fields) { | 533 for (idlModel.FieldDeclaration field in cls.fields) { |
| 522 String returnType = dartType(field.type); | 534 String returnType = dartType(field.type); |
| 523 String fieldName = field.name; | 535 String fieldName = field.name; |
| 524 out('$returnType _$fieldName;'); | 536 out('$returnType _$fieldName;'); |
| 525 } | 537 } |
| 526 // Write getters. | 538 // Write getters. |
| 527 cls.fields.asMap().forEach((index, field) { | 539 cls.fields.asMap().forEach((index, field) { |
| 528 String fieldName = field.name; | 540 String fieldName = field.name; |
| 529 idlModel.FieldType type = field.type; | 541 idlModel.FieldType type = field.type; |
| 530 String typeName = type.typeName; | 542 String typeName = type.typeName; |
| 531 // Prepare "readCode" + "def" | 543 // Prepare "readCode" + "def" |
| 532 String readCode; | 544 String readCode; |
| 533 String def = defaultValue(type, false); | 545 String def = defaultValue(type, false); |
| 534 if (type.isList) { | 546 if (type.isList) { |
| 535 if (typeName == 'int') { | 547 if (typeName == 'int') { |
| 536 String itemCode = 'const fb.Uint32Reader()'; | 548 String itemCode = 'const fb.Uint32Reader()'; |
| 537 readCode = 'const fb.ListReader<int>($itemCode)'; | 549 readCode = 'const fb.ListReader<int>($itemCode)'; |
| 538 } else if (typeName == 'double') { | 550 } else if (typeName == 'double') { |
| 539 readCode = 'const fb.Float64ListReader()'; | 551 readCode = 'const fb.Float64ListReader()'; |
| 540 } else if (typeName == 'String') { | 552 } else if (typeName == 'String') { |
| 541 String itemCode = 'const fb.StringReader()'; | 553 String itemCode = 'const fb.StringReader()'; |
| 542 readCode = 'const fb.ListReader<String>($itemCode)'; | 554 readCode = 'const fb.ListReader<String>($itemCode)'; |
| 543 } else if (_idl.classes.containsKey(typeName)) { | 555 } else if (_idl.classes.containsKey(typeName)) { |
| 544 String itemCode = '$typeName>(const _${typeName}Reader()'; | 556 String itemCode = 'const _${typeName}Reader()'; |
| 545 readCode = 'const fb.ListReader<$itemCode)'; | 557 readCode = 'const fb.ListReader<${idlPrefix(typeName)}>($itemCode)'; |
| 546 } else { | 558 } else { |
| 547 assert(_idl.enums.containsKey(typeName)); | 559 assert(_idl.enums.containsKey(typeName)); |
| 548 String itemCode = 'const _${typeName}Reader()'; | 560 String itemCode = 'const _${typeName}Reader()'; |
| 549 readCode = 'const fb.ListReader<$typeName>($itemCode)'; | 561 readCode = 'const fb.ListReader<${idlPrefix(typeName)}>($itemCode)'; |
| 550 } | 562 } |
| 551 } else if (typeName == 'bool') { | 563 } else if (typeName == 'bool') { |
| 552 readCode = 'const fb.BoolReader()'; | 564 readCode = 'const fb.BoolReader()'; |
| 553 } else if (typeName == 'int') { | 565 } else if (typeName == 'int') { |
| 554 readCode = 'const fb.Uint32Reader()'; | 566 readCode = 'const fb.Uint32Reader()'; |
| 555 } else if (typeName == 'String') { | 567 } else if (typeName == 'String') { |
| 556 readCode = 'const fb.StringReader()'; | 568 readCode = 'const fb.StringReader()'; |
| 557 } else if (_idl.enums.containsKey(typeName)) { | 569 } else if (_idl.enums.containsKey(typeName)) { |
| 558 readCode = 'const _${typeName}Reader()'; | 570 readCode = 'const _${typeName}Reader()'; |
| 559 } else if (_idl.classes.containsKey(typeName)) { | 571 } else if (_idl.classes.containsKey(typeName)) { |
| 560 readCode = 'const _${typeName}Reader()'; | 572 readCode = 'const _${typeName}Reader()'; |
| 561 } | 573 } |
| 562 assert(readCode != null); | 574 assert(readCode != null); |
| 563 // Write the getter implementation. | 575 // Write the getter implementation. |
| 564 out(); | 576 out(); |
| 565 out('@override'); | 577 out('@override'); |
| 566 String returnType = dartType(type); | 578 String returnType = dartType(type); |
| 567 out('$returnType get $fieldName {'); | 579 out('$returnType get $fieldName {'); |
| 568 indent(() { | 580 indent(() { |
| 569 String readExpr = '$readCode.vTableGet(_bp, $index, $def)'; | 581 String readExpr = '$readCode.vTableGet(_bp, $index, $def)'; |
| 570 out('_$fieldName ??= $readExpr;'); | 582 out('_$fieldName ??= $readExpr;'); |
| 571 out('return _$fieldName;'); | 583 out('return _$fieldName;'); |
| 572 }); | 584 }); |
| 573 out('}'); | 585 out('}'); |
| 574 }); | 586 }); |
| 575 }); | 587 }); |
| 576 out('}'); | 588 out('}'); |
| 577 } | 589 } |
| 578 | 590 |
| 579 void _generateInterface(idlModel.ClassDeclaration cls) { | |
| 580 String name = cls.name; | |
| 581 outDoc(cls.documentation); | |
| 582 out('abstract class $name extends base.SummaryClass {'); | |
| 583 indent(() { | |
| 584 if (cls.isTopLevel) { | |
| 585 out('factory $name.fromBuffer(List<int> buffer) {'); | |
| 586 indent(() { | |
| 587 out('fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer)
;'); | |
| 588 out('return const _${name}Reader().read(rootRef);'); | |
| 589 }); | |
| 590 out('}'); | |
| 591 } | |
| 592 cls.fields.asMap().forEach((index, field) { | |
| 593 String fieldName = field.name; | |
| 594 idlModel.FieldType type = field.type; | |
| 595 out(); | |
| 596 outDoc(field.documentation); | |
| 597 out('${dartType(type)} get $fieldName;'); | |
| 598 }); | |
| 599 }); | |
| 600 out('}'); | |
| 601 } | |
| 602 | |
| 603 void _generateMixin(idlModel.ClassDeclaration cls) { | 591 void _generateMixin(idlModel.ClassDeclaration cls) { |
| 604 String name = cls.name; | 592 String name = cls.name; |
| 605 String mixinName = '_${name}Mixin'; | 593 String mixinName = '_${name}Mixin'; |
| 606 out('abstract class $mixinName implements $name {'); | 594 out('abstract class $mixinName implements ${idlPrefix(name)} {'); |
| 607 indent(() { | 595 indent(() { |
| 608 // Write toMap(). | 596 // Write toMap(). |
| 609 out('@override'); | 597 out('@override'); |
| 610 out('Map<String, Object> toMap() => {'); | 598 out('Map<String, Object> toMap() => {'); |
| 611 indent(() { | 599 indent(() { |
| 612 for (idlModel.FieldDeclaration field in cls.fields) { | 600 for (idlModel.FieldDeclaration field in cls.fields) { |
| 613 String fieldName = field.name; | 601 String fieldName = field.name; |
| 614 out('${quoted(fieldName)}: $fieldName,'); | 602 out('${quoted(fieldName)}: $fieldName,'); |
| 615 } | 603 } |
| 616 }); | 604 }); |
| 617 out('};'); | 605 out('};'); |
| 618 }); | 606 }); |
| 619 out('}'); | 607 out('}'); |
| 620 } | 608 } |
| 621 | 609 |
| 622 void _generateReader(idlModel.ClassDeclaration cls) { | 610 void _generateReader(idlModel.ClassDeclaration cls) { |
| 623 String name = cls.name; | 611 String name = cls.name; |
| 624 String readerName = '_${name}Reader'; | 612 String readerName = '_${name}Reader'; |
| 625 String implName = '_${name}Impl'; | 613 String implName = '_${name}Impl'; |
| 626 out('class $readerName extends fb.TableReader<$implName> {'); | 614 out('class $readerName extends fb.TableReader<$implName> {'); |
| 627 indent(() { | 615 indent(() { |
| 628 out('const $readerName();'); | 616 out('const $readerName();'); |
| 629 out(); | 617 out(); |
| 630 out('@override'); | 618 out('@override'); |
| 631 out('$implName createObject(fb.BufferPointer bp) => new $implName(bp);'); | 619 out('$implName createObject(fb.BufferPointer bp) => new $implName(bp);'); |
| 632 }); | 620 }); |
| 633 out('}'); | 621 out('}'); |
| 634 } | 622 } |
| 635 | 623 |
| 624 void _generateReadFunction(idlModel.ClassDeclaration cls) { |
| 625 String name = cls.name; |
| 626 out('${idlPrefix(name)} read$name(List<int> buffer) {'); |
| 627 indent(() { |
| 628 out('fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);'); |
| 629 out('return const _${name}Reader().read(rootRef);'); |
| 630 }); |
| 631 out('}'); |
| 632 } |
| 633 |
| 636 /** | 634 /** |
| 637 * Return the documentation text of the given [node], or `null` if the [node] | 635 * Return the documentation text of the given [node], or `null` if the [node] |
| 638 * does not have a comment. Each line is `\n` separated. | 636 * does not have a comment. Each line is `\n` separated. |
| 639 */ | 637 */ |
| 640 String _getNodeDoc(LineInfo lineInfo, AnnotatedNode node) { | 638 String _getNodeDoc(LineInfo lineInfo, AnnotatedNode node) { |
| 641 Comment comment = node.documentationComment; | 639 Comment comment = node.documentationComment; |
| 642 if (comment != null && | 640 if (comment != null && |
| 643 comment.isDocumentation && | 641 comment.isDocumentation && |
| 644 comment.tokens.length == 1 && | 642 comment.tokens.length == 1 && |
| 645 comment.tokens.first.type == TokenType.MULTI_LINE_COMMENT) { | 643 comment.tokens.first.type == TokenType.MULTI_LINE_COMMENT) { |
| 646 Token token = comment.tokens.first; | 644 Token token = comment.tokens.first; |
| 647 int column = lineInfo.getLocation(token.offset).columnNumber; | 645 int column = lineInfo.getLocation(token.offset).columnNumber; |
| 648 String indent = ' ' * (column - 1); | 646 String indent = ' ' * (column - 1); |
| 649 return token.lexeme.split('\n').map((String line) { | 647 return token.lexeme.split('\n').map((String line) { |
| 650 if (line.startsWith(indent)) { | 648 if (line.startsWith(indent)) { |
| 651 line = line.substring(indent.length); | 649 line = line.substring(indent.length); |
| 652 } | 650 } |
| 653 return line; | 651 return line; |
| 654 }).join('\n'); | 652 }).join('\n'); |
| 655 } | 653 } |
| 656 return null; | 654 return null; |
| 657 } | 655 } |
| 658 } | 656 } |
| OLD | NEW |