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