diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/compile.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/compiler/compile.c b/compiler/compile.c index e0d694e..2d66286 100644 --- a/compiler/compile.c +++ b/compiler/compile.c @@ -28,6 +28,7 @@ enum { KIND_KEY = 1, KIND_MESSAGE = 2, KIND_TEXT = 3, KIND_TIMER = 4, KIND_OUTPU FIELD_ROWS = 5, FIELD_BOOL = 6, FIELD_I64 = 7 }; /* A list of a message's rows: filled as the message arrives, emptied when its event ends (Pure's flag). */ enum { LIST_ROWS = 256 }; +enum { STATE_TRANSIENT = 256 }; enum { STATE_NUM = 0, STATE_TEXT = 1, STATE_CURSOR = 2, STATE_LIST = 3, STATE_INDEX = 4, STATE_BOOL = 5, STATE_I64 = 6, UNIT_CHAR = 0, UNIT_LINE = 1 }; /* Pure's view types, record field types (0 a number, 1 a text, 2 a bool, 3 an i64) and what a local holds. */ @@ -151,6 +152,7 @@ typedef struct { char state_names[STATES][NAME], state_target[STATES][NAME]; int state_types[STATES], state_line[STATES], state_column[STATES]; bool state_stays[STATES]; /* a mark: a cursor that stays before text inserted at it */ + bool state_transient[STATES]; /* held while the app runs, never stored (Pure 018) */ int state_rows[STATES]; /* a list of a message's rows: its input + 1, or 0 */ int state_library[STATES]; /* a list's record's library (LIBRARY.NAME), or 0: the app's */ /* A keyed list: the field named after by, and once resolved, that field + 1. */ @@ -221,7 +223,8 @@ typedef struct { static const char *const reserved[] = {"state", "input", "view", "on", "if", "else", "key", "frame", "dt", "min", "max", "clamp", "message", "by", "bytes", "u32", "reply", "require", "record", "each", "fn", "use", "now", "every", - "floor", "output", "send", "for", "let", "true", "false"}; + "floor", "output", "send", "for", "let", "true", "false", + "transient"}; /* An error in the module being parsed or inlined; inside a fn it names the call. */ static _Noreturn void fail_at(Compiler *c, int line, int column, const char *format, ...) { @@ -1408,10 +1411,11 @@ static Token held_record(Compiler *c, char name[NAME], int *library) { return second; } -static void state_declaration(Compiler *c) { +static void state_declaration(Compiler *c, bool transient) { Token name = expect_name(c, "state name"); declare(c, &name); if (is(c, ":") && lookahead(c)->kind == T_NAME && !strcmp(lookahead(c)->text, "bytes")) { + if (transient) fail_at(c, name.line, name.column, "a keyed collection is stored; only a state can be transient"); take(c); take(c); expect_word(c, "by"); @@ -1423,6 +1427,7 @@ static void state_declaration(Compiler *c) { if (c->states == STATES) fail_at(c, name.line, name.column, "at most 32 states are allowed"); unsigned index = c->states; memcpy(c->state_names[index], name.text, NAME); + c->state_transient[index] = transient; c->state_line[index] = name.line; c->state_column[index] = name.column; if (is(c, ":")) { @@ -1658,13 +1663,18 @@ static void view_arguments(Compiler *c, unsigned view, const Token *name) { } static void declaration(Compiler *c) { - Token kind = expect_name(c, "state, record, input, output, view, fn, use, or on"); + Token kind = expect_name(c, "state, transient, record, input, output, view, fn, use, or on"); if (!strcmp(kind.text, "fn")) { fn_declaration(c); } else if (!strcmp(kind.text, "use")) { use_declaration(c); } else if (!strcmp(kind.text, "state")) { - state_declaration(c); + state_declaration(c, false); + } else if (!strcmp(kind.text, "transient")) { + /* transient state x = 0: the app's while it runs, never stored */ + if (!word(c, "state")) fail_at(c, c->token.line, c->token.column, "expected 'state' after 'transient'"); + take(c); + state_declaration(c, true); } else if (!strcmp(kind.text, "record")) { record_declaration(c); } else if (!strcmp(kind.text, "input")) { @@ -3026,6 +3036,9 @@ static void generate(Compiler *c, unsigned char **module, size_t *size) { fail_at(c, c->state_line[i], c->state_column[i], cursor ? "a cursor moves in a text state; '%s' is not one" : "an index points into a list state; '%s' is not one", c->state_target[i]); state_ref[i] = (uint32_t)target; + if (!c->state_transient[i] && c->state_transient[target]) + fail_at(c, c->state_line[i], c->state_column[i], "'%s' is stored but points into transient '%s'; make it " + "transient too", c->state_names[i], c->state_target[i]); } else if (c->state_types[i] == STATE_LIST) { int record = module_record(c, c->state_library[i], c->state_target[i]); for (unsigned l = 1; record < 0 && l < c->module_count; ++l) /* a library's, written without its name */ @@ -3170,7 +3183,7 @@ static void generate(Compiler *c, unsigned char **module, size_t *size) { p += 40; for (unsigned i = 0; i < c->states; ++i) { p = put32(p, state_name[i]); - p = put32(p, (uint32_t)c->state_types[i]); + p = put32(p, (uint32_t)c->state_types[i] | (c->state_transient[i] ? STATE_TRANSIENT : 0)); if (c->state_types[i] == STATE_NUM || c->state_types[i] == STATE_BOOL) p = put_double(p, c->initial[i]); else if (c->state_types[i] == STATE_I64) p = put64(p, (uint64_t)c->state_integer[i]); else { /* flags: a mark (1: the cursor stays), or a keyed list's key field + 1 */ |
