From 446ab037b0ddbdf970db1a90f4c9b83d891dd7f0 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 17 Jun 2019 23:40:02 -0400 Subject: [PATCH] Allow marshaling pegs. --- src/core/peg.c | 59 +++++++++++++++++++++++++++++++++++++++-------- test/suite6.janet | 6 +++++ 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/core/peg.c b/src/core/peg.c index d67e941d..d9869fd0 100644 --- a/src/core/peg.c +++ b/src/core/peg.c @@ -945,6 +945,7 @@ static uint32_t peg_compile1(Builder *b, Janet peg) { typedef struct { uint32_t *bytecode; Janet *constants; + size_t bytecode_len; uint32_t num_constants; } Peg; @@ -956,16 +957,15 @@ static int peg_mark(void *p, size_t size) { return 0; } -static JanetAbstractType peg_type = { - "core/peg", - NULL, - peg_mark, - NULL, - NULL, - NULL, - NULL, - NULL -}; +static void peg_marshal(void *p, JanetMarshalContext *ctx) { + Peg *peg = (Peg *)p; + janet_marshal_size(ctx, peg->bytecode_len); + janet_marshal_int(ctx, (int32_t)peg->num_constants); + for (size_t i = 0; i < peg->bytecode_len; i++) + janet_marshal_int(ctx, (int32_t) peg->bytecode[i]); + for (uint32_t j = 0; j < peg->num_constants; j++) + janet_marshal_janet(ctx, peg->constants[j]); +} /* Used to ensure that if we place several arrays in one memory chunk, each * array will be correctly aligned */ @@ -974,6 +974,43 @@ static size_t size_padded(size_t offset, size_t size) { return x - (x % size); } +static void peg_unmarshal(void *p, JanetMarshalContext *ctx) { + char *mem = p; + Peg *peg = (Peg *)p; + peg->bytecode_len = janet_unmarshal_size(ctx); + peg->num_constants = (uint32_t) janet_unmarshal_int(ctx); + + /* Calculate offsets. Should match those in make_peg */ + size_t bytecode_start = size_padded(sizeof(Peg), sizeof(uint32_t)); + size_t bytecode_size = peg->bytecode_len * sizeof(uint32_t); + size_t constants_start = size_padded(bytecode_start + bytecode_size, sizeof(Janet)); + uint32_t *bytecode = (uint32_t *)(mem + bytecode_start); + Janet *constants = (Janet *)(mem + constants_start); + peg->bytecode = bytecode; + peg->constants = constants; + + for (size_t i = 0; i < peg->bytecode_len; i++) + bytecode[i] = (uint32_t) janet_unmarshal_int(ctx); + for (uint32_t j = 0; j < peg->num_constants; j++) + constants[j] = janet_unmarshal_janet(ctx); + + /* TODO - verify peg bytecode. This is basically iterating + * the bytecode and making sure instructions don't reference + * memory outside the bytecode array. Otherwise, all programs + * should be valid.*/ +} + +static const JanetAbstractType peg_type = { + "core/peg", + NULL, + peg_mark, + NULL, + NULL, + peg_marshal, + peg_unmarshal, + NULL +}; + /* Convert Builder to Peg (Janet Abstract Value) */ static Peg *make_peg(Builder *b) { size_t bytecode_start = size_padded(sizeof(Peg), sizeof(uint32_t)); @@ -988,6 +1025,7 @@ static Peg *make_peg(Builder *b) { peg->num_constants = janet_v_count(b->constants); memcpy(peg->bytecode, b->bytecode, bytecode_size); memcpy(peg->constants, b->constants, constants_size); + peg->bytecode_len = janet_v_count(b->bytecode); return peg; } @@ -1072,6 +1110,7 @@ static const JanetReg peg_cfuns[] = { /* Load the peg module */ void janet_lib_peg(JanetTable *env) { janet_core_cfuns(env, NULL, peg_cfuns); + janet_register_abstract_type(&peg_type); } #endif /* ifdef JANET_PEG */ diff --git a/test/suite6.janet b/test/suite6.janet index 2c7b2b19..18cfb1fa 100644 --- a/test/suite6.janet +++ b/test/suite6.janet @@ -125,4 +125,10 @@ (assert (not (string/check-set "abc" "")) "string/check-set 4") (assert (not (string/check-set "" "aabc")) "string/check-set 5") +# Marshal and unmarshal pegs +(def p (-> "abcd" peg/compile marshal unmarshal)) +(assert (peg/match p "abcd") "peg marshal 1") +(assert (peg/match p "abcdefg") "peg marshal 2") +(assert (not (peg/match p "zabcdefg")) "peg marshal 3") + (end-suite)