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.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 import 'package:servicec/util.dart' as strings; | |
12 | |
13 import 'shared.dart'; | |
14 | |
15 import '../emitter.dart'; | |
16 import '../primitives.dart' as primitives; | |
17 import '../struct_layout.dart'; | |
18 | |
19 const COPYRIGHT = """ | |
20 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
21 // for details. All rights reserved. Use of this source code is governed by a | |
22 // BSD-style license that can be found in the LICENSE.md file. | |
23 """; | |
24 | |
25 const List<String> RESOURCES = const [ | |
26 "struct.h", | |
27 "struct.cc", | |
28 "unicode.h", | |
29 "unicode.cc", | |
30 ]; | |
31 | |
32 const int RESPONSE_HEADER_SIZE = 8; | |
33 | |
34 void generate(String path, | |
35 Unit unit, | |
36 String resourcesDirectory, | |
37 String outputDirectory) { | |
38 String directory = join(outputDirectory, "cc"); | |
39 _generateHeaderFile(path, unit, directory); | |
40 _generateImplementationFile(path, unit, directory); | |
41 | |
42 resourcesDirectory = join(resourcesDirectory, 'cc'); | |
43 for (String resource in RESOURCES) { | |
44 String resourcePath = join(resourcesDirectory, resource); | |
45 File file = new File(resourcePath); | |
46 String contents = file.readAsStringSync(); | |
47 writeToFile(directory, resource, contents); | |
48 } | |
49 } | |
50 | |
51 void _generateHeaderFile(String path, Unit unit, String directory) { | |
52 _HeaderVisitor visitor = new _HeaderVisitor(path); | |
53 visitor.visit(unit); | |
54 String contents = visitor.buffer.toString(); | |
55 writeToFile(directory, path, contents, extension: 'h'); | |
56 } | |
57 | |
58 void _generateImplementationFile(String path, Unit unit, String directory) { | |
59 _ImplementationVisitor visitor = new _ImplementationVisitor(path); | |
60 visitor.visit(unit); | |
61 String contents = visitor.buffer.toString(); | |
62 writeToFile(directory, path, contents, extension: 'cc'); | |
63 } | |
64 | |
65 abstract class CcVisitor extends CodeGenerationVisitor { | |
66 CcVisitor(String path) : super(path); | |
67 | |
68 static const int REQUEST_HEADER_SIZE = 56; | |
69 static const PRIMITIVE_TYPES = const <String, String> { | |
70 'void' : 'void', | |
71 'bool' : 'bool', | |
72 | |
73 'uint8' : 'uint8_t', | |
74 'uint16' : 'uint16_t', | |
75 | |
76 'int8' : 'int8_t', | |
77 'int16' : 'int16_t', | |
78 'int32' : 'int32_t', | |
79 'int64' : 'int64_t', | |
80 | |
81 'float32' : 'float', | |
82 'float64' : 'double', | |
83 }; | |
84 | |
85 static String cast(String type, bool cStyle) => cStyle | |
86 ? '($type)' | |
87 : 'reinterpret_cast<$type>'; | |
88 | |
89 visitUnion(Union node) { | |
90 throw "Unreachable"; | |
91 } | |
92 | |
93 visitFormal(Formal node) { | |
94 writeType(node.type); | |
95 write(' ${node.name}'); | |
96 } | |
97 | |
98 void writeType(Type node) { | |
99 Node resolved = node.resolved; | |
100 if (resolved != null) { | |
101 write('${node.identifier}Builder'); | |
102 } else { | |
103 String type = PRIMITIVE_TYPES[node.identifier]; | |
104 write(type); | |
105 } | |
106 } | |
107 | |
108 void writeReturnType(Type node) { | |
109 Node resolved = node.resolved; | |
110 if (resolved != null) { | |
111 write('${node.identifier}'); | |
112 } else { | |
113 String type = PRIMITIVE_TYPES[node.identifier]; | |
114 write(type); | |
115 } | |
116 } | |
117 | |
118 visitArguments(List<Formal> formals) { | |
119 visitNodes(formals, (first) => first ? '' : ', '); | |
120 } | |
121 | |
122 visitStructArgumentMethodBody(String id, | |
123 Method method, | |
124 {String callback}) { | |
125 bool async = callback != null; | |
126 String argumentName = method.arguments.single.name; | |
127 if (method.outputKind == OutputKind.STRUCT) { | |
128 if (async) { | |
129 write(' '); | |
130 writeln('$argumentName.InvokeMethodAsync(service_id_, $id,' | |
131 ' $callback, reinterpret_cast<void*>(callback), callback_data);'
); | |
132 } else { | |
133 writeln(' int64_t result = $argumentName.' | |
134 'InvokeMethod(service_id_, $id);'); | |
135 writeln(' char* memory = reinterpret_cast<char*>(result);'); | |
136 // TODO(ajohnsen): Do range-check between size and segment size. | |
137 writeln(' Segment* segment = MessageReader::GetRootSegment(memory);'); | |
138 writeln(' return ${method.returnType.identifier}' | |
139 '(segment, $RESPONSE_HEADER_SIZE);'); | |
140 } | |
141 } else { | |
142 write(' '); | |
143 if (!method.returnType.isVoid && !async) write('return '); | |
144 String suffix = async ? 'Async' : ''; | |
145 String cb = async ? ', $callback, reinterpret_cast<void*>(callback), callb
ack_data' : ''; | |
146 writeln('$argumentName.InvokeMethod$suffix(service_id_, $id$cb);'); | |
147 } | |
148 } | |
149 | |
150 visitMethodBody(String id, | |
151 Method method, | |
152 {bool cStyle: false, | |
153 List<String> extraArguments: const [], | |
154 String callback}) { | |
155 List<Formal> arguments = method.arguments; | |
156 assert(method.inputKind == InputKind.PRIMITIVES); | |
157 StructLayout layout = method.inputPrimitiveStructLayout; | |
158 final bool async = callback != null; | |
159 int size = REQUEST_HEADER_SIZE + layout.size; | |
160 if (async) { | |
161 write(' static const int kSize = '); | |
162 writeln('${size} + ${extraArguments.length} * sizeof(void*);'); | |
163 } else { | |
164 writeln(' static const int kSize = ${size};'); | |
165 } | |
166 | |
167 String cast(String type) => CcVisitor.cast(type, cStyle); | |
168 | |
169 String pointerToArgument(int offset, int pointers, String type) { | |
170 offset += REQUEST_HEADER_SIZE; | |
171 String prefix = cast('$type*'); | |
172 if (pointers == 0) return '$prefix(_buffer + $offset)'; | |
173 return '$prefix(_buffer + $offset + $pointers * sizeof(void*))'; | |
174 } | |
175 | |
176 if (async) { | |
177 writeln(' char* _buffer = ${cast("char*")}(malloc(kSize));'); | |
178 } else { | |
179 writeln(' char _bits[kSize];'); | |
180 writeln(' char* _buffer = _bits;'); | |
181 } | |
182 | |
183 // Mark the message as being non-segmented. | |
184 writeln(' *${pointerToArgument(-8, 0, "int64_t")} = 0;'); | |
185 | |
186 int arity = arguments.length; | |
187 for (int i = 0; i < arity; i++) { | |
188 String name = arguments[i].name; | |
189 int offset = layout[arguments[i]].offset; | |
190 String type = PRIMITIVE_TYPES[arguments[i].type.identifier]; | |
191 writeln(' *${pointerToArgument(offset, 0, type)} = $name;'); | |
192 } | |
193 | |
194 if (async) { | |
195 String callbackFunction = pointerToArgument(-16, 0, 'void*'); | |
196 String callbackData = pointerToArgument(-24, 0, 'void*'); | |
197 writeln(' *$callbackFunction = ${cast("void*")}(callback);'); | |
198 writeln(' *$callbackData = callback_data;'); | |
199 for (int i = 0; i < extraArguments.length; i++) { | |
200 String dataArgument = pointerToArgument(layout.size, i, 'void*'); | |
201 String arg = extraArguments[i]; | |
202 writeln(' *$dataArgument = ${cast("void*")}($arg);'); | |
203 } | |
204 write(' ServiceApiInvokeAsync(service_id_, $id, $callback, '); | |
205 writeln('_buffer, kSize);'); | |
206 } else { | |
207 writeln(' ServiceApiInvoke(service_id_, $id, _buffer, kSize);'); | |
208 if (method.outputKind == OutputKind.STRUCT) { | |
209 writeln(' int64_t result = *${pointerToArgument(0, 0, 'int64_t')};'); | |
210 writeln(' char* memory = reinterpret_cast<char*>(result);'); | |
211 // TODO(ajohnsen): Do range-check between size and segment size. | |
212 writeln(' Segment* segment = MessageReader::GetRootSegment(memory);'); | |
213 writeln(' return ${method.returnType.identifier}' | |
214 '(segment, $RESPONSE_HEADER_SIZE);'); | |
215 } else if (!method.returnType.isVoid) { | |
216 writeln(' return *${pointerToArgument(0, 0, 'int64_t')};'); | |
217 } | |
218 } | |
219 } | |
220 } | |
221 | |
222 class _HeaderVisitor extends CcVisitor { | |
223 _HeaderVisitor(String path) : super(path); | |
224 | |
225 String computeHeaderGuard() { | |
226 String base = basenameWithoutExtension(path).toUpperCase(); | |
227 return '${base}_H'; | |
228 } | |
229 | |
230 visitUnit(Unit node) { | |
231 String headerGuard = computeHeaderGuard(); | |
232 writeln(COPYRIGHT); | |
233 | |
234 writeln('// Generated file. Do not edit.'); | |
235 writeln(); | |
236 | |
237 writeln('#ifndef $headerGuard'); | |
238 writeln('#define $headerGuard'); | |
239 | |
240 writeln(); | |
241 writeln('#include <inttypes.h>'); | |
242 writeln('#include "struct.h"'); | |
243 | |
244 if (node.structs.isNotEmpty) writeln(); | |
245 for (Struct struct in node.structs) { | |
246 writeln('class ${struct.name};'); | |
247 writeln('class ${struct.name}Builder;'); | |
248 } | |
249 | |
250 node.services.forEach(visit); | |
251 node.structs.forEach(visit); | |
252 | |
253 writeln(); | |
254 writeln('#endif // $headerGuard'); | |
255 } | |
256 | |
257 visitService(Service node) { | |
258 writeln(); | |
259 writeln('class ${node.name} {'); | |
260 writeln(' public:'); | |
261 writeln(' static void setup();'); | |
262 writeln(' static void tearDown();'); | |
263 | |
264 node.methods.forEach(visit); | |
265 | |
266 writeln('};'); | |
267 } | |
268 | |
269 visitMethod(Method node) { | |
270 write(' static '); | |
271 writeReturnType(node.returnType); | |
272 write(' ${node.name}('); | |
273 visitArguments(node.arguments); | |
274 writeln(');'); | |
275 | |
276 write(' static void ${node.name}Async('); | |
277 visitArguments(node.arguments); | |
278 if (node.arguments.isNotEmpty) write(', '); | |
279 write('void (*callback)('); | |
280 if (!node.returnType.isVoid) { | |
281 writeReturnType(node.returnType); | |
282 write(', '); | |
283 } | |
284 writeln('void*), void* callback_data);'); | |
285 } | |
286 | |
287 visitStruct(Struct node) { | |
288 writeReader(node); | |
289 writeBuilder(node); | |
290 } | |
291 | |
292 void writeReader(Struct node) { | |
293 String name = node.name; | |
294 StructLayout layout = node.layout; | |
295 | |
296 writeln(); | |
297 writeln('class $name : public Reader {'); | |
298 writeln(' public:'); | |
299 writeln(' static const int kSize = ${layout.size};'); | |
300 | |
301 writeln(' $name(Segment* segment, int offset)'); | |
302 writeln(' : Reader(segment, offset) { }'); | |
303 writeln(); | |
304 | |
305 for (StructSlot slot in layout.slots) { | |
306 Type slotType = slot.slot.type; | |
307 String camel = camelize(slot.slot.name); | |
308 | |
309 if (slot.isUnionSlot) { | |
310 String tagName = camelize(slot.union.tag.name); | |
311 int tag = slot.unionTag; | |
312 writeln(' bool is$camel() const { return $tag == get$tagName(); }'); | |
313 } | |
314 | |
315 if (slotType.isList) { | |
316 write(' '); | |
317 write('List<'); | |
318 writeReturnType(slotType); | |
319 write('> get$camel() const { '); | |
320 write('return ReadList<'); | |
321 writeReturnType(slotType); | |
322 writeln('>(${slot.offset}); }'); | |
323 } else if (slotType.isVoid) { | |
324 // No getters for void slots. | |
325 } else if (slotType.isString) { | |
326 writeln(' char* get$camel() const ' | |
327 '{ return ReadString(${slot.offset}); }'); | |
328 writeln(' List<uint16_t> get${camel}Data() const ' | |
329 '{ return ReadList<uint16_t>(${slot.offset}); }'); | |
330 } else if (slotType.isPrimitive) { | |
331 write(' '); | |
332 writeType(slotType); | |
333 write(' get$camel() const { return *PointerTo<'); | |
334 if (slotType.isBool) { | |
335 writeln('uint8_t>(${slot.offset}) != 0; }'); | |
336 } else { | |
337 writeType(slotType); | |
338 writeln('>(${slot.offset}); }'); | |
339 } | |
340 } else { | |
341 write(' '); | |
342 writeReturnType(slotType); | |
343 writeln(' get$camel() const;'); | |
344 } | |
345 } | |
346 | |
347 writeln('};'); | |
348 } | |
349 | |
350 void writeBuilder(Struct node) { | |
351 String name = "${node.name}Builder"; | |
352 StructLayout layout = node.layout; | |
353 | |
354 writeln(); | |
355 writeln('class $name : public Builder {'); | |
356 writeln(' public:'); | |
357 writeln(' static const int kSize = ${layout.size};'); | |
358 writeln(); | |
359 | |
360 writeln(' explicit $name(const Builder& builder)'); | |
361 writeln(' : Builder(builder) { }'); | |
362 writeln(' $name(Segment* segment, int offset)'); | |
363 writeln(' : Builder(segment, offset) { }'); | |
364 writeln(); | |
365 | |
366 for (StructSlot slot in layout.slots) { | |
367 String slotName = slot.slot.name; | |
368 Type slotType = slot.slot.type; | |
369 | |
370 String updateTag = ''; | |
371 if (slot.isUnionSlot) { | |
372 String tagName = camelize(slot.union.tag.name); | |
373 int tag = slot.unionTag; | |
374 updateTag = 'set$tagName($tag); '; | |
375 } | |
376 | |
377 String camel = camelize(slotName); | |
378 if (slotType.isList) { | |
379 write(' List<'); | |
380 writeType(slotType); | |
381 writeln('> init$camel(int length);'); | |
382 } else if (slotType.isVoid) { | |
383 assert(slot.isUnionSlot); | |
384 String tagName = camelize(slot.union.tag.name); | |
385 int tag = slot.unionTag; | |
386 writeln(' void set$camel() { set$tagName($tag); }'); | |
387 } else if (slotType.isString) { | |
388 write(' void set$camel(const char* value) { '); | |
389 write(updateTag); | |
390 writeln('NewString(${slot.offset}, value); }'); | |
391 writeln(' List<uint16_t> init${camel}Data(int length);'); | |
392 } else if (slotType.isPrimitive) { | |
393 write(' void set$camel('); | |
394 writeType(slotType); | |
395 write(' value) { '); | |
396 write(updateTag); | |
397 write('*PointerTo<'); | |
398 if (slotType.isBool) { | |
399 writeln('uint8_t>(${slot.offset}) = value ? 1 : 0; }'); | |
400 } else { | |
401 writeType(slotType); | |
402 writeln('>(${slot.offset}) = value; }'); | |
403 } | |
404 } else { | |
405 write(' '); | |
406 writeType(slotType); | |
407 writeln(' init$camel();'); | |
408 } | |
409 } | |
410 | |
411 writeln('};'); | |
412 } | |
413 } | |
414 | |
415 class _ImplementationVisitor extends CcVisitor { | |
416 int methodId = 1; | |
417 String serviceName; | |
418 | |
419 _ImplementationVisitor(String path) : super(path); | |
420 | |
421 String computeHeaderFile() { | |
422 String base = basenameWithoutExtension(path); | |
423 return '$base.h'; | |
424 } | |
425 | |
426 visitUnit(Unit node) { | |
427 String headerFile = computeHeaderFile(); | |
428 writeln(COPYRIGHT); | |
429 | |
430 writeln('// Generated file. Do not edit.'); | |
431 writeln(); | |
432 | |
433 writeln('#include "$headerFile"'); | |
434 writeln('#include "include/service_api.h"'); | |
435 writeln('#include <stdlib.h>'); | |
436 | |
437 node.services.forEach(visit); | |
438 node.structs.forEach(visit); | |
439 } | |
440 | |
441 visitService(Service node) { | |
442 writeln(); | |
443 writeln('static ServiceId service_id_ = kNoServiceId;'); | |
444 | |
445 serviceName = node.name; | |
446 | |
447 writeln(); | |
448 writeln('void ${serviceName}::setup() {'); | |
449 writeln(' service_id_ = ServiceApiLookup("$serviceName");'); | |
450 writeln('}'); | |
451 | |
452 writeln(); | |
453 writeln('void ${serviceName}::tearDown() {'); | |
454 writeln(' ServiceApiTerminate(service_id_);'); | |
455 writeln(' service_id_ = kNoServiceId;'); | |
456 writeln('}'); | |
457 | |
458 node.methods.forEach(visit); | |
459 } | |
460 | |
461 visitStruct(Struct node) { | |
462 writeBuilder(node); | |
463 writeReader(node); | |
464 } | |
465 | |
466 void writeBuilder(Struct node) { | |
467 String name = "${node.name}Builder"; | |
468 StructLayout layout = node.layout; | |
469 | |
470 for (StructSlot slot in layout.slots) { | |
471 String slotName = slot.slot.name; | |
472 Type slotType = slot.slot.type; | |
473 | |
474 String updateTag = ''; | |
475 if (slot.isUnionSlot) { | |
476 String tagName = camelize(slot.union.tag.name); | |
477 int tag = slot.unionTag; | |
478 updateTag = ' set$tagName($tag);\n'; | |
479 } | |
480 | |
481 String camel = camelize(slotName); | |
482 if (slotType.isList) { | |
483 writeln(); | |
484 write('List<'); | |
485 writeType(slotType); | |
486 writeln('> $name::init$camel(int length) {'); | |
487 write(updateTag); | |
488 int size = 0; | |
489 if (slotType.isPrimitive) { | |
490 size = primitives.size(slotType.primitiveType); | |
491 } else { | |
492 Struct element = slot.slot.type.resolved; | |
493 StructLayout elementLayout = element.layout; | |
494 size = elementLayout.size; | |
495 } | |
496 writeln(' Reader result = NewList(${slot.offset}, length, $size);'); | |
497 write(' return List<'); | |
498 writeType(slotType); | |
499 writeln('>(result.segment(), result.offset(), length);'); | |
500 writeln('}'); | |
501 } else if (slotType.isString) { | |
502 writeln(); | |
503 writeln('List<uint16_t> $name::init${camel}Data(int length) {'); | |
504 write(updateTag); | |
505 writeln(' Reader result = NewList(${slot.offset}, length, 2);'); | |
506 writeln(' return List<uint16_t>(result.segment(), result.offset(),' | |
507 ' length);'); | |
508 writeln('}'); | |
509 } else if (!slotType.isPrimitive) { | |
510 writeln(); | |
511 writeType(slotType); | |
512 writeln(' $name::init$camel() {'); | |
513 Struct element = slot.slot.type.resolved; | |
514 StructLayout elementLayout = element.layout; | |
515 int size = elementLayout.size; | |
516 write(updateTag); | |
517 if (!slotType.isPointer) { | |
518 write(' return '); | |
519 writeType(slotType); | |
520 writeln('(segment(), offset() + ${slot.offset});'); | |
521 } else { | |
522 writeln(' Builder result = NewStruct(${slot.offset}, $size);'); | |
523 write(' return '); | |
524 writeType(slotType); | |
525 writeln('(result);'); | |
526 } | |
527 writeln('}'); | |
528 } | |
529 } | |
530 } | |
531 | |
532 void writeReader(Struct node) { | |
533 String name = "${node.name}"; | |
534 StructLayout layout = node.layout; | |
535 | |
536 for (StructSlot slot in layout.slots) { | |
537 String slotName = slot.slot.name; | |
538 Type slotType = slot.slot.type; | |
539 | |
540 String camel = camelize(slotName); | |
541 if (!slotType.isPrimitive && !slotType.isList && !slotType.isString) { | |
542 writeln(); | |
543 writeReturnType(slotType); | |
544 write(' $name::get$camel() const { return '); | |
545 if (!slotType.isPointer) { | |
546 writeReturnType(slotType); | |
547 writeln('(segment(), offset() + ${slot.offset}); }'); | |
548 } else { | |
549 write('ReadStruct<'); | |
550 writeReturnType(slotType); | |
551 writeln('>(${slot.offset}); }'); | |
552 } | |
553 } | |
554 } | |
555 } | |
556 | |
557 visitMethod(Method node) { | |
558 String name = node.name; | |
559 String id = 'k${camelize(name)}Id_'; | |
560 | |
561 writeln(); | |
562 write('static const MethodId $id = '); | |
563 writeln('reinterpret_cast<MethodId>(${methodId++});'); | |
564 | |
565 writeln(); | |
566 writeReturnType(node.returnType); | |
567 write(' $serviceName::${name}('); | |
568 visitArguments(node.arguments); | |
569 writeln(') {'); | |
570 | |
571 if (node.inputKind == InputKind.STRUCT) { | |
572 visitStructArgumentMethodBody(id, node); | |
573 } else { | |
574 assert(node.inputKind == InputKind.PRIMITIVES); | |
575 visitMethodBody(id, node); | |
576 } | |
577 | |
578 writeln('}'); | |
579 | |
580 String callback; | |
581 if (node.inputKind == InputKind.STRUCT) { | |
582 Struct struct = node.arguments.single.type.resolved; | |
583 StructLayout layout = struct.layout; | |
584 callback = ensureCallback(node.returnType, layout); | |
585 } else { | |
586 callback = | |
587 ensureCallback(node.returnType, node.inputPrimitiveStructLayout); | |
588 } | |
589 | |
590 writeln(); | |
591 write('void $serviceName::${name}Async('); | |
592 visitArguments(node.arguments); | |
593 if (node.arguments.isNotEmpty) write(', '); | |
594 write('void (*callback)('); | |
595 if (!node.returnType.isVoid) { | |
596 writeReturnType(node.returnType); | |
597 write(', '); | |
598 } | |
599 writeln('void*), void* callback_data) {'); | |
600 | |
601 if (node.inputKind == InputKind.STRUCT) { | |
602 visitStructArgumentMethodBody(id, node, callback: callback); | |
603 } else { | |
604 visitMethodBody(id, node, callback: callback); | |
605 } | |
606 | |
607 writeln('}'); | |
608 } | |
609 | |
610 final Map<String, String> callbacks = {}; | |
611 String ensureCallback(Type type, | |
612 StructLayout layout, | |
613 {bool cStyle: false}) { | |
614 String key = '${type.identifier}_${layout.size}'; | |
615 return callbacks.putIfAbsent(key, () { | |
616 String cast(String type) => CcVisitor.cast(type, cStyle); | |
617 String pointerToArgument(int offset, int pointers, String type) { | |
618 offset += CcVisitor.REQUEST_HEADER_SIZE; | |
619 String prefix = cast('$type*'); | |
620 if (pointers == 0) return '$prefix(buffer + $offset)'; | |
621 return '$prefix(buffer + $offset + $pointers * sizeof(void*))'; | |
622 } | |
623 String name = 'Unwrap_$key'; | |
624 writeln(); | |
625 writeln('static void $name(void* raw) {'); | |
626 if (type.isVoid) { | |
627 writeln(' typedef void (*cbt)(void*);'); | |
628 } else { | |
629 write(' typedef void (*cbt)('); | |
630 writeReturnType(type); | |
631 writeln(', void*);'); | |
632 } | |
633 writeln(' char* buffer = ${cast('char*')}(raw);'); | |
634 int offset = CcVisitor.REQUEST_HEADER_SIZE; | |
635 if (!type.isVoid) { | |
636 writeln(' int64_t result = *${cast('int64_t*')}(buffer + $offset);'); | |
637 if (!type.isPrimitive) { | |
638 writeln(' char* memory = reinterpret_cast<char*>(result);'); | |
639 writeln(' Segment* segment = ' | |
640 'MessageReader::GetRootSegment(memory);'); | |
641 } | |
642 } | |
643 String callbackFunction = pointerToArgument(-16, 0, 'cbt'); | |
644 String callbackData = pointerToArgument(-24, 0, 'void*'); | |
645 writeln(' cbt callback = *$callbackFunction;'); | |
646 writeln(' void* callback_data = *$callbackData;'); | |
647 writeln(' MessageBuilder::DeleteMessage(buffer);'); | |
648 if (type.isVoid) { | |
649 writeln(' callback(callback_data);'); | |
650 } else { | |
651 if (type.isPrimitive) { | |
652 writeln(' callback(result, callback_data);'); | |
653 } else { | |
654 write(' callback('); | |
655 writeReturnType(type); | |
656 writeln('(segment, 8), callback_data);'); | |
657 } | |
658 } | |
659 writeln('}'); | |
660 return name; | |
661 }); | |
662 } | |
663 } | |
OLD | NEW |