Index: tools/servicec/lib/src/plugins/cc.dart |
diff --git a/tools/servicec/lib/src/plugins/cc.dart b/tools/servicec/lib/src/plugins/cc.dart |
deleted file mode 100644 |
index 8cd464837804db77637ab351010916f2b6e9a220..0000000000000000000000000000000000000000 |
--- a/tools/servicec/lib/src/plugins/cc.dart |
+++ /dev/null |
@@ -1,663 +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 old_servicec.plugins.cc; |
- |
-import 'dart:core' hide Type; |
-import 'dart:io' show Platform, File; |
- |
-import 'package:path/path.dart' show basenameWithoutExtension, join, dirname; |
-import 'package:servicec/util.dart' as strings; |
- |
-import 'shared.dart'; |
- |
-import '../emitter.dart'; |
-import '../primitives.dart' as primitives; |
-import '../struct_layout.dart'; |
- |
-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 List<String> RESOURCES = const [ |
- "struct.h", |
- "struct.cc", |
- "unicode.h", |
- "unicode.cc", |
-]; |
- |
-const int RESPONSE_HEADER_SIZE = 8; |
- |
-void generate(String path, |
- Unit unit, |
- String resourcesDirectory, |
- String outputDirectory) { |
- String directory = join(outputDirectory, "cc"); |
- _generateHeaderFile(path, unit, directory); |
- _generateImplementationFile(path, unit, directory); |
- |
- resourcesDirectory = join(resourcesDirectory, 'cc'); |
- 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, Unit unit, String directory) { |
- _HeaderVisitor visitor = new _HeaderVisitor(path); |
- visitor.visit(unit); |
- String contents = visitor.buffer.toString(); |
- writeToFile(directory, path, contents, extension: 'h'); |
-} |
- |
-void _generateImplementationFile(String path, Unit unit, String directory) { |
- _ImplementationVisitor visitor = new _ImplementationVisitor(path); |
- visitor.visit(unit); |
- String contents = visitor.buffer.toString(); |
- writeToFile(directory, path, contents, extension: 'cc'); |
-} |
- |
-abstract class CcVisitor extends CodeGenerationVisitor { |
- CcVisitor(String path) : super(path); |
- |
- static const int REQUEST_HEADER_SIZE = 56; |
- static const PRIMITIVE_TYPES = const <String, String> { |
- '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', |
- }; |
- |
- static String cast(String type, bool cStyle) => cStyle |
- ? '($type)' |
- : 'reinterpret_cast<$type>'; |
- |
- visitUnion(Union node) { |
- throw "Unreachable"; |
- } |
- |
- visitFormal(Formal node) { |
- writeType(node.type); |
- write(' ${node.name}'); |
- } |
- |
- void writeType(Type node) { |
- Node resolved = node.resolved; |
- if (resolved != null) { |
- write('${node.identifier}Builder'); |
- } else { |
- String type = PRIMITIVE_TYPES[node.identifier]; |
- write(type); |
- } |
- } |
- |
- void writeReturnType(Type node) { |
- Node resolved = node.resolved; |
- if (resolved != null) { |
- write('${node.identifier}'); |
- } else { |
- String type = PRIMITIVE_TYPES[node.identifier]; |
- write(type); |
- } |
- } |
- |
- visitArguments(List<Formal> formals) { |
- visitNodes(formals, (first) => first ? '' : ', '); |
- } |
- |
- visitStructArgumentMethodBody(String id, |
- Method method, |
- {String callback}) { |
- bool async = callback != null; |
- String argumentName = method.arguments.single.name; |
- if (method.outputKind == OutputKind.STRUCT) { |
- if (async) { |
- write(' '); |
- writeln('$argumentName.InvokeMethodAsync(service_id_, $id,' |
- ' $callback, reinterpret_cast<void*>(callback), callback_data);'); |
- } else { |
- writeln(' int64_t result = $argumentName.' |
- 'InvokeMethod(service_id_, $id);'); |
- writeln(' char* memory = reinterpret_cast<char*>(result);'); |
- // TODO(ajohnsen): Do range-check between size and segment size. |
- writeln(' Segment* segment = MessageReader::GetRootSegment(memory);'); |
- writeln(' return ${method.returnType.identifier}' |
- '(segment, $RESPONSE_HEADER_SIZE);'); |
- } |
- } else { |
- write(' '); |
- if (!method.returnType.isVoid && !async) write('return '); |
- String suffix = async ? 'Async' : ''; |
- String cb = async ? ', $callback, reinterpret_cast<void*>(callback), callback_data' : ''; |
- writeln('$argumentName.InvokeMethod$suffix(service_id_, $id$cb);'); |
- } |
- } |
- |
- visitMethodBody(String id, |
- Method method, |
- {bool cStyle: false, |
- List<String> extraArguments: const [], |
- String callback}) { |
- List<Formal> arguments = method.arguments; |
- assert(method.inputKind == InputKind.PRIMITIVES); |
- StructLayout layout = method.inputPrimitiveStructLayout; |
- final bool async = callback != null; |
- int size = REQUEST_HEADER_SIZE + layout.size; |
- if (async) { |
- write(' static const int kSize = '); |
- writeln('${size} + ${extraArguments.length} * sizeof(void*);'); |
- } else { |
- writeln(' static const int kSize = ${size};'); |
- } |
- |
- String cast(String type) => CcVisitor.cast(type, cStyle); |
- |
- String pointerToArgument(int offset, int pointers, String type) { |
- offset += REQUEST_HEADER_SIZE; |
- String prefix = cast('$type*'); |
- if (pointers == 0) return '$prefix(_buffer + $offset)'; |
- return '$prefix(_buffer + $offset + $pointers * sizeof(void*))'; |
- } |
- |
- if (async) { |
- writeln(' char* _buffer = ${cast("char*")}(malloc(kSize));'); |
- } else { |
- writeln(' char _bits[kSize];'); |
- writeln(' char* _buffer = _bits;'); |
- } |
- |
- // Mark the message as being non-segmented. |
- writeln(' *${pointerToArgument(-8, 0, "int64_t")} = 0;'); |
- |
- int arity = arguments.length; |
- for (int i = 0; i < arity; i++) { |
- String name = arguments[i].name; |
- int offset = layout[arguments[i]].offset; |
- String type = PRIMITIVE_TYPES[arguments[i].type.identifier]; |
- writeln(' *${pointerToArgument(offset, 0, type)} = $name;'); |
- } |
- |
- if (async) { |
- String callbackFunction = pointerToArgument(-16, 0, 'void*'); |
- String callbackData = pointerToArgument(-24, 0, 'void*'); |
- writeln(' *$callbackFunction = ${cast("void*")}(callback);'); |
- writeln(' *$callbackData = callback_data;'); |
- for (int i = 0; i < extraArguments.length; i++) { |
- String dataArgument = pointerToArgument(layout.size, i, 'void*'); |
- String arg = extraArguments[i]; |
- writeln(' *$dataArgument = ${cast("void*")}($arg);'); |
- } |
- write(' ServiceApiInvokeAsync(service_id_, $id, $callback, '); |
- writeln('_buffer, kSize);'); |
- } else { |
- writeln(' ServiceApiInvoke(service_id_, $id, _buffer, kSize);'); |
- if (method.outputKind == OutputKind.STRUCT) { |
- writeln(' int64_t result = *${pointerToArgument(0, 0, 'int64_t')};'); |
- writeln(' char* memory = reinterpret_cast<char*>(result);'); |
- // TODO(ajohnsen): Do range-check between size and segment size. |
- writeln(' Segment* segment = MessageReader::GetRootSegment(memory);'); |
- writeln(' return ${method.returnType.identifier}' |
- '(segment, $RESPONSE_HEADER_SIZE);'); |
- } else if (!method.returnType.isVoid) { |
- writeln(' return *${pointerToArgument(0, 0, 'int64_t')};'); |
- } |
- } |
- } |
-} |
- |
-class _HeaderVisitor extends CcVisitor { |
- _HeaderVisitor(String path) : super(path); |
- |
- String computeHeaderGuard() { |
- String base = basenameWithoutExtension(path).toUpperCase(); |
- return '${base}_H'; |
- } |
- |
- visitUnit(Unit node) { |
- String headerGuard = computeHeaderGuard(); |
- writeln(COPYRIGHT); |
- |
- writeln('// Generated file. Do not edit.'); |
- writeln(); |
- |
- writeln('#ifndef $headerGuard'); |
- writeln('#define $headerGuard'); |
- |
- writeln(); |
- writeln('#include <inttypes.h>'); |
- writeln('#include "struct.h"'); |
- |
- if (node.structs.isNotEmpty) writeln(); |
- for (Struct struct in node.structs) { |
- writeln('class ${struct.name};'); |
- writeln('class ${struct.name}Builder;'); |
- } |
- |
- node.services.forEach(visit); |
- node.structs.forEach(visit); |
- |
- writeln(); |
- writeln('#endif // $headerGuard'); |
- } |
- |
- visitService(Service node) { |
- writeln(); |
- writeln('class ${node.name} {'); |
- writeln(' public:'); |
- writeln(' static void setup();'); |
- writeln(' static void tearDown();'); |
- |
- node.methods.forEach(visit); |
- |
- writeln('};'); |
- } |
- |
- visitMethod(Method node) { |
- write(' static '); |
- writeReturnType(node.returnType); |
- write(' ${node.name}('); |
- visitArguments(node.arguments); |
- writeln(');'); |
- |
- write(' static void ${node.name}Async('); |
- visitArguments(node.arguments); |
- if (node.arguments.isNotEmpty) write(', '); |
- write('void (*callback)('); |
- if (!node.returnType.isVoid) { |
- writeReturnType(node.returnType); |
- write(', '); |
- } |
- writeln('void*), void* callback_data);'); |
- } |
- |
- visitStruct(Struct node) { |
- writeReader(node); |
- writeBuilder(node); |
- } |
- |
- void writeReader(Struct node) { |
- String name = node.name; |
- StructLayout layout = node.layout; |
- |
- writeln(); |
- writeln('class $name : public Reader {'); |
- writeln(' public:'); |
- writeln(' static const int kSize = ${layout.size};'); |
- |
- writeln(' $name(Segment* segment, int offset)'); |
- writeln(' : Reader(segment, offset) { }'); |
- writeln(); |
- |
- for (StructSlot slot in layout.slots) { |
- Type slotType = slot.slot.type; |
- String camel = camelize(slot.slot.name); |
- |
- if (slot.isUnionSlot) { |
- String tagName = camelize(slot.union.tag.name); |
- int tag = slot.unionTag; |
- writeln(' bool is$camel() const { return $tag == get$tagName(); }'); |
- } |
- |
- if (slotType.isList) { |
- write(' '); |
- write('List<'); |
- writeReturnType(slotType); |
- write('> get$camel() const { '); |
- write('return ReadList<'); |
- writeReturnType(slotType); |
- writeln('>(${slot.offset}); }'); |
- } else if (slotType.isVoid) { |
- // No getters for void slots. |
- } else if (slotType.isString) { |
- writeln(' char* get$camel() const ' |
- '{ return ReadString(${slot.offset}); }'); |
- writeln(' List<uint16_t> get${camel}Data() const ' |
- '{ return ReadList<uint16_t>(${slot.offset}); }'); |
- } else if (slotType.isPrimitive) { |
- write(' '); |
- writeType(slotType); |
- write(' get$camel() const { return *PointerTo<'); |
- if (slotType.isBool) { |
- writeln('uint8_t>(${slot.offset}) != 0; }'); |
- } else { |
- writeType(slotType); |
- writeln('>(${slot.offset}); }'); |
- } |
- } else { |
- write(' '); |
- writeReturnType(slotType); |
- writeln(' get$camel() const;'); |
- } |
- } |
- |
- writeln('};'); |
- } |
- |
- void writeBuilder(Struct node) { |
- String name = "${node.name}Builder"; |
- StructLayout layout = node.layout; |
- |
- writeln(); |
- writeln('class $name : public Builder {'); |
- writeln(' public:'); |
- writeln(' static const int kSize = ${layout.size};'); |
- writeln(); |
- |
- writeln(' explicit $name(const Builder& builder)'); |
- writeln(' : Builder(builder) { }'); |
- writeln(' $name(Segment* segment, int offset)'); |
- writeln(' : Builder(segment, offset) { }'); |
- writeln(); |
- |
- for (StructSlot slot in layout.slots) { |
- String slotName = slot.slot.name; |
- Type slotType = slot.slot.type; |
- |
- String updateTag = ''; |
- if (slot.isUnionSlot) { |
- String tagName = camelize(slot.union.tag.name); |
- int tag = slot.unionTag; |
- updateTag = 'set$tagName($tag); '; |
- } |
- |
- String camel = camelize(slotName); |
- if (slotType.isList) { |
- write(' List<'); |
- writeType(slotType); |
- writeln('> init$camel(int length);'); |
- } else if (slotType.isVoid) { |
- assert(slot.isUnionSlot); |
- String tagName = camelize(slot.union.tag.name); |
- int tag = slot.unionTag; |
- writeln(' void set$camel() { set$tagName($tag); }'); |
- } else if (slotType.isString) { |
- write(' void set$camel(const char* value) { '); |
- write(updateTag); |
- writeln('NewString(${slot.offset}, value); }'); |
- writeln(' List<uint16_t> init${camel}Data(int length);'); |
- } else if (slotType.isPrimitive) { |
- write(' void set$camel('); |
- writeType(slotType); |
- write(' value) { '); |
- write(updateTag); |
- write('*PointerTo<'); |
- if (slotType.isBool) { |
- writeln('uint8_t>(${slot.offset}) = value ? 1 : 0; }'); |
- } else { |
- writeType(slotType); |
- writeln('>(${slot.offset}) = value; }'); |
- } |
- } else { |
- write(' '); |
- writeType(slotType); |
- writeln(' init$camel();'); |
- } |
- } |
- |
- writeln('};'); |
- } |
-} |
- |
-class _ImplementationVisitor extends CcVisitor { |
- int methodId = 1; |
- String serviceName; |
- |
- _ImplementationVisitor(String path) : super(path); |
- |
- String computeHeaderFile() { |
- String base = basenameWithoutExtension(path); |
- return '$base.h'; |
- } |
- |
- visitUnit(Unit node) { |
- String headerFile = computeHeaderFile(); |
- writeln(COPYRIGHT); |
- |
- writeln('// Generated file. Do not edit.'); |
- writeln(); |
- |
- writeln('#include "$headerFile"'); |
- writeln('#include "include/service_api.h"'); |
- writeln('#include <stdlib.h>'); |
- |
- node.services.forEach(visit); |
- node.structs.forEach(visit); |
- } |
- |
- visitService(Service node) { |
- writeln(); |
- writeln('static ServiceId service_id_ = kNoServiceId;'); |
- |
- serviceName = node.name; |
- |
- writeln(); |
- writeln('void ${serviceName}::setup() {'); |
- writeln(' service_id_ = ServiceApiLookup("$serviceName");'); |
- writeln('}'); |
- |
- writeln(); |
- writeln('void ${serviceName}::tearDown() {'); |
- writeln(' ServiceApiTerminate(service_id_);'); |
- writeln(' service_id_ = kNoServiceId;'); |
- writeln('}'); |
- |
- node.methods.forEach(visit); |
- } |
- |
- visitStruct(Struct node) { |
- writeBuilder(node); |
- writeReader(node); |
- } |
- |
- void writeBuilder(Struct node) { |
- String name = "${node.name}Builder"; |
- StructLayout layout = node.layout; |
- |
- for (StructSlot slot in layout.slots) { |
- String slotName = slot.slot.name; |
- Type slotType = slot.slot.type; |
- |
- String updateTag = ''; |
- if (slot.isUnionSlot) { |
- String tagName = camelize(slot.union.tag.name); |
- int tag = slot.unionTag; |
- updateTag = ' set$tagName($tag);\n'; |
- } |
- |
- String camel = camelize(slotName); |
- if (slotType.isList) { |
- writeln(); |
- write('List<'); |
- writeType(slotType); |
- writeln('> $name::init$camel(int length) {'); |
- write(updateTag); |
- int size = 0; |
- if (slotType.isPrimitive) { |
- size = primitives.size(slotType.primitiveType); |
- } else { |
- Struct element = slot.slot.type.resolved; |
- StructLayout elementLayout = element.layout; |
- size = elementLayout.size; |
- } |
- writeln(' Reader result = NewList(${slot.offset}, length, $size);'); |
- write(' return List<'); |
- writeType(slotType); |
- writeln('>(result.segment(), result.offset(), length);'); |
- writeln('}'); |
- } else if (slotType.isString) { |
- writeln(); |
- writeln('List<uint16_t> $name::init${camel}Data(int length) {'); |
- write(updateTag); |
- writeln(' Reader result = NewList(${slot.offset}, length, 2);'); |
- writeln(' return List<uint16_t>(result.segment(), result.offset(),' |
- ' length);'); |
- writeln('}'); |
- } else if (!slotType.isPrimitive) { |
- writeln(); |
- writeType(slotType); |
- writeln(' $name::init$camel() {'); |
- Struct element = slot.slot.type.resolved; |
- StructLayout elementLayout = element.layout; |
- int size = elementLayout.size; |
- write(updateTag); |
- if (!slotType.isPointer) { |
- write(' return '); |
- writeType(slotType); |
- writeln('(segment(), offset() + ${slot.offset});'); |
- } else { |
- writeln(' Builder result = NewStruct(${slot.offset}, $size);'); |
- write(' return '); |
- writeType(slotType); |
- writeln('(result);'); |
- } |
- writeln('}'); |
- } |
- } |
- } |
- |
- void writeReader(Struct node) { |
- String name = "${node.name}"; |
- StructLayout layout = node.layout; |
- |
- for (StructSlot slot in layout.slots) { |
- String slotName = slot.slot.name; |
- Type slotType = slot.slot.type; |
- |
- String camel = camelize(slotName); |
- if (!slotType.isPrimitive && !slotType.isList && !slotType.isString) { |
- writeln(); |
- writeReturnType(slotType); |
- write(' $name::get$camel() const { return '); |
- if (!slotType.isPointer) { |
- writeReturnType(slotType); |
- writeln('(segment(), offset() + ${slot.offset}); }'); |
- } else { |
- write('ReadStruct<'); |
- writeReturnType(slotType); |
- writeln('>(${slot.offset}); }'); |
- } |
- } |
- } |
- } |
- |
- visitMethod(Method node) { |
- String name = node.name; |
- String id = 'k${camelize(name)}Id_'; |
- |
- writeln(); |
- write('static const MethodId $id = '); |
- writeln('reinterpret_cast<MethodId>(${methodId++});'); |
- |
- writeln(); |
- writeReturnType(node.returnType); |
- write(' $serviceName::${name}('); |
- visitArguments(node.arguments); |
- writeln(') {'); |
- |
- if (node.inputKind == InputKind.STRUCT) { |
- visitStructArgumentMethodBody(id, node); |
- } else { |
- assert(node.inputKind == InputKind.PRIMITIVES); |
- visitMethodBody(id, node); |
- } |
- |
- writeln('}'); |
- |
- String callback; |
- if (node.inputKind == InputKind.STRUCT) { |
- Struct struct = node.arguments.single.type.resolved; |
- StructLayout layout = struct.layout; |
- callback = ensureCallback(node.returnType, layout); |
- } else { |
- callback = |
- ensureCallback(node.returnType, node.inputPrimitiveStructLayout); |
- } |
- |
- writeln(); |
- write('void $serviceName::${name}Async('); |
- visitArguments(node.arguments); |
- if (node.arguments.isNotEmpty) write(', '); |
- write('void (*callback)('); |
- if (!node.returnType.isVoid) { |
- writeReturnType(node.returnType); |
- write(', '); |
- } |
- writeln('void*), void* callback_data) {'); |
- |
- if (node.inputKind == InputKind.STRUCT) { |
- visitStructArgumentMethodBody(id, node, callback: callback); |
- } else { |
- visitMethodBody(id, node, callback: callback); |
- } |
- |
- writeln('}'); |
- } |
- |
- final Map<String, String> callbacks = {}; |
- String ensureCallback(Type type, |
- StructLayout layout, |
- {bool cStyle: false}) { |
- String key = '${type.identifier}_${layout.size}'; |
- return callbacks.putIfAbsent(key, () { |
- String cast(String type) => CcVisitor.cast(type, cStyle); |
- String pointerToArgument(int offset, int pointers, String type) { |
- offset += CcVisitor.REQUEST_HEADER_SIZE; |
- String prefix = cast('$type*'); |
- if (pointers == 0) return '$prefix(buffer + $offset)'; |
- return '$prefix(buffer + $offset + $pointers * sizeof(void*))'; |
- } |
- String name = 'Unwrap_$key'; |
- writeln(); |
- writeln('static void $name(void* raw) {'); |
- if (type.isVoid) { |
- writeln(' typedef void (*cbt)(void*);'); |
- } else { |
- write(' typedef void (*cbt)('); |
- writeReturnType(type); |
- writeln(', void*);'); |
- } |
- writeln(' char* buffer = ${cast('char*')}(raw);'); |
- int offset = CcVisitor.REQUEST_HEADER_SIZE; |
- if (!type.isVoid) { |
- writeln(' int64_t result = *${cast('int64_t*')}(buffer + $offset);'); |
- if (!type.isPrimitive) { |
- writeln(' char* memory = reinterpret_cast<char*>(result);'); |
- writeln(' Segment* segment = ' |
- 'MessageReader::GetRootSegment(memory);'); |
- } |
- } |
- String callbackFunction = pointerToArgument(-16, 0, 'cbt'); |
- String callbackData = pointerToArgument(-24, 0, 'void*'); |
- writeln(' cbt callback = *$callbackFunction;'); |
- writeln(' void* callback_data = *$callbackData;'); |
- writeln(' MessageBuilder::DeleteMessage(buffer);'); |
- if (type.isVoid) { |
- writeln(' callback(callback_data);'); |
- } else { |
- if (type.isPrimitive) { |
- writeln(' callback(result, callback_data);'); |
- } else { |
- write(' callback('); |
- writeReturnType(type); |
- writeln('(segment, 8), callback_data);'); |
- } |
- } |
- writeln('}'); |
- return name; |
- }); |
- } |
-} |