]> git.lizzy.rs Git - protogen.git/blob - protogen.lua
Update endian include
[protogen.git] / protogen.lua
1 #!/usr/bin/env lua
2 require "luax"
3
4 local h   = io.open("types.h",   "w")
5 local c   = io.open("types.c",   "w")
6 local def = io.open(arg[1] or "types.def", "r")
7
8 local function emit_h(str)
9         h:write(str)
10 end
11
12 local function emit_c(str)
13         c:write(str)
14 end
15
16 local function emit(fun, code)
17         emit_h(fun .. ";\n")
18         emit_c(fun ..  "\n" .. code)
19 end
20
21 -- fn prefixes
22 local struct_prefix = "__attribute__((packed)) "
23 local export_prefix = ""
24 local local_prefix = "__attribute__((unused)) static inline "
25
26 -- head
27
28 local disclaimer = [[
29 /*
30         This file was automatically generated by Protogen.
31         DO NOT EDIT it manually. Instead, edit types.def and re-run protogen.
32 */
33
34 ]]
35
36 emit_h(disclaimer)
37 emit_h([[
38 #ifndef _PROTOGEN_TYPES_H_
39 #define _PROTOGEN_TYPES_H_
40
41 #ifdef USE_DRAGONNET
42 #include <dragonnet/peer.h>
43 #endif
44
45 #include <stdbool.h>
46 #include <stddef.h>
47 #include <stdint.h>
48
49 typedef char *String;
50
51 typedef struct {
52         uint64_t siz;
53         unsigned char *data;
54 } ]] .. struct_prefix .. [[Blob;
55
56 ]]
57 )
58
59 emit_c(disclaimer)
60 emit_c([[
61 #ifdef USE_DRAGONNET
62 #include <dragonnet/send.h>
63 #include <dragonnet/recv.h>
64 #endif
65
66 #include <endian.h>
67 #include <inttypes.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <zlib.h>
73
74 #define htobe8(x) (x)
75 #define be8toh(x) (x)
76
77 #include "types.h"
78
79 ]] .. local_prefix ..  [[void raw_write(Blob *buffer, const void *data, size_t len)
80 {
81         buffer->data = realloc(buffer->data, len + buffer->siz);
82         memcpy(&buffer->data[buffer->siz], data, len);
83         buffer->siz += len;
84 }
85
86 ]] .. local_prefix ..  [[bool raw_read(Blob *buffer, void *data, size_t len)
87 {
88         if (len == 0)
89                 return true;
90
91         if (buffer->siz < len) {
92                 fprintf(stderr, "[warning] buffer exhausted (requested bytes: %zu, remaining bytes: %" PRIu64 ")\n", len, buffer->siz);
93                 return false;
94         }
95
96         memcpy(data, buffer->data, len);
97         buffer->data += len;
98         buffer->siz -= len;
99         return true;
100 }
101
102 ]]
103 )
104
105 -- existing types
106 local existing_types = {}
107 local has_deallocator = {}
108
109 -- vector components
110
111 local base_vector_components = {"x", "y", "z", "w"}
112 local vector_components = {}
113
114 for i = 2, 4 do
115         local components = {}
116
117         for j = 1, i do
118                 table.insert(components, base_vector_components[j])
119         end
120
121         vector_components[i] = components
122 end
123
124 -- numeric types
125
126 local numeric_types = {}
127
128 local function emit_vector(type, l)
129         local name = "v" .. l .. type
130         local box = "aabb" .. l .. type
131
132         existing_types[name] = true
133         has_deallocator[name] = false
134
135         existing_types[box] = true
136         has_deallocator[box] = false
137
138         local typedef, equals, add, sub, clamp, cmp, scale, mix, write, read, send, recv =
139                    "",     "",  "",  "",    "",  "",    "",  "",    "",   "",   "",   ""
140
141         for i, c in ipairs(vector_components[l]) do
142                 local last = i == l
143
144                 typedef = typedef
145                         .. c ..
146                         (last
147                                 and ";\n"
148                                 or ", "
149                         )
150
151                 equals = equals
152                         .. "a." .. c .. " == "
153                         .. "b." .. c ..
154                         (last
155                                 and ";\n"
156                                 or " && "
157                         )
158
159                 add = add
160                         .. "a." .. c .. " + "
161                         .. "b." .. c ..
162                         (last
163                                 and "};\n"
164                                 or ", "
165                         )
166
167                 sub = sub
168                         .. "a." .. c .. " - "
169                         .. "b." .. c ..
170                         (last
171                                 and "};\n"
172                                 or ", "
173                         )
174
175                 clamp = clamp
176                         .. type .. "_clamp("
177                         .. "val." .. c .. ", "
178                         .. "min." .. c .. ", "
179                         .. "max." .. c .. ")" ..
180                         (last
181                                 and "};\n"
182                                 or ", "
183                         )
184
185                 cmp = cmp
186                         .. "\tif ((i = " .. type .. "_cmp("
187                         .. "&((const " .. name .. " *) a)->" .. c .. ", "
188                         .. "&((const " .. name .. " *) b)->" .. c .. ")) != 0)"
189                         .. "\n\t\treturn i;\n"
190
191                 scale = scale
192                         .. "v." .. c .. " * s" ..
193                         (last
194                                 and "};\n"
195                                 or ", "
196                         )
197
198                 mix = mix
199                         .. type .. "_mix("
200                         .. "a." .. c .. ", "
201                         .. "b." .. c .. ", "
202                         .. "f" .. ")" ..
203                         (last
204                                 and "};\n"
205                                 or ", "
206                         )
207
208                 write = write
209                         .. "\t" .. type .. "_write(buffer, &val->" .. c .. ");\n"
210
211                 read = read
212                         .. "\tif (!" .. type .. "_read(buffer, &val->" .. c .. "))\n\t\treturn false;\n"
213
214                 send = send
215                         .. "\tif (!" .. type .. "_send(peer, " .. (last and "submit" or "false") .. ", &val->" .. c .. "))\n\t\treturn false;\n"
216
217                 recv = recv
218                         .. "\tif (!" .. type .. "_recv(peer, &val->" .. c .. "))\n\t\treturn false;\n"
219         end
220
221         emit_h("typedef struct {\n\t" .. type .. " " .. typedef ..  "} " .. struct_prefix .. name .. ";\n")
222
223         emit(export_prefix .. "bool " .. name .. "_equals(" .. name .. " a, " .. name .. " b)", "{\n\treturn " .. equals .. "}\n\n")
224         emit(export_prefix .. name .. " " .. name .. "_add(" .. name .. " a, " .. name .. " b)", "{\n\treturn (" .. name .. ") {" .. add .. "}\n\n")
225         emit(export_prefix .. name .. " " .. name .. "_sub(" .. name .. " a, " .. name .. " b)", "{\n\treturn (" .. name .. ") {" .. sub .. "}\n\n")
226         emit(export_prefix .. name .. " " .. name .. "_clamp(" .. name .. " val, " .. name .. " min, " .. name .. " max)", "{\n\treturn (" .. name .. ") {" .. clamp .. "}\n\n")
227         emit(export_prefix .. "int " .. name .. "_cmp(const void *a, const void *b)", "{\n\tint i;\n" .. cmp .. "\treturn 0;\n}\n\n")
228         emit(export_prefix .. name .. " " .. name .. "_scale(" .. name .. " v, " .. type .. " s)", "{\n\treturn (" .. name .. ") {" .. scale .. "}\n\n")
229
230         if type:sub(1, 1) == "f" then
231                 emit(export_prefix .. name .. " " .. name .. "_mix(" .. name .. " a, " .. name .. " b, " .. type .. " f)", "{\n\treturn (" .. name .. ") {" .. mix .. "}\n\n")
232         end
233
234         emit(export_prefix .. "void " .. name .. "_write(Blob *buffer, " .. name .. " *val)", "{\n" .. write .. "}\n\n")
235         emit(export_prefix .. "bool " .. name .. "_read(Blob *buffer, " .. name .. " *val)", "{\n" .. read .. "\treturn true;\n}\n\n")
236
237         emit_c("#ifdef USE_DRAGONNET\n")
238         emit_c(local_prefix .. "bool " .. name .. "_send(DragonnetPeer *peer, bool submit, " .. name .. " *val)\n{\n" .. send .. "\treturn true;\n}\n\n")
239         emit_c(local_prefix .. "bool " .. name .. "_recv(DragonnetPeer *peer, " .. name .. " *val)\n{\n" .. recv .. "\treturn true;\n}\n")
240         emit_c("#endif\n\n")
241
242         emit_h("\n")
243
244         emit_h("typedef struct {\n\t" .. name .. " min, max;\n} " .. struct_prefix .. box .. ";\n")
245
246         emit(export_prefix .. "void " .. box .. "_write(Blob *buffer, " .. box .. " *val)", "{\n\t" .. name .. "_write(buffer, &val->min);\n\t" .. name .. "_write(buffer, &val->max);\n}\n\n")
247         emit(export_prefix .. "bool " .. box .. "_read(Blob *buffer, " .. box .. " *val)", "{\n\tif (!" .. name .. "_read(buffer, &val->min))\n\t\treturn false;\n\tif (!" .. name .. "_read(buffer, &val->max))\n\t\treturn false;\n\treturn true;\n}\n\n")
248
249         emit_c("#ifdef USE_DRAGONNET\n")
250         emit_c(local_prefix .. "bool " .. box .. "_send(DragonnetPeer *peer, bool submit, " .. box .. " *val)\n{\n\tif (!" .. name .. "_send(peer, false, &val->min))\n\t\treturn false;\n\tif (!" .. name .. "_send(peer, submit, &val->max))\n\t\treturn false;\n\treturn true;\n}\n\n")
251         emit_c(local_prefix .. "bool " .. box .. "_recv(DragonnetPeer *peer, " .. box .. " *val)\n{\n\tif (!" .. name .. "_recv(peer, &val->min))\n\t\treturn false;\n\t if (!" .. name .. "_recv(peer, &val->max))\n\t\treturn false;\n\treturn true;\n}\n")
252         emit_c("#endif\n\n")
253
254         emit_h("\n")
255 end
256
257 local function emit_numeric(class, bits, alias)
258         local name = class .. bits
259         table.insert(numeric_types, name)
260
261         existing_types[name] = true
262         has_deallocator[name] = false
263
264         emit_h("typedef " .. alias .. " " .. name .. ";\n")
265
266         emit(export_prefix .. name .. " " .. name .. "_min(" .. name .. " a, " .. name .. " b)", "{\n\treturn a < b ? a : b;\n}\n\n")
267         emit(export_prefix .. name .. " " .. name .. "_max(" .. name .. " a, " .. name .. " b)", "{\n\treturn a > b ? a : b;\n}\n\n")
268         emit(export_prefix .. name .. " " .. name .. "_clamp(" .. name .. " val, " .. name .. " min, " .. name .. " max)", "{\n\treturn val < min ? min : val > max ? max : val;\n}\n\n")
269         emit(export_prefix .. "int " .. name .. "_cmp(const void *a, const void *b)", "{\n\treturn\n\t\t*(const " .. name .. " *) a < *(const " .. name .. " *) b ? -1 :\n\t\t*(const " .. name .. " *) a > *(const " .. name .. " *) b ? +1 :\n\t\t0;\n}\n\n")
270
271         if class == "f" then
272                 emit(export_prefix .. name .. " " .. name .. "_mix(" .. name .. " a, " .. name .. " b, " .. name .. " f)", "{\n\treturn (1.0 - f) * a + b * f;\n}\n\n")
273         end
274
275         emit(export_prefix .. "void " .. name .. "_write(Blob *buffer, " .. name .. " *val)", "{\n" .. (class == "u"
276                 and "\t" .. name .. " be = htobe" .. bits .. "(*val);\n\traw_write(buffer, &be, sizeof be);\n"
277                 or  "\tu" .. bits .. "_write(buffer, (u" .. bits .. " *) val);\n"
278         ) .. "}\n\n")
279         emit(export_prefix .. "bool " .. name .. "_read(Blob *buffer, " .. name .. " *val)", "{\n" .. (class == "u"
280                 and "\t" .. name .. " be;\n\tif (!raw_read(buffer, &be, sizeof be))\n\t\treturn false;\n\t*val = be" .. bits .. "toh(be);\n\treturn true;\n"
281                 or  "\treturn u" .. bits .. "_read(buffer, (u" .. bits .. " *) val);\n"
282         ) .. "}\n\n")
283
284         emit_c("#ifdef USE_DRAGONNET\n")
285         emit_c(local_prefix .. "bool " .. name .. "_send(DragonnetPeer *peer, bool submit, " .. name .. " *val)\n{\n" .. (class == "u"
286                 and "\t" .. name .. " be = htobe" .. bits .. "(*val);\n\treturn dragonnet_send_raw(peer, submit, &be, sizeof be);\n"
287                 or  "\treturn u" .. bits .. "_send(peer, submit, (u" .. bits .. " *) val);\n"
288         ) .. "}\n\n")
289         emit_c(local_prefix .. "bool " .. name .. "_recv(DragonnetPeer *peer, " .. name .. " *val)\n{\n" .. (class == "u"
290                 and "\t" .. name .. " be;\n\tif (!dragonnet_recv_raw(peer, &be, sizeof be))\n\t\treturn false;\n\t*val = be" .. bits .. "toh(be);\n\treturn true;\n"
291                 or  "\treturn u" .. bits .. "_recv(peer, (u" .. bits .. " *) val);\n"
292         ) .. "}\n")
293         emit_c("#endif\n\n")
294
295         emit_h("\n")
296
297         for i = 2, 4 do
298                 emit_vector(name, i)
299         end
300 end
301
302 for i = 0, 3 do
303         local bytes = math.floor(2 ^ i)
304         local bits = 8 * bytes
305
306         emit_numeric("u", bits, "uint" .. bits .. "_t")
307         emit_numeric("s", bits,  "int" .. bits .. "_t")
308
309         if i >= 2 then
310                 emit_numeric("f", bits, ({"float", "double"})[i - 1])
311         end
312 end
313
314 local converters = {}
315
316 for l = 2, 4 do
317         converters[l] = ""
318
319         for i, c in ipairs(vector_components[l]) do
320                 converters[l] = converters[l]
321                         .. "v." .. c ..
322                         ((i == l)
323                                 and "};\n"
324                                 or ", "
325                         )
326         end
327 end
328
329 for _, from in ipairs(numeric_types) do
330         for _, to in ipairs(numeric_types) do
331                 if from ~= to then
332                         for i = 2, 4 do
333                                 local v_from = "v" .. i .. from
334                                 local v_to   = "v" .. i .. to
335
336                                 emit(export_prefix .. v_to .. " " .. v_from .. "_to_" .. to  .. "(" .. v_from .. " v)", "{\n\treturn (" .. v_to .. ") {" .. converters[i] .. "}\n\n")
337                         end
338                 end
339         end
340 end
341
342 emit_h("\n")
343
344 -- string
345
346 existing_types.String = true
347 has_deallocator.String = true
348
349 emit(
350 export_prefix .. "void String_free(String *val)", [[
351 {
352         if (*val)
353                 free(*val);
354 }
355
356 ]]
357 )
358
359 emit(
360 export_prefix .. "void String_write(Blob *buffer, String *val)", [[
361 {
362         *val ? raw_write(buffer, *val, strlen(*val) + 1) : raw_write(buffer, "", 1);
363 }
364
365 ]]
366 )
367
368 emit(
369 export_prefix .. "bool String_read(Blob *buffer, String *val)", [[
370 {
371         String v = malloc(1 + (1 << 16));
372
373         char c;
374         for (u16 i = 0;; i++) {
375                 if (!raw_read(buffer, &c, 1)) {
376                         free(v);
377                         return false;
378                 }
379
380                 v[i] = c;
381                 if (c == '\0')
382                         break;
383         }
384
385         *val = realloc(v, strlen(v) + 1);
386
387         return true;
388 }
389
390 ]]
391 )
392
393 emit_c(
394 [[
395 #ifdef USE_DRAGONNET
396 ]] .. local_prefix .. [[bool String_send(DragonnetPeer *peer, bool submit, String *val)
397 {
398         return *val ? dragonnet_send_raw(peer, submit, *val, strlen(*val) + 1) : dragonnet_send_raw(peer, submit, "", 1);
399 }
400
401 ]] .. local_prefix .. [[bool String_recv(DragonnetPeer *peer, String *val)
402 {
403         String v = malloc(1 + (1 << 16));
404
405         char c;
406         for (u16 i = 0;; i++) {
407                 if (!dragonnet_recv_raw(peer, &c, 1)) {
408                         free(v);
409                         return false;
410                 }
411
412                 v[i] = c;
413                 if (c == '\0')
414                         break;
415         }
416
417         *val = realloc(v, strlen(v) + 1);
418
419         return true;
420 }
421 #endif
422
423 ]]
424 )
425
426 emit_h("\n")
427
428 -- blob
429
430 existing_types.Blob = true
431 has_deallocator.Blob = true
432
433 emit(
434 export_prefix .. "void Blob_compress(Blob *buffer, Blob *val)", [[
435 {
436         buffer->siz = 8 + 2 + val->siz;
437         buffer->data = malloc(buffer->siz);
438
439         *(u64 *) buffer->data = val->siz;
440
441         z_stream s;
442         s.zalloc = Z_NULL;
443         s.zfree = Z_NULL;
444         s.opaque = Z_NULL;
445
446         s.avail_in = val->siz;
447         s.next_in = (Bytef *) val->data;
448         s.avail_out = buffer->siz - 8 + 1;
449         s.next_out = (Bytef *) buffer->data + 8;
450
451         deflateInit(&s, Z_BEST_COMPRESSION);
452         deflate(&s, Z_FINISH);
453         deflateEnd(&s);
454
455         buffer->siz = s.total_out + 8;
456 }
457
458 ]]
459 )
460
461 emit(
462 export_prefix .. "void Blob_decompress(Blob *buffer, Blob *val)", [[
463 {
464         buffer->siz = *(u64 *) val->data;
465         buffer->data = malloc(buffer->siz);
466
467         z_stream s;
468         s.zalloc = Z_NULL;
469         s.zfree = Z_NULL;
470         s.opaque = Z_NULL;
471
472         s.avail_in = val->siz - 8;
473         s.next_in = val->data + 8;
474         s.avail_out = buffer->siz;
475         s.next_out = (Bytef *) buffer->data;
476
477         inflateInit(&s);
478         inflate(&s, Z_NO_FLUSH);
479         inflateEnd(&s);
480
481         buffer->siz = s.total_out;
482 }
483
484 ]]
485 )
486
487 emit(
488 export_prefix .. "void Blob_shrink(Blob *val)", [[
489 {
490         val->data = realloc(val->data, val->siz);
491 }
492
493 ]]
494 )
495
496 emit(
497 export_prefix .. "void Blob_free(Blob *val)", [[
498 {
499         if (val->data)
500                 free(val->data);
501 }
502
503 ]]
504 )
505
506 emit(
507 export_prefix .. "void Blob_write(Blob *buffer, Blob *val)", [[
508 {
509         u64_write(buffer, &val->siz);
510         raw_write(buffer, val->data, val->siz);
511 }
512
513 ]]
514 )
515
516 emit(
517 export_prefix .. "bool Blob_read(Blob *buffer, Blob *val)", [[
518 {
519         if (!u64_read(buffer, &val->siz))
520                 return false;
521
522         if (!raw_read(buffer, val->data = malloc(val->siz), val->siz)) {
523                 free(val->data);
524                 val->data = NULL;
525                 return false;
526         }
527
528         return true;
529 }
530
531 ]]
532 )
533
534 emit_c(
535 [[
536 #ifdef USE_DRAGONNET
537 ]] .. local_prefix .. [[bool Blob_send(DragonnetPeer *peer, bool submit, Blob *val)
538 {
539         if (!u64_send(peer, false, &val->siz))
540                 return false;
541         return dragonnet_send_raw(peer, submit, val->data, val->siz);
542 }
543
544 ]] .. local_prefix .. [[bool Blob_recv(DragonnetPeer *peer, Blob *val)
545 {
546         if (!u64_recv(peer, &val->siz))
547                 return false;
548
549         if (!dragonnet_recv_raw(peer, val->data = malloc(val->siz), val->siz)) {
550                 free(val->data);
551                 val->data = NULL;
552                 return false;
553         }
554
555         return true;
556 }
557 #endif
558
559 ]]
560 )
561
562 emit_h("\n")
563
564
565 emit_c(
566 [[
567 ]] .. local_prefix .. [[void raw_write_compressed(Blob *buffer, void *val, void (*val_write)(Blob *, void *))
568 {
569         Blob compressed, raw = {0};
570         val_write(&raw, val);
571         Blob_compress(&compressed, &raw);
572         Blob_write(buffer, &compressed);
573
574         Blob_free(&compressed);
575         Blob_free(&raw);
576 }
577
578 ]] .. local_prefix .. [[bool raw_read_compressed(Blob *buffer, void *val, bool (*val_read)(Blob *, void *))
579 {
580         Blob compressed, raw = {0};
581         bool success = Blob_read(buffer, &compressed);
582
583         if (success) {
584                 Blob_decompress(&raw, &compressed);
585                 Blob raw_buffer = raw;
586                 success = success && val_read(&raw_buffer, val);
587         }
588
589         Blob_free(&compressed);
590         Blob_free(&raw);
591
592         return success;
593 }
594
595 #ifdef USE_DRAGONNET
596 ]] .. local_prefix .. [[bool raw_send_compressed(DragonnetPeer *peer, bool submit, void *val, void (*val_write)(Blob *, void *))
597 {
598         Blob compressed, raw = {0};
599         val_write(&raw, val);
600         Blob_compress(&compressed, &raw);
601         bool success = Blob_send(peer, submit, &compressed);
602
603         Blob_free(&compressed);
604         Blob_free(&raw);
605
606         return success;
607 }
608
609 ]] .. local_prefix .. [[bool raw_recv_compressed(DragonnetPeer *peer, void *val, bool (*val_read)(Blob *, void *))
610 {
611         Blob compressed, raw = {0};
612         bool success = Blob_recv(peer, &compressed);
613
614         if (success) {
615                 Blob_decompress(&raw, &compressed);
616                 Blob raw_buffer = raw;
617                 success = success && val_read(&raw_buffer, val);
618         }
619
620         Blob_free(&compressed);
621         Blob_free(&raw);
622
623         return success;
624 }
625 #endif
626
627 ]]
628 )
629
630 local custom_types = {}
631 local current_type
632
633 local function consume_name(name)
634         if current_type then
635                 table.insert(custom_types, current_type)
636         end
637
638         if name == "" then
639                 current_type = nil
640         else
641                 current_type = {components = {}, component_names = {}}
642
643                 current_type.flags = name:split(" ")
644                 current_type.name = table.remove(current_type.flags, #current_type.flags)
645
646                 if existing_types[current_type.name] then
647                         error("redeclaration of type " .. current_type.name)
648                 end
649
650                 existing_types[current_type.name] = true
651                 has_deallocator[current_type.name] = false
652         end
653 end
654
655 local function consume_comp(comp)
656         if not current_type then
657                 error("component without a type: " .. comp)
658         end
659
660         local component = {}
661
662         component.flags = comp:split(" ")
663         component.name = table.remove(component.flags, #component.flags)
664         component.type = table.remove(component.flags, #component.flags)
665
666         component.full_name = current_type.name .. "." .. component.name
667
668         local base_type = ""
669         local met_brace = false
670         local brace_level = 0
671
672         for i = 1, #component.type do
673                 local c = component.type:sub(i, i)
674                 local append = false
675
676                 if c == "[" then
677                         if not met_brace then
678                                 component.array = {}
679                         end
680
681                         met_brace = true
682                         brace_level = brace_level + 1
683
684                         if brace_level == 1 then
685                                 table.insert(component.array, "")
686                         else
687                                 append = true
688                         end
689                 elseif c == "]" then
690                         brace_level = brace_level - 1
691
692                         if brace_level < 0 then
693                                 error("missing [ in " .. component.full_name)
694                         elseif brace_level > 0 then
695                                 append = true
696                         end
697                 elseif not met_brace then
698                         base_type = base_type .. c
699                 elseif brace_level == 1 then
700                         append = true
701                 elseif brace_level == 0 then
702                         error("invalid character " .. c .. " outside of braces in " .. component.full_name)
703                 end
704
705                 if append then
706                         component.array[#component.array] = component.array[#component.array] .. c
707                 end
708         end
709
710         component.type = base_type
711
712         if brace_level > 0 then
713                 error("missing ] in " .. component.full_name)
714         end
715
716         if not existing_types[component.type] then
717                 error("type " .. component.type .. " of " .. component.full_name .. " does not exist ")
718         end
719
720         has_deallocator[current_type.name] = has_deallocator[current_type.name] or has_deallocator[component.type]
721
722         if current_type.component_names[component.name] then
723                 error("component " .. component.full_name .. " redeclared")
724         end
725
726         current_type.component_names[component.name] = true
727
728         table.insert(current_type.components, component)
729 end
730
731 if def then
732         for l in def:lines() do
733                 local f = l:sub(1, 1)
734
735                 if f == "\t" then
736                         consume_comp(l:sub(2, #l))
737                 elseif f == "#" then
738                         emit_h(l .. "\n\n")
739                 elseif f ~= ";" then
740                         consume_name(l)
741                 end
742         end
743 end
744
745 consume_name("")
746
747 local dragonnet_types_h = ""
748 local dragonnet_types_c = ""
749
750 for _, t in ipairs(custom_types) do
751         local pkt
752
753         for _, f in pairs(t.flags) do
754                 if f == "pkt" then
755                         pkt = true
756                 else
757                         error("invalid flag " .. f .. " for " .. t.name)
758                 end
759         end
760
761         local typedef, free, write, read, send, recv =
762                    "",   "",    "",   "",   "",   ""
763
764         for ic, c in ipairs(t.components) do
765                 local type = c.type
766                 local type_end = ""
767
768                 if c.array then
769                         local indices = {}
770
771                         for _, a in ipairs(c.array) do
772                                 table.insert(indices, 1, a)
773                         end
774
775                         for _, a in ipairs(indices) do
776                                 if a == "" then
777                                         type = "struct { size_t siz; " .. type .. " (*ptr)" .. type_end .. "; }"
778                                         type_end = ""
779                                 else
780                                         type_end = "[" .. a .. "]" .. type_end
781                                 end
782                         end
783                 end
784
785                 typedef = typedef
786                         .. "\t" .. type .. " " .. c.name .. type_end .. ";\n"
787
788                 local compressed = false
789
790                 for _, f in pairs(c.flags) do
791                         if f == "compressed" then
792                                 compressed = true
793                         else
794                                 error("invalid flag " .. f .. " for " .. c.full_name)
795                         end
796                 end
797
798                 local indent = {
799                         free = "\t",
800                         write = "\t",
801                         read = "\t",
802                         send = "\t",
803                         recv = "\t",
804                 }
805                 local loop = {
806                         free = "",
807                         write = "",
808                         read = "",
809                         send = "",
810                         recv = ""
811                 }
812                 local loop_end = {
813                         free = "",
814                         write = "",
815                         read = "",
816                         send = "",
817                         recv = ""
818                 }
819                 local index = ""
820                 local array_submit = ""
821
822                 if c.array then
823                         for ia, a in ipairs(c.array) do
824                                 local it = "i" .. ia
825                                 local siz = a
826
827                                 if a == "" then
828                                         local var = "val->" .. c.name .. index
829                                         local ptr = var .. ".ptr"
830                                         siz = var .. ".siz"
831
832                                         loop.free = loop.free .. indent.free .. "if (" .. ptr .. ") {\n"
833                                         loop_end.free = indent.free .. "}\n" .. loop_end.free
834                                         indent.free = indent.free .. "\t"
835                                         loop_end.free = indent.free .. "free(" .. ptr .. ");\n" .. loop_end.free
836
837                                         loop.write = loop.write .. indent.write .. "u64_write(buffer, &" .. siz .. ");\n"
838
839                                         loop.send = loop.send .. indent.send .. "if (!u64_send(peer, &" .. siz .. ", false))\n"
840                                                 .. indent.send .. "\treturn false;\n"
841
842                                         loop.read = loop.read .. indent.read .. "if (!u64_read(buffer, &" .. siz .. "))\n"
843                                                 .. indent.read .. "\treturn false;\n"
844                                                 .. indent.read .. ptr .. " = calloc(" .. siz .. ", sizeof *" .. ptr .. ");\n"
845
846                                         loop.recv = loop.recv .. indent.recv .. "if (!u64_recv(peer, &" .. siz .. "))\n"
847                                                 .. indent.recv .. "\treturn false;\n"
848                                                 .. indent.recv .. ptr .. " = calloc(" .. siz .. ", sizeof *" .. ptr .. ");\n"
849
850                                         index = index .. ".ptr"
851                                 end
852
853                                 for f in pairs(loop) do
854                                         loop[f] = loop[f] .. indent[f] .. "for (size_t " .. it .. " = 0; " .. it .. " < " .. siz .. "; " .. it .. "++) {\n"
855                                         loop_end[f] = indent[f] .. "}\n" .. loop_end[f]
856                                         indent[f] = indent[f] .. "\t"
857                                 end
858         
859                                 index = index .. "[" .. it .. "]"
860                                 array_submit = array_submit .. " && " .. it .. " == " .. siz .. " - 1"
861                         end
862                 end
863
864                 local addr = "&val->" .. c.name .. index
865
866                 if has_deallocator[c.type] then
867                         free = free
868                                 .. loop.free .. indent.free .. c.type .. "_free(" .. addr .. ");\n" .. loop_end.free
869                 end
870
871                 write = write
872                         .. loop.write .. indent.write .. (compressed
873                                 and "raw_write_compressed(buffer, " .. addr .. ", (void *) &" .. c.type .. "_write);\n"
874                                 or      c.type .. "_write(buffer, " .. addr .. ");\n"
875                         ) .. loop_end.write
876
877                 read = read
878                         .. loop.read .. indent.read .. "if (!" .. (compressed
879                                 and "raw_read_compressed(buffer, " .. addr .. ", (void *) &" .. c.type .. "_read)"
880                                 or      c.type .. "_read(buffer, " .. addr .. ")"
881                         ) .. ")\n" .. indent.read .. "\treturn false;\n" .. loop_end.read
882
883                 local submit = ic == #t.components and "submit" .. array_submit or "false"
884                 send = send
885                         .. loop.send .. indent.send .. "if (!" .. (compressed
886                                 and "raw_send_compressed(peer, " .. submit .. ", " .. addr .. ", (void *) &" .. c.type .. "_write)"
887                                 or      c.type .. "_send(peer, " .. submit .. ", " .. addr .. ")"
888                         ) .. ")\n" .. indent.send .. "\treturn false;\n" .. loop_end.send
889
890                 recv = recv
891                         .. loop.recv .. indent.recv .. "if (!" .. (compressed
892                                 and "raw_recv_compressed(peer, " .. addr .. ", (void *) &" .. c.type .. "_read)"
893                                 or      c.type .. "_recv(peer, " .. addr .. ")"
894                         ) .. ")\n" .. indent.recv .. "\treturn false;\n" .. loop_end.recv
895         end
896
897         emit_h("typedef struct {\n" .. typedef .. "} " .. struct_prefix .. t.name .. ";\n")
898
899         if has_deallocator[t.name] then
900                 emit(export_prefix .. "void " .. t.name .. "_free(" .. t.name .. " *val)", "{\n" .. free .. "}\n\n")
901         end
902
903         emit(export_prefix .. "void " .. t.name .. "_write(Blob *buffer, " .. t.name .. " *val)", "{\n" .. write .. "}\n\n")
904         emit(export_prefix .. "bool " .. t.name .. "_read(Blob *buffer, " .. t.name .. " *val)", "{\n" .. read .. "\treturn true;\n}\n\n")
905
906         if pkt then
907                 emit_h("#ifdef USE_DRAGONNET\n")
908         end
909
910         emit_c("#ifdef USE_DRAGONNET\n")
911
912         emit_c(local_prefix .. "bool " .. t.name .. "_send(DragonnetPeer *peer, bool submit, " .. t.name .. " *val)\n{\n" .. send .. "\treturn true;\n}\n\n")
913         emit_c(local_prefix .. "bool " .. t.name .. "_recv(DragonnetPeer *peer, " .. t.name .. " *val)\n{\n" .. recv .. "\treturn true;\n}\n")
914
915         if pkt then
916                 emit_c("\n")
917                 emit_c("static DragonnetTypeId " .. t.name .. "_type_id = DRAGONNET_TYPE_" .. t.name .. ";\n")
918
919                 emit("bool dragonnet_peer_send_" .. t.name .. "(DragonnetPeer *peer, " .. t.name .. " *val)", "{\n\tpthread_mutex_lock(&peer->mtx);\n\tif (!u16_send(peer, false, &" .. t.name .. "_type_id))\n\t\treturn false;\n\tif (!" .. t.name .. "_send(peer, true, val))\n\t\treturn false;\n\treturn true;\n}\n")
920                 emit_h("#endif\n")
921
922                 dragonnet_types_h = dragonnet_types_h
923                         .. "\tDRAGONNET_TYPE_" .. t.name .. ",\n"
924
925                 dragonnet_types_c = dragonnet_types_c
926                         .. "\t{\n\t\t.siz = sizeof(" .. t.name .. "),\n\t\t.deserialize = (void *) &" .. t.name .. "_recv,\n\t\t.free = " .. (has_deallocator[t.name] and "(void *) &" .. t.name .. "_free" or "NULL") .. ",\n\t},\n"
927         end
928
929         emit_c("#endif\n\n")
930
931         emit_h("\n")
932 end
933
934 emit_h("#ifdef USE_DRAGONNET\n")
935 emit_h("typedef enum {\n" .. dragonnet_types_h .. "\tDRAGONNET_NUM_TYPES\n} DragonnetTypeNum;\n")
936 emit_h("#endif\n\n")
937
938 emit_c("#ifdef USE_DRAGONNET\n")
939 emit_c("DragonnetTypeId dragonnet_num_types = DRAGONNET_NUM_TYPES;\nDragonnetType dragonnet_types[] = {\n" .. dragonnet_types_c .. "};\n")
940 emit_c("#endif\n")
941
942 emit_h("#endif\n")
943
944 h:close()
945 c:close()
946 def:close()