| OLD | NEW |
| 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 codegen.protocol; | 5 library codegen.protocol; |
| 6 | 6 |
| 7 import 'dart:convert'; | 7 import 'dart:convert'; |
| 8 | 8 |
| 9 import 'api.dart'; | 9 import 'api.dart'; |
| 10 import 'codegen_tools.dart'; | 10 import 'codegen_tools.dart'; |
| 11 import 'from_html.dart'; | 11 import 'from_html.dart'; |
| 12 import 'implied_types.dart'; | 12 import 'implied_types.dart'; |
| 13 import 'to_html.dart'; | 13 import 'to_html.dart'; |
| 14 | 14 |
| 15 import 'package:html5lib/dom.dart' as dom; |
| 16 |
| 15 /** | 17 /** |
| 16 * Container for code that can be used to translate a data type from JSON. | 18 * Container for code that can be used to translate a data type from JSON. |
| 17 */ | 19 */ |
| 18 abstract class FromJsonCode { | 20 abstract class FromJsonCode { |
| 19 /** | 21 /** |
| 20 * True if the data type is already in JSON form, so the translation is the | 22 * True if the data type is already in JSON form, so the translation is the |
| 21 * identity function. | 23 * identity function. |
| 22 */ | 24 */ |
| 23 bool get isIdentity; | 25 bool get isIdentity; |
| 24 | 26 |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 * Representation of FromJsonCode for the identity transformation. | 158 * Representation of FromJsonCode for the identity transformation. |
| 157 */ | 159 */ |
| 158 class ToJsonIdentity extends ToJsonSnippet { | 160 class ToJsonIdentity extends ToJsonSnippet { |
| 159 ToJsonIdentity(String type) : super(type, (String value) => value); | 161 ToJsonIdentity(String type) : super(type, (String value) => value); |
| 160 | 162 |
| 161 @override | 163 @override |
| 162 bool get isIdentity => true; | 164 bool get isIdentity => true; |
| 163 } | 165 } |
| 164 | 166 |
| 165 /** | 167 /** |
| 168 * Special flags that need to be inserted into the declaration of the Element |
| 169 * class. |
| 170 */ |
| 171 const Map<String, String> specialElementFlags = const { |
| 172 'abstract': '0x01', |
| 173 'const': '0x02', |
| 174 'final': '0x04', |
| 175 'static': '0x08', |
| 176 'private': '0x10', |
| 177 'deprecated': '0x20' |
| 178 }; |
| 179 |
| 180 /** |
| 166 * Visitor which produces Dart code representing the API. | 181 * Visitor which produces Dart code representing the API. |
| 167 */ | 182 */ |
| 168 class CodegenProtocolVisitor extends HierarchicalApiVisitor with CodeGenerator { | 183 class CodegenProtocolVisitor extends HierarchicalApiVisitor with CodeGenerator { |
| 169 /** | 184 /** |
| 170 * Type references in the spec that are named something else in Dart. | 185 * Type references in the spec that are named something else in Dart. |
| 171 */ | 186 */ |
| 172 static const Map<String, String> _typeRenames = const { | 187 static const Map<String, String> _typeRenames = const { |
| 173 'object': 'Object', | 188 'object': 'Object', |
| 174 }; | 189 }; |
| 175 | 190 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 docComment(toHtmlVisitor.collectHtml(() { | 240 docComment(toHtmlVisitor.collectHtml(() { |
| 226 toHtmlVisitor.p(() { | 241 toHtmlVisitor.p(() { |
| 227 toHtmlVisitor.write(impliedType.humanReadableName); | 242 toHtmlVisitor.write(impliedType.humanReadableName); |
| 228 }); | 243 }); |
| 229 if (impliedType.type != null) { | 244 if (impliedType.type != null) { |
| 230 toHtmlVisitor.showType(null, impliedType.type); | 245 toHtmlVisitor.showType(null, impliedType.type); |
| 231 } | 246 } |
| 232 })); | 247 })); |
| 233 writeln('class $className implements HasToJson {'); | 248 writeln('class $className implements HasToJson {'); |
| 234 indent(() { | 249 indent(() { |
| 250 if (emitSpecialStaticMembers(className)) { |
| 251 writeln(); |
| 252 } |
| 235 for (TypeObjectField field in type.fields) { | 253 for (TypeObjectField field in type.fields) { |
| 236 if (field.value != null) { | 254 if (field.value != null) { |
| 237 continue; | 255 continue; |
| 238 } | 256 } |
| 239 docComment(toHtmlVisitor.collectHtml(() { | 257 docComment(toHtmlVisitor.collectHtml(() { |
| 240 toHtmlVisitor.translateHtml(field.html); | 258 toHtmlVisitor.translateHtml(field.html); |
| 241 })); | 259 })); |
| 242 writeln('${dartType(field.type)} ${field.name};'); | 260 writeln('${dartType(field.type)} ${field.name};'); |
| 243 writeln(); | 261 writeln(); |
| 244 } | 262 } |
| 245 emitObjectConstructor(type, className); | 263 emitObjectConstructor(type, className); |
| 246 writeln(); | 264 writeln(); |
| 247 emitObjectFromJsonConstructor(className, type, impliedType); | 265 emitObjectFromJsonConstructor(className, type, impliedType); |
| 248 writeln(); | 266 writeln(); |
| 249 if (emitConvenienceConstructor(className, impliedType)) { | 267 if (emitConvenienceConstructor(className, impliedType)) { |
| 250 writeln(); | 268 writeln(); |
| 251 } | 269 } |
| 270 if (emitSpecialConstructors(className)) { |
| 271 writeln(); |
| 272 } |
| 273 if (emitSpecialGetters(className)) { |
| 274 writeln(); |
| 275 } |
| 252 emitToJsonMember(type); | 276 emitToJsonMember(type); |
| 253 writeln(); | 277 writeln(); |
| 254 if (emitToRequestMember(impliedType)) { | 278 if (emitToRequestMember(impliedType)) { |
| 255 writeln(); | 279 writeln(); |
| 256 } | 280 } |
| 281 if (emitSpecialMembers(className)) { |
| 282 writeln(); |
| 283 } |
| 257 writeln('@override'); | 284 writeln('@override'); |
| 258 writeln('String toString() => JSON.encode(toJson());'); | 285 writeln('String toString() => JSON.encode(toJson());'); |
| 259 writeln(); | 286 writeln(); |
| 260 emitObjectEqualsMember(type, className); | 287 emitObjectEqualsMember(type, className); |
| 261 writeln(); | 288 writeln(); |
| 262 emitObjectHashCode(type); | 289 emitObjectHashCode(type); |
| 263 }); | 290 }); |
| 264 writeln('}'); | 291 writeln('}'); |
| 265 } | 292 } |
| 266 | 293 |
| 267 /** | 294 /** |
| 295 * If the class named [className] requires special static members, emit them |
| 296 * and return true. |
| 297 */ |
| 298 bool emitSpecialStaticMembers(String className) { |
| 299 switch (className) { |
| 300 case 'Element': |
| 301 List<String> makeFlagsArgs = <String>[]; |
| 302 List<String> makeFlagsStatements = <String>[]; |
| 303 specialElementFlags.forEach((String name, String value) { |
| 304 String flag = 'FLAG_${name.toUpperCase()}'; |
| 305 String camelName = camelJoin(['is', name]); |
| 306 writeln('static const int $flag = $value;'); |
| 307 makeFlagsArgs.add('$camelName: false'); |
| 308 makeFlagsStatements.add('if ($camelName) flags |= $flag;'); |
| 309 }); |
| 310 writeln(); |
| 311 writeln('static int makeFlags({${makeFlagsArgs.join(', ')}}) {'); |
| 312 indent(() { |
| 313 writeln('int flags = 0;'); |
| 314 for (String statement in makeFlagsStatements) { |
| 315 writeln(statement); |
| 316 } |
| 317 writeln('return flags;'); |
| 318 }); |
| 319 writeln('}'); |
| 320 return true; |
| 321 case 'SourceEdit': |
| 322 docComment([new dom.Text('Get the result of applying a set of ' + |
| 323 '[edits] to the given [code]. Edits are applied in the order ' + |
| 324 'they appear in [edits].')]); |
| 325 writeln( |
| 326 'static String applySequence(String code, Iterable<SourceEdit> edits
) =>'); |
| 327 writeln(' _applySequence(code, edits);'); |
| 328 return true; |
| 329 default: |
| 330 return false; |
| 331 } |
| 332 } |
| 333 |
| 334 /** |
| 335 * If the class named [className] requires special constructors, emit them |
| 336 * and return true. |
| 337 */ |
| 338 bool emitSpecialConstructors(String className) { |
| 339 switch (className) { |
| 340 case 'AnalysisError': |
| 341 docComment([new dom.Text( |
| 342 'Construct based on error information from the analyzer engine.')]); |
| 343 writeln( |
| 344 'factory AnalysisError.fromEngine(engine.LineInfo lineInfo, engine.A
nalysisError error) =>' |
| 345 ); |
| 346 writeln(' _analysisErrorFromEngine(lineInfo, error);'); |
| 347 return true; |
| 348 case 'ElementKind': |
| 349 docComment([new dom.Text( |
| 350 'Construct based on a value from the analyzer engine.')]); |
| 351 writeln('factory ElementKind.fromEngine(engine.ElementKind kind) =>'); |
| 352 writeln(' _elementKindFromEngine(kind);'); |
| 353 return true; |
| 354 case 'SourceEdit': |
| 355 docComment([new dom.Text('Construct based on a SourceRange.')]); |
| 356 writeln( |
| 357 'SourceEdit.range(engine.SourceRange range, String replacement, {Str
ing id})'); |
| 358 writeln(' : this(range.offset, range.length, replacement, id: id);'); |
| 359 return true; |
| 360 default: |
| 361 return false; |
| 362 } |
| 363 } |
| 364 |
| 365 /** |
| 366 * If the class named [className] requires special getters, emit them and |
| 367 * return true. |
| 368 */ |
| 369 bool emitSpecialGetters(String className) { |
| 370 switch (className) { |
| 371 case 'Element': |
| 372 for (String name in specialElementFlags.keys) { |
| 373 String flag = 'FLAG_${name.toUpperCase()}'; |
| 374 writeln('bool get ${camelJoin(['is', name])} => (flags & $flag) != 0;' |
| 375 ); |
| 376 } |
| 377 return true; |
| 378 case 'SourceEdit': |
| 379 docComment([new dom.Text('The end of the region to be modified.')]); |
| 380 writeln('int get end => offset + length;'); |
| 381 return true; |
| 382 default: |
| 383 return false; |
| 384 } |
| 385 } |
| 386 |
| 387 /** |
| 388 * If the class named [className] requires special members, emit them and |
| 389 * return true. |
| 390 */ |
| 391 bool emitSpecialMembers(String className) { |
| 392 switch (className) { |
| 393 case 'SourceEdit': |
| 394 docComment([new dom.Text( |
| 395 'Get the result of applying the edit to the given [code].')]); |
| 396 writeln('String apply(String code) => _applyEdit(code, this);'); |
| 397 return true; |
| 398 default: |
| 399 return false; |
| 400 } |
| 401 } |
| 402 |
| 403 /** |
| 268 * Emit the constructor for an object class. | 404 * Emit the constructor for an object class. |
| 269 */ | 405 */ |
| 270 void emitObjectConstructor(TypeObject type, String className) { | 406 void emitObjectConstructor(TypeObject type, String className) { |
| 271 List<String> args = <String>[]; | 407 List<String> args = <String>[]; |
| 272 List<String> optionalArgs = <String>[]; | 408 List<String> optionalArgs = <String>[]; |
| 273 for (TypeObjectField field in type.fields) { | 409 for (TypeObjectField field in type.fields) { |
| 274 if (field.value != null) { | 410 if (field.value != null) { |
| 275 continue; | 411 continue; |
| 276 } | 412 } |
| 277 String arg = 'this.${field.name}'; | 413 String arg = 'this.${field.name}'; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 docComment(toHtmlVisitor.collectHtml(() { | 530 docComment(toHtmlVisitor.collectHtml(() { |
| 395 toHtmlVisitor.p(() { | 531 toHtmlVisitor.p(() { |
| 396 toHtmlVisitor.write(impliedType.humanReadableName); | 532 toHtmlVisitor.write(impliedType.humanReadableName); |
| 397 }); | 533 }); |
| 398 if (impliedType.type != null) { | 534 if (impliedType.type != null) { |
| 399 toHtmlVisitor.showType(null, impliedType.type); | 535 toHtmlVisitor.showType(null, impliedType.type); |
| 400 } | 536 } |
| 401 })); | 537 })); |
| 402 writeln('class $className {'); | 538 writeln('class $className {'); |
| 403 indent(() { | 539 indent(() { |
| 540 if (emitSpecialStaticMembers(className)) { |
| 541 writeln(); |
| 542 } |
| 404 for (TypeEnumValue value in type.values) { | 543 for (TypeEnumValue value in type.values) { |
| 405 docComment(toHtmlVisitor.collectHtml(() { | 544 docComment(toHtmlVisitor.collectHtml(() { |
| 406 toHtmlVisitor.translateHtml(value.html); | 545 toHtmlVisitor.translateHtml(value.html); |
| 407 })); | 546 })); |
| 408 String valueString = literalString(value.value); | 547 String valueString = literalString(value.value); |
| 409 writeln( | 548 writeln( |
| 410 'static const ${value.value} = const $className._($valueString);'); | 549 'static const ${value.value} = const $className._($valueString);'); |
| 411 writeln(); | 550 writeln(); |
| 412 } | 551 } |
| 413 writeln('final String name;'); | 552 writeln('final String name;'); |
| 414 writeln(); | 553 writeln(); |
| 415 writeln('const $className._(this.name);'); | 554 writeln('const $className._(this.name);'); |
| 416 writeln(); | 555 writeln(); |
| 417 emitEnumClassConstructor(className, type); | 556 emitEnumClassConstructor(className, type); |
| 418 writeln(); | 557 writeln(); |
| 419 emitEnumFromJsonConstructor(className, type, impliedType); | 558 emitEnumFromJsonConstructor(className, type, impliedType); |
| 420 writeln(); | 559 writeln(); |
| 560 if (emitSpecialConstructors(className)) { |
| 561 writeln(); |
| 562 } |
| 563 if (emitSpecialGetters(className)) { |
| 564 writeln(); |
| 565 } |
| 566 if (emitSpecialMembers(className)) { |
| 567 writeln(); |
| 568 } |
| 421 writeln('@override'); | 569 writeln('@override'); |
| 422 writeln('String toString() => "$className.\$name";'); | 570 writeln('String toString() => "$className.\$name";'); |
| 423 writeln(); | 571 writeln(); |
| 424 writeln('String toJson() => name;'); | 572 writeln('String toJson() => name;'); |
| 425 }); | 573 }); |
| 426 writeln('}'); | 574 writeln('}'); |
| 427 } | 575 } |
| 428 | 576 |
| 429 /** | 577 /** |
| 430 * Emit the constructor for an enum class. | 578 * Emit the constructor for an enum class. |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 828 CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi()); | 976 CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi()); |
| 829 return visitor.collectCode(visitor.visitApi); | 977 return visitor.collectCode(visitor.visitApi); |
| 830 }); | 978 }); |
| 831 | 979 |
| 832 /** | 980 /** |
| 833 * Translate spec_input.html into protocol_matchers.dart. | 981 * Translate spec_input.html into protocol_matchers.dart. |
| 834 */ | 982 */ |
| 835 main() { | 983 main() { |
| 836 target.generate(); | 984 target.generate(); |
| 837 } | 985 } |
| OLD | NEW |