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