aboutsummaryrefslogtreecommitdiffstats
path: root/core/module.h
diff options
context:
space:
mode:
Diffstat (limited to 'core/module.h')
-rw-r--r--core/module.h50
1 files changed, 47 insertions, 3 deletions
diff --git a/core/module.h b/core/module.h
index 52cd4d8..9ce354f 100644
--- a/core/module.h
+++ b/core/module.h
@@ -46,6 +46,7 @@ typedef enum {
PURE_OP_I64_BITS, PURE_OP_BYTE_AT, PURE_OP_BYTES_OF, PURE_OP_INDEX_AT,
PURE_OP_BYTES_SLICE, PURE_OP_BYTE, PURE_OP_BYTES_LOAD, PURE_OP_BYTES_STORE,
PURE_OP_LIST_VALUE, PURE_OP_LIST_BIND, PURE_OP_APPEND_IN, PURE_OP_NUM_PARSE,
+ PURE_OP_CALL, PURE_OP_RETURN, PURE_OP_CHAR_AT, PURE_OP_CHAR,
PURE_OP_COUNT
} PureOpcode;
/* A bool is its own type (docs/design/016-bool-and-i64.md), held as a
@@ -110,10 +111,31 @@ enum { PURE_MODULE_HELD = 32, PURE_HELD_TEXT = 16, PURE_HELD_APPEND = 1 << 8 };
typedef enum { PURE_FORMAT_PLAIN, PURE_FORMAT_DECIMAL, PURE_FORMAT_HEX, PURE_FORMAT_HEX_UPPER, PURE_FORMAT_BINARY,
PURE_FORMAT_OCTAL, PURE_FORMAT_FIXED } PureFormat;
enum { PURE_FORMAT_WIDTH = 8, PURE_FORMAT_ZEROS = 1 << 16, PURE_FORMAT_FORM = 17, PURE_FORMAT_DIGITS = 20 };
+/* 027's stage 2c: functions and characters. A function (PureFunction) is a
+ * block CALL runs (its argument the function's number): the block begins with
+ * the call's arguments as its stack, its parameters' types, and RETURN ends
+ * it with its results on top (the rest of its stack let go), which take the
+ * arguments' place on the caller's stack. Each call has its own stack and
+ * locals (0 as it begins), and its own of what the function's code names:
+ * values held by name (empty), an event's lists (empty) and registers (bound
+ * to none); the caller's are as they were when the call returns. A function
+ * runs as a handler's code does but for a message (no field, document or
+ * reply); a handler and the functions run CALL (not a view), and a walk around
+ * a call keeps to what the callee changes as it keeps to its own block's
+ * changes. Calls nest as deep as the event's room allows: each counts its
+ * frame's bytes there (MEMORY past it) and its block's length as work.
+ * Outside a function, LOOP and EACH take their operands from a stack that
+ * holds nothing else: a loop's block begins at the bottom of its run's stack.
+ * CHAR_AT gives the character at a byte position of a text (an i64: its code
+ * point), failing as LIMIT where no character begins there; CHAR makes the
+ * text of a code point, failing as LIMIT outside 0-0x10FFFF and as ENCODING
+ * for a surrogate. */
+enum { PURE_MODULE_FUNCTIONS = 64, PURE_MODULE_SIGNATURES = 1024, PURE_SIGNATURE_BYTES = 5 };
/* A local: one of an event's PURE_MODULE_LOCALS slots, 0 when the event
* begins and never saved. LOCAL_LOAD and LOCAL_STORE name the slot (bits
- * 0-7), what it holds (bits 8-15: 0 a number, 1 an index, 2 a bool) and an index's
- * list (bits 16-31); a handler uses a slot for one of them. A handler, the
+ * 0-7), what it holds (bits 8-15: 0 a number, 1 an index, 2 a bool, 3 an i64,
+ * 4 a list value, 027's 2c) and an index's list or a list's record (bits
+ * 16-31); a handler uses a slot for one of them. A handler, the
* walks in it and the folds in those read locals; the handler and its walks
* store them. */
enum { PURE_MODULE_LOCALS = 64 };
@@ -256,6 +278,17 @@ const char *pure_fault_name(PureFault);
typedef struct { union { double value; int64_t integer; }; uint32_t arg; uint8_t op, plan, shape, range; } PureOp;
typedef struct { uint32_t start, length; } PureBlock;
typedef struct { uint32_t event; PureBlock code; } PureHandler;
+/* A function's block and its parameters' and results' types, from first among the module's signature items: a record
+ * field's type (PureRecordType: a list's with its record) or PURE_SIGNATURE_BYTES. Set at load: the event's lists,
+ * registers and held values each call has its own of (a bit each), the lists not an event's it changes (or a function
+ * it calls does), and its frame: its stack's height at most, its locals and its loops. */
+typedef struct {
+ PureBlock code;
+ uint16_t first;
+ uint8_t params, results;
+ uint32_t lists, registers, held, changes;
+ uint8_t height, locals, nesting;
+} PureFunction;
typedef struct { char name[PURE_MODULE_NAME]; uint8_t type; uint16_t rows; uint32_t offset; } PureField;
typedef struct {
uint8_t kind;
@@ -315,6 +348,7 @@ typedef struct {
uint32_t batch_plan_count; /* in their loops' order */
struct PureJit *jit; /* its blocks compiled (module-jit.c, docs/design/021), or NULL */
bool batches; /* a loop of it is planned to run in batches (module-batch.c, docs/design/024) */
+ uint8_t runner; /* which executor runs its blocks: 0 run's own steps, 1 with batches, 2 with calls (module.c) */
bool held; /* it holds bytes or texts by name (BYTES_STORE): events and views empty them as they begin */
PureInputShape input[PURE_MODULE_INPUTS];
PureField field[PURE_MODULE_FIELDS];
@@ -347,6 +381,11 @@ typedef struct {
PureValue record_field_default[PURE_MODULE_RECORD_FIELDS]; /* a number (a bool's 0 or 1), an i64, a text constant's index
* or a list's record (LIST, its i64) */
bool record_nested[PURE_MODULE_RECORDS]; /* a record with a LIST field (set at load) */
+ uint16_t functions;
+ PureFunction function[PURE_MODULE_FUNCTIONS];
+ uint8_t signature_type[PURE_MODULE_SIGNATURES];
+ uint16_t signature_record[PURE_MODULE_SIGNATURES];
+ bool calls; /* it has functions: its blocks run in the executor that calls (module.c) */
} PureModule;
/* Whether a state of m is transient (PURE_STATE_TRANSIENT). */
@@ -540,11 +579,16 @@ typedef struct {
PureRetired retired; /* list items let go since it was made */
bool reading; /* a reader: its states are a snapshot's */
/* The values an event or a view's body holds by name (BYTES_STORE): emptied as it begins. */
- struct { unsigned char *data; size_t size, capacity; } held[PURE_MODULE_HELD];
+ /* A value of the event's payload, arguments or constants is held as it is (by_ref: ref, nothing copied). */
+ struct { unsigned char *data; size_t size, capacity; PureBytes ref; bool by_ref; } held[PURE_MODULE_HELD];
/* The lists in records an event or a view's body made (LIST fields: a value is a number here, 1 on), how many
* values share each, and the bound lists' own (a register's list while another is bound to it). */
struct { PureList **list; uint32_t *shared; size_t count, capacity; } nested;
PureList *unbound[PURE_MODULE_STATES];
+ /* Calls (027's 2c): the frames of those open, in blocks that never move (code points into a frame), the block in
+ * use and how much of it; and the event's lists calls let go, emptied, each state's for its next calls. */
+ struct { unsigned char **blocks; size_t *sizes; unsigned count, at; size_t used; } calls;
+ struct { PureList **lists; unsigned count, capacity; } spare[PURE_MODULE_STATES];
} PureApp;
PureResult pure_app_start(PureApp *, const PureModule *, PureData data);