| Index: tools/immic/lib/src/plugins/objc.dart
|
| diff --git a/tools/immic/lib/src/plugins/objc.dart b/tools/immic/lib/src/plugins/objc.dart
|
| deleted file mode 100644
|
| index a3311d9e0d5bf338c5e4319b9cbb00e69815d462..0000000000000000000000000000000000000000
|
| --- a/tools/immic/lib/src/plugins/objc.dart
|
| +++ /dev/null
|
| @@ -1,1217 +0,0 @@
|
| -// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -library servicec.plugins.cc;
|
| -
|
| -import 'dart:core' hide Type;
|
| -import 'dart:io' show Platform, File;
|
| -
|
| -import 'package:path/path.dart' show basenameWithoutExtension, join, dirname;
|
| -
|
| -import 'shared.dart';
|
| -
|
| -import '../emitter.dart';
|
| -import '../primitives.dart' as primitives;
|
| -import '../struct_layout.dart';
|
| -
|
| -const List<String> RESOURCES = const [
|
| - "ImmiBase.h",
|
| -];
|
| -
|
| -const COPYRIGHT = """
|
| -// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE.md file.
|
| -""";
|
| -
|
| -const Map<String, String> _TYPES = const {
|
| - 'void' : 'void',
|
| - 'bool' : 'bool',
|
| -
|
| - 'uint8' : 'uint8_t',
|
| - 'uint16' : 'uint16_t',
|
| -
|
| - 'int8' : 'int8_t',
|
| - 'int16' : 'int16_t',
|
| - 'int32' : 'int32_t',
|
| - 'int64' : 'int64_t',
|
| -
|
| - 'float32' : 'float',
|
| - 'float64' : 'double',
|
| -
|
| - 'String' : 'NSString*',
|
| -};
|
| -
|
| -String getTypePointer(Type type) {
|
| - if (type.isNode) return 'Node*';
|
| - if (type.resolved != null) {
|
| - return "${type.identifier}Node*";
|
| - }
|
| - return _TYPES[type.identifier];
|
| -}
|
| -
|
| -String getTypeName(Type type) {
|
| - if (type.isNode) return 'Node';
|
| - if (type.resolved != null) {
|
| - return "${type.identifier}Node";
|
| - }
|
| - return _TYPES[type.identifier];
|
| -}
|
| -
|
| -void generate(String path, Map units, String outputDirectory) {
|
| - String directory = join(outputDirectory, "objc");
|
| - _generateHeaderFile(path, units, directory);
|
| - _generateImplementationFile(path, units, directory);
|
| -
|
| - String resourcesDirectory = join(dirname(Platform.script.path),
|
| - '..', 'lib', 'src', 'resources', 'objc');
|
| - for (String resource in RESOURCES) {
|
| - String resourcePath = join(resourcesDirectory, resource);
|
| - File file = new File(resourcePath);
|
| - String contents = file.readAsStringSync();
|
| - writeToFile(directory, resource, contents);
|
| - }
|
| -}
|
| -
|
| -void _generateHeaderFile(String path, Map units, String directory) {
|
| - _HeaderVisitor visitor = new _HeaderVisitor(path);
|
| - visitor.visitUnits(units);
|
| - String contents = visitor.buffer.toString();
|
| - String file = visitor.immiImplFile;
|
| - writeToFile(directory, file, contents, extension: 'h');
|
| -}
|
| -
|
| -void _generateImplementationFile(String path, Map units, String directory) {
|
| - _ImplementationVisitor visitor = new _ImplementationVisitor(path);
|
| - visitor.visitUnits(units);
|
| - String contents = visitor.buffer.toString();
|
| - String file = visitor.immiImplFile;
|
| - writeToFile(directory, file, contents, extension: 'mm');
|
| -}
|
| -
|
| - String getName(node) {
|
| - if (node is Struct) return node.name;
|
| - if (node is String) return node;
|
| - throw 'Invalid arg';
|
| - }
|
| -
|
| - String applyToMethodName(node) {
|
| - return 'applyTo';
|
| - }
|
| -
|
| - String presentMethodName(node) {
|
| - String name = getName(node);
|
| - return 'present${name}';
|
| - }
|
| -
|
| - String patchMethodName(node) {
|
| - String name = getName(node);
|
| - return 'patch${name}';
|
| - }
|
| -
|
| - String applyToMethodSignature(node) {
|
| - String name = getName(node);
|
| - return '- (void)${applyToMethodName(name)}:(id <${name}Presenter>)presenter';
|
| - }
|
| -
|
| - String presentMethodSignature(node) {
|
| - String name = getName(node);
|
| - String type = name == 'Node' ? name : '${name}Node';
|
| - return '- (void)${presentMethodName(name)}:(${type}*)node';
|
| - }
|
| -
|
| - String patchMethodSignature(node) {
|
| - String name = getName(node);
|
| - return '- (void)${patchMethodName(name)}:(${name}Patch*)patch';
|
| - }
|
| -
|
| - String applyToMethodDeclaration(Struct node) {
|
| - return applyToMethodSignature(node) + ';';
|
| - }
|
| -
|
| - String presentMethodDeclaration(Struct node) {
|
| - return presentMethodSignature(node) + ';';
|
| - }
|
| -
|
| - String patchMethodDeclaration(Struct node) {
|
| - return patchMethodSignature(node) + ';';
|
| - }
|
| -
|
| -
|
| -abstract class _ObjCVisitor extends CodeGenerationVisitor {
|
| - _ObjCVisitor(String path) : super(path);
|
| -
|
| - String immiBaseFile = 'ImmiBase.h';
|
| - String immiImplFile = 'Immi.h';
|
| -}
|
| -
|
| -class _HeaderVisitor extends _ObjCVisitor {
|
| - _HeaderVisitor(String path) : super(path);
|
| -
|
| - List nodes = [];
|
| -
|
| - visitUnits(Map units) {
|
| - units.values.forEach(collectMethodSignatures);
|
| - units.values.forEach((unit) { nodes.addAll(unit.structs); });
|
| - _writeHeader();
|
| - nodes.forEach((node) { writeln('@class ${node.name}Node;'); });
|
| - writeln();
|
| - nodes.forEach((node) { writeln('@class ${node.name}Patch;'); });
|
| - writeln();
|
| - _writeActions();
|
| - units.values.forEach(visit);
|
| - }
|
| -
|
| - visitUnit(Unit unit) {
|
| - unit.structs.forEach(visit);
|
| - }
|
| -
|
| - visitStruct(Struct node) {
|
| - StructLayout layout = node.layout;
|
| - String nodeName = "${node.name}Node";
|
| - String nodeNameData = "${nodeName}Data";
|
| - String patchName = "${node.name}Patch";
|
| - String patchNameData = "${nodeName}PatchData";
|
| - String presenterName = "${node.name}Presenter";
|
| - writeln('@protocol $presenterName');
|
| - writeln(presentMethodDeclaration(node));
|
| - writeln(patchMethodDeclaration(node));
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@interface $nodeName : NSObject <Node>');
|
| - forEachSlot(node, null, (Type slotType, String slotName) {
|
| - write('@property (readonly) ');
|
| - _writeNSType(slotType);
|
| - writeln(' $slotName;');
|
| - });
|
| - for (var method in node.methods) {
|
| - List<Type> formalTypes = method.arguments.map((formal) => formal.type);
|
| - String actionBlock = 'Action${actionTypeSuffix(formalTypes)}Block';
|
| - writeln('@property (readonly) $actionBlock ${method.name};');
|
| - }
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@interface $patchName : NSObject <NodePatch>');
|
| - writeln('@property (readonly) bool changed;');
|
| - writeln('@property (readonly) $nodeName* previous;');
|
| - writeln('@property (readonly) $nodeName* current;');
|
| - forEachSlot(node, null, (Type slotType, String slotName) {
|
| - writeln('@property (readonly) ${patchType(slotType)}* $slotName;');
|
| - });
|
| - for (var method in node.methods) {
|
| - String actionPatch = actionPatchType(method);
|
| - writeln('@property (readonly) $actionPatch* ${method.name};');
|
| - }
|
| - writeln(applyToMethodDeclaration(node));
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writeFormalWithKeyword(String keyword, Formal formal) {
|
| - write('$keyword:(${getTypeName(formal.type)})${formal.name}');
|
| - }
|
| -
|
| - _writeActions() {
|
| - for (List<Type> formals in methodSignatures.values) {
|
| - String actionName = 'Action${actionTypeSuffix(formals)}';
|
| - String actionBlock = '${actionName}Block';
|
| - String actionPatch = '${actionName}Patch';
|
| - write('typedef void (^$actionBlock)(${actionTypeFormals(formals)});');
|
| - writeln();
|
| - writeln('@interface $actionPatch : NSObject <Patch>');
|
| - writeln('@property (readonly) $actionBlock current;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| - }
|
| -
|
| - void _writeNSType(Type type) {
|
| - if (type.isList) {
|
| - write('NSArray*');
|
| - } else {
|
| - write(getTypePointer(type));
|
| - }
|
| - }
|
| -
|
| - void _writeHeader() {
|
| - writeln(COPYRIGHT);
|
| - writeln('// Generated file. Do not edit.');
|
| - writeln();
|
| - writeln('#import "$immiBaseFile"');
|
| - writeln();
|
| - }
|
| -
|
| - String patchType(Type type) {
|
| - if (type.isList) return 'ListPatch';
|
| - return '${camelize(type.identifier)}Patch';
|
| - }
|
| -
|
| - String actionTypeSuffix(List<Type> types) {
|
| - if (types.isEmpty) return 'Void';
|
| - return types.map((Type type) => camelize(type.identifier)).join();
|
| - }
|
| -
|
| - String actionTypeFormals(List<Type> types) {
|
| - return types.map((Type type) => getTypeName(type)).join(', ');
|
| - }
|
| -
|
| - String actionPatchType(Method method) {
|
| - List<Type> types = method.arguments.map((formal) => formal.type);
|
| - return 'Action${actionTypeSuffix(types)}Patch';
|
| - }
|
| -
|
| - String actionBlockType(Method method) {
|
| - List<Type> types = method.arguments.map((formal) => formal.type);
|
| - return 'Action${actionTypeSuffix(types)}Block';
|
| - }
|
| -}
|
| -
|
| -class _ImplementationVisitor extends _ObjCVisitor {
|
| - _ImplementationVisitor(String path) : super(path);
|
| -
|
| - List<Struct> nodes = [];
|
| -
|
| - visitUnits(Map units) {
|
| - units.values.forEach(collectMethodSignatures);
|
| - units.values.forEach((unit) { nodes.addAll(unit.structs); });
|
| - _writeHeader();
|
| -
|
| - _writeNodeBaseExtendedInterface();
|
| - _writePatchBaseExtendedInterface();
|
| - _writePatchPrimitivesExtendedInterface();
|
| - _writeActionsExtendedInterface();
|
| - units.values.forEach((unit) {
|
| - unit.structs.forEach(_writeNodeExtendedInterface);
|
| - });
|
| -
|
| - _writeImmiServiceExtendedInterface();
|
| - _writeImmiRootExtendedInterface();
|
| -
|
| - _writeEventUtils();
|
| - _writeStringUtils();
|
| - _writeListUtils();
|
| -
|
| - _writeNodeBaseImplementation();
|
| - _writePatchBaseImplementation();
|
| - _writePatchPrimitivesImplementation();
|
| - _writeActionsImplementation();
|
| - units.values.forEach((unit) {
|
| - unit.structs.forEach(_writeNodeImplementation);
|
| - });
|
| -
|
| - _writeImmiServiceImplementation();
|
| - _writeImmiRootImplementation();
|
| - }
|
| -
|
| - visitUnit(Unit unit) {
|
| - // Everything is done in visitUnits.
|
| - }
|
| -
|
| - _writeImmiServiceExtendedInterface() {
|
| - writeln('@interface ImmiService ()');
|
| - writeln('@property NSMutableArray* storyboards;');
|
| - writeln('@property NSMutableDictionary* roots;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - _writeImmiServiceImplementation() {
|
| - writeln('@implementation ImmiService');
|
| - writeln();
|
| - writeln('- (id)init {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _storyboards = [NSMutableArray array];');
|
| - writeln(' _roots = [NSMutableDictionary dictionary];');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (ImmiRoot*)registerPresenter:(id <NodePresenter>)presenter');
|
| - writeln(' forName:(NSString*)name {');
|
| - writeln(' assert(self.roots[name] == nil);');
|
| - writeln(' int length = name.length;');
|
| - writeln(' int size = 48 + PresenterDataBuilder::kSize + length;');
|
| - writeln(' MessageBuilder message(size);');
|
| - writeln(' PresenterDataBuilder builder =');
|
| - writeln(' message.initRoot<PresenterDataBuilder>();');
|
| - writeln(' List<unichar> chars = builder.initNameData(length);');
|
| - writeln(' [name getCharacters:chars.data()');
|
| - writeln(' range:NSMakeRange(0, length)];');
|
| - writeln(' uint16_t pid = ImmiServiceLayer::getPresenter(builder);');
|
| - writeln(' ImmiRoot* root =');
|
| - writeln(' [[ImmiRoot alloc] init:pid presenter:presenter];');
|
| - writeln(' self.roots[name] = root;');
|
| - writeln(' return root;');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (void)registerStoryboard:(UIStoryboard*)storyboard {');
|
| - writeln(' [self.storyboards addObject:storyboard];');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (ImmiRoot*)getRootByName:(NSString*)name {');
|
| - writeln(' ImmiRoot* root = self.roots[name];');
|
| - writeln(' if (root != nil) return root;');
|
| - writeln(' id <NodePresenter> presenter = nil;');
|
| - writeln(' for (int i = 0; i < self.storyboards.count; ++i) {');
|
| - writeln(' @try {');
|
| - writeln(' presenter = [self.storyboards[i]');
|
| - writeln(' instantiateViewControllerWithIdentifier:name];');
|
| - writeln(' break;');
|
| - writeln(' }');
|
| - writeln(' @catch (NSException* e) {');
|
| - writeln(' if (e.name != NSInvalidArgumentException) {');
|
| - writeln(' @throw e;');
|
| - writeln(' }');
|
| - writeln(' }');
|
| - writeln(' }');
|
| - writeln(' if (presenter == nil) abort();');
|
| - writeln(' return [self registerPresenter:presenter forName:name];');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (id <NodePresenter>)getPresenterByName:(NSString*)name {');
|
| - writeln(' return [[self getRootByName:name] presenter];');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - _writeImmiRootExtendedInterface() {
|
| - writeln('@interface ImmiRoot ()');
|
| - writeln('@property (readonly) uint16_t pid;');
|
| - writeln('@property (readonly) id <NodePresenter> presenter;');
|
| - writeln('@property Node* previous;');
|
| - writeln('@property bool refreshPending;');
|
| - writeln('@property bool refreshRequired;');
|
| - writeln('@property (nonatomic) dispatch_queue_t refreshQueue;');
|
| - writeln('- (id)init:(uint16_t)pid presenter:(id <NodePresenter>)presenter;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - _writeImmiRootImplementation() {
|
| - writeln('typedef void (^ImmiRefreshCallback)(const PatchData&);');
|
| - writeln('void ImmiRefresh(PatchData patchData, void* callbackData) {');
|
| - writeln(' @autoreleasepool {');
|
| - writeln(' ImmiRefreshCallback block =');
|
| - writeln(' (__bridge_transfer ImmiRefreshCallback)callbackData;');
|
| - writeln(' block(patchData);');
|
| - writeln(' patchData.Delete();');
|
| - writeln(' }');
|
| - writeln('}');
|
| - writeln('@implementation ImmiRoot');
|
| - writeln();
|
| - writeln('- (id)init:(uint16_t)pid');
|
| - writeln(' presenter:(id <NodePresenter>)presenter {');
|
| - writeln(' self = [super init];');
|
| - writeln(' assert(pid > 0);');
|
| - writeln(' _pid = pid;');
|
| - writeln(' _presenter = presenter;');
|
| - writeln(' _refreshPending = false;');
|
| - writeln(' _refreshRequired = false;');
|
| - writeln(' _refreshQueue = dispatch_queue_create(');
|
| - writeln(' "com.google.immi.refreshQueue", DISPATCH_QUEUE_SERIAL);');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (void)refresh {');
|
| - writeln(' ImmiRefreshCallback doApply = ^(const PatchData& patchData) {');
|
| - writeln(' if (patchData.isNode()) {');
|
| - writeln(' NodePatch* patch = [[NodePatch alloc]');
|
| - writeln(' initWith:patchData.getNode()');
|
| - writeln(' previous:self.previous');
|
| - writeln(' inGraph:self];');
|
| - writeln(' self.previous = patch.current;');
|
| - writeln(' [patch applyTo:self.presenter];');
|
| - writeln(' }');
|
| - writeln(' dispatch_async(self.refreshQueue, ^{');
|
| - writeln(' if (self.refreshRequired) {');
|
| - writeln(' self.refreshRequired = false;');
|
| - writeln(' [self refresh];');
|
| - writeln(' } else {');
|
| - writeln(' self.refreshPending = false;');
|
| - writeln(' }');
|
| - writeln(' });');
|
| - writeln(' };');
|
| - writeln(' ${serviceName}::refreshAsync(');
|
| - writeln(' self.pid,');
|
| - writeln(' ImmiRefresh,');
|
| - writeln(' (__bridge_retained void*)[doApply copy]);');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (void)reset {');
|
| - writeln(' ${serviceName}::reset(self.pid);');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (void)dispatch:(ImmiDispatchBlock)block {');
|
| - writeln(' block();');
|
| - writeln(' [self requestRefresh];');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (void)requestRefresh {');
|
| - writeln(' dispatch_async(self.refreshQueue, ^{');
|
| - writeln(' if (self.refreshPending) {');
|
| - writeln(' self.refreshRequired = true;');
|
| - writeln(' } else {');
|
| - writeln(' self.refreshPending = true;');
|
| - writeln(' [self refresh];');
|
| - writeln(' }');
|
| - writeln(' });');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - _writeNodeExtendedInterface(Struct node) {
|
| - String name = node.name;
|
| - String nodeName = "${name}Node";
|
| - String patchName = "${name}Patch";
|
| - String nodeDataName = "${nodeName}Data";
|
| - String patchDataName = "${patchName}Data";
|
| - writeln('@interface $nodeName ()');
|
| - if (node.methods.isNotEmpty) {
|
| - writeln('@property (weak) ImmiRoot* root;');
|
| - }
|
| - writeln('- (id)initWith:(const $nodeDataName&)data');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('- (id)initWithPatch:($patchName*)patch;');
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@interface $patchName ()');
|
| - writeln('- (id)initIdentityPatch:($nodeName*)previous;');
|
| - writeln('- (id)initWith:(const $patchDataName&)data');
|
| - writeln(' previous:($nodeName*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - _writeNodeImplementation(Struct node) {
|
| - String name = node.name;
|
| - String nodeName = "${node.name}Node";
|
| - String patchName = "${node.name}Patch";
|
| - String nodeDataName = "${nodeName}Data";
|
| - String patchDataName = "${patchName}Data";
|
| - String updateDataName = "${node.name}UpdateData";
|
| - writeln('@implementation $nodeName');
|
| - writeln('- (id)initWith:(const $nodeDataName&)data');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init];');
|
| - forEachSlot(node, null, (Type slotType, String slotName) {
|
| - String camelName = camelize(slotName);
|
| - write(' _$slotName = ');
|
| - if (slotType.isList) {
|
| - String slotTypeName = getTypeName(slotType.elementType.isNode ?
|
| - slotType.elementType :
|
| - slotType);
|
| - String slotTypeData = "${slotTypeName}Data";
|
| - writeln('ListUtils<$slotTypeData>::decodeList(');
|
| - writeln(' data.get${camelName}(), create$slotTypeName, root);');
|
| - } else if (slotType.isString) {
|
| - writeln('decodeString(data.get${camelName}Data());');
|
| - } else if (slotType.isNode || slotType.resolved != null) {
|
| - String slotTypeName = getTypeName(slotType);
|
| - writeln('[[$slotTypeName alloc] initWith:data.get${camelName}()');
|
| - writeln(' inGraph:(ImmiRoot*)root];');
|
| - } else {
|
| - writeln('data.get${camelName}();');
|
| - }
|
| - });
|
| - for (var method in node.methods) {
|
| - String actionId = '${method.name}Id';
|
| - writeln(' uint16_t $actionId = data.get${camelize(method.name)}();');
|
| - write(' _${method.name} = ');
|
| - List<Type> formals = method.arguments.map((formal) => formal.type);
|
| - _writeActionBlockImplementation(actionId, formals);
|
| - writeln(';');
|
| - }
|
| - writeln(' return self;');
|
| - writeln('}');
|
| -
|
| - writeln('- (id)initWithPatch:($patchName*)patch {');
|
| - writeln(' self = [super init];');
|
| - forEachSlot(node, null, (Type slotType, String slotName) {
|
| - writeln(' _$slotName = patch.$slotName.current;');
|
| - });
|
| - for (Method method in node.methods) {
|
| - String name = method.name;
|
| - writeln(' _$name = patch.$name.current;');
|
| - }
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@implementation $patchName {');
|
| - writeln(' NodePatchType _type;');
|
| - writeln('}');
|
| - writeln('- (id)initIdentityPatch:($nodeName*)previous {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _type = kIdentityNodePatch;');
|
| - writeln(' _previous = previous;');
|
| - writeln(' _current = previous;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (id)initWith:(const $patchDataName&)data');
|
| - writeln(' previous:($nodeName*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _previous = previous;');
|
| - if (node.layout.slots.isNotEmpty || node.methods.isNotEmpty) {
|
| - // The updates list is ordered consistently with the struct fields.
|
| - writeln(' if (data.isUpdates()) {');
|
| - writeln(' List<$updateDataName> updates = data.getUpdates();');
|
| - writeln(' int length = updates.length();');
|
| - writeln(' int next = 0;');
|
| - forEachSlotAndMethod(node, null, (field, String name) {
|
| - String camelName = camelize(name);
|
| - String fieldPatchType =
|
| - field is Method ? actionPatchType(field) : patchType(field.type);
|
| - writeln(' if (next < length && updates[next].is${camelName}()) {');
|
| - writeln(' _$name = [[$fieldPatchType alloc]');
|
| - write(' ');
|
| - String dataGetter = 'updates[next++].get${camelName}';
|
| - if (field is Formal && !field.type.isList && field.type.isString) {
|
| - writeln('initWith:decodeString(${dataGetter}Data())');
|
| - } else {
|
| - writeln('initWith:$dataGetter()');
|
| - }
|
| - writeln(' previous:previous.$name');
|
| - writeln(' inGraph:root];');
|
| - writeln(' } else {');
|
| - writeln(' _$name = [[$fieldPatchType alloc]');
|
| - writeln(' initIdentityPatch:previous.$name];');
|
| - writeln(' }');
|
| - });
|
| - writeln(' assert(next == length);');
|
| - writeln(' _type = kUpdateNodePatch;');
|
| - writeln(' _current = [[$nodeName alloc] initWithPatch:self];');
|
| - writeln(' return self;');
|
| - writeln(' }');
|
| - }
|
| - writeln(' assert(data.isReplace());');
|
| - writeln(' _type = kReplaceNodePatch;');
|
| - writeln(' _current = [[$nodeName alloc] initWith:data.getReplace()');
|
| - writeln(' inGraph:root];');
|
| - // For replace patches we leave fields and methods as default initialized.
|
| - writeln(' return self;');
|
| - writeln('}');
|
| -
|
| - writeln('- (bool)changed { return _type != kIdentityNodePatch; }');
|
| - writeln('- (bool)replaced { return _type == kReplaceNodePatch; }');
|
| - writeln('- (bool)updated { return _type == kUpdateNodePatch; }');
|
| - write(applyToMethodSignature(node));
|
| - writeln(' {');
|
| - writeln(' if (!self.changed) return;');
|
| - writeln(' if (self.replaced) {');
|
| - writeln(' [presenter present${node.name}:self.current];');
|
| - writeln(' } else {');
|
| - writeln(' [presenter patch${node.name}:self];');
|
| - writeln(' }');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writeNodeBaseExtendedInterface() {
|
| - writeln('@interface Node ()');
|
| - writeln('@property (readonly) id <Node> node;');
|
| - writeln('- (id)init:(id <Node>)node;');
|
| - writeln('- (id)initWith:(const NodeData&)data');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('+ (id <Node>)createNode:(const NodeData&)data');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writeNodeBaseImplementation() {
|
| - writeln('@implementation Node');
|
| - writeln('- (bool)is:(Class)klass {');
|
| - writeln(' return [self.node isMemberOfClass:klass];');
|
| - writeln('}');
|
| - writeln('- (id)as:(Class)klass {');
|
| - writeln(' assert([self is:klass]);');
|
| - writeln(' return self.node;');
|
| - writeln('}');
|
| - writeln('- (id)init:(id <Node>)node {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _node = node;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (id)initWith:(const NodeData&)data');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' return [self init:[Node createNode:data inGraph:root]];');
|
| - writeln('}');
|
| - writeln('+ (id <Node>)createNode:(const NodeData&)data');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - nodes.forEach((node) {
|
| - writeln(' if (data.is${node.name}()) {');
|
| - writeln(' return [[${node.name}Node alloc]');
|
| - writeln(' initWith:data.get${node.name}()');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - });
|
| - writeln(' abort();');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writePatchBaseExtendedInterface() {
|
| - writeln('typedef enum { kIdentityNodePatch, kReplaceNodePatch, kUpdateNodePatch } NodePatchType;');
|
| - writeln('@interface NodePatch ()');
|
| - writeln('@property (readonly) id <NodePatch> patch;');
|
| - writeln('@property (readonly) Node* node;');
|
| - writeln('- (id)initIdentityPatch:(Node*)previous;');
|
| - writeln('- (id)initWith:(const NodePatchData&)data');
|
| - writeln(' previous:(Node*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('+ (id <NodePatch>)createPatch:(const NodePatchData&)data');
|
| - writeln(' previous:(id <Node>)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writePatchBaseImplementation() {
|
| - writeln('@implementation NodePatch {');
|
| - writeln(' NodePatchType _type;');
|
| - writeln('}');
|
| - writeln('+ (id <NodePatch>)createPatch:(const NodePatchData&)data');
|
| - writeln(' previous:(id <Node>)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - nodes.forEach((node) {
|
| - String name = node.name;
|
| - String nodeName = '${name}Node';
|
| - String patchName = '${name}Patch';
|
| - writeln(' if (data.is$name()) {');
|
| - writeln(' $nodeName* previousNode =');
|
| - writeln(' [previous isMemberOfClass:$nodeName.class] ?');
|
| - writeln(' previous :');
|
| - writeln(' nil;');
|
| - writeln(' return [[$patchName alloc]');
|
| - writeln(' initWith:data.get$name()');
|
| - writeln(' previous:previousNode');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - });
|
| - writeln(' abort();');
|
| - writeln('}');
|
| - writeln('- (id)initIdentityPatch:(Node*)previous {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _type = kIdentityNodePatch;');
|
| - writeln(' _previous = previous;');
|
| - writeln(' _current = previous;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (id)initWith:(const NodePatchData&)data');
|
| - writeln(' previous:(Node*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _previous = previous;');
|
| - writeln(' _patch = [NodePatch');
|
| - writeln(' createPatch:data');
|
| - writeln(' previous:previous.node');
|
| - writeln(' inGraph:root];');
|
| - writeln(' _type = _patch.replaced ? kReplaceNodePatch : kUpdateNodePatch;');
|
| - writeln(' _current = [[Node alloc] init:_patch.current];');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln();
|
| - writeln('- (bool)changed { return _type != kIdentityNodePatch; }');
|
| - writeln('- (bool)replaced { return _type == kReplaceNodePatch; }');
|
| - writeln('- (bool)updated { return _type == kUpdateNodePatch; }');
|
| - writeln();
|
| - write(applyToMethodSignature('Node'));
|
| - writeln(' {');
|
| - writeln(' if (!self.changed) return;');
|
| - writeln(' if (self.replaced) {');
|
| - writeln(' [presenter presentNode:self.current];');
|
| - writeln(' } else {');
|
| - writeln(' [presenter patchNode:self];');
|
| - writeln(' }');
|
| - writeln('}');
|
| - writeln('- (bool)is:(Class)klass {');
|
| - writeln(' return [self.patch isMemberOfClass:klass];');
|
| - writeln('}');
|
| - writeln('- (id)as:(Class)klass {');
|
| - writeln(' assert([self is:klass]);');
|
| - writeln(' return self.patch;');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writePatchPrimitivesExtendedInterface() {
|
| - _TYPES.forEach((String idlType, String objcType) {
|
| - if (idlType == 'void') return;
|
| - String patchTypeName = '${camelize(idlType)}Patch';
|
| - String patchDataName = objcType;
|
| - writeln('@interface $patchTypeName ()');
|
| - writeln('- (id)initIdentityPatch:($objcType)previous;');
|
| - writeln('- (id)initWith:($patchDataName)data');
|
| - writeln(' previous:($objcType)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln();
|
| - });
|
| -
|
| - writeln('typedef enum { kAnyNode, kSpecificNode } ListPatchType;');
|
| - writeln();
|
| - writeln('@interface ListRegionPatch ()');
|
| - writeln('@property (readonly) int countDelta;');
|
| - writeln('- (int)applyTo:(NSMutableArray*)outArray');
|
| - writeln(' with:(NSArray*)inArray;');
|
| - writeln('+ (ListRegionPatch*)regionPatch:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' previous:(NSArray*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln('@interface ListRegionRemovePatch ()');
|
| - writeln('- (id)initWith:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln('@interface ListRegionInsertPatch ()');
|
| - writeln('- (id)initWith:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln('@interface ListRegionUpdatePatch ()');
|
| - writeln('- (id)initWith:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' previous:(NSArray*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| -
|
| - writeln('@interface ListPatch ()');
|
| - writeln('- (id)initIdentityPatch:(NSArray*)previous;');
|
| - writeln('- (id)initWith:(const ListPatchData&)data');
|
| - writeln(' previous:(NSArray*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writePatchPrimitivesImplementation() {
|
| - _TYPES.forEach((String idlType, String objcType) {
|
| - if (idlType == 'void') return;
|
| - String patchTypeName = '${camelize(idlType)}Patch';
|
| - String patchDataName = objcType;
|
| - writeln('@implementation $patchTypeName');
|
| - writeln('- (id)initIdentityPatch:($objcType)previous {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _previous = previous;');
|
| - writeln(' _current = previous;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (id)initWith:($patchDataName)data');
|
| - writeln(' previous:($objcType)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _previous = previous;');
|
| - writeln(' _current = data;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (bool)changed {');
|
| - writeln(' return _previous != _current;');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - });
|
| -
|
| - writeln('@implementation ListRegionPatch');
|
| - writeln('+ (ListRegionPatch*)regionPatch:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' previous:(NSArray*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' if (data.isRemove()) {');
|
| - writeln(' return [[ListRegionRemovePatch alloc] initWith:data');
|
| - writeln(' type:type');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - writeln(' if (data.isInsert()) {');
|
| - writeln(' return [[ListRegionInsertPatch alloc] initWith:data');
|
| - writeln(' type:type');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - writeln(' NSAssert(data.isUpdate(), @"Invalid list patch for region");');
|
| - writeln(' return [[ListRegionUpdatePatch alloc] initWith:data');
|
| - writeln(' type:type');
|
| - writeln(' previous:previous');
|
| - writeln(' inGraph:root];');
|
| - writeln('}');
|
| - writeln('- (id)init:(int)index {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _index = index;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (bool)isRemove { return false; }');
|
| - writeln('- (bool)isInsert { return false; }');
|
| - writeln('- (bool)isUpdate { return false; }');
|
| - writeln('- (int)applyTo:(NSMutableArray*)outArray');
|
| - writeln(' with:(NSArray*)inArray {');
|
| - writeln(' @throw [NSException');
|
| - writeln(' exceptionWithName:NSInternalInconsistencyException');
|
| - writeln(' reason:@"-applyTo:with: base is abstract"');
|
| - writeln(' userInfo:nil];');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@implementation ListRegionRemovePatch');
|
| - writeln('- (id)initWith:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init:data.getIndex()];');
|
| - writeln(' _count = data.getRemove();');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (bool)isRemove { return true; }');
|
| - writeln('- (int)countDelta { return -self.count; }');
|
| - writeln('- (int)applyTo:(NSMutableArray*)outArray');
|
| - writeln(' with:(NSArray*)inArray {');
|
| - writeln(' return self.count;');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@implementation ListRegionInsertPatch');
|
| - writeln('- (id)initWith:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init:data.getIndex()];');
|
| - writeln(' const List<NodeData>& insertData = data.getInsert();');
|
| - writeln(' NSMutableArray* nodes =');
|
| - writeln(' [NSMutableArray arrayWithCapacity:insertData.length()];');
|
| - writeln(' int length = insertData.length();');
|
| - writeln(' if (type == kAnyNode) {');
|
| - writeln(' for (int i = 0; i < length; ++i) {');
|
| - writeln(' nodes[i] = [[Node alloc] initWith:insertData[i]');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - writeln(' } else {');
|
| - writeln(' assert(type == kSpecificNode);');
|
| - writeln(' for (int i = 0; i < length; ++i) {');
|
| - writeln(' nodes[i] = [Node createNode:insertData[i] inGraph:root];');
|
| - writeln(' }');
|
| - writeln(' }');
|
| - writeln(' _nodes = nodes;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (bool)isInsert { return true; }');
|
| - writeln('- (int)countDelta { return self.nodes.count; }');
|
| - writeln('- (int)applyTo:(NSMutableArray*)outArray');
|
| - writeln(' with:(NSArray*)inArray {');
|
| - writeln(' [outArray addObjectsFromArray:self.nodes];');
|
| - writeln(' return 0;');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@implementation ListRegionUpdatePatch');
|
| - writeln('- (id)initWith:(const ListRegionData&)data');
|
| - writeln(' type:(ListPatchType)type');
|
| - writeln(' previous:(NSArray*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init:data.getIndex()];');
|
| - writeln(' const List<NodePatchData>& updateData = data.getUpdate();');
|
| - writeln(' int length = updateData.length();');
|
| - writeln(' NSMutableArray* updates =');
|
| - writeln(' [NSMutableArray arrayWithCapacity:length];');
|
| - writeln(' if (type == kAnyNode) {');
|
| - writeln(' for (int i = 0; i < length; ++i) {');
|
| - writeln(' updates[i] = [[NodePatch alloc]');
|
| - writeln(' initWith:updateData[i]');
|
| - writeln(' previous:previous[self.index + i]');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - writeln(' } else {');
|
| - writeln(' assert(type == kSpecificNode);');
|
| - writeln(' for (int i = 0; i < length; ++i) {');
|
| - writeln(' updates[i] = [NodePatch');
|
| - writeln(' createPatch:updateData[i]');
|
| - writeln(' previous:previous[self.index + i]');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - writeln(' }');
|
| - writeln(' _updates = updates;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (bool)isUpdate { return true; }');
|
| - writeln('- (int)countDelta { return 0; }');
|
| - writeln('- (int)applyTo:(NSMutableArray*)outArray');
|
| - writeln(' with:(NSArray*)inArray {');
|
| - writeln(' int length = self.updates.count;');
|
| - writeln(' for (int i = 0; i < length; ++i) {');
|
| - writeln(' id <NodePatch> patch = self.updates[i];');
|
| - writeln(' [outArray addObject:patch.current];');
|
| - writeln(' }');
|
| - writeln(' return length;');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - writeln('@implementation ListPatch {');
|
| - writeln(' NSMutableArray* _regions;');
|
| - writeln('}');
|
| - writeln('- (id)initIdentityPatch:(NSArray*)previous {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _changed = false;');
|
| - writeln(' _previous = previous;');
|
| - writeln(' _current = previous;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (id)initWith:(const ListPatchData&)data');
|
| - writeln(' previous:(NSArray*)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _changed = true;');
|
| - writeln(' _previous = previous;');
|
| - writeln(' ListPatchType type = (ListPatchType)data.getType();');
|
| - writeln(' const List<ListRegionData>& regions = data.getRegions();');
|
| - writeln(' NSMutableArray* patches =');
|
| - writeln(' [NSMutableArray arrayWithCapacity:regions.length()];');
|
| - writeln(' for (int i = 0; i < regions.length(); ++i) {');
|
| - writeln(' patches[i] =');
|
| - writeln(' [ListRegionPatch regionPatch:regions[i]');
|
| - writeln(' type:type');
|
| - writeln(' previous:previous');
|
| - writeln(' inGraph:root];');
|
| - writeln(' }');
|
| - writeln(' _regions = patches;');
|
| - writeln(' _current = [self applyWith:previous];');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (NSArray*)applyWith:(NSArray*)array {');
|
| - writeln(' int newCount = array.count;');
|
| - writeln(' for (int i = 0; i < self.regions.count; ++i) {');
|
| - writeln(' ListRegionPatch* patch = self.regions[i];');
|
| - writeln(' newCount += patch.countDelta;');
|
| - writeln(' }');
|
| - writeln(' int sourceIndex = 0;');
|
| - writeln(' NSMutableArray* newArray =');
|
| - writeln(' [NSMutableArray arrayWithCapacity:newCount];');
|
| - writeln(' for (int i = 0; i < self.regions.count; ++i) {');
|
| - writeln(' ListRegionPatch* patch = self.regions[i];');
|
| - writeln(' while (sourceIndex < patch.index) {');
|
| - writeln(' [newArray addObject:array[sourceIndex++]];');
|
| - writeln(' }');
|
| - writeln(' sourceIndex += [patch applyTo:newArray with:array];');
|
| - writeln(' }');
|
| - writeln(' while (sourceIndex < array.count) {');
|
| - writeln(' [newArray addObject:array[sourceIndex++]];');
|
| - writeln(' }');
|
| - writeln(' return newArray;');
|
| - writeln('}');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| -
|
| - void _writeActionsExtendedInterface() {
|
| - for (List<Type> formals in methodSignatures.values) {
|
| - String actionName = 'Action${actionTypeSuffix(formals)}';
|
| - String actionBlock = '${actionName}Block';
|
| - String actionPatch = '${actionName}Patch';
|
| - writeln('@interface $actionPatch ()');
|
| - writeln('- (id)initIdentityPatch:($actionBlock)previous;');
|
| - writeln('- (id)initWith:(uint16_t)actionId');
|
| - writeln(' previous:($actionBlock)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root;');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| - }
|
| -
|
| - void _writeActionsImplementation() {
|
| - for (List<Type> formals in methodSignatures.values) {
|
| - String suffix = actionTypeSuffix(formals);
|
| - String actionName = 'Action$suffix';
|
| - String actionBlock = '${actionName}Block';
|
| - String actionPatch = '${actionName}Patch';
|
| -
|
| - writeln('@implementation $actionPatch {');
|
| - writeln(' NodePatchType _type;');
|
| - writeln('}');
|
| - writeln('- (id)initIdentityPatch:($actionBlock)previous {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _type = kIdentityNodePatch;');
|
| - writeln(' _current = previous;');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (id)initWith:(uint16_t)actionId');
|
| - writeln(' previous:($actionBlock)previous');
|
| - writeln(' inGraph:(ImmiRoot*)root {');
|
| - writeln(' self = [super init];');
|
| - writeln(' _type = kReplaceNodePatch;');
|
| - write(' _current = ');
|
| - _writeActionBlockImplementation('actionId', formals);
|
| - writeln(';');
|
| - writeln(' return self;');
|
| - writeln('}');
|
| - writeln('- (bool)changed { return _type != kIdentityNodePatch; }');
|
| - writeln('@end');
|
| - writeln();
|
| - }
|
| - }
|
| -
|
| - void _writeActionBlockImplementation(String actionId, List<Type> formals) {
|
| - String suffix = actionTypeSuffix(formals);
|
| - bool boxedArguments = formals.any((t) => t.isString);
|
| - String actionFormals = '';
|
| - if (formals.isNotEmpty) {
|
| - var typedFormals =
|
| - mapWithIndex(formals, (i, f) => '${getTypeName(f)} arg$i').join(', ');
|
| - actionFormals = '(${typedFormals})';
|
| - }
|
| - writeln('^$actionFormals{');
|
| - writeln(' [root dispatch:^{');
|
| - if (boxedArguments) {
|
| - writeln(' int size = 48 + Action${suffix}ArgsBuilder::kSize;');
|
| - int i = 0;
|
| - for (Type formal in formals) {
|
| - if (formal.isString) {
|
| - writeln(' size += arg$i.length;');
|
| - }
|
| - i++;
|
| - }
|
| - writeln(' MessageBuilder message(size);');
|
| - writeln(' Action${suffix}ArgsBuilder args =');
|
| - writeln(' message.initRoot<Action${suffix}ArgsBuilder>();');
|
| - writeln(' args.setId($actionId);');
|
| - i = 0;
|
| - for (Type formal in formals) {
|
| - if (formal.isString) {
|
| - String charBuffer = 'args.initArg${i}Data(arg$i.length).data()';
|
| - writeln(' [arg$i');
|
| - writeln(' getCharacters:$charBuffer');
|
| - writeln(' range:NSMakeRange(0, arg$i.length)];');
|
| - } else {
|
| - writeln(' args.setArg$i(arg$i);');
|
| - }
|
| - i++;
|
| - }
|
| - }
|
| - writeln(' ${serviceName}::dispatch${suffix}Async(');
|
| - if (boxedArguments) {
|
| - writeln(' args,');
|
| - } else {
|
| - writeln(' $actionId,');
|
| - for (int i = 0; i < formals.length; ++i) {
|
| - writeln(' arg$i,');
|
| - }
|
| - }
|
| - writeln(' noopVoidEventCallback,');
|
| - writeln(' NULL);');
|
| - writeln(' }];');
|
| - write(' }');
|
| - }
|
| -
|
| - void _writeListUtils() {
|
| - nodes.forEach((Struct node) {
|
| - String name = node.name;
|
| - String nodeName = "${node.name}Node";
|
| - String patchName = "${node.name}Patch";
|
| - String nodeDataName = "${nodeName}Data";
|
| - String patchDataName = "${patchName}Data";
|
| - writeln('id create$nodeName(const $nodeDataName& data, ImmiRoot* root) {');
|
| - writeln(' return [[$nodeName alloc] initWith:data inGraph:root];');
|
| - writeln('}');
|
| - writeln();
|
| - });
|
| - // TODO(zerny): Support lists of primitive types.
|
| - writeln("""
|
| -Node* createNode(const NodeData& data, ImmiRoot* root) {
|
| - return [[Node alloc] initWith:data inGraph:root];
|
| -}
|
| -
|
| -template<typename T>
|
| -class ListUtils {
|
| -public:
|
| - typedef id (*DecodeElementFunction)(const T&, ImmiRoot*);
|
| -
|
| - static NSMutableArray* decodeList(const List<T>& list,
|
| - DecodeElementFunction decodeElement,
|
| - ImmiRoot* root) {
|
| - NSMutableArray* array = [NSMutableArray arrayWithCapacity:list.length()];
|
| - for (int i = 0; i < list.length(); ++i) {
|
| - [array addObject:decodeElement(list[i], root)];
|
| - }
|
| - return array;
|
| - }
|
| -};
|
| -""");
|
| - }
|
| -
|
| - void _writeStringUtils() {
|
| - write("""
|
| -NSString* decodeString(const List<unichar>& chars) {
|
| - List<unichar>& tmp = const_cast<List<unichar>&>(chars);
|
| - return [[NSString alloc] initWithCharacters:tmp.data()
|
| - length:tmp.length()];
|
| -}
|
| -
|
| -void encodeString(NSString* string, List<unichar> chars) {
|
| - assert(string.length == chars.length());
|
| - [string getCharacters:chars.data()
|
| - range:NSMakeRange(0, string.length)];
|
| -}
|
| -
|
| -""");
|
| - }
|
| -
|
| - void _writeEventUtils() {
|
| - writeln('typedef uint16_t EventID;');
|
| - writeln('void noopVoidEventCallback(void*) {}');
|
| - writeln();
|
| - }
|
| -
|
| - void _writeHeader() {
|
| - String fileName = basenameWithoutExtension(path);
|
| - writeln(COPYRIGHT);
|
| - writeln('// Generated file. Do not edit.');
|
| - writeln();
|
| - writeln('#import "$immiImplFile"');
|
| - writeln();
|
| - }
|
| -
|
| - void _writeFormalWithKeyword(String keyword, Formal formal) {
|
| - write('$keyword:(${getTypeName(formal.type)})${formal.name}');
|
| - }
|
| -
|
| - String patchType(Type type) {
|
| - if (type.isList) return 'ListPatch';
|
| - return '${camelize(type.identifier)}Patch';
|
| - }
|
| -
|
| - void _writeNSType(Type type) {
|
| - if (type.isList) {
|
| - write('NSArray*');
|
| - } else {
|
| - write(getTypePointer(type));
|
| - }
|
| - }
|
| -
|
| - String actionFormalTypes(List<Type> types) {
|
| - return types.map((Type type) => getTypeName(type)).join(', ');
|
| - }
|
| -
|
| - String actionTypedArguments(List<Formal> types) {
|
| - return types.map((Formal formal) {
|
| - return '${getTypeName(formal.type)} ${formal.name}';
|
| - }).join(', ');
|
| - }
|
| -
|
| - String actionArguments(List<Formal> types) {
|
| - return types.map((Formal formal) {
|
| - return '${formal.name}';
|
| - }).join(', ');
|
| - }
|
| -
|
| - String actionPatchType(Method method) {
|
| - List<Type> types = method.arguments.map((formal) => formal.type);
|
| - return 'Action${actionTypeSuffix(types)}Patch';
|
| - }
|
| -
|
| - String actionBlockType(Method method) {
|
| - List<Type> types = method.arguments.map((formal) => formal.type);
|
| - return 'Action${actionTypeSuffix(types)}Block';
|
| - }
|
| -}
|
|
|