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

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

Issue 1563453002: Generate documentation for summaries. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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/summary/format.dart ('k') | pkg/analyzer/tool/summary/idl_model.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) 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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 PhysicalResourceProvider provider = new PhysicalResourceProvider( 47 PhysicalResourceProvider provider = new PhysicalResourceProvider(
48 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS); 48 PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS);
49 String idlPath = join(pkgPath, 'tool', 'summary', 'idl.dart'); 49 String idlPath = join(pkgPath, 'tool', 'summary', 'idl.dart');
50 File idlFile = provider.getFile(idlPath); 50 File idlFile = provider.getFile(idlPath);
51 Source idlSource = provider.getFile(idlPath).createSource(); 51 Source idlSource = provider.getFile(idlPath).createSource();
52 String idlText = idlFile.readAsStringSync(); 52 String idlText = idlFile.readAsStringSync();
53 BooleanErrorListener errorListener = new BooleanErrorListener(); 53 BooleanErrorListener errorListener = new BooleanErrorListener();
54 CharacterReader idlReader = new CharSequenceReader(idlText); 54 CharacterReader idlReader = new CharSequenceReader(idlText);
55 Scanner scanner = new Scanner(idlSource, idlReader, errorListener); 55 Scanner scanner = new Scanner(idlSource, idlReader, errorListener);
56 Token tokenStream = scanner.tokenize(); 56 Token tokenStream = scanner.tokenize();
57 LineInfo lineInfo = new LineInfo(scanner.lineStarts);
57 Parser parser = new Parser(idlSource, new BooleanErrorListener()); 58 Parser parser = new Parser(idlSource, new BooleanErrorListener());
58 CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream); 59 CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream);
59 _CodeGenerator codeGenerator = new _CodeGenerator(); 60 _CodeGenerator codeGenerator = new _CodeGenerator();
60 codeGenerator.processCompilationUnit(idlParsed); 61 codeGenerator.processCompilationUnit(lineInfo, idlParsed);
61 return codeGenerator._outBuffer.toString(); 62 return codeGenerator._outBuffer.toString();
62 }); 63 });
63 64
64 class _CodeGenerator { 65 class _CodeGenerator {
65 /** 66 /**
66 * Buffer in which generated code is accumulated. 67 * Buffer in which generated code is accumulated.
67 */ 68 */
68 final StringBuffer _outBuffer = new StringBuffer(); 69 final StringBuffer _outBuffer = new StringBuffer();
69 70
70 /** 71 /**
71 * Current indentation level. 72 * Current indentation level.
72 */ 73 */
73 String _indentation = ''; 74 String _indentation = '';
74 75
75 /** 76 /**
76 * Semantic model of the "IDL" input file. 77 * Semantic model of the "IDL" input file.
77 */ 78 */
78 idlModel.Idl _idl; 79 idlModel.Idl _idl;
79 80
80 /** 81 /**
81 * Perform basic sanity checking of the IDL (over and above that done by 82 * Perform basic sanity checking of the IDL (over and above that done by
82 * [extractIdl]). 83 * [extractIdl]).
83 */ 84 */
84 void checkIdl() { 85 void checkIdl() {
85 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { 86 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) {
86 cls.fields.forEach((String fieldName, idlModel.FieldType type) { 87 for (idlModel.FieldDeclaration field in cls.fields) {
88 String fieldName = field.name;
89 idlModel.FieldType type = field.type;
87 if (type.isList) { 90 if (type.isList) {
88 if (_idl.classes.containsKey(type.typeName)) { 91 if (_idl.classes.containsKey(type.typeName)) {
89 // List of classes is ok 92 // List of classes is ok
90 } else if (type.typeName == 'int') { 93 } else if (type.typeName == 'int') {
91 // List of ints is ok 94 // List of ints is ok
92 } else if (type.typeName == 'String') { 95 } else if (type.typeName == 'String') {
93 // List of strings is ok 96 // List of strings is ok
94 } else { 97 } else {
95 throw new Exception( 98 throw new Exception(
96 '$name.$fieldName: illegal type (list of ${type.typeName})'); 99 '$name.$fieldName: illegal type (list of ${type.typeName})');
97 } 100 }
98 } 101 }
99 }); 102 }
100 }); 103 });
101 } 104 }
102 105
103 /** 106 /**
104 * Generate a string representing the Dart type which should be used to 107 * Generate a string representing the Dart type which should be used to
105 * represent [type] when deserialized. 108 * represent [type] when deserialized.
106 */ 109 */
107 String dartType(idlModel.FieldType type) { 110 String dartType(idlModel.FieldType type) {
108 if (type.isList) { 111 if (type.isList) {
109 return 'List<${type.typeName}>'; 112 return 'List<${type.typeName}>';
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 return 'List<$typeStr>'; 150 return 'List<$typeStr>';
148 } else { 151 } else {
149 return typeStr; 152 return typeStr;
150 } 153 }
151 } 154 }
152 155
153 /** 156 /**
154 * Process the AST in [idlParsed] and store the resulting semantic model in 157 * Process the AST in [idlParsed] and store the resulting semantic model in
155 * [_idl]. Also perform some error checking. 158 * [_idl]. Also perform some error checking.
156 */ 159 */
157 void extractIdl(CompilationUnit idlParsed) { 160 void extractIdl(LineInfo lineInfo, CompilationUnit idlParsed) {
158 _idl = new idlModel.Idl(); 161 _idl = new idlModel.Idl();
159 for (CompilationUnitMember decl in idlParsed.declarations) { 162 for (CompilationUnitMember decl in idlParsed.declarations) {
160 if (decl is ClassDeclaration) { 163 if (decl is ClassDeclaration) {
161 bool isTopLevel = false; 164 bool isTopLevel = false;
162 for (Annotation annotation in decl.metadata) { 165 for (Annotation annotation in decl.metadata) {
163 if (annotation.arguments == null && 166 if (annotation.arguments == null &&
164 annotation.name.name == 'topLevel') { 167 annotation.name.name == 'topLevel') {
165 isTopLevel = true; 168 isTopLevel = true;
166 } 169 }
167 } 170 }
171 String doc = _getNodeDoc(lineInfo, decl);
168 idlModel.ClassDeclaration cls = 172 idlModel.ClassDeclaration cls =
169 new idlModel.ClassDeclaration(isTopLevel); 173 new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel);
170 _idl.classes[decl.name.name] = cls; 174 _idl.classes[cls.name] = cls;
171 for (ClassMember classMember in decl.members) { 175 for (ClassMember classMember in decl.members) {
172 if (classMember is FieldDeclaration) { 176 if (classMember is FieldDeclaration) {
173 TypeName type = classMember.fields.type; 177 TypeName type = classMember.fields.type;
174 bool isList = false; 178 bool isList = false;
175 if (type.name.name == 'List' && 179 if (type.name.name == 'List' &&
176 type.typeArguments != null && 180 type.typeArguments != null &&
177 type.typeArguments.arguments.length == 1) { 181 type.typeArguments.arguments.length == 1) {
178 isList = true; 182 isList = true;
179 type = type.typeArguments.arguments[0]; 183 type = type.typeArguments.arguments[0];
180 } 184 }
181 if (type.typeArguments != null) { 185 if (type.typeArguments != null) {
182 throw new Exception('Cannot handle type arguments in `$type`'); 186 throw new Exception('Cannot handle type arguments in `$type`');
183 } 187 }
188 String doc = _getNodeDoc(lineInfo, classMember);
184 idlModel.FieldType fieldType = 189 idlModel.FieldType fieldType =
185 new idlModel.FieldType(type.name.name, isList); 190 new idlModel.FieldType(type.name.name, isList);
186 for (VariableDeclaration field in classMember.fields.variables) { 191 for (VariableDeclaration field in classMember.fields.variables) {
187 cls.fields[field.name.name] = fieldType; 192 // TODO(scheglov) use actual documentation
Paul Berry 2016/01/05 17:49:50 Can you clarify what this means? Isn't `doc` the
193 cls.fields.add(new idlModel.FieldDeclaration(
194 doc, field.name.name, fieldType));
188 } 195 }
189 } else { 196 } else {
190 throw new Exception('Unexpected class member `$classMember`'); 197 throw new Exception('Unexpected class member `$classMember`');
191 } 198 }
192 } 199 }
193 } else if (decl is EnumDeclaration) { 200 } else if (decl is EnumDeclaration) {
194 idlModel.EnumDeclaration enm = new idlModel.EnumDeclaration(); 201 String doc = _getNodeDoc(lineInfo, decl);
195 _idl.enums[decl.name.name] = enm; 202 idlModel.EnumDeclaration enm =
203 new idlModel.EnumDeclaration(doc, decl.name.name);
204 _idl.enums[enm.name] = enm;
196 for (EnumConstantDeclaration constDecl in decl.constants) { 205 for (EnumConstantDeclaration constDecl in decl.constants) {
197 enm.values.add(constDecl.name.name); 206 enm.values.add(constDecl.name.name);
198 } 207 }
199 } else if (decl is TopLevelVariableDeclaration) { 208 } else if (decl is TopLevelVariableDeclaration) {
200 // Ignore top level variable declarations; they are present just to make 209 // Ignore top level variable declarations; they are present just to make
201 // the IDL analyze without warnings. 210 // the IDL analyze without warnings.
202 } else { 211 } else {
203 throw new Exception('Unexpected declaration `$decl`'); 212 throw new Exception('Unexpected declaration `$decl`');
204 } 213 }
205 } 214 }
(...skipping 17 matching lines...) Expand all
223 * appropriate. 232 * appropriate.
224 */ 233 */
225 void out([String s = '']) { 234 void out([String s = '']) {
226 if (s == '') { 235 if (s == '') {
227 _outBuffer.writeln(''); 236 _outBuffer.writeln('');
228 } else { 237 } else {
229 _outBuffer.writeln('$_indentation$s'); 238 _outBuffer.writeln('$_indentation$s');
230 } 239 }
231 } 240 }
232 241
242 void outDoc(String documentation) {
243 if (documentation != null) {
244 documentation.split('\n').forEach(out);
245 }
246 }
247
233 /** 248 /**
234 * Entry point to the code generator. Interpret the AST in [idlParsed], 249 * Entry point to the code generator. Interpret the AST in [idlParsed],
235 * generate code, and output it to [_outBuffer]. 250 * generate code, and output it to [_outBuffer].
236 */ 251 */
237 void processCompilationUnit(CompilationUnit idlParsed) { 252 void processCompilationUnit(LineInfo lineInfo, CompilationUnit idlParsed) {
238 extractIdl(idlParsed); 253 extractIdl(lineInfo, idlParsed);
239 checkIdl(); 254 checkIdl();
240 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR S file'); 255 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR S file');
241 out('// for details. All rights reserved. Use of this source code is governe d by a'); 256 out('// for details. All rights reserved. Use of this source code is governe d by a');
242 out('// BSD-style license that can be found in the LICENSE file.'); 257 out('// BSD-style license that can be found in the LICENSE file.');
243 out('//'); 258 out('//');
244 out('// This file has been automatically generated. Please do not edit it m anually.'); 259 out('// This file has been automatically generated. Please do not edit it m anually.');
245 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f iles".'); 260 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f iles".');
246 out(); 261 out();
247 out('library analyzer.src.summary.format;'); 262 out('library analyzer.src.summary.format;');
248 out(); 263 out();
249 out("import 'dart:convert';"); 264 out("import 'dart:convert';");
250 out("import 'base.dart' as base;"); 265 out("import 'base.dart' as base;");
251 out(); 266 out();
252 _idl.enums.forEach((String name, idlModel.EnumDeclaration enm) { 267 _idl.enums.forEach((String name, idlModel.EnumDeclaration enm) {
268 outDoc(enm.documentation);
253 out('enum $name {'); 269 out('enum $name {');
254 indent(() { 270 indent(() {
255 for (String value in enm.values) { 271 for (String value in enm.values) {
256 out('$value,'); 272 out('$value,');
257 } 273 }
258 }); 274 });
259 out('}'); 275 out('}');
260 out(); 276 out();
261 }); 277 });
262 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { 278 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) {
279 outDoc(cls.documentation);
263 out('class $name extends base.SummaryClass {'); 280 out('class $name extends base.SummaryClass {');
264 indent(() { 281 indent(() {
265 cls.fields.forEach((String fieldName, idlModel.FieldType type) { 282 for (idlModel.FieldDeclaration field in cls.fields) {
283 String fieldName = field.name;
284 idlModel.FieldType type = field.type;
266 out('${dartType(type)} _$fieldName;'); 285 out('${dartType(type)} _$fieldName;');
267 }); 286 }
268 out(); 287 out();
269 out('$name.fromJson(Map json)'); 288 out('$name.fromJson(Map json)');
270 indent(() { 289 indent(() {
271 List<String> initializers = <String>[]; 290 List<String> initializers = <String>[];
272 cls.fields.forEach((String fieldName, idlModel.FieldType type) { 291 for (idlModel.FieldDeclaration field in cls.fields) {
292 String fieldName = field.name;
293 idlModel.FieldType type = field.type;
273 String convert = 'json[${quoted(fieldName)}]'; 294 String convert = 'json[${quoted(fieldName)}]';
274 if (type.isList) { 295 if (type.isList) {
275 if (type.typeName == 'int' || type.typeName == 'String') { 296 if (type.typeName == 'int' || type.typeName == 'String') {
276 // No conversion necessary. 297 // No conversion necessary.
277 } else { 298 } else {
278 convert = 299 convert =
279 '$convert?.map((x) => new ${type.typeName}.fromJson(x))?.toL ist()'; 300 '$convert?.map((x) => new ${type.typeName}.fromJson(x))?.toL ist()';
280 } 301 }
281 } else if (_idl.classes.containsKey(type.typeName)) { 302 } else if (_idl.classes.containsKey(type.typeName)) {
282 convert = 303 convert =
283 '$convert == null ? null : new ${type.typeName}.fromJson($conv ert)'; 304 '$convert == null ? null : new ${type.typeName}.fromJson($conv ert)';
284 } else if (_idl.enums.containsKey(type.typeName)) { 305 } else if (_idl.enums.containsKey(type.typeName)) {
285 convert = 306 convert =
286 '$convert == null ? null : ${type.typeName}.values[$convert]'; 307 '$convert == null ? null : ${type.typeName}.values[$convert]';
287 } 308 }
288 initializers.add('_$fieldName = $convert'); 309 initializers.add('_$fieldName = $convert');
289 }); 310 }
290 for (int i = 0; i < initializers.length; i++) { 311 for (int i = 0; i < initializers.length; i++) {
291 String prefix = i == 0 ? ': ' : ' '; 312 String prefix = i == 0 ? ': ' : ' ';
292 String suffix = i == initializers.length - 1 ? ';' : ','; 313 String suffix = i == initializers.length - 1 ? ';' : ',';
293 out('$prefix${initializers[i]}$suffix'); 314 out('$prefix${initializers[i]}$suffix');
294 } 315 }
295 }); 316 });
296 out(); 317 out();
297 out('@override'); 318 out('@override');
298 out('Map<String, Object> toMap() => {'); 319 out('Map<String, Object> toMap() => {');
299 indent(() { 320 indent(() {
300 cls.fields.forEach((String fieldName, idlModel.FieldType type) { 321 for (idlModel.FieldDeclaration field in cls.fields) {
322 String fieldName = field.name;
301 out('${quoted(fieldName)}: $fieldName,'); 323 out('${quoted(fieldName)}: $fieldName,');
302 }); 324 }
303 }); 325 });
304 out('};'); 326 out('};');
305 out(); 327 out();
306 if (cls.isTopLevel) { 328 if (cls.isTopLevel) {
307 out('$name.fromBuffer(List<int> buffer) : this.fromJson(JSON.decode(UT F8.decode(buffer)));'); 329 out('$name.fromBuffer(List<int> buffer) : this.fromJson(JSON.decode(UT F8.decode(buffer)));');
308 out(); 330 out();
309 } 331 }
310 cls.fields.forEach((String fieldName, idlModel.FieldType type) { 332 cls.fields.asMap().forEach((index, field) {
333 String fieldName = field.name;
334 idlModel.FieldType type = field.type;
335 if (index != 0) {
336 out();
337 }
311 String def = defaultValue(type); 338 String def = defaultValue(type);
312 String defaultSuffix = def == null ? '' : ' ?? $def'; 339 String defaultSuffix = def == null ? '' : ' ?? $def';
340 outDoc(field.documentation);
313 out('${dartType(type)} get $fieldName => _$fieldName$defaultSuffix;'); 341 out('${dartType(type)} get $fieldName => _$fieldName$defaultSuffix;');
314 }); 342 });
315 }); 343 });
316 out('}'); 344 out('}');
317 out(); 345 out();
318 List<String> builderParams = <String>[]; 346 List<String> builderParams = <String>[];
319 out('class ${name}Builder {'); 347 out('class ${name}Builder {');
320 indent(() { 348 indent(() {
321 out('final Map _json = {};'); 349 out('final Map _json = {};');
322 out(); 350 out();
323 out('bool _finished = false;'); 351 out('bool _finished = false;');
324 out(); 352 out();
325 out('${name}Builder(base.BuilderContext context);'); 353 out('${name}Builder(base.BuilderContext context);');
326 cls.fields.forEach((String fieldName, idlModel.FieldType type) { 354 for (idlModel.FieldDeclaration field in cls.fields) {
355 String fieldName = field.name;
356 idlModel.FieldType type = field.type;
327 out(); 357 out();
358 outDoc(field.documentation);
328 String conversion = '_value'; 359 String conversion = '_value';
329 String condition = ''; 360 String condition = '';
330 if (type.isList) { 361 if (type.isList) {
331 if (_idl.classes.containsKey(type.typeName)) { 362 if (_idl.classes.containsKey(type.typeName)) {
332 conversion = '$conversion.map((b) => b.finish()).toList()'; 363 conversion = '$conversion.map((b) => b.finish()).toList()';
333 } else { 364 } else {
334 conversion = '$conversion.toList()'; 365 conversion = '$conversion.toList()';
335 } 366 }
336 condition = ' || _value.isEmpty'; 367 condition = ' || _value.isEmpty';
337 } else if (_idl.enums.containsKey(type.typeName)) { 368 } else if (_idl.enums.containsKey(type.typeName)) {
(...skipping 11 matching lines...) Expand all
349 out('if (_value != null) {'); 380 out('if (_value != null) {');
350 } else { 381 } else {
351 out('if (!(_value == null$condition)) {'); 382 out('if (!(_value == null$condition)) {');
352 } 383 }
353 indent(() { 384 indent(() {
354 out('_json[${quoted(fieldName)}] = $conversion;'); 385 out('_json[${quoted(fieldName)}] = $conversion;');
355 }); 386 });
356 out('}'); 387 out('}');
357 }); 388 });
358 out('}'); 389 out('}');
359 }); 390 }
360 if (cls.isTopLevel) { 391 if (cls.isTopLevel) {
361 out(); 392 out();
362 out('List<int> toBuffer() => UTF8.encode(JSON.encode(finish()));'); 393 out('List<int> toBuffer() => UTF8.encode(JSON.encode(finish()));');
363 } 394 }
364 out(); 395 out();
365 out('Map finish() {'); 396 out('Map finish() {');
366 indent(() { 397 indent(() {
367 out('assert(!_finished);'); 398 out('assert(!_finished);');
368 out('_finished = true;'); 399 out('_finished = true;');
369 out('return _json;'); 400 out('return _json;');
370 }); 401 });
371 out('}'); 402 out('}');
372 }); 403 });
373 out('}'); 404 out('}');
374 out(); 405 out();
375 out('${name}Builder encode$name(base.BuilderContext builderContext, {${bui lderParams.join(', ')}}) {'); 406 out('${name}Builder encode$name(base.BuilderContext builderContext, {${bui lderParams.join(', ')}}) {');
376 indent(() { 407 indent(() {
377 out('${name}Builder builder = new ${name}Builder(builderContext);'); 408 out('${name}Builder builder = new ${name}Builder(builderContext);');
378 cls.fields.forEach((String fieldName, idlModel.FieldType type) { 409 for (idlModel.FieldDeclaration field in cls.fields) {
410 String fieldName = field.name;
379 out('builder.$fieldName = $fieldName;'); 411 out('builder.$fieldName = $fieldName;');
380 }); 412 }
381 out('return builder;'); 413 out('return builder;');
382 }); 414 });
383 out('}'); 415 out('}');
384 out(); 416 out();
385 }); 417 });
386 } 418 }
387 419
388 /** 420 /**
389 * Enclose [s] in quotes, escaping as necessary. 421 * Enclose [s] in quotes, escaping as necessary.
390 */ 422 */
391 String quoted(String s) { 423 String quoted(String s) {
392 return JSON.encode(s); 424 return JSON.encode(s);
393 } 425 }
426
427 /**
428 * Return the documentation text of the given [node], or `null` if the [node]
429 * does not have a comment. Each line is `\n` separated.
430 */
431 String _getNodeDoc(LineInfo lineInfo, AnnotatedNode node) {
432 Comment comment = node.documentationComment;
433 if (comment != null &&
434 comment.isDocumentation &&
435 comment.tokens.length == 1 &&
436 comment.tokens.first.type == TokenType.MULTI_LINE_COMMENT) {
437 Token token = comment.tokens.first;
438 int column = lineInfo.getLocation(token.offset).columnNumber;
439 String indent = ' ' * (column - 1);
440 return token.lexeme.split('\n').map((String line) {
441 if (line.startsWith(indent)) {
442 line = line.substring(indent.length);
443 }
444 return line;
445 }).join('\n');
446 }
447 return null;
448 }
394 } 449 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/summary/format.dart ('k') | pkg/analyzer/tool/summary/idl_model.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698