aboutsummaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-30 05:59:09 +0100
committereunhhu <[email protected]>2026-09-30 05:59:09 +0100
commitaa279fb959024134416fc33f90f648d8332e9af4 (patch)
treeb8640d24f0700d82798fac2c9378c281c0b4cdda /compiler
parente5716bd108039982d55bcd3b2da25e9f28b5825a (diff)
downloadaup-aa279fb959024134416fc33f90f648d8332e9af4.tar.gz
aup-aa279fb959024134416fc33f90f648d8332e9af4.zip
Write a message once for its output and the input that takes it
Growing a board two nodes share (Pure's research 105), one field took five places, two of them the same list: the output a node sends its changes on and the input it takes the other's with. A message may now take the fields of a message input or output declared before, in their order: input remote = message like changed. The module is the same as with the fields written out, byte for byte (checked). An unknown name, one that is no message, the message itself, and an output taking an input's rows are diagnosed.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/compile.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/compiler/compile.c b/compiler/compile.c
index af9899a..4e49b4b 100644
--- a/compiler/compile.c
+++ b/compiler/compile.c
@@ -1102,6 +1102,30 @@ static bool path_taken(const Input *in, const char *path) {
* (Pure lays them out: docs/design/008-module-format.md). name: { ... } is a
* group of fields inside the message, named group.name (a JSON object inside
* a request's body). */
+/* message like other: the fields of a message input or output declared
+ * before, in its order. So an output and the input that takes what another
+ * node sends from it are written once. */
+static void message_like(Compiler *c, Input *in) {
+ Token other = expect_name(c, "a message input or output declared before");
+ const Input *from = NULL;
+ for (unsigned i = 0; i + 1 < c->input_count && !from; ++i)
+ if (!strcmp(c->inputs[i].name, other.text)) from = &c->inputs[i];
+ if (!from || (from->kind != KIND_MESSAGE && from->kind != KIND_OUTPUT))
+ fail_at(c, other.line, other.column, "'%s' is no message input or output declared before", other.text);
+ for (unsigned f = 0; f < from->fields; ++f) {
+ if (in->kind == KIND_OUTPUT && from->field_types[f] == FIELD_ROWS)
+ fail_at(c, other.line, other.column, "an output sends no rows: '%s' has rows (%s)", other.text,
+ from->field_names[f]);
+ if (c->field_count == FIELDS) fail_at(c, other.line, other.column, "at most %d message fields are allowed", FIELDS);
+ memcpy(in->field_names[in->fields], from->field_names[f], NAME);
+ memcpy(in->field_record[in->fields], from->field_record[f], NAME);
+ in->field_line[in->fields] = from->field_line[f];
+ in->field_column[in->fields] = from->field_column[f];
+ in->field_types[in->fields++] = from->field_types[f];
+ ++c->field_count;
+ }
+}
+
static void message_fields(Compiler *c, Input *in, const char *group) {
if (!is(c, "{")) return; /* the field block opens on the declaration's line */
take(c);
@@ -1471,7 +1495,11 @@ static void declaration(Compiler *c) {
in->kind = KIND_MESSAGE;
if (word(c, "by")) { take(c); expect_word(c, "key"); in->keyed = true; }
++c->input_count;
- message_fields(c, in, "");
+ if (word(c, "like")) {
+ take(c);
+ message_like(c, in);
+ } else
+ message_fields(c, in, "");
} else if (word(c, "text")) {
take(c);
in->kind = KIND_TEXT;
@@ -1519,7 +1547,11 @@ static void declaration(Compiler *c) {
expect_word(c, "message");
in->kind = KIND_OUTPUT;
++c->input_count;
- message_fields(c, in, "");
+ if (word(c, "like")) {
+ take(c);
+ message_like(c, in);
+ } else
+ message_fields(c, in, "");
} else if (!strcmp(kind.text, "view")) {
Token name = expect_name(c, "view name");
declare(c, &name);