summaryrefslogtreecommitdiffstats
path: root/bytecode/encoding.c
diff options
context:
space:
mode:
Diffstat (limited to 'bytecode/encoding.c')
-rw-r--r--bytecode/encoding.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/bytecode/encoding.c b/bytecode/encoding.c
new file mode 100644
index 0000000..62c9762
--- /dev/null
+++ b/bytecode/encoding.c
@@ -0,0 +1,118 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "panic.h"
+#include "slice.h"
+#include "value.h"
+
+#include "encoding.h"
+
+struct reader {
+ struct slice data;
+ int n;
+};
+
+static void advance(struct reader *r, int size)
+{
+ r->data = slice1(r->data, size);
+ r->n += size;
+}
+
+static uint8_t parse_byte(struct reader *r)
+{
+ if (r->data.size < 1) {
+ panicf("read byte: no data!\n");
+ }
+ uint8_t res = r->data.buf[0];
+ advance(r, 1);
+ return res;
+}
+
+static local parse_local(struct reader *r)
+{
+ if (r->data.size < 1) {
+ panicf("local: no data!\n");
+ }
+ local res = r->data.buf[0];
+ if (res > 7) {
+ panicf("Invalid local (out of range): %d\n", res);
+ }
+ advance(r, 1);
+ return res;
+}
+
+static value parse_value(struct reader *r)
+{
+ if (r->data.size < 8) {
+ panicf("value: no data!\n");
+ }
+ uint64_t res = *(uint64_t *) r->data.buf;
+ advance(r, 8);
+ return res;
+}
+
+static struct arg parse_arg(struct reader *r, bool is_const)
+{
+ if (is_const) {
+ return (struct arg) { .constant = parse_value(r) };
+ }
+ return (struct arg) { .local = parse_local(r) };
+}
+
+static uint8_t parse_offset(struct reader *r)
+{
+ if (r->data.size < 1) {
+ panicf("offset: no data!\n");
+ }
+ uint8_t res = r->data.buf[0];
+ advance(r, 1);
+ return res;
+}
+
+struct result parse(struct slice data)
+{
+ struct reader r = { .data = data, .n = 0 };
+
+ uint8_t codeByte = parse_byte(&r);
+ enum opcode code = codeByte >> 2;
+ bool arg1_const = codeByte & 0x2;
+ // bool arg2_const = codeByte & 0x1;
+
+ struct op out = {
+ .code = code,
+ };
+
+ switch (code) {
+ case OALLOC:
+ out.alloc.out = parse_local(&r);
+ out.alloc.size = parse_arg(&r, arg1_const);
+ break;
+ case OCALL:
+ // No arguments.
+ break;
+ case OPOKE:
+ out.poke.offset = parse_offset(&r);
+ out.poke.pointer = parse_local(&r);
+ out.poke.value = parse_arg(&r, arg1_const);
+ break;
+ case OPEEK:
+ out.peek.out = parse_local(&r);
+ out.peek.offset = parse_offset(&r);
+ out.peek.value = parse_arg(&r, arg1_const);
+ break;
+ case OSHUF:
+ out.shuf.out = parse_local(&r);
+ out.shuf.value = parse_arg(&r, arg1_const);
+ break;
+ case OEXIT:
+ out.exit.value = parse_arg(&r, arg1_const);
+ break;
+ default:
+ panicf("Invalid code %d\n", code);
+ }
+
+ return (struct result) {
+ .op = out,
+ .n = r.n,
+ };
+}