| 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 old_servicec.plugins.dart; | |
| 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:servicec/util.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 const int HEADER_SIZE = 56; | |
| 25 | |
| 26 const List<String> RESOURCES = const [ | |
| 27 "struct.dart", | |
| 28 ]; | |
| 29 | |
| 30 void generate(String path, | |
| 31 Unit unit, | |
| 32 String resourcesDirectory, | |
| 33 String outputDirectory) { | |
| 34 _DartVisitor visitor = new _DartVisitor(path); | |
| 35 visitor.visit(unit); | |
| 36 String contents = visitor.buffer.toString(); | |
| 37 String directory = join(outputDirectory, 'dart'); | |
| 38 writeToFile(directory, path, contents, extension: 'dart'); | |
| 39 | |
| 40 resourcesDirectory = join(resourcesDirectory, 'dart'); | |
| 41 for (String resource in RESOURCES) { | |
| 42 String resourcePath = join(resourcesDirectory, resource); | |
| 43 File file = new File(resourcePath); | |
| 44 String contents = file.readAsStringSync(); | |
| 45 writeToFile(directory, resource, contents); | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 class _DartVisitor extends CodeGenerationVisitor { | |
| 50 final Set<Type> neededListTypes = new Set<Type>(); | |
| 51 final List<Method> methods = new List(); | |
| 52 _DartVisitor(String path) : super(path); | |
| 53 | |
| 54 static Map<String, String> _GETTERS = const { | |
| 55 'bool' : 'getUint8', | |
| 56 | |
| 57 'uint8' : 'getUint8', | |
| 58 'uint16' : 'getUint16', | |
| 59 | |
| 60 'int8' : 'getInt8', | |
| 61 'int16' : 'getInt16', | |
| 62 'int32' : 'getInt32', | |
| 63 'int64' : 'getInt64', | |
| 64 | |
| 65 'float32' : 'getFloat32', | |
| 66 'float64' : 'getFloat64', | |
| 67 }; | |
| 68 | |
| 69 static Map<String, String> _SETTERS = const { | |
| 70 'bool' : 'setUint8', | |
| 71 | |
| 72 'uint8' : 'setUint8', | |
| 73 'uint16' : 'setUint16', | |
| 74 | |
| 75 'int8' : 'setInt8', | |
| 76 'int16' : 'setInt16', | |
| 77 'int32' : 'setInt32', | |
| 78 'int64' : 'setInt64', | |
| 79 | |
| 80 'float32' : 'setFloat32', | |
| 81 'float64' : 'setFloat64', | |
| 82 }; | |
| 83 | |
| 84 visitUnit(Unit node) { | |
| 85 writeln(COPYRIGHT); | |
| 86 | |
| 87 writeln('// Generated file. Do not edit.'); | |
| 88 writeln(); | |
| 89 | |
| 90 String libraryName = basenameWithoutExtension(path); | |
| 91 writeln('library $libraryName;'); | |
| 92 writeln(); | |
| 93 | |
| 94 writeln('import "dart:dartino";'); | |
| 95 writeln('import "dart:dartino.ffi";'); | |
| 96 writeln('import "dart:dartino.service" as service;'); | |
| 97 if (node.structs.isNotEmpty) { | |
| 98 writeln('import "struct.dart";'); | |
| 99 } | |
| 100 writeln(); | |
| 101 | |
| 102 writeln('final Channel _channel = new Channel();'); | |
| 103 writeln('final Port _port = new Port(_channel);'); | |
| 104 write('final ForeignFunction _postResult = '); | |
| 105 writeln('ForeignLibrary.main.lookup("PostResultToService");'); | |
| 106 | |
| 107 node.services.forEach(visit); | |
| 108 node.structs.forEach(visit); | |
| 109 | |
| 110 for (Type listType in neededListTypes) { | |
| 111 String name = listType.identifier; | |
| 112 if (listType.isPrimitive) { | |
| 113 int elementSize = primitives.size(listType.primitiveType); | |
| 114 String getter = '\$segment.memory.${_GETTERS[name]}'; | |
| 115 String setter = '\$segment.memory.${_SETTERS[name]}'; | |
| 116 String offset = '\$offset + index * $elementSize'; | |
| 117 | |
| 118 writeln(); | |
| 119 write('class _${name}List extends ListReader<'); | |
| 120 writeType(listType); | |
| 121 write('> implements List<'); | |
| 122 writeType(listType); | |
| 123 writeln('> {'); | |
| 124 write(' '); | |
| 125 writeType(listType); | |
| 126 writeln(' operator[](int index) => $getter($offset);'); | |
| 127 writeln('}'); | |
| 128 | |
| 129 writeln(); | |
| 130 write('class _${name}BuilderList extends ListBuilder<'); | |
| 131 writeType(listType); | |
| 132 write('> implements List<'); | |
| 133 writeType(listType); | |
| 134 writeln('> {'); | |
| 135 write(' '); | |
| 136 writeType(listType); | |
| 137 writeln(' operator[](int index) => $getter($offset);'); | |
| 138 write(' void operator[]=(int index, '); | |
| 139 writeType(listType); | |
| 140 writeln(' value) { $setter($offset, value); }'); | |
| 141 writeln('}'); | |
| 142 } else { | |
| 143 Struct element = listType.resolved; | |
| 144 StructLayout elementLayout = element.layout; | |
| 145 int elementSize = elementLayout.size; | |
| 146 | |
| 147 writeln(); | |
| 148 write('class _${name}List extends ListReader<$name>'); | |
| 149 writeln(' implements List<$name> {'); | |
| 150 writeln(' $name operator[](int index) => ' | |
| 151 'readListElement(new $name(), index, $elementSize);'); | |
| 152 writeln('}'); | |
| 153 | |
| 154 writeln(); | |
| 155 write('class _${name}BuilderList extends ListBuilder<${name}Builder>'); | |
| 156 writeln(' implements List<${name}Builder> {'); | |
| 157 writeln(' ${name}Builder operator[](int index) => ' | |
| 158 'readListElement(new ${name}Builder(), index, $elementSize);'); | |
| 159 writeln('}'); | |
| 160 } | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 writeImplCall(Method method) { | |
| 165 write('_impl.${method.name}('); | |
| 166 if (method.inputKind == InputKind.STRUCT) { | |
| 167 write('getRoot(new '); | |
| 168 writeType(method.arguments.single.type); | |
| 169 write('(), request)'); | |
| 170 } else { | |
| 171 assert(method.inputKind == InputKind.PRIMITIVES); | |
| 172 StructLayout inputLayout = method.inputPrimitiveStructLayout; | |
| 173 for (int i = 0; i < method.arguments.length; i++) { | |
| 174 if (i != 0) write(', '); | |
| 175 Formal argument = method.arguments[i]; | |
| 176 String getter = _GETTERS[argument.type.identifier]; | |
| 177 int offset = inputLayout[argument].offset + HEADER_SIZE; | |
| 178 write('request.$getter($offset)'); | |
| 179 } | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 visitService(Service node) { | |
| 184 String serviceName = node.name; | |
| 185 | |
| 186 writeln(); | |
| 187 writeln('bool _terminated = false;'); | |
| 188 writeln('$serviceName _impl;'); | |
| 189 | |
| 190 writeln(); | |
| 191 writeln('abstract class $serviceName {'); | |
| 192 | |
| 193 node.methods.forEach(visit); | |
| 194 | |
| 195 writeln(); | |
| 196 writeln(' static void initialize($serviceName impl) {'); | |
| 197 writeln(' if (_impl != null) {'); | |
| 198 writeln(' throw new UnsupportedError("Cannot re-initialize");'); | |
| 199 writeln(' }'); | |
| 200 writeln(' _impl = impl;'); | |
| 201 writeln(' _terminated = false;'); | |
| 202 writeln(' service.register("$serviceName", _port);'); | |
| 203 writeln(' }'); | |
| 204 | |
| 205 writeln(); | |
| 206 writeln(' static bool hasNextEvent() {'); | |
| 207 writeln(' return !_terminated;'); | |
| 208 writeln(' }'); | |
| 209 | |
| 210 | |
| 211 List<String> methodIds = methods.map((method) => | |
| 212 '_${strings.underscore(method.name).toUpperCase()}_METHOD_ID') | |
| 213 .toList(); | |
| 214 | |
| 215 writeln(); | |
| 216 writeln(' static void handleNextEvent() {'); | |
| 217 writeln(' var request = _channel.receive();'); | |
| 218 writeln(' switch (request.getInt32(0)) {'); | |
| 219 writeln(' case _TERMINATE_METHOD_ID:'); | |
| 220 writeln(' _terminated = true;'); | |
| 221 writeln(' _postResult.vcall\$1(request);'); | |
| 222 writeln(' break;'); | |
| 223 | |
| 224 String setInt32() => 'request.setInt32($HEADER_SIZE, result)'; | |
| 225 String setInt64() => 'request.setInt64($HEADER_SIZE, result)'; | |
| 226 | |
| 227 for (int i = 0; i < methods.length; ++i) { | |
| 228 Method method = methods[i]; | |
| 229 writeln(' case ${methodIds[i]}:'); | |
| 230 if (method.returnType.isVoid) { | |
| 231 write(' '); | |
| 232 writeImplCall(method); | |
| 233 writeln(');'); | |
| 234 } else if (method.returnType.isPrimitive) { | |
| 235 write(' var result = '); | |
| 236 writeImplCall(method); | |
| 237 writeln(');'); | |
| 238 writeln(' ${setInt32()};'); | |
| 239 } else { | |
| 240 Struct resultType = method.returnType.resolved; | |
| 241 StructLayout resultLayout = new StructLayout(resultType); | |
| 242 int size = resultLayout.size; | |
| 243 writeln(' MessageBuilder mb = new MessageBuilder(${size + 8});'); | |
| 244 String builderName = '${method.returnType.identifier}Builder'; | |
| 245 writeln(' $builderName builder = ' | |
| 246 'mb.initRoot(new $builderName(), $size);'); | |
| 247 write(' '); | |
| 248 writeImplCall(method); | |
| 249 write('${method.arguments.length > 0 ? ", " : ""}builder'); | |
| 250 writeln(');'); | |
| 251 writeln(' var result = getResultMessage(builder);'); | |
| 252 writeln(' ${setInt64()};'); | |
| 253 } | |
| 254 writeln(' _postResult.vcall\$1(request);'); | |
| 255 writeln(' break;'); | |
| 256 } | |
| 257 writeln(' default:'); | |
| 258 writeln(' throw new UnsupportedError("Unknown method");'); | |
| 259 writeln(' }'); | |
| 260 writeln(' }'); | |
| 261 | |
| 262 writeln(); | |
| 263 int nextId = 0; | |
| 264 writeln(' static const int _TERMINATE_METHOD_ID = ${nextId++};'); | |
| 265 for (String id in methodIds) { | |
| 266 writeln(' static const int $id = ${nextId++};'); | |
| 267 } | |
| 268 | |
| 269 writeln('}'); | |
| 270 } | |
| 271 | |
| 272 visitStruct(Struct node) { | |
| 273 StructLayout layout = node.layout; | |
| 274 | |
| 275 writeln(); | |
| 276 writeln('class ${node.name} extends Reader {'); | |
| 277 for (StructSlot slot in layout.slots) { | |
| 278 String slotName = slot.slot.name; | |
| 279 Type slotType = slot.slot.type; | |
| 280 | |
| 281 if (slot.isUnionSlot) { | |
| 282 String camel = camelize(slotName); | |
| 283 String tagName = slot.union.tag.name; | |
| 284 int tag = slot.unionTag; | |
| 285 writeln(' bool get is$camel => $tag == this.$tagName;'); | |
| 286 } | |
| 287 | |
| 288 if (slotType.isList) { | |
| 289 write(' List<'); | |
| 290 writeType(slotType); | |
| 291 write('> get $slotName => '); | |
| 292 neededListTypes.add(slotType); | |
| 293 writeln('readList(new _${slotType.identifier}List(), ${slot.offset});'); | |
| 294 } else if (slotType.isVoid) { | |
| 295 // No getters for void slots. | |
| 296 } else if (slotType.isString) { | |
| 297 Type uint16ListType = new ListType(new SimpleType("uint16", false)); | |
| 298 uint16ListType.primitiveType = primitives.lookup("uint16"); | |
| 299 neededListTypes.add(uint16ListType); | |
| 300 writeln(' String get $slotName => ' | |
| 301 'readString(new _uint16List(), ${slot.offset});'); | |
| 302 writeln(' List<int> get ${slotName}Data => ' | |
| 303 'readList(new _uint16List(), ${slot.offset});'); | |
| 304 } else if (slotType.isPrimitive) { | |
| 305 String getter = _GETTERS[slotType.identifier]; | |
| 306 String offset = '\$offset + ${slot.offset}'; | |
| 307 | |
| 308 write(' '); | |
| 309 writeType(slotType); | |
| 310 if (slotType.isBool) { | |
| 311 writeln(' get $slotName => \$segment.memory.$getter($offset) != 0;'); | |
| 312 } else { | |
| 313 writeln(' get $slotName => \$segment.memory.$getter($offset);'); | |
| 314 } | |
| 315 } else { | |
| 316 write(' '); | |
| 317 writeType(slotType); | |
| 318 write(' get $slotName => '); | |
| 319 if (!slotType.isPointer) { | |
| 320 write('new '); | |
| 321 writeType(slotType); | |
| 322 writeln('()'); | |
| 323 writeln(' ..\$segment = \$segment'); | |
| 324 writeln(' ..\$offset = \$offset + ${slot.offset};'); | |
| 325 } else { | |
| 326 write('readStruct(new '); | |
| 327 writeType(slotType); | |
| 328 writeln('(), ${slot.offset});'); | |
| 329 } | |
| 330 } | |
| 331 } | |
| 332 writeln('}'); | |
| 333 | |
| 334 writeln(); | |
| 335 writeln('class ${node.name}Builder extends Builder {'); | |
| 336 for (StructSlot slot in layout.slots) { | |
| 337 String slotName = slot.slot.name; | |
| 338 Type slotType = slot.slot.type; | |
| 339 | |
| 340 String updateTag = ''; | |
| 341 if (slot.isUnionSlot) { | |
| 342 String tagName = slot.union.tag.name; | |
| 343 int tag = slot.unionTag; | |
| 344 updateTag = ' $tagName = $tag;\n'; | |
| 345 } | |
| 346 | |
| 347 String camel = camelize(slotName); | |
| 348 if (slotType.isList) { | |
| 349 write(' List<'); | |
| 350 writeReturnType(slotType); | |
| 351 writeln('> init$camel(int length) {'); | |
| 352 write(updateTag); | |
| 353 int size = 0; | |
| 354 if (slotType.isPrimitive) { | |
| 355 size = primitives.size(slotType.primitiveType); | |
| 356 } else { | |
| 357 Struct element = slotType.resolved; | |
| 358 StructLayout elementLayout = element.layout; | |
| 359 size = elementLayout.size; | |
| 360 } | |
| 361 String type = '_${slotType.identifier}BuilderList'; | |
| 362 writeln(' $type result = NewList(new $type(), ${slot.offset},' | |
| 363 ' length, $size);'); | |
| 364 writeln(' return result;'); | |
| 365 writeln(' }'); | |
| 366 } else if (slotType.isVoid) { | |
| 367 writeln(' void set$camel() {'); | |
| 368 write(updateTag); | |
| 369 writeln(' }'); | |
| 370 } else if (slotType.isString) { | |
| 371 String type = '_uint16BuilderList'; | |
| 372 writeln(' void set ${slotName}(String value) {'); | |
| 373 write(updateTag); | |
| 374 writeln(' NewString(new $type(), ${slot.offset}, value);'); | |
| 375 writeln(' }'); | |
| 376 writeln(' List<int> init${camel}Data(int length) {'); | |
| 377 write(updateTag); | |
| 378 writeln(' $type result = NewList(new $type(), ${slot.offset},' | |
| 379 ' length, 2);'); | |
| 380 writeln(' return result;'); | |
| 381 writeln(' }'); | |
| 382 } else if (slotType.isPrimitive) { | |
| 383 String setter = _SETTERS[slotType.identifier]; | |
| 384 write(' void set ${slotName}('); | |
| 385 writeType(slotType); | |
| 386 writeln(' value) {'); | |
| 387 write(updateTag); | |
| 388 String offset = '\$offset + ${slot.offset}'; | |
| 389 if (slotType.isBool) { | |
| 390 writeln(' \$segment.memory.$setter($offset, value ? 1 : 0);'); | |
| 391 } else { | |
| 392 writeln(' \$segment.memory.$setter($offset, value);'); | |
| 393 } | |
| 394 writeln(' }'); | |
| 395 } else { | |
| 396 write(' '); | |
| 397 writeReturnType(slotType); | |
| 398 writeln(' init$camel() {'); | |
| 399 write(updateTag); | |
| 400 if (!slotType.isPointer) { | |
| 401 write(' return new '); | |
| 402 writeReturnType(slotType); | |
| 403 writeln('()'); | |
| 404 writeln(' ..\$segment = \$segment'); | |
| 405 writeln(' ..\$offset = \$offset + ${slot.offset};'); | |
| 406 } else { | |
| 407 Struct element = slotType.resolved; | |
| 408 StructLayout elementLayout = element.layout; | |
| 409 int size = elementLayout.size; | |
| 410 write(' return NewStruct(new '); | |
| 411 writeReturnType(slotType); | |
| 412 writeln('(), ${slot.offset}, $size);'); | |
| 413 } | |
| 414 writeln(' }'); | |
| 415 } | |
| 416 } | |
| 417 writeln('}'); | |
| 418 } | |
| 419 | |
| 420 visitUnion(Union node) { | |
| 421 // Ignored for now. | |
| 422 } | |
| 423 | |
| 424 visitMethod(Method node) { | |
| 425 methods.add(node); | |
| 426 if (node.outputKind == OutputKind.STRUCT) { | |
| 427 String builderName = '${node.returnType.identifier}Builder'; | |
| 428 write(' void ${node.name}('); | |
| 429 visitNodes(node.arguments, (first) => first ? '' : ', '); | |
| 430 write('${node.arguments.length > 0 ? ", " : ""}$builderName result'); | |
| 431 } else { | |
| 432 assert(node.outputKind == OutputKind.PRIMITIVE); | |
| 433 write(' '); | |
| 434 writeType(node.returnType); | |
| 435 write(' ${node.name}('); | |
| 436 visitNodes(node.arguments, (first) => first ? '' : ', '); | |
| 437 } | |
| 438 writeln(');'); | |
| 439 } | |
| 440 | |
| 441 visitFormal(Formal node) { | |
| 442 writeType(node.type); | |
| 443 write(' ${node.name}'); | |
| 444 } | |
| 445 | |
| 446 static const Map<String, String> _types = const { | |
| 447 'void' : 'void', | |
| 448 'bool' : 'bool', | |
| 449 | |
| 450 'uint8' : 'int', | |
| 451 'uint16' : 'int', | |
| 452 | |
| 453 'int8' : 'int', | |
| 454 'int16' : 'int', | |
| 455 'int32' : 'int', | |
| 456 'int64' : 'int', | |
| 457 | |
| 458 'float32' : 'double', | |
| 459 'float64' : 'double', | |
| 460 }; | |
| 461 | |
| 462 void writeType(Type node) { | |
| 463 Node resolved = node.resolved; | |
| 464 if (resolved != null) { | |
| 465 write(node.identifier); | |
| 466 } else { | |
| 467 String type = _types[node.identifier]; | |
| 468 write(type); | |
| 469 } | |
| 470 } | |
| 471 | |
| 472 void writeReturnType(Type node) { | |
| 473 Node resolved = node.resolved; | |
| 474 if (resolved != null) { | |
| 475 write('${node.identifier}Builder'); | |
| 476 } else { | |
| 477 String type = _types[node.identifier]; | |
| 478 write(type); | |
| 479 } | |
| 480 } | |
| 481 | |
| 482 } | |
| OLD | NEW |