| 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 immic.plugins.idl; | |
| 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 import 'package:strings/strings.dart' as strings; | |
| 12 | |
| 13 import 'shared.dart'; | |
| 14 import '../emitter.dart'; | |
| 15 import '../struct_layout.dart'; | |
| 16 import '../primitives.dart' as primitives; | |
| 17 | |
| 18 const COPYRIGHT = """ | |
| 19 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
| 20 // for details. All rights reserved. Use of this source code is governed by a | |
| 21 // BSD-style license that can be found in the LICENSE.md file. | |
| 22 """; | |
| 23 | |
| 24 void generate(String path, | |
| 25 Map<String, Unit> units, | |
| 26 String outputDirectory) { | |
| 27 _IDLVisitor visitor = new _IDLVisitor(path); | |
| 28 visitor.visitUnits(units); | |
| 29 String content = visitor.buffer.toString(); | |
| 30 String directory = join(outputDirectory, 'idl'); | |
| 31 String outPath = visitor.serviceFile; | |
| 32 writeToFile(directory, outPath, content, extension: 'idl'); | |
| 33 } | |
| 34 | |
| 35 class _IDLVisitor extends CodeGenerationVisitor { | |
| 36 List<Struct> nodes = <Struct>[]; | |
| 37 _IDLVisitor(String path) : super(path); | |
| 38 | |
| 39 HashMap<String, List<Type>> _methodSignatures = {}; | |
| 40 | |
| 41 void visitUnits(Map<String, Unit> units) { | |
| 42 _writeCopyright(); | |
| 43 units.values.forEach(_collectMethodSignatures); | |
| 44 _writeService(); | |
| 45 // Genereate node specific IDL entries. | |
| 46 units.values.forEach(visit); | |
| 47 // Genereate shared definitions. | |
| 48 _writeNodeDataStruct(nodes); | |
| 49 _writePatchDataStructs(); | |
| 50 _writeActionArgumentStructs(); | |
| 51 } | |
| 52 | |
| 53 visitUnit(Unit node) { | |
| 54 node.structs.forEach(visit); | |
| 55 } | |
| 56 | |
| 57 visitStruct(Struct node) { | |
| 58 nodes.add(node); | |
| 59 StructLayout layout = node.layout; | |
| 60 writeln('struct ${node.name}NodeData {'); | |
| 61 for (StructSlot slot in layout.slots) { | |
| 62 String slotName = slot.slot.name; | |
| 63 Type slotType = slot.slot.type; | |
| 64 write(' '); | |
| 65 writeType(slotType); | |
| 66 writeln(' $slotName;'); | |
| 67 } | |
| 68 node.methods.forEach(visit); | |
| 69 writeln('}'); | |
| 70 writeln(); | |
| 71 } | |
| 72 | |
| 73 visitUnion(Union node) { | |
| 74 // Ignored for now. | |
| 75 } | |
| 76 | |
| 77 visitMethod(Method node) { | |
| 78 writeln(' uint16 ${node.name};'); | |
| 79 } | |
| 80 | |
| 81 void writeType(Type node) { | |
| 82 if (node.isList) write('List<'); | |
| 83 Node resolved = node.resolved; | |
| 84 if (resolved != null) { | |
| 85 write("${node.identifier}NodeData"); | |
| 86 } else if (node.isNode || node.isList && node.elementType.isNode) { | |
| 87 write("NodeData"); | |
| 88 } else { | |
| 89 write(node.identifier); | |
| 90 } | |
| 91 if (node.isList) write('>'); | |
| 92 } | |
| 93 | |
| 94 void _collectMethodSignatures(Unit unit) { | |
| 95 for (var node in unit.structs) { | |
| 96 for (var method in node.methods) { | |
| 97 assert(method.returnType.isVoid); | |
| 98 String signature = | |
| 99 method.arguments.map((formal) => formal.type.identifier); | |
| 100 _methodSignatures.putIfAbsent('$signature', () { | |
| 101 return method.arguments.map((formal) => formal.type); | |
| 102 }); | |
| 103 } | |
| 104 } | |
| 105 } | |
| 106 | |
| 107 void _writeCopyright() { | |
| 108 writeln(COPYRIGHT); | |
| 109 writeln('// Generated file. Do not edit.'); | |
| 110 writeln(); | |
| 111 } | |
| 112 | |
| 113 void _writeService() { | |
| 114 writeln('service ${serviceName} {'); | |
| 115 writeln(' uint16 getPresenter(PresenterData* data);'); | |
| 116 writeln(' void reset(uint16 pid);'); | |
| 117 writeln(' PatchData* refresh(uint16 pid);'); | |
| 118 for (List<Type> formals in _methodSignatures.values) { | |
| 119 String suffix = actionTypeSuffix(formals); | |
| 120 bool boxedArguments = formals.any((t) => t.isString); | |
| 121 if (boxedArguments) { | |
| 122 writeln(' void dispatch$suffix(Action${suffix}Args* args);'); | |
| 123 continue; | |
| 124 } | |
| 125 write(' void dispatch$suffix(uint16 id'); | |
| 126 int i = 0; | |
| 127 for (var formal in formals) { | |
| 128 write(', ${formal.identifier} arg${i++}'); | |
| 129 } | |
| 130 writeln(');'); | |
| 131 } | |
| 132 writeln('}'); | |
| 133 writeln(); | |
| 134 } | |
| 135 | |
| 136 void _writeNodeDataStruct(List<Struct> nodes) { | |
| 137 writeln('struct NodeData {'); | |
| 138 writeln(' union {'); | |
| 139 nodes.forEach((Struct node) { | |
| 140 String nodeType = "${node.name}NodeData"; | |
| 141 String nodeField = camelize(node.name); | |
| 142 writeln(' $nodeType* $nodeField;'); | |
| 143 }); | |
| 144 writeln(' }'); | |
| 145 writeln('}'); | |
| 146 writeln(); | |
| 147 | |
| 148 writeln('struct NodePatchData {'); | |
| 149 writeln(' union {'); | |
| 150 nodes.forEach((Struct node) { | |
| 151 String patchType = "${node.name}PatchData"; | |
| 152 String nodeField = camelize(node.name); | |
| 153 writeln(' $patchType* $nodeField;'); | |
| 154 }); | |
| 155 writeln(' }'); | |
| 156 writeln('}'); | |
| 157 writeln(); | |
| 158 | |
| 159 nodes.forEach((Struct node) { | |
| 160 String nodeType = "${node.name}NodeData"; | |
| 161 String patchType = "${node.name}PatchData"; | |
| 162 String updateType = "${node.name}UpdateData"; | |
| 163 writeln('struct $patchType {'); | |
| 164 writeln(' union {'); | |
| 165 writeln(' $nodeType* replace;'); | |
| 166 writeln(' List<${updateType}> updates;'); | |
| 167 writeln(' }'); | |
| 168 writeln('}'); | |
| 169 writeln('struct $updateType {'); | |
| 170 writeln(' union {'); | |
| 171 forEachSlot(node, null, (Type slotType, String slotName) { | |
| 172 if (slotType.isList) { | |
| 173 writeln(' ListPatchData $slotName;'); | |
| 174 } else if (slotType.isNode || slotType.resolved != null) { | |
| 175 writeln(' ${camelize(slotType.identifier)}PatchData $slotName;'); | |
| 176 } else { | |
| 177 write(' '); | |
| 178 writeType(slotType); | |
| 179 writeln(' $slotName;'); | |
| 180 } | |
| 181 }); | |
| 182 for (Method method in node.methods) { | |
| 183 writeln(' uint16 ${method.name};'); | |
| 184 } | |
| 185 writeln(' }'); | |
| 186 writeln('}'); | |
| 187 writeln(); | |
| 188 }); | |
| 189 } | |
| 190 | |
| 191 void _writePatchDataStructs() { | |
| 192 writeln(""" | |
| 193 struct PresenterData { | |
| 194 String name; | |
| 195 } | |
| 196 | |
| 197 struct ListPatchData { | |
| 198 uint8 type; | |
| 199 List<ListRegionData> regions; | |
| 200 } | |
| 201 | |
| 202 // TODO(zerny): Support lists of primitives. | |
| 203 struct ListRegionData { | |
| 204 int32 index; | |
| 205 union { | |
| 206 int32 remove; | |
| 207 List<NodeData> insert; | |
| 208 List<NodePatchData> update; | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 struct PatchData { | |
| 213 union { | |
| 214 void noPatch; | |
| 215 NodePatchData* node; | |
| 216 } | |
| 217 } | |
| 218 """); | |
| 219 } | |
| 220 | |
| 221 void _writeActionArgumentStructs() { | |
| 222 for (List<Type> formals in _methodSignatures.values) { | |
| 223 String suffix = actionTypeSuffix(formals); | |
| 224 bool boxedArguments = formals.any((t) => t.isString); | |
| 225 if (!boxedArguments) continue; | |
| 226 writeln('struct Action${suffix}Args {'); | |
| 227 int i = 0; | |
| 228 writeln(' uint16 id;'); | |
| 229 for (Type formal in formals) { | |
| 230 writeln(' ${formal.identifier} arg${i++};'); | |
| 231 } | |
| 232 writeln('}'); | |
| 233 } | |
| 234 } | |
| 235 } | |
| OLD | NEW |