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 |