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