mirror of
https://github.com/zap-proto/c.git
synced 2026-10-30 15:05:52 +00:00
C had no front end for the schema language at all. The compiler directory holds a code generator plugin, which is handed a request by another tool and never sees schema text, so a .zap file could not be read here in either form -- indentation or braces. zapgen reads it. Whitespace-significant source is rewritten into the brace form BEFORE the parser, exactly as the Go reference does it: a near identity that only adds the two tokens the brace grammar requires where the indented form leaves them out. A file already in braces comes back byte for byte, so one grammar reads both styles and neither is a dialect of the other. The identifier grammar is not restated. Its Unicode ranges are taken from Go's own tables by gen/table, so a name this parser accepts is a name the Go parser accepts, and a Go release that moves Unicode moves both. The generated header gives each struct a view over the message bytes and one reader per field at a fixed offset. Reading is in place and total: a field past the end reads zero, a pointer into the head or out of the message reads null. zap_view.h is the one place that says so. Checked against the Go front end on every .zap in the estate plus 55 adversarial cases and 15000 random ones: the brace form each writes is byte-identical, the layout each reads is field-for-field the same, and they accept and refuse the same files for the same stated reason. A message built by the Go runtime reads back through these bindings with every field equal.
70 lines
1.0 KiB
C
70 lines
1.0 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause-Eco */
|
|
|
|
#include "arena.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define CHUNK (64 * 1024)
|
|
|
|
struct chunk {
|
|
struct chunk *next;
|
|
size_t len, cap;
|
|
char data[];
|
|
};
|
|
|
|
struct arena {
|
|
struct chunk *head;
|
|
};
|
|
|
|
struct arena *arena_new(void)
|
|
{
|
|
return calloc(1, sizeof(struct arena));
|
|
}
|
|
|
|
void arena_free(struct arena *a)
|
|
{
|
|
struct chunk *c, *next;
|
|
|
|
if (!a)
|
|
return;
|
|
for (c = a->head; c; c = next) {
|
|
next = c->next;
|
|
free(c);
|
|
}
|
|
free(a);
|
|
}
|
|
|
|
void *arena_get(struct arena *a, size_t n)
|
|
{
|
|
struct chunk *c;
|
|
size_t cap;
|
|
void *p;
|
|
|
|
n = (n + 15) & ~(size_t)15;
|
|
if (!a->head || a->head->cap - a->head->len < n) {
|
|
cap = n > CHUNK ? n : CHUNK;
|
|
c = calloc(1, sizeof(*c) + cap);
|
|
if (!c)
|
|
return NULL;
|
|
c->cap = cap;
|
|
c->next = a->head;
|
|
a->head = c;
|
|
}
|
|
c = a->head;
|
|
p = c->data + c->len;
|
|
c->len += n;
|
|
return p;
|
|
}
|
|
|
|
char *arena_str(struct arena *a, const char *s, size_t n)
|
|
{
|
|
char *p = arena_get(a, n + 1);
|
|
|
|
if (!p)
|
|
return NULL;
|
|
memcpy(p, s, n);
|
|
p[n] = '\0';
|
|
return p;
|
|
}
|