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