| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library servicec.plugins.cc; | |
| 6 | |
| 7 import 'dart:core' hide Type; | |
| 8 import 'dart:io' show Platform, File; | |
| 9 | |
| 10 import 'package:strings/strings.dart' as strings; | |
| 11 import 'package:path/path.dart' show basenameWithoutExtension, join, dirname; | |
| 12 | |
| 13 import 'shared.dart'; | |
| 14 | |
| 15 import '../emitter.dart'; | |
| 16 import '../primitives.dart' as primitives; | |
| 17 import '../struct_layout.dart'; | |
| 18 | |
| 19 const List<String> RESOURCES = const [ | |
| 20 'Action.java', | |
| 21 'ActionPatch.java', | |
| 22 'AnyNodePresenter.java', | |
| 23 'ImmiRoot.java', | |
| 24 'ImmiService.java', | |
| 25 'ListPatch.java', | |
| 26 'Node.java', | |
| 27 'NodePatch.java', | |
| 28 'NodePresenter.java', | |
| 29 'Patch.java', | |
| 30 ]; | |
| 31 | |
| 32 const Map<String, String> _TYPES = const <String, String>{ | |
| 33 'void' : 'void', | |
| 34 'bool' : 'boolean', | |
| 35 | |
| 36 'uint8' : 'int', | |
| 37 'uint16' : 'int', | |
| 38 | |
| 39 'int8' : 'int', | |
| 40 'int16' : 'int', | |
| 41 'int32' : 'int', | |
| 42 'int64' : 'long', | |
| 43 | |
| 44 'float32' : 'float', | |
| 45 'float64' : 'double', | |
| 46 | |
| 47 'String' : 'String', | |
| 48 }; | |
| 49 | |
| 50 void generate(String path, Map units, String outputDirectory) { | |
| 51 String directory = join(outputDirectory, 'java', 'immi'); | |
| 52 _generateNodeFiles(path, units, directory); | |
| 53 | |
| 54 String resourcesDirectory = join(dirname(Platform.script.path), | |
| 55 '..', 'lib', 'src', 'resources', 'java', 'immi'); | |
| 56 for (String resource in RESOURCES) { | |
| 57 String resourcePath = join(resourcesDirectory, resource); | |
| 58 File file = new File(resourcePath); | |
| 59 String contents = file.readAsStringSync(); | |
| 60 writeToFile(directory, resource, contents); | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 void _generateNodeFiles(String path, Map units, String outputDirectory) { | |
| 65 var actions = new _ActionsCollector(); | |
| 66 new _AnyNodeWriter(units).writeTo(outputDirectory); | |
| 67 new _AnyNodePatchWriter(units).writeTo(outputDirectory); | |
| 68 for (Unit unit in units.values) { | |
| 69 actions.collectMethodSignatures(unit); | |
| 70 for (Struct node in unit.structs) { | |
| 71 new _JavaNodeWriter(node).writeTo(outputDirectory); | |
| 72 new _JavaNodePatchWriter(node).writeTo(outputDirectory); | |
| 73 new _JavaNodePresenterWriter(node).writeTo(outputDirectory); | |
| 74 } | |
| 75 } | |
| 76 _TYPES.forEach((idlType, javaType) { | |
| 77 if (idlType == 'void') return; | |
| 78 new _JavaPrimitivePatchWriter(idlType, javaType).writeTo(outputDirectory); | |
| 79 }); | |
| 80 for (var types in actions.methodSignatures.values) { | |
| 81 _JavaActionWriter.fromTypes(types.toList()).writeTo(outputDirectory); | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 class _ActionsCollector extends CodeGenerationVisitor { | |
| 86 _ActionsCollector() : super(null); | |
| 87 } | |
| 88 | |
| 89 class _JavaVisitor extends CodeGenerationVisitor { | |
| 90 static const COPYRIGHT = """ | |
| 91 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
| 92 // for details. All rights reserved. Use of this source code is governed by a | |
| 93 // BSD-style license that can be found in the LICENSE.md file. | |
| 94 """; | |
| 95 | |
| 96 _JavaVisitor(String path) : super(path); | |
| 97 } | |
| 98 | |
| 99 class _JavaWriter extends _JavaVisitor { | |
| 100 | |
| 101 final String className; | |
| 102 | |
| 103 bool shouldWriteHeader = false; | |
| 104 Set<String> imports = new Set<String>(); | |
| 105 | |
| 106 _JavaWriter(String className) | |
| 107 : super(className), | |
| 108 className = className; | |
| 109 | |
| 110 void writeHeader([List<String> imports]) { | |
| 111 shouldWriteHeader = true; | |
| 112 if (imports != null) imports.forEach((i) { this.imports.add(i); }); | |
| 113 } | |
| 114 | |
| 115 void writeTo(String directory) { | |
| 116 var content = buffer.toString(); | |
| 117 buffer.clear(); | |
| 118 if (shouldWriteHeader) { | |
| 119 writeln(_JavaVisitor.COPYRIGHT); | |
| 120 writeln('// Generated file. Do not edit.'); | |
| 121 writeln(); | |
| 122 writeln('package immi;'); | |
| 123 writeln(); | |
| 124 if (imports.isNotEmpty) { | |
| 125 var sorted = imports.toList()..sort(); | |
| 126 var inJava = <String>[]; | |
| 127 var inOther = <String>[]; | |
| 128 for (var import in sorted) { | |
| 129 if (import.startsWith('java')) { | |
| 130 inJava.add(import); | |
| 131 } else { | |
| 132 inOther.add(import); | |
| 133 } | |
| 134 } | |
| 135 inJava.forEach(writeImport); | |
| 136 if (inJava.isNotEmpty) writeln(); | |
| 137 inOther.forEach(writeImport); | |
| 138 if (inOther.isNotEmpty) writeln(); | |
| 139 } | |
| 140 } | |
| 141 buffer.write(content); | |
| 142 writeToFile(directory, className, buffer.toString(), extension: 'java'); | |
| 143 } | |
| 144 | |
| 145 writeImport(import) { | |
| 146 writeln('import $import;'); | |
| 147 } | |
| 148 | |
| 149 String instanceOrNull(String name, String type) { | |
| 150 return '($name instanceof $type) ? ($type)$name : null'; | |
| 151 } | |
| 152 | |
| 153 String getTypeName(Type type) { | |
| 154 if (type.isList) { | |
| 155 imports.add('java.util.List'); | |
| 156 return 'List<${getNonListTypeName(type)}>'; | |
| 157 } | |
| 158 return getNonListTypeName(type); | |
| 159 } | |
| 160 | |
| 161 String getNonListTypeName(Type type) { | |
| 162 // TODO(zerny): Make the type structure regular! | |
| 163 if (type.isNode || type.isList && type.elementType.isNode) return 'AnyNode'; | |
| 164 if (type.resolved != null) { | |
| 165 return "${type.identifier}Node"; | |
| 166 } | |
| 167 return _TYPES[type.identifier]; | |
| 168 } | |
| 169 | |
| 170 String getNodeDataTypeName(Type type) { | |
| 171 if (type.isList && type.elementType.isNode) return 'NodeDataList'; | |
| 172 if (type.isList) return '${getNonListTypeName(type)}DataList'; | |
| 173 if (type.isNode) return 'NodeData'; | |
| 174 assert(type.resolved != null); | |
| 175 return '${type.identifier}NodeData'; | |
| 176 } | |
| 177 | |
| 178 String getPatchTypeName(Type type) { | |
| 179 if (type.isList) return 'ListPatch<${getNonListTypeName(type)}>'; | |
| 180 if (type.isNode) return 'AnyNodePatch'; | |
| 181 if (type.resolved != null) { | |
| 182 return "${type.identifier}Patch"; | |
| 183 } | |
| 184 return "${camelize(type.identifier)}Patch"; | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 class _JavaPrimitivePatchWriter extends _JavaWriter { | |
| 189 _JavaPrimitivePatchWriter(String idlType, javaType) | |
| 190 : super('${strings.camelize(strings.underscore(idlType))}Patch') { | |
| 191 writeHeader(); | |
| 192 writeln('public class $className implements Patch {'); | |
| 193 writeln(); | |
| 194 writeln(' // Public interface.'); | |
| 195 writeln(); | |
| 196 writeln(' @Override'); | |
| 197 writeln(' public boolean hasChanged() { return previous != current; }'); | |
| 198 writeln(); | |
| 199 writeln(' public $javaType getCurrent() { return current; }'); | |
| 200 writeln(' public $javaType getPrevious() { return previous; }'); | |
| 201 writeln(); | |
| 202 writeln(' // Package private implementation.'); | |
| 203 writeln(); | |
| 204 writeln(' $className($javaType previous) {'); | |
| 205 writeln(' this.previous = previous;'); | |
| 206 writeln(' current = previous;'); | |
| 207 writeln(' }'); | |
| 208 writeln(); | |
| 209 writeln(' $className($javaType data, $javaType previous, ImmiRoot root) {')
; | |
| 210 writeln(' this.previous = previous;'); | |
| 211 writeln(' current = data;'); | |
| 212 writeln(' }'); | |
| 213 writeln(); | |
| 214 writeln(' private $javaType previous;'); | |
| 215 writeln(' private $javaType current;'); | |
| 216 writeln('}'); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 class _JavaActionWriter extends _JavaWriter { | |
| 221 Method method; | |
| 222 List<Type> types; | |
| 223 List<String> arguments; | |
| 224 | |
| 225 _JavaActionWriter(this.method, this.types, this.arguments) | |
| 226 : super(null); | |
| 227 | |
| 228 static _JavaActionWriter fromTypes(List<Type> types) { | |
| 229 int i = 0; | |
| 230 return new _JavaActionWriter( | |
| 231 null, | |
| 232 types, | |
| 233 types.map((_) => 'arg${i++}').toList()); | |
| 234 } | |
| 235 | |
| 236 static _JavaActionWriter fromMethod(Method method) { | |
| 237 return new _JavaActionWriter( | |
| 238 method, | |
| 239 method.arguments.map((f) => f.type).toList(), | |
| 240 method.arguments.map((f) => f.name).toList()); | |
| 241 } | |
| 242 | |
| 243 writeTo(String outputDirectory) { | |
| 244 bool boxedArguments = types.any((t) => t.isString); | |
| 245 writeHeader([ | |
| 246 'dartino.ImmiServiceLayer', | |
| 247 ]); | |
| 248 writeln('public final class $className implements Action {'); | |
| 249 writeln(); | |
| 250 writeln(' // Public interface.'); | |
| 251 writeln(); | |
| 252 writeln(' public void dispatch($actionFormals) {'); | |
| 253 writeln(' root.dispatch(new Runnable() {'); | |
| 254 writeln(' @Override'); | |
| 255 writeln(' public void run() {'); | |
| 256 if (boxedArguments) { | |
| 257 String builder = actionArgsBuilder; | |
| 258 imports.add('dartino.MessageBuilder'); | |
| 259 imports.add('dartino.$builder'); | |
| 260 writeln(' int space = 48 + $builder.kSize;'); | |
| 261 for (int i = 0; i < types.length; ++i) { | |
| 262 if (types[i].isString) { | |
| 263 writeln(' space += ${arguments[i]}.length();'); | |
| 264 } | |
| 265 } | |
| 266 writeln(' MessageBuilder message = new MessageBuilder(space);'); | |
| 267 writeln(' $builder args = new $builder();'); | |
| 268 writeln(' message.initRoot(args, $builder.kSize);'); | |
| 269 writeln(' args.setId(id);'); | |
| 270 arguments.forEach((a) { | |
| 271 writeln(' args.set${camelize(a)}($a);'); | |
| 272 }); | |
| 273 } | |
| 274 write(' ImmiServiceLayer.dispatch${actionSuffix}Async('); | |
| 275 if (boxedArguments) { | |
| 276 write('args, '); | |
| 277 } else { | |
| 278 write('id, '); | |
| 279 arguments.forEach((a) { write('$a, '); }); | |
| 280 } | |
| 281 writeln('null);'); | |
| 282 writeln(' }'); | |
| 283 writeln(' });'); | |
| 284 writeln(' }'); | |
| 285 writeln(); | |
| 286 writeln(' // Package private implementation.'); | |
| 287 writeln(); | |
| 288 writeln(' $className(int id, ImmiRoot root) {'); | |
| 289 writeln(' this.id = id;'); | |
| 290 writeln(' this.root = root;'); | |
| 291 writeln(' }'); | |
| 292 writeln(); | |
| 293 writeln(' private int id;'); | |
| 294 writeln(' private ImmiRoot root;'); | |
| 295 writeln('}'); | |
| 296 super.writeTo(outputDirectory); | |
| 297 } | |
| 298 | |
| 299 // Override className since we can't provide it in the constructor. | |
| 300 String get className => actionName; | |
| 301 | |
| 302 String get actionFormals { | |
| 303 int i = 0; | |
| 304 return types.map((t) => 'final ${getTypeName(t)} arg${i++}').join(', '); | |
| 305 } | |
| 306 | |
| 307 String get actionName { | |
| 308 return 'Action${actionSuffix}'; | |
| 309 } | |
| 310 | |
| 311 String get actionPatchName { | |
| 312 return 'ActionPatch<$actionName>'; | |
| 313 } | |
| 314 | |
| 315 String get actionSuffix { | |
| 316 if (types.isEmpty) return 'Void'; | |
| 317 return types.map((t) => camelize(t.identifier)).join(); | |
| 318 } | |
| 319 | |
| 320 String get actionArgsBuilder { | |
| 321 return '${actionName}ArgsBuilder'; | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 class _JavaNodeBaseWriter extends _JavaWriter { | |
| 326 final String name; | |
| 327 final String nodeName; | |
| 328 final String patchName; | |
| 329 final String presenterName; | |
| 330 | |
| 331 _JavaNodeBaseWriter(String name, String fileName) | |
| 332 : super(fileName), | |
| 333 name = name, | |
| 334 nodeName = '${name}Node', | |
| 335 patchName = '${name}Patch', | |
| 336 presenterName = '${name}Presenter'; | |
| 337 } | |
| 338 | |
| 339 class _JavaNodePresenterWriter extends _JavaNodeBaseWriter { | |
| 340 | |
| 341 _JavaNodePresenterWriter(Struct node) | |
| 342 : super(node.name, '${node.name}Presenter') { | |
| 343 visitStruct(node); | |
| 344 } | |
| 345 | |
| 346 visitStruct(Struct node) { | |
| 347 writeHeader(); | |
| 348 write('public interface $presenterName'); | |
| 349 writeln(' extends NodePresenter<$nodeName, $patchName> {}'); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 class _JavaNodeWriter extends _JavaNodeBaseWriter { | |
| 354 Struct node; | |
| 355 Iterable<_JavaNodeWriter> actions; | |
| 356 | |
| 357 _JavaNodeWriter(Struct node) | |
| 358 : super(node.name, '${node.name}Node') { | |
| 359 visitStruct(node); | |
| 360 } | |
| 361 | |
| 362 visitStruct(Struct node) { | |
| 363 this.node = node; | |
| 364 actions = node.methods.map(_JavaActionWriter.fromMethod); | |
| 365 writeHeader([ | |
| 366 'dartino.${nodeName}Data', | |
| 367 ]); | |
| 368 writeln('public final class $nodeName implements Node {'); | |
| 369 writeln(); | |
| 370 writeln(' // Public interface.'); | |
| 371 writeln(); | |
| 372 forEachSlot(node, null, writeFieldGetter); | |
| 373 actions.forEach(writeActionGetter); | |
| 374 writeln(); | |
| 375 writeln(' // Package private implementation.'); | |
| 376 writeln(); | |
| 377 writeConstructorFromData(); | |
| 378 writeln(); | |
| 379 writeConstructorFromPatch(); | |
| 380 writeln(); | |
| 381 forEachSlot(node, null, writeFieldBacking); | |
| 382 actions.forEach(writeActionBacking); | |
| 383 writeln('}'); | |
| 384 } | |
| 385 | |
| 386 writeConstructorFromData() { | |
| 387 writeln(' $nodeName(${nodeName}Data data, ImmiRoot root) {'); | |
| 388 forEachSlot(node, null, writeFieldInitializationFromData); | |
| 389 actions.forEach(writeActionInitializationFromData); | |
| 390 writeln(' }'); | |
| 391 } | |
| 392 | |
| 393 writeConstructorFromPatch() { | |
| 394 writeln(' $nodeName($patchName patch) {'); | |
| 395 forEachSlot(node, null, writeFieldInitializationFromPatch); | |
| 396 actions.forEach(writeActionInitializationFromPatch); | |
| 397 writeln(' }'); | |
| 398 } | |
| 399 | |
| 400 writeFieldGetter(Type type, String name) { | |
| 401 String typeName = getTypeName(type); | |
| 402 writeln(' public $typeName get${camelize(name)}() { return $name; }'); | |
| 403 } | |
| 404 | |
| 405 writeFieldBacking(Type type, String name) { | |
| 406 String typeName = getTypeName(type); | |
| 407 writeln(' private $typeName $name;'); | |
| 408 } | |
| 409 | |
| 410 writeFieldInitializationFromData(Type type, String name) { | |
| 411 String camelName = camelize(name); | |
| 412 String typeName = getTypeName(type); | |
| 413 if (type.isList) { | |
| 414 String typeName = getNonListTypeName(type); | |
| 415 String dataName = getNodeDataTypeName(type); | |
| 416 imports.add('dartino.$dataName'); | |
| 417 imports.add('java.util.Collections'); | |
| 418 imports.add('java.util.ArrayList'); | |
| 419 writeln(' {'); | |
| 420 writeln(' $dataName dataList = data.get$camelName();'); | |
| 421 writeln(' int length = dataList.size();'); | |
| 422 writeln(' List<$typeName> list = new ArrayList<$typeName>(length);'); | |
| 423 writeln(' for (int i = 0; i < length; ++i) {'); | |
| 424 writeln(' list.add(new $typeName(dataList.get(i), root));'); | |
| 425 writeln(' }'); | |
| 426 writeln(' $name = Collections.unmodifiableList(list);'); | |
| 427 writeln(' }'); | |
| 428 } else if (type.isNode || type.resolved != null) { | |
| 429 writeln(' $name = new $typeName(data.get$camelName(), root);'); | |
| 430 } else { | |
| 431 writeln(' $name = data.get$camelName();'); | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 writeFieldInitializationFromPatch(Type type, String name) { | |
| 436 String camelName = camelize(name); | |
| 437 writeln(' $name = patch.get$camelName().getCurrent();'); | |
| 438 } | |
| 439 | |
| 440 writeActionBacking(_JavaActionWriter action) { | |
| 441 String name = action.method.name; | |
| 442 writeln(' private ${action.actionName} $name;'); | |
| 443 } | |
| 444 | |
| 445 writeActionGetter(_JavaActionWriter action) { | |
| 446 String name = action.method.name; | |
| 447 String camelName = camelize(name); | |
| 448 writeln(' public ${action.actionName} get$camelName() { return $name; }'); | |
| 449 } | |
| 450 | |
| 451 writeActionInitializationFromData(_JavaActionWriter action) { | |
| 452 String name = action.method.name; | |
| 453 Strin camelName = camelize(name); | |
| 454 writeln(' $name = new ${action.actionName}(data.get$camelName(), root);')
; | |
| 455 } | |
| 456 | |
| 457 writeActionInitializationFromPatch(_JavaActionWriter action) { | |
| 458 String name = action.method.name; | |
| 459 Strin camelName = camelize(name); | |
| 460 writeln(' $name = patch.get$camelName().getCurrent();'); | |
| 461 } | |
| 462 } | |
| 463 | |
| 464 class _JavaNodePatchWriter extends _JavaNodeBaseWriter { | |
| 465 Struct node; | |
| 466 Iterable<_JavaNodeWriter> actions; | |
| 467 | |
| 468 _JavaNodePatchWriter(Struct node) | |
| 469 : super(node.name, '${node.name}Patch') { | |
| 470 visitStruct(node); | |
| 471 } | |
| 472 | |
| 473 visitStruct(Struct node) { | |
| 474 this.node = node; | |
| 475 actions = node.methods.map(_JavaActionWriter.fromMethod); | |
| 476 writeHeader([ | |
| 477 'dartino.${patchName}Data', | |
| 478 'dartino.${node.name}UpdateData', | |
| 479 'dartino.${node.name}UpdateDataList', | |
| 480 'java.util.List', | |
| 481 ]); | |
| 482 write('public final class $patchName'); | |
| 483 writeln(' implements NodePatch<$nodeName, $presenterName> {'); | |
| 484 writeln(); | |
| 485 writeln(' // Public interface.'); | |
| 486 writeln(); | |
| 487 writeln(' @Override'); | |
| 488 write(' public boolean hasChanged()'); | |
| 489 writeln(' { return type != PatchType.IdentityNodePatch; }'); | |
| 490 writeln(' @Override'); | |
| 491 write(' public boolean wasReplaced()'); | |
| 492 writeln(' { return type == PatchType.ReplaceNodePatch; }'); | |
| 493 writeln(' @Override'); | |
| 494 write(' public boolean wasUpdated()'); | |
| 495 writeln(' { return type == PatchType.UpdateNodePatch; }'); | |
| 496 writeln(); | |
| 497 writeln(' @Override'); | |
| 498 writeln(' public $nodeName getCurrent() { return current; }'); | |
| 499 writeln(' @Override'); | |
| 500 writeln(' public $nodeName getPrevious() { return previous; }'); | |
| 501 writeln(); | |
| 502 forEachSlot(node, null, writeFieldGetter); | |
| 503 actions.forEach(writeActionGetter); | |
| 504 writeln(); | |
| 505 writeln(' @Override'); | |
| 506 writeln(' public void applyTo($presenterName presenter) {'); | |
| 507 writeln(' if (!hasChanged()) return;'); | |
| 508 writeln(' if (wasReplaced()) {'); | |
| 509 writeln(' presenter.present(current);'); | |
| 510 writeln(' } else {'); | |
| 511 writeln(' assert wasUpdated();'); | |
| 512 writeln(' presenter.patch(this);'); | |
| 513 writeln(' }'); | |
| 514 writeln(' }'); | |
| 515 writeln(); | |
| 516 writeln(' // Package private implementation.'); | |
| 517 writeln(); | |
| 518 writeConstructorIdentity(); | |
| 519 writeln(); | |
| 520 writeConstructorFromData(); | |
| 521 writeln(); | |
| 522 writeln(' private PatchType type;'); | |
| 523 writeln(' private $nodeName current;'); | |
| 524 writeln(' private $nodeName previous;'); | |
| 525 forEachSlot(node, null, writeFieldBacking); | |
| 526 actions.forEach(writeActionBacking); | |
| 527 writeln('}'); | |
| 528 } | |
| 529 | |
| 530 writeConstructorIdentity() { | |
| 531 writeln(' $patchName($nodeName previous) {'); | |
| 532 writeln(' this.previous = previous;'); | |
| 533 writeln(' current = previous;'); | |
| 534 writeln(' type = PatchType.IdentityNodePatch;'); | |
| 535 writeln(' }'); | |
| 536 } | |
| 537 | |
| 538 writeConstructorFromData() { | |
| 539 writeln(' $patchName(${patchName}Data data, $nodeName previous, ImmiRoot ro
ot) {'); | |
| 540 writeln(' this.previous = previous;'); | |
| 541 if (node.layout.slots.isNotEmpty || node.methods.isNotEmpty) { | |
| 542 // The updates list is ordered consistently with the struct members. | |
| 543 writeln(' if (data.isUpdates()) {'); | |
| 544 writeln(' ${name}UpdateDataList updates = data.getUpdates();'); | |
| 545 writeln(' int length = updates.size();'); | |
| 546 writeln(' int next = 0;'); | |
| 547 forEachSlot(node, null, writeFieldInitializationFromData); | |
| 548 actions.forEach(writeActionInitializationFromData); | |
| 549 // TODO(zerny): Implement actions. | |
| 550 writeln(' assert next == length;'); | |
| 551 writeln(' type = PatchType.UpdateNodePatch;'); | |
| 552 writeln(' current = new $nodeName(this);'); | |
| 553 writeln(' return;'); | |
| 554 writeln(' }'); | |
| 555 } | |
| 556 writeln(' assert data.isReplace();'); | |
| 557 writeln(' type = PatchType.ReplaceNodePatch;'); | |
| 558 writeln(' current = new $nodeName(data.getReplace(), root);'); | |
| 559 writeln(' }'); | |
| 560 } | |
| 561 | |
| 562 writeFieldGetter(Type type, String name) { | |
| 563 String camelName = camelize(name); | |
| 564 String patchTypeName = getPatchTypeName(type); | |
| 565 writeln(' public $patchTypeName get$camelName() { return $name; }'); | |
| 566 } | |
| 567 | |
| 568 writeFieldBacking(Type type, String name) { | |
| 569 String patchTypeName = getPatchTypeName(type); | |
| 570 writeln(' private $patchTypeName $name;'); | |
| 571 } | |
| 572 | |
| 573 writeFieldInitializationFromData(Type type, String name) { | |
| 574 String camelName = camelize(name); | |
| 575 String patchTypeName = getPatchTypeName(type); | |
| 576 String dataGetter = 'updates.get(next++).get$camelName'; | |
| 577 writeln(' if (next < length && updates.get(next).is$camelName()) {'); | |
| 578 writeln(' $name = new $patchTypeName('); | |
| 579 writeln(' $dataGetter(), previous.get$camelName(), root);'); | |
| 580 writeln(' } else {'); | |
| 581 writeln(' $name = new $patchTypeName(previous.get$camelName());'); | |
| 582 writeln(' }'); | |
| 583 } | |
| 584 | |
| 585 writeActionGetter(_JavaActionWriter action) { | |
| 586 String name = action.method.name; | |
| 587 String camelName = camelize(name); | |
| 588 writeln(' public ${action.actionPatchName} get$camelName() {'); | |
| 589 writeln(' return $name;'); | |
| 590 writeln(' }'); | |
| 591 } | |
| 592 | |
| 593 writeActionBacking(_JavaActionWriter action) { | |
| 594 String name = action.method.name; | |
| 595 writeln(' private ${action.actionPatchName} $name;'); | |
| 596 } | |
| 597 | |
| 598 writeActionInitializationFromData(_JavaActionWriter action) { | |
| 599 String name = action.method.name; | |
| 600 String camelName = camelize(name); | |
| 601 String actionName = action.actionName; | |
| 602 String patchTypeName = action.actionPatchName; | |
| 603 String dataGetter = 'updates.get(next++).get$camelName'; | |
| 604 writeln(' if (next < length && updates.get(next).is$camelName()) {'); | |
| 605 writeln(' $name = new $patchTypeName('); | |
| 606 writeln(' new $actionName($dataGetter(), root),'); | |
| 607 writeln(' previous.get$camelName(),'); | |
| 608 writeln(' root);'); | |
| 609 writeln(' } else {'); | |
| 610 writeln(' $name = new $patchTypeName(previous.get$camelName());'); | |
| 611 writeln(' }'); | |
| 612 } | |
| 613 } | |
| 614 | |
| 615 class _AnyNodeWriter extends _JavaNodeBaseWriter { | |
| 616 final String nodeName = 'AnyNode'; | |
| 617 | |
| 618 _AnyNodeWriter(Map units) | |
| 619 : super('AnyNode', 'AnyNode') { | |
| 620 writeHeader([ | |
| 621 'dartino.NodeData', | |
| 622 ]); | |
| 623 writeln('public final class $nodeName implements Node {'); | |
| 624 writeln(); | |
| 625 writeln(' // Public interface.'); | |
| 626 writeln(); | |
| 627 writeln(' public boolean is(java.lang.Class clazz) {'); | |
| 628 writeln(' return clazz.isInstance(node);'); | |
| 629 writeln(' }'); | |
| 630 writeln(' public <T> T as(java.lang.Class<T> clazz) {'); | |
| 631 writeln(' return clazz.cast(node);'); | |
| 632 writeln(' }'); | |
| 633 writeln(); | |
| 634 writeln(' // Package private implementation.'); | |
| 635 writeln(); | |
| 636 writeln(' $nodeName(Node node) {'); | |
| 637 writeln(' this.node = node;'); | |
| 638 writeln(' }'); | |
| 639 writeln(); | |
| 640 writeln(' $nodeName(NodeData data, ImmiRoot root) {'); | |
| 641 writeln(' node = fromData(data, root);'); | |
| 642 writeln(' }'); | |
| 643 writeln(); | |
| 644 writeln(' static Node fromData(NodeData data, ImmiRoot root) {'); | |
| 645 units.values.forEach(visit); | |
| 646 writeln(' throw new RuntimeException("Invalid node-type tag");'); | |
| 647 writeln(' }'); | |
| 648 writeln(); | |
| 649 writeln(' Node getNode() { return node; }'); | |
| 650 writeln(); | |
| 651 writeln(' private Node node;'); | |
| 652 writeln('}'); | |
| 653 } | |
| 654 | |
| 655 visitUnit(Unit unit) { | |
| 656 unit.structs.forEach(visit); | |
| 657 } | |
| 658 | |
| 659 visitStruct(Struct node) { | |
| 660 write(' if (data.is${node.name}())'); | |
| 661 writeln(' return new ${node.name}Node(data.get${node.name}(), root);'); | |
| 662 } | |
| 663 } | |
| 664 | |
| 665 class _AnyNodePatchWriter extends _JavaNodeBaseWriter { | |
| 666 final String nodeName = 'AnyNode'; | |
| 667 | |
| 668 _AnyNodePatchWriter(Map units) | |
| 669 : super('AnyNode', 'AnyNodePatch') { | |
| 670 writeHeader([ | |
| 671 'dartino.NodePatchData', | |
| 672 ]); | |
| 673 write('public final class $patchName'); | |
| 674 writeln(' implements NodePatch<$nodeName, $presenterName> {'); | |
| 675 writeln(); | |
| 676 writeln(' // Public interface.'); | |
| 677 writeln(); | |
| 678 writeln(' @Override'); | |
| 679 write(' public boolean hasChanged()'); | |
| 680 writeln(' { return patch != null; }'); | |
| 681 writeln(' @Override'); | |
| 682 write(' public boolean wasReplaced()'); | |
| 683 writeln(' { return patch != null && patch.wasReplaced(); }'); | |
| 684 writeln(' @Override'); | |
| 685 write(' public boolean wasUpdated()'); | |
| 686 writeln(' { return patch != null && patch.wasUpdated(); }'); | |
| 687 writeln(); | |
| 688 writeln(' @Override'); | |
| 689 writeln(' public $nodeName getCurrent() { return current; }'); | |
| 690 writeln(' @Override'); | |
| 691 writeln(' public $nodeName getPrevious() { return previous; }'); | |
| 692 writeln(); | |
| 693 writeln(' @Override'); | |
| 694 writeln(' public void applyTo($presenterName presenter) {'); | |
| 695 writeln(' if (!hasChanged()) return;'); | |
| 696 writeln(' if (wasReplaced()) {'); | |
| 697 writeln(' presenter.present(current);'); | |
| 698 writeln(' } else {'); | |
| 699 writeln(' assert wasUpdated();'); | |
| 700 writeln(' presenter.patch(this);'); | |
| 701 writeln(' }'); | |
| 702 writeln(' }'); | |
| 703 writeln(); | |
| 704 writeln(' public boolean is(java.lang.Class clazz) {'); | |
| 705 writeln(' return clazz.isInstance(patch);'); | |
| 706 writeln(' }'); | |
| 707 writeln(' public <T> T as(java.lang.Class<T> clazz) {'); | |
| 708 writeln(' return clazz.cast(patch);'); | |
| 709 writeln(' }'); | |
| 710 writeln(); | |
| 711 writeln(' // Package private implementation.'); | |
| 712 writeln(); | |
| 713 writeln(' $patchName($nodeName previous) {'); | |
| 714 writeln(' this.previous = previous;'); | |
| 715 writeln(' current = previous;'); | |
| 716 writeln(' }'); | |
| 717 writeln(); | |
| 718 writeln(' $patchName('); | |
| 719 writeln(' NodePatchData data,'); | |
| 720 writeln(' $nodeName previous,'); | |
| 721 writeln(' ImmiRoot root) {'); | |
| 722 writeln(' Node node = previous == null ? null : previous.getNode();'); | |
| 723 writeln(' patch = fromData(data, node, root);'); | |
| 724 writeln(' current = new AnyNode(patch.getCurrent());'); | |
| 725 writeln(' this.previous = previous;'); | |
| 726 writeln(' }'); | |
| 727 writeln(); | |
| 728 writeln(' static NodePatch fromData('); | |
| 729 writeln(' NodePatchData data,'); | |
| 730 writeln(' Node previous,'); | |
| 731 writeln(' ImmiRoot root) {'); | |
| 732 // Create the patch based on the concrete type-tag. | |
| 733 units.values.forEach(visit); | |
| 734 writeln(' throw new RuntimeException("Unknown node-patch tag");'); | |
| 735 writeln(' }'); | |
| 736 writeln(); | |
| 737 writeln(' private NodePatch patch;'); | |
| 738 writeln(' private $nodeName current;'); | |
| 739 writeln(' private $nodeName previous;'); | |
| 740 writeln('}'); | |
| 741 } | |
| 742 | |
| 743 visitUnit(Unit unit) { | |
| 744 unit.structs.forEach(visit); | |
| 745 } | |
| 746 | |
| 747 visitStruct(Struct node) { | |
| 748 String name = node.name; | |
| 749 String patchName = '${name}Patch'; | |
| 750 String nodeName = '${name}Node'; | |
| 751 writeln(' if (data.is$name()) {'); | |
| 752 writeln(' $nodeName typedPrevious = null;'); | |
| 753 writeln(' if (previous instanceof $nodeName) {'); | |
| 754 writeln(' typedPrevious = ($nodeName)previous;'); | |
| 755 writeln(' }'); | |
| 756 writeln(' return new $patchName('); | |
| 757 writeln(' data.get$name(), typedPrevious, root);'); | |
| 758 writeln(' }'); | |
| 759 } | |
| 760 } | |
| OLD | NEW |