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

Side by Side Diff: tools/immic/lib/src/plugins/objc.dart

Issue 2035023003: Remove service-compiler related code. (Closed) Base URL: git@github.com:dartino/sdk.git@master
Patch Set: Created 4 years, 6 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 | « tools/immic/lib/src/plugins/java.dart ('k') | tools/immic/lib/src/plugins/shared.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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:path/path.dart' show basenameWithoutExtension, join, dirname;
11
12 import 'shared.dart';
13
14 import '../emitter.dart';
15 import '../primitives.dart' as primitives;
16 import '../struct_layout.dart';
17
18 const List<String> RESOURCES = const [
19 "ImmiBase.h",
20 ];
21
22 const COPYRIGHT = """
23 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
24 // for details. All rights reserved. Use of this source code is governed by a
25 // BSD-style license that can be found in the LICENSE.md file.
26 """;
27
28 const Map<String, String> _TYPES = const {
29 'void' : 'void',
30 'bool' : 'bool',
31
32 'uint8' : 'uint8_t',
33 'uint16' : 'uint16_t',
34
35 'int8' : 'int8_t',
36 'int16' : 'int16_t',
37 'int32' : 'int32_t',
38 'int64' : 'int64_t',
39
40 'float32' : 'float',
41 'float64' : 'double',
42
43 'String' : 'NSString*',
44 };
45
46 String getTypePointer(Type type) {
47 if (type.isNode) return 'Node*';
48 if (type.resolved != null) {
49 return "${type.identifier}Node*";
50 }
51 return _TYPES[type.identifier];
52 }
53
54 String getTypeName(Type type) {
55 if (type.isNode) return 'Node';
56 if (type.resolved != null) {
57 return "${type.identifier}Node";
58 }
59 return _TYPES[type.identifier];
60 }
61
62 void generate(String path, Map units, String outputDirectory) {
63 String directory = join(outputDirectory, "objc");
64 _generateHeaderFile(path, units, directory);
65 _generateImplementationFile(path, units, directory);
66
67 String resourcesDirectory = join(dirname(Platform.script.path),
68 '..', 'lib', 'src', 'resources', 'objc');
69 for (String resource in RESOURCES) {
70 String resourcePath = join(resourcesDirectory, resource);
71 File file = new File(resourcePath);
72 String contents = file.readAsStringSync();
73 writeToFile(directory, resource, contents);
74 }
75 }
76
77 void _generateHeaderFile(String path, Map units, String directory) {
78 _HeaderVisitor visitor = new _HeaderVisitor(path);
79 visitor.visitUnits(units);
80 String contents = visitor.buffer.toString();
81 String file = visitor.immiImplFile;
82 writeToFile(directory, file, contents, extension: 'h');
83 }
84
85 void _generateImplementationFile(String path, Map units, String directory) {
86 _ImplementationVisitor visitor = new _ImplementationVisitor(path);
87 visitor.visitUnits(units);
88 String contents = visitor.buffer.toString();
89 String file = visitor.immiImplFile;
90 writeToFile(directory, file, contents, extension: 'mm');
91 }
92
93 String getName(node) {
94 if (node is Struct) return node.name;
95 if (node is String) return node;
96 throw 'Invalid arg';
97 }
98
99 String applyToMethodName(node) {
100 return 'applyTo';
101 }
102
103 String presentMethodName(node) {
104 String name = getName(node);
105 return 'present${name}';
106 }
107
108 String patchMethodName(node) {
109 String name = getName(node);
110 return 'patch${name}';
111 }
112
113 String applyToMethodSignature(node) {
114 String name = getName(node);
115 return '- (void)${applyToMethodName(name)}:(id <${name}Presenter>)presenter' ;
116 }
117
118 String presentMethodSignature(node) {
119 String name = getName(node);
120 String type = name == 'Node' ? name : '${name}Node';
121 return '- (void)${presentMethodName(name)}:(${type}*)node';
122 }
123
124 String patchMethodSignature(node) {
125 String name = getName(node);
126 return '- (void)${patchMethodName(name)}:(${name}Patch*)patch';
127 }
128
129 String applyToMethodDeclaration(Struct node) {
130 return applyToMethodSignature(node) + ';';
131 }
132
133 String presentMethodDeclaration(Struct node) {
134 return presentMethodSignature(node) + ';';
135 }
136
137 String patchMethodDeclaration(Struct node) {
138 return patchMethodSignature(node) + ';';
139 }
140
141
142 abstract class _ObjCVisitor extends CodeGenerationVisitor {
143 _ObjCVisitor(String path) : super(path);
144
145 String immiBaseFile = 'ImmiBase.h';
146 String immiImplFile = 'Immi.h';
147 }
148
149 class _HeaderVisitor extends _ObjCVisitor {
150 _HeaderVisitor(String path) : super(path);
151
152 List nodes = [];
153
154 visitUnits(Map units) {
155 units.values.forEach(collectMethodSignatures);
156 units.values.forEach((unit) { nodes.addAll(unit.structs); });
157 _writeHeader();
158 nodes.forEach((node) { writeln('@class ${node.name}Node;'); });
159 writeln();
160 nodes.forEach((node) { writeln('@class ${node.name}Patch;'); });
161 writeln();
162 _writeActions();
163 units.values.forEach(visit);
164 }
165
166 visitUnit(Unit unit) {
167 unit.structs.forEach(visit);
168 }
169
170 visitStruct(Struct node) {
171 StructLayout layout = node.layout;
172 String nodeName = "${node.name}Node";
173 String nodeNameData = "${nodeName}Data";
174 String patchName = "${node.name}Patch";
175 String patchNameData = "${nodeName}PatchData";
176 String presenterName = "${node.name}Presenter";
177 writeln('@protocol $presenterName');
178 writeln(presentMethodDeclaration(node));
179 writeln(patchMethodDeclaration(node));
180 writeln('@end');
181 writeln();
182 writeln('@interface $nodeName : NSObject <Node>');
183 forEachSlot(node, null, (Type slotType, String slotName) {
184 write('@property (readonly) ');
185 _writeNSType(slotType);
186 writeln(' $slotName;');
187 });
188 for (var method in node.methods) {
189 List<Type> formalTypes = method.arguments.map((formal) => formal.type);
190 String actionBlock = 'Action${actionTypeSuffix(formalTypes)}Block';
191 writeln('@property (readonly) $actionBlock ${method.name};');
192 }
193 writeln('@end');
194 writeln();
195 writeln('@interface $patchName : NSObject <NodePatch>');
196 writeln('@property (readonly) bool changed;');
197 writeln('@property (readonly) $nodeName* previous;');
198 writeln('@property (readonly) $nodeName* current;');
199 forEachSlot(node, null, (Type slotType, String slotName) {
200 writeln('@property (readonly) ${patchType(slotType)}* $slotName;');
201 });
202 for (var method in node.methods) {
203 String actionPatch = actionPatchType(method);
204 writeln('@property (readonly) $actionPatch* ${method.name};');
205 }
206 writeln(applyToMethodDeclaration(node));
207 writeln('@end');
208 writeln();
209 }
210
211 void _writeFormalWithKeyword(String keyword, Formal formal) {
212 write('$keyword:(${getTypeName(formal.type)})${formal.name}');
213 }
214
215 _writeActions() {
216 for (List<Type> formals in methodSignatures.values) {
217 String actionName = 'Action${actionTypeSuffix(formals)}';
218 String actionBlock = '${actionName}Block';
219 String actionPatch = '${actionName}Patch';
220 write('typedef void (^$actionBlock)(${actionTypeFormals(formals)});');
221 writeln();
222 writeln('@interface $actionPatch : NSObject <Patch>');
223 writeln('@property (readonly) $actionBlock current;');
224 writeln('@end');
225 writeln();
226 }
227 }
228
229 void _writeNSType(Type type) {
230 if (type.isList) {
231 write('NSArray*');
232 } else {
233 write(getTypePointer(type));
234 }
235 }
236
237 void _writeHeader() {
238 writeln(COPYRIGHT);
239 writeln('// Generated file. Do not edit.');
240 writeln();
241 writeln('#import "$immiBaseFile"');
242 writeln();
243 }
244
245 String patchType(Type type) {
246 if (type.isList) return 'ListPatch';
247 return '${camelize(type.identifier)}Patch';
248 }
249
250 String actionTypeSuffix(List<Type> types) {
251 if (types.isEmpty) return 'Void';
252 return types.map((Type type) => camelize(type.identifier)).join();
253 }
254
255 String actionTypeFormals(List<Type> types) {
256 return types.map((Type type) => getTypeName(type)).join(', ');
257 }
258
259 String actionPatchType(Method method) {
260 List<Type> types = method.arguments.map((formal) => formal.type);
261 return 'Action${actionTypeSuffix(types)}Patch';
262 }
263
264 String actionBlockType(Method method) {
265 List<Type> types = method.arguments.map((formal) => formal.type);
266 return 'Action${actionTypeSuffix(types)}Block';
267 }
268 }
269
270 class _ImplementationVisitor extends _ObjCVisitor {
271 _ImplementationVisitor(String path) : super(path);
272
273 List<Struct> nodes = [];
274
275 visitUnits(Map units) {
276 units.values.forEach(collectMethodSignatures);
277 units.values.forEach((unit) { nodes.addAll(unit.structs); });
278 _writeHeader();
279
280 _writeNodeBaseExtendedInterface();
281 _writePatchBaseExtendedInterface();
282 _writePatchPrimitivesExtendedInterface();
283 _writeActionsExtendedInterface();
284 units.values.forEach((unit) {
285 unit.structs.forEach(_writeNodeExtendedInterface);
286 });
287
288 _writeImmiServiceExtendedInterface();
289 _writeImmiRootExtendedInterface();
290
291 _writeEventUtils();
292 _writeStringUtils();
293 _writeListUtils();
294
295 _writeNodeBaseImplementation();
296 _writePatchBaseImplementation();
297 _writePatchPrimitivesImplementation();
298 _writeActionsImplementation();
299 units.values.forEach((unit) {
300 unit.structs.forEach(_writeNodeImplementation);
301 });
302
303 _writeImmiServiceImplementation();
304 _writeImmiRootImplementation();
305 }
306
307 visitUnit(Unit unit) {
308 // Everything is done in visitUnits.
309 }
310
311 _writeImmiServiceExtendedInterface() {
312 writeln('@interface ImmiService ()');
313 writeln('@property NSMutableArray* storyboards;');
314 writeln('@property NSMutableDictionary* roots;');
315 writeln('@end');
316 writeln();
317 }
318
319 _writeImmiServiceImplementation() {
320 writeln('@implementation ImmiService');
321 writeln();
322 writeln('- (id)init {');
323 writeln(' self = [super init];');
324 writeln(' _storyboards = [NSMutableArray array];');
325 writeln(' _roots = [NSMutableDictionary dictionary];');
326 writeln(' return self;');
327 writeln('}');
328 writeln();
329 writeln('- (ImmiRoot*)registerPresenter:(id <NodePresenter>)presenter');
330 writeln(' forName:(NSString*)name {');
331 writeln(' assert(self.roots[name] == nil);');
332 writeln(' int length = name.length;');
333 writeln(' int size = 48 + PresenterDataBuilder::kSize + length;');
334 writeln(' MessageBuilder message(size);');
335 writeln(' PresenterDataBuilder builder =');
336 writeln(' message.initRoot<PresenterDataBuilder>();');
337 writeln(' List<unichar> chars = builder.initNameData(length);');
338 writeln(' [name getCharacters:chars.data()');
339 writeln(' range:NSMakeRange(0, length)];');
340 writeln(' uint16_t pid = ImmiServiceLayer::getPresenter(builder);');
341 writeln(' ImmiRoot* root =');
342 writeln(' [[ImmiRoot alloc] init:pid presenter:presenter];');
343 writeln(' self.roots[name] = root;');
344 writeln(' return root;');
345 writeln('}');
346 writeln();
347 writeln('- (void)registerStoryboard:(UIStoryboard*)storyboard {');
348 writeln(' [self.storyboards addObject:storyboard];');
349 writeln('}');
350 writeln();
351 writeln('- (ImmiRoot*)getRootByName:(NSString*)name {');
352 writeln(' ImmiRoot* root = self.roots[name];');
353 writeln(' if (root != nil) return root;');
354 writeln(' id <NodePresenter> presenter = nil;');
355 writeln(' for (int i = 0; i < self.storyboards.count; ++i) {');
356 writeln(' @try {');
357 writeln(' presenter = [self.storyboards[i]');
358 writeln(' instantiateViewControllerWithIdentifier:name];');
359 writeln(' break;');
360 writeln(' }');
361 writeln(' @catch (NSException* e) {');
362 writeln(' if (e.name != NSInvalidArgumentException) {');
363 writeln(' @throw e;');
364 writeln(' }');
365 writeln(' }');
366 writeln(' }');
367 writeln(' if (presenter == nil) abort();');
368 writeln(' return [self registerPresenter:presenter forName:name];');
369 writeln('}');
370 writeln();
371 writeln('- (id <NodePresenter>)getPresenterByName:(NSString*)name {');
372 writeln(' return [[self getRootByName:name] presenter];');
373 writeln('}');
374 writeln();
375 writeln('@end');
376 writeln();
377 }
378
379 _writeImmiRootExtendedInterface() {
380 writeln('@interface ImmiRoot ()');
381 writeln('@property (readonly) uint16_t pid;');
382 writeln('@property (readonly) id <NodePresenter> presenter;');
383 writeln('@property Node* previous;');
384 writeln('@property bool refreshPending;');
385 writeln('@property bool refreshRequired;');
386 writeln('@property (nonatomic) dispatch_queue_t refreshQueue;');
387 writeln('- (id)init:(uint16_t)pid presenter:(id <NodePresenter>)presenter;') ;
388 writeln('@end');
389 writeln();
390 }
391
392 _writeImmiRootImplementation() {
393 writeln('typedef void (^ImmiRefreshCallback)(const PatchData&);');
394 writeln('void ImmiRefresh(PatchData patchData, void* callbackData) {');
395 writeln(' @autoreleasepool {');
396 writeln(' ImmiRefreshCallback block =');
397 writeln(' (__bridge_transfer ImmiRefreshCallback)callbackData;');
398 writeln(' block(patchData);');
399 writeln(' patchData.Delete();');
400 writeln(' }');
401 writeln('}');
402 writeln('@implementation ImmiRoot');
403 writeln();
404 writeln('- (id)init:(uint16_t)pid');
405 writeln(' presenter:(id <NodePresenter>)presenter {');
406 writeln(' self = [super init];');
407 writeln(' assert(pid > 0);');
408 writeln(' _pid = pid;');
409 writeln(' _presenter = presenter;');
410 writeln(' _refreshPending = false;');
411 writeln(' _refreshRequired = false;');
412 writeln(' _refreshQueue = dispatch_queue_create(');
413 writeln(' "com.google.immi.refreshQueue", DISPATCH_QUEUE_SERIAL);');
414 writeln(' return self;');
415 writeln('}');
416 writeln();
417 writeln('- (void)refresh {');
418 writeln(' ImmiRefreshCallback doApply = ^(const PatchData& patchData) {');
419 writeln(' if (patchData.isNode()) {');
420 writeln(' NodePatch* patch = [[NodePatch alloc]');
421 writeln(' initWith:patchData.getNode()');
422 writeln(' previous:self.previous');
423 writeln(' inGraph:self];');
424 writeln(' self.previous = patch.current;');
425 writeln(' [patch applyTo:self.presenter];');
426 writeln(' }');
427 writeln(' dispatch_async(self.refreshQueue, ^{');
428 writeln(' if (self.refreshRequired) {');
429 writeln(' self.refreshRequired = false;');
430 writeln(' [self refresh];');
431 writeln(' } else {');
432 writeln(' self.refreshPending = false;');
433 writeln(' }');
434 writeln(' });');
435 writeln(' };');
436 writeln(' ${serviceName}::refreshAsync(');
437 writeln(' self.pid,');
438 writeln(' ImmiRefresh,');
439 writeln(' (__bridge_retained void*)[doApply copy]);');
440 writeln('}');
441 writeln();
442 writeln('- (void)reset {');
443 writeln(' ${serviceName}::reset(self.pid);');
444 writeln('}');
445 writeln();
446 writeln('- (void)dispatch:(ImmiDispatchBlock)block {');
447 writeln(' block();');
448 writeln(' [self requestRefresh];');
449 writeln('}');
450 writeln();
451 writeln('- (void)requestRefresh {');
452 writeln(' dispatch_async(self.refreshQueue, ^{');
453 writeln(' if (self.refreshPending) {');
454 writeln(' self.refreshRequired = true;');
455 writeln(' } else {');
456 writeln(' self.refreshPending = true;');
457 writeln(' [self refresh];');
458 writeln(' }');
459 writeln(' });');
460 writeln('}');
461 writeln();
462 writeln('@end');
463 writeln();
464 }
465
466 _writeNodeExtendedInterface(Struct node) {
467 String name = node.name;
468 String nodeName = "${name}Node";
469 String patchName = "${name}Patch";
470 String nodeDataName = "${nodeName}Data";
471 String patchDataName = "${patchName}Data";
472 writeln('@interface $nodeName ()');
473 if (node.methods.isNotEmpty) {
474 writeln('@property (weak) ImmiRoot* root;');
475 }
476 writeln('- (id)initWith:(const $nodeDataName&)data');
477 writeln(' inGraph:(ImmiRoot*)root;');
478 writeln('- (id)initWithPatch:($patchName*)patch;');
479 writeln('@end');
480 writeln();
481 writeln('@interface $patchName ()');
482 writeln('- (id)initIdentityPatch:($nodeName*)previous;');
483 writeln('- (id)initWith:(const $patchDataName&)data');
484 writeln(' previous:($nodeName*)previous');
485 writeln(' inGraph:(ImmiRoot*)root;');
486 writeln('@end');
487 writeln();
488 }
489
490 _writeNodeImplementation(Struct node) {
491 String name = node.name;
492 String nodeName = "${node.name}Node";
493 String patchName = "${node.name}Patch";
494 String nodeDataName = "${nodeName}Data";
495 String patchDataName = "${patchName}Data";
496 String updateDataName = "${node.name}UpdateData";
497 writeln('@implementation $nodeName');
498 writeln('- (id)initWith:(const $nodeDataName&)data');
499 writeln(' inGraph:(ImmiRoot*)root {');
500 writeln(' self = [super init];');
501 forEachSlot(node, null, (Type slotType, String slotName) {
502 String camelName = camelize(slotName);
503 write(' _$slotName = ');
504 if (slotType.isList) {
505 String slotTypeName = getTypeName(slotType.elementType.isNode ?
506 slotType.elementType :
507 slotType);
508 String slotTypeData = "${slotTypeName}Data";
509 writeln('ListUtils<$slotTypeData>::decodeList(');
510 writeln(' data.get${camelName}(), create$slotTypeName, root);');
511 } else if (slotType.isString) {
512 writeln('decodeString(data.get${camelName}Data());');
513 } else if (slotType.isNode || slotType.resolved != null) {
514 String slotTypeName = getTypeName(slotType);
515 writeln('[[$slotTypeName alloc] initWith:data.get${camelName}()');
516 writeln(' inGraph:(ImmiRoot*)root];');
517 } else {
518 writeln('data.get${camelName}();');
519 }
520 });
521 for (var method in node.methods) {
522 String actionId = '${method.name}Id';
523 writeln(' uint16_t $actionId = data.get${camelize(method.name)}();');
524 write(' _${method.name} = ');
525 List<Type> formals = method.arguments.map((formal) => formal.type);
526 _writeActionBlockImplementation(actionId, formals);
527 writeln(';');
528 }
529 writeln(' return self;');
530 writeln('}');
531
532 writeln('- (id)initWithPatch:($patchName*)patch {');
533 writeln(' self = [super init];');
534 forEachSlot(node, null, (Type slotType, String slotName) {
535 writeln(' _$slotName = patch.$slotName.current;');
536 });
537 for (Method method in node.methods) {
538 String name = method.name;
539 writeln(' _$name = patch.$name.current;');
540 }
541 writeln(' return self;');
542 writeln('}');
543 writeln('@end');
544 writeln();
545 writeln('@implementation $patchName {');
546 writeln(' NodePatchType _type;');
547 writeln('}');
548 writeln('- (id)initIdentityPatch:($nodeName*)previous {');
549 writeln(' self = [super init];');
550 writeln(' _type = kIdentityNodePatch;');
551 writeln(' _previous = previous;');
552 writeln(' _current = previous;');
553 writeln(' return self;');
554 writeln('}');
555 writeln('- (id)initWith:(const $patchDataName&)data');
556 writeln(' previous:($nodeName*)previous');
557 writeln(' inGraph:(ImmiRoot*)root {');
558 writeln(' self = [super init];');
559 writeln(' _previous = previous;');
560 if (node.layout.slots.isNotEmpty || node.methods.isNotEmpty) {
561 // The updates list is ordered consistently with the struct fields.
562 writeln(' if (data.isUpdates()) {');
563 writeln(' List<$updateDataName> updates = data.getUpdates();');
564 writeln(' int length = updates.length();');
565 writeln(' int next = 0;');
566 forEachSlotAndMethod(node, null, (field, String name) {
567 String camelName = camelize(name);
568 String fieldPatchType =
569 field is Method ? actionPatchType(field) : patchType(field.type);
570 writeln(' if (next < length && updates[next].is${camelName}()) {');
571 writeln(' _$name = [[$fieldPatchType alloc]');
572 write(' ');
573 String dataGetter = 'updates[next++].get${camelName}';
574 if (field is Formal && !field.type.isList && field.type.isString) {
575 writeln('initWith:decodeString(${dataGetter}Data())');
576 } else {
577 writeln('initWith:$dataGetter()');
578 }
579 writeln(' previous:previous.$name');
580 writeln(' inGraph:root];');
581 writeln(' } else {');
582 writeln(' _$name = [[$fieldPatchType alloc]');
583 writeln(' initIdentityPatch:previous.$name];');
584 writeln(' }');
585 });
586 writeln(' assert(next == length);');
587 writeln(' _type = kUpdateNodePatch;');
588 writeln(' _current = [[$nodeName alloc] initWithPatch:self];');
589 writeln(' return self;');
590 writeln(' }');
591 }
592 writeln(' assert(data.isReplace());');
593 writeln(' _type = kReplaceNodePatch;');
594 writeln(' _current = [[$nodeName alloc] initWith:data.getReplace()');
595 writeln(' inGraph:root];');
596 // For replace patches we leave fields and methods as default initialized.
597 writeln(' return self;');
598 writeln('}');
599
600 writeln('- (bool)changed { return _type != kIdentityNodePatch; }');
601 writeln('- (bool)replaced { return _type == kReplaceNodePatch; }');
602 writeln('- (bool)updated { return _type == kUpdateNodePatch; }');
603 write(applyToMethodSignature(node));
604 writeln(' {');
605 writeln(' if (!self.changed) return;');
606 writeln(' if (self.replaced) {');
607 writeln(' [presenter present${node.name}:self.current];');
608 writeln(' } else {');
609 writeln(' [presenter patch${node.name}:self];');
610 writeln(' }');
611 writeln('}');
612 writeln('@end');
613 writeln();
614 }
615
616 void _writeNodeBaseExtendedInterface() {
617 writeln('@interface Node ()');
618 writeln('@property (readonly) id <Node> node;');
619 writeln('- (id)init:(id <Node>)node;');
620 writeln('- (id)initWith:(const NodeData&)data');
621 writeln(' inGraph:(ImmiRoot*)root;');
622 writeln('+ (id <Node>)createNode:(const NodeData&)data');
623 writeln(' inGraph:(ImmiRoot*)root;');
624 writeln('@end');
625 writeln();
626 }
627
628 void _writeNodeBaseImplementation() {
629 writeln('@implementation Node');
630 writeln('- (bool)is:(Class)klass {');
631 writeln(' return [self.node isMemberOfClass:klass];');
632 writeln('}');
633 writeln('- (id)as:(Class)klass {');
634 writeln(' assert([self is:klass]);');
635 writeln(' return self.node;');
636 writeln('}');
637 writeln('- (id)init:(id <Node>)node {');
638 writeln(' self = [super init];');
639 writeln(' _node = node;');
640 writeln(' return self;');
641 writeln('}');
642 writeln('- (id)initWith:(const NodeData&)data');
643 writeln(' inGraph:(ImmiRoot*)root {');
644 writeln(' return [self init:[Node createNode:data inGraph:root]];');
645 writeln('}');
646 writeln('+ (id <Node>)createNode:(const NodeData&)data');
647 writeln(' inGraph:(ImmiRoot*)root {');
648 nodes.forEach((node) {
649 writeln(' if (data.is${node.name}()) {');
650 writeln(' return [[${node.name}Node alloc]');
651 writeln(' initWith:data.get${node.name}()');
652 writeln(' inGraph:root];');
653 writeln(' }');
654 });
655 writeln(' abort();');
656 writeln('}');
657 writeln('@end');
658 writeln();
659 }
660
661 void _writePatchBaseExtendedInterface() {
662 writeln('typedef enum { kIdentityNodePatch, kReplaceNodePatch, kUpdateNodePa tch } NodePatchType;');
663 writeln('@interface NodePatch ()');
664 writeln('@property (readonly) id <NodePatch> patch;');
665 writeln('@property (readonly) Node* node;');
666 writeln('- (id)initIdentityPatch:(Node*)previous;');
667 writeln('- (id)initWith:(const NodePatchData&)data');
668 writeln(' previous:(Node*)previous');
669 writeln(' inGraph:(ImmiRoot*)root;');
670 writeln('+ (id <NodePatch>)createPatch:(const NodePatchData&)data');
671 writeln(' previous:(id <Node>)previous');
672 writeln(' inGraph:(ImmiRoot*)root;');
673 writeln('@end');
674 writeln();
675 }
676
677 void _writePatchBaseImplementation() {
678 writeln('@implementation NodePatch {');
679 writeln(' NodePatchType _type;');
680 writeln('}');
681 writeln('+ (id <NodePatch>)createPatch:(const NodePatchData&)data');
682 writeln(' previous:(id <Node>)previous');
683 writeln(' inGraph:(ImmiRoot*)root {');
684 nodes.forEach((node) {
685 String name = node.name;
686 String nodeName = '${name}Node';
687 String patchName = '${name}Patch';
688 writeln(' if (data.is$name()) {');
689 writeln(' $nodeName* previousNode =');
690 writeln(' [previous isMemberOfClass:$nodeName.class] ?');
691 writeln(' previous :');
692 writeln(' nil;');
693 writeln(' return [[$patchName alloc]');
694 writeln(' initWith:data.get$name()');
695 writeln(' previous:previousNode');
696 writeln(' inGraph:root];');
697 writeln(' }');
698 });
699 writeln(' abort();');
700 writeln('}');
701 writeln('- (id)initIdentityPatch:(Node*)previous {');
702 writeln(' self = [super init];');
703 writeln(' _type = kIdentityNodePatch;');
704 writeln(' _previous = previous;');
705 writeln(' _current = previous;');
706 writeln(' return self;');
707 writeln('}');
708 writeln('- (id)initWith:(const NodePatchData&)data');
709 writeln(' previous:(Node*)previous');
710 writeln(' inGraph:(ImmiRoot*)root {');
711 writeln(' self = [super init];');
712 writeln(' _previous = previous;');
713 writeln(' _patch = [NodePatch');
714 writeln(' createPatch:data');
715 writeln(' previous:previous.node');
716 writeln(' inGraph:root];');
717 writeln(' _type = _patch.replaced ? kReplaceNodePatch : kUpdateNodePatch;') ;
718 writeln(' _current = [[Node alloc] init:_patch.current];');
719 writeln(' return self;');
720 writeln('}');
721 writeln();
722 writeln('- (bool)changed { return _type != kIdentityNodePatch; }');
723 writeln('- (bool)replaced { return _type == kReplaceNodePatch; }');
724 writeln('- (bool)updated { return _type == kUpdateNodePatch; }');
725 writeln();
726 write(applyToMethodSignature('Node'));
727 writeln(' {');
728 writeln(' if (!self.changed) return;');
729 writeln(' if (self.replaced) {');
730 writeln(' [presenter presentNode:self.current];');
731 writeln(' } else {');
732 writeln(' [presenter patchNode:self];');
733 writeln(' }');
734 writeln('}');
735 writeln('- (bool)is:(Class)klass {');
736 writeln(' return [self.patch isMemberOfClass:klass];');
737 writeln('}');
738 writeln('- (id)as:(Class)klass {');
739 writeln(' assert([self is:klass]);');
740 writeln(' return self.patch;');
741 writeln('}');
742 writeln('@end');
743 writeln();
744 }
745
746 void _writePatchPrimitivesExtendedInterface() {
747 _TYPES.forEach((String idlType, String objcType) {
748 if (idlType == 'void') return;
749 String patchTypeName = '${camelize(idlType)}Patch';
750 String patchDataName = objcType;
751 writeln('@interface $patchTypeName ()');
752 writeln('- (id)initIdentityPatch:($objcType)previous;');
753 writeln('- (id)initWith:($patchDataName)data');
754 writeln(' previous:($objcType)previous');
755 writeln(' inGraph:(ImmiRoot*)root;');
756 writeln('@end');
757 writeln();
758 });
759
760 writeln('typedef enum { kAnyNode, kSpecificNode } ListPatchType;');
761 writeln();
762 writeln('@interface ListRegionPatch ()');
763 writeln('@property (readonly) int countDelta;');
764 writeln('- (int)applyTo:(NSMutableArray*)outArray');
765 writeln(' with:(NSArray*)inArray;');
766 writeln('+ (ListRegionPatch*)regionPatch:(const ListRegionData&)data');
767 writeln(' type:(ListPatchType)type');
768 writeln(' previous:(NSArray*)previous');
769 writeln(' inGraph:(ImmiRoot*)root;');
770 writeln('@end');
771 writeln('@interface ListRegionRemovePatch ()');
772 writeln('- (id)initWith:(const ListRegionData&)data');
773 writeln(' type:(ListPatchType)type');
774 writeln(' inGraph:(ImmiRoot*)root;');
775 writeln('@end');
776 writeln('@interface ListRegionInsertPatch ()');
777 writeln('- (id)initWith:(const ListRegionData&)data');
778 writeln(' type:(ListPatchType)type');
779 writeln(' inGraph:(ImmiRoot*)root;');
780 writeln('@end');
781 writeln('@interface ListRegionUpdatePatch ()');
782 writeln('- (id)initWith:(const ListRegionData&)data');
783 writeln(' type:(ListPatchType)type');
784 writeln(' previous:(NSArray*)previous');
785 writeln(' inGraph:(ImmiRoot*)root;');
786 writeln('@end');
787
788 writeln('@interface ListPatch ()');
789 writeln('- (id)initIdentityPatch:(NSArray*)previous;');
790 writeln('- (id)initWith:(const ListPatchData&)data');
791 writeln(' previous:(NSArray*)previous');
792 writeln(' inGraph:(ImmiRoot*)root;');
793 writeln('@end');
794 writeln();
795 }
796
797 void _writePatchPrimitivesImplementation() {
798 _TYPES.forEach((String idlType, String objcType) {
799 if (idlType == 'void') return;
800 String patchTypeName = '${camelize(idlType)}Patch';
801 String patchDataName = objcType;
802 writeln('@implementation $patchTypeName');
803 writeln('- (id)initIdentityPatch:($objcType)previous {');
804 writeln(' self = [super init];');
805 writeln(' _previous = previous;');
806 writeln(' _current = previous;');
807 writeln(' return self;');
808 writeln('}');
809 writeln('- (id)initWith:($patchDataName)data');
810 writeln(' previous:($objcType)previous');
811 writeln(' inGraph:(ImmiRoot*)root {');
812 writeln(' self = [super init];');
813 writeln(' _previous = previous;');
814 writeln(' _current = data;');
815 writeln(' return self;');
816 writeln('}');
817 writeln('- (bool)changed {');
818 writeln(' return _previous != _current;');
819 writeln('}');
820 writeln('@end');
821 writeln();
822 });
823
824 writeln('@implementation ListRegionPatch');
825 writeln('+ (ListRegionPatch*)regionPatch:(const ListRegionData&)data');
826 writeln(' type:(ListPatchType)type');
827 writeln(' previous:(NSArray*)previous');
828 writeln(' inGraph:(ImmiRoot*)root {');
829 writeln(' if (data.isRemove()) {');
830 writeln(' return [[ListRegionRemovePatch alloc] initWith:data');
831 writeln(' type:type');
832 writeln(' inGraph:root];');
833 writeln(' }');
834 writeln(' if (data.isInsert()) {');
835 writeln(' return [[ListRegionInsertPatch alloc] initWith:data');
836 writeln(' type:type');
837 writeln(' inGraph:root];');
838 writeln(' }');
839 writeln(' NSAssert(data.isUpdate(), @"Invalid list patch for region");');
840 writeln(' return [[ListRegionUpdatePatch alloc] initWith:data');
841 writeln(' type:type');
842 writeln(' previous:previous');
843 writeln(' inGraph:root];');
844 writeln('}');
845 writeln('- (id)init:(int)index {');
846 writeln(' self = [super init];');
847 writeln(' _index = index;');
848 writeln(' return self;');
849 writeln('}');
850 writeln('- (bool)isRemove { return false; }');
851 writeln('- (bool)isInsert { return false; }');
852 writeln('- (bool)isUpdate { return false; }');
853 writeln('- (int)applyTo:(NSMutableArray*)outArray');
854 writeln(' with:(NSArray*)inArray {');
855 writeln(' @throw [NSException');
856 writeln(' exceptionWithName:NSInternalInconsistencyException');
857 writeln(' reason:@"-applyTo:with: base is abstract"');
858 writeln(' userInfo:nil];');
859 writeln('}');
860 writeln('@end');
861 writeln();
862 writeln('@implementation ListRegionRemovePatch');
863 writeln('- (id)initWith:(const ListRegionData&)data');
864 writeln(' type:(ListPatchType)type');
865 writeln(' inGraph:(ImmiRoot*)root {');
866 writeln(' self = [super init:data.getIndex()];');
867 writeln(' _count = data.getRemove();');
868 writeln(' return self;');
869 writeln('}');
870 writeln('- (bool)isRemove { return true; }');
871 writeln('- (int)countDelta { return -self.count; }');
872 writeln('- (int)applyTo:(NSMutableArray*)outArray');
873 writeln(' with:(NSArray*)inArray {');
874 writeln(' return self.count;');
875 writeln('}');
876 writeln('@end');
877 writeln();
878 writeln('@implementation ListRegionInsertPatch');
879 writeln('- (id)initWith:(const ListRegionData&)data');
880 writeln(' type:(ListPatchType)type');
881 writeln(' inGraph:(ImmiRoot*)root {');
882 writeln(' self = [super init:data.getIndex()];');
883 writeln(' const List<NodeData>& insertData = data.getInsert();');
884 writeln(' NSMutableArray* nodes =');
885 writeln(' [NSMutableArray arrayWithCapacity:insertData.length()];');
886 writeln(' int length = insertData.length();');
887 writeln(' if (type == kAnyNode) {');
888 writeln(' for (int i = 0; i < length; ++i) {');
889 writeln(' nodes[i] = [[Node alloc] initWith:insertData[i]');
890 writeln(' inGraph:root];');
891 writeln(' }');
892 writeln(' } else {');
893 writeln(' assert(type == kSpecificNode);');
894 writeln(' for (int i = 0; i < length; ++i) {');
895 writeln(' nodes[i] = [Node createNode:insertData[i] inGraph:root];');
896 writeln(' }');
897 writeln(' }');
898 writeln(' _nodes = nodes;');
899 writeln(' return self;');
900 writeln('}');
901 writeln('- (bool)isInsert { return true; }');
902 writeln('- (int)countDelta { return self.nodes.count; }');
903 writeln('- (int)applyTo:(NSMutableArray*)outArray');
904 writeln(' with:(NSArray*)inArray {');
905 writeln(' [outArray addObjectsFromArray:self.nodes];');
906 writeln(' return 0;');
907 writeln('}');
908 writeln('@end');
909 writeln();
910 writeln('@implementation ListRegionUpdatePatch');
911 writeln('- (id)initWith:(const ListRegionData&)data');
912 writeln(' type:(ListPatchType)type');
913 writeln(' previous:(NSArray*)previous');
914 writeln(' inGraph:(ImmiRoot*)root {');
915 writeln(' self = [super init:data.getIndex()];');
916 writeln(' const List<NodePatchData>& updateData = data.getUpdate();');
917 writeln(' int length = updateData.length();');
918 writeln(' NSMutableArray* updates =');
919 writeln(' [NSMutableArray arrayWithCapacity:length];');
920 writeln(' if (type == kAnyNode) {');
921 writeln(' for (int i = 0; i < length; ++i) {');
922 writeln(' updates[i] = [[NodePatch alloc]');
923 writeln(' initWith:updateData[i]');
924 writeln(' previous:previous[self.index + i]');
925 writeln(' inGraph:root];');
926 writeln(' }');
927 writeln(' } else {');
928 writeln(' assert(type == kSpecificNode);');
929 writeln(' for (int i = 0; i < length; ++i) {');
930 writeln(' updates[i] = [NodePatch');
931 writeln(' createPatch:updateData[i]');
932 writeln(' previous:previous[self.index + i]');
933 writeln(' inGraph:root];');
934 writeln(' }');
935 writeln(' }');
936 writeln(' _updates = updates;');
937 writeln(' return self;');
938 writeln('}');
939 writeln('- (bool)isUpdate { return true; }');
940 writeln('- (int)countDelta { return 0; }');
941 writeln('- (int)applyTo:(NSMutableArray*)outArray');
942 writeln(' with:(NSArray*)inArray {');
943 writeln(' int length = self.updates.count;');
944 writeln(' for (int i = 0; i < length; ++i) {');
945 writeln(' id <NodePatch> patch = self.updates[i];');
946 writeln(' [outArray addObject:patch.current];');
947 writeln(' }');
948 writeln(' return length;');
949 writeln('}');
950 writeln('@end');
951 writeln();
952 writeln('@implementation ListPatch {');
953 writeln(' NSMutableArray* _regions;');
954 writeln('}');
955 writeln('- (id)initIdentityPatch:(NSArray*)previous {');
956 writeln(' self = [super init];');
957 writeln(' _changed = false;');
958 writeln(' _previous = previous;');
959 writeln(' _current = previous;');
960 writeln(' return self;');
961 writeln('}');
962 writeln('- (id)initWith:(const ListPatchData&)data');
963 writeln(' previous:(NSArray*)previous');
964 writeln(' inGraph:(ImmiRoot*)root {');
965 writeln(' self = [super init];');
966 writeln(' _changed = true;');
967 writeln(' _previous = previous;');
968 writeln(' ListPatchType type = (ListPatchType)data.getType();');
969 writeln(' const List<ListRegionData>& regions = data.getRegions();');
970 writeln(' NSMutableArray* patches =');
971 writeln(' [NSMutableArray arrayWithCapacity:regions.length()];');
972 writeln(' for (int i = 0; i < regions.length(); ++i) {');
973 writeln(' patches[i] =');
974 writeln(' [ListRegionPatch regionPatch:regions[i]');
975 writeln(' type:type');
976 writeln(' previous:previous');
977 writeln(' inGraph:root];');
978 writeln(' }');
979 writeln(' _regions = patches;');
980 writeln(' _current = [self applyWith:previous];');
981 writeln(' return self;');
982 writeln('}');
983 writeln('- (NSArray*)applyWith:(NSArray*)array {');
984 writeln(' int newCount = array.count;');
985 writeln(' for (int i = 0; i < self.regions.count; ++i) {');
986 writeln(' ListRegionPatch* patch = self.regions[i];');
987 writeln(' newCount += patch.countDelta;');
988 writeln(' }');
989 writeln(' int sourceIndex = 0;');
990 writeln(' NSMutableArray* newArray =');
991 writeln(' [NSMutableArray arrayWithCapacity:newCount];');
992 writeln(' for (int i = 0; i < self.regions.count; ++i) {');
993 writeln(' ListRegionPatch* patch = self.regions[i];');
994 writeln(' while (sourceIndex < patch.index) {');
995 writeln(' [newArray addObject:array[sourceIndex++]];');
996 writeln(' }');
997 writeln(' sourceIndex += [patch applyTo:newArray with:array];');
998 writeln(' }');
999 writeln(' while (sourceIndex < array.count) {');
1000 writeln(' [newArray addObject:array[sourceIndex++]];');
1001 writeln(' }');
1002 writeln(' return newArray;');
1003 writeln('}');
1004 writeln('@end');
1005 writeln();
1006 }
1007
1008 void _writeActionsExtendedInterface() {
1009 for (List<Type> formals in methodSignatures.values) {
1010 String actionName = 'Action${actionTypeSuffix(formals)}';
1011 String actionBlock = '${actionName}Block';
1012 String actionPatch = '${actionName}Patch';
1013 writeln('@interface $actionPatch ()');
1014 writeln('- (id)initIdentityPatch:($actionBlock)previous;');
1015 writeln('- (id)initWith:(uint16_t)actionId');
1016 writeln(' previous:($actionBlock)previous');
1017 writeln(' inGraph:(ImmiRoot*)root;');
1018 writeln('@end');
1019 writeln();
1020 }
1021 }
1022
1023 void _writeActionsImplementation() {
1024 for (List<Type> formals in methodSignatures.values) {
1025 String suffix = actionTypeSuffix(formals);
1026 String actionName = 'Action$suffix';
1027 String actionBlock = '${actionName}Block';
1028 String actionPatch = '${actionName}Patch';
1029
1030 writeln('@implementation $actionPatch {');
1031 writeln(' NodePatchType _type;');
1032 writeln('}');
1033 writeln('- (id)initIdentityPatch:($actionBlock)previous {');
1034 writeln(' self = [super init];');
1035 writeln(' _type = kIdentityNodePatch;');
1036 writeln(' _current = previous;');
1037 writeln(' return self;');
1038 writeln('}');
1039 writeln('- (id)initWith:(uint16_t)actionId');
1040 writeln(' previous:($actionBlock)previous');
1041 writeln(' inGraph:(ImmiRoot*)root {');
1042 writeln(' self = [super init];');
1043 writeln(' _type = kReplaceNodePatch;');
1044 write(' _current = ');
1045 _writeActionBlockImplementation('actionId', formals);
1046 writeln(';');
1047 writeln(' return self;');
1048 writeln('}');
1049 writeln('- (bool)changed { return _type != kIdentityNodePatch; }');
1050 writeln('@end');
1051 writeln();
1052 }
1053 }
1054
1055 void _writeActionBlockImplementation(String actionId, List<Type> formals) {
1056 String suffix = actionTypeSuffix(formals);
1057 bool boxedArguments = formals.any((t) => t.isString);
1058 String actionFormals = '';
1059 if (formals.isNotEmpty) {
1060 var typedFormals =
1061 mapWithIndex(formals, (i, f) => '${getTypeName(f)} arg$i').join(', ');
1062 actionFormals = '(${typedFormals})';
1063 }
1064 writeln('^$actionFormals{');
1065 writeln(' [root dispatch:^{');
1066 if (boxedArguments) {
1067 writeln(' int size = 48 + Action${suffix}ArgsBuilder::kSize;');
1068 int i = 0;
1069 for (Type formal in formals) {
1070 if (formal.isString) {
1071 writeln(' size += arg$i.length;');
1072 }
1073 i++;
1074 }
1075 writeln(' MessageBuilder message(size);');
1076 writeln(' Action${suffix}ArgsBuilder args =');
1077 writeln(' message.initRoot<Action${suffix}ArgsBuilder>();');
1078 writeln(' args.setId($actionId);');
1079 i = 0;
1080 for (Type formal in formals) {
1081 if (formal.isString) {
1082 String charBuffer = 'args.initArg${i}Data(arg$i.length).data()';
1083 writeln(' [arg$i');
1084 writeln(' getCharacters:$charBuffer');
1085 writeln(' range:NSMakeRange(0, arg$i.length)];');
1086 } else {
1087 writeln(' args.setArg$i(arg$i);');
1088 }
1089 i++;
1090 }
1091 }
1092 writeln(' ${serviceName}::dispatch${suffix}Async(');
1093 if (boxedArguments) {
1094 writeln(' args,');
1095 } else {
1096 writeln(' $actionId,');
1097 for (int i = 0; i < formals.length; ++i) {
1098 writeln(' arg$i,');
1099 }
1100 }
1101 writeln(' noopVoidEventCallback,');
1102 writeln(' NULL);');
1103 writeln(' }];');
1104 write(' }');
1105 }
1106
1107 void _writeListUtils() {
1108 nodes.forEach((Struct node) {
1109 String name = node.name;
1110 String nodeName = "${node.name}Node";
1111 String patchName = "${node.name}Patch";
1112 String nodeDataName = "${nodeName}Data";
1113 String patchDataName = "${patchName}Data";
1114 writeln('id create$nodeName(const $nodeDataName& data, ImmiRoot* root) {') ;
1115 writeln(' return [[$nodeName alloc] initWith:data inGraph:root];');
1116 writeln('}');
1117 writeln();
1118 });
1119 // TODO(zerny): Support lists of primitive types.
1120 writeln("""
1121 Node* createNode(const NodeData& data, ImmiRoot* root) {
1122 return [[Node alloc] initWith:data inGraph:root];
1123 }
1124
1125 template<typename T>
1126 class ListUtils {
1127 public:
1128 typedef id (*DecodeElementFunction)(const T&, ImmiRoot*);
1129
1130 static NSMutableArray* decodeList(const List<T>& list,
1131 DecodeElementFunction decodeElement,
1132 ImmiRoot* root) {
1133 NSMutableArray* array = [NSMutableArray arrayWithCapacity:list.length()];
1134 for (int i = 0; i < list.length(); ++i) {
1135 [array addObject:decodeElement(list[i], root)];
1136 }
1137 return array;
1138 }
1139 };
1140 """);
1141 }
1142
1143 void _writeStringUtils() {
1144 write("""
1145 NSString* decodeString(const List<unichar>& chars) {
1146 List<unichar>& tmp = const_cast<List<unichar>&>(chars);
1147 return [[NSString alloc] initWithCharacters:tmp.data()
1148 length:tmp.length()];
1149 }
1150
1151 void encodeString(NSString* string, List<unichar> chars) {
1152 assert(string.length == chars.length());
1153 [string getCharacters:chars.data()
1154 range:NSMakeRange(0, string.length)];
1155 }
1156
1157 """);
1158 }
1159
1160 void _writeEventUtils() {
1161 writeln('typedef uint16_t EventID;');
1162 writeln('void noopVoidEventCallback(void*) {}');
1163 writeln();
1164 }
1165
1166 void _writeHeader() {
1167 String fileName = basenameWithoutExtension(path);
1168 writeln(COPYRIGHT);
1169 writeln('// Generated file. Do not edit.');
1170 writeln();
1171 writeln('#import "$immiImplFile"');
1172 writeln();
1173 }
1174
1175 void _writeFormalWithKeyword(String keyword, Formal formal) {
1176 write('$keyword:(${getTypeName(formal.type)})${formal.name}');
1177 }
1178
1179 String patchType(Type type) {
1180 if (type.isList) return 'ListPatch';
1181 return '${camelize(type.identifier)}Patch';
1182 }
1183
1184 void _writeNSType(Type type) {
1185 if (type.isList) {
1186 write('NSArray*');
1187 } else {
1188 write(getTypePointer(type));
1189 }
1190 }
1191
1192 String actionFormalTypes(List<Type> types) {
1193 return types.map((Type type) => getTypeName(type)).join(', ');
1194 }
1195
1196 String actionTypedArguments(List<Formal> types) {
1197 return types.map((Formal formal) {
1198 return '${getTypeName(formal.type)} ${formal.name}';
1199 }).join(', ');
1200 }
1201
1202 String actionArguments(List<Formal> types) {
1203 return types.map((Formal formal) {
1204 return '${formal.name}';
1205 }).join(', ');
1206 }
1207
1208 String actionPatchType(Method method) {
1209 List<Type> types = method.arguments.map((formal) => formal.type);
1210 return 'Action${actionTypeSuffix(types)}Patch';
1211 }
1212
1213 String actionBlockType(Method method) {
1214 List<Type> types = method.arguments.map((formal) => formal.type);
1215 return 'Action${actionTypeSuffix(types)}Block';
1216 }
1217 }
OLDNEW
« no previous file with comments | « tools/immic/lib/src/plugins/java.dart ('k') | tools/immic/lib/src/plugins/shared.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698