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 |