From 465f4d5e4a9ac35f768809c13605599a13512c52 Mon Sep 17 00:00:00 2001 From: CPunch Date: Thu, 25 May 2023 19:41:13 -0500 Subject: [PATCH] started cdump.c:cosmoD_dump() --- src/cdump.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cdump.h | 18 ++++++ 2 files changed, 197 insertions(+) create mode 100644 src/cdump.c create mode 100644 src/cdump.h diff --git a/src/cdump.c b/src/cdump.c new file mode 100644 index 0000000..8e12ca8 --- /dev/null +++ b/src/cdump.c @@ -0,0 +1,179 @@ +#include "cdump.h" + +#include "cmem.h" +#include "cobj.h" +#include "cvalue.h" + +typedef struct +{ + CState *state; + const void *userData; + cosmo_Writer writer; + int writerStatus; +} DumpState; + +static void writeCValue(DumpState *dstate, CValue val); + +static void initDumpState(CState *state, DumpState *dstate, cosmo_Writer writer, + const void *userData) +{ + dstate->state = state; + dstate->userData = userData; + dstate->writer = writer; + dstate->writerStatus = 0; +} + +static void writeBlock(DumpState *dstate, const void *data, size_t size) +{ + if (dstate->writerStatus == 0) { + dstate->writerStatus = dstate->writer(dstate->state, data, size, dstate->userData); + } +} + +static void writeu8(DumpState *dstate, uint8_t d) +{ + writeBlock(dstate, &d, sizeof(uint8_t)); +} + +static void writeu32(DumpState *dstate, uint32_t d) +{ + writeBlock(dstate, &d, sizeof(uint32_t)); +} + +static void writeSize(DumpState *dstate, size_t d) +{ + writeBlock(dstate, &d, sizeof(size_t)); +} + +static void writeVector(DumpState *dstate, const void *data, size_t size) +{ + writeSize(dstate, size); + writeBlock(dstate, data, size); +} + +static void writeHeader(DumpState *dstate) +{ + writeBlock(dstate, COSMO_MAGIC, COSMO_MAGIC_LEN); + + /* after the magic, we write some platform information */ + writeu8(dstate, cosmoD_isBigEndian()); + writeu8(dstate, sizeof(cosmo_Number)); + writeu8(dstate, sizeof(size_t)); + writeu8(dstate, sizeof(int)); +} + +static void writeCObjString(DumpState *dstate, CObjString *obj) +{ + if (obj == NULL) { /* this is in case cobjfunction's name or module strings are null */ + writeu32(dstate, 0); + return; + } + + /* write string length */ + writeu32(dstate, obj->length); + + /* write string data */ + writeBlock(dstate, obj->str, obj->length); +} + +static void writeCObjFunction(DumpState *dstate, CObjFunction *obj) +{ + writeCObjString(dstate, obj->name); + writeCObjString(dstate, obj->module); + + writeu32(dstate, obj->args); + writeu32(dstate, obj->upvals); + writeu8(dstate, obj->variadic); + + /* write chunk info */ + writeVector(dstate, obj->chunk.buf, sizeof(uint8_t) * obj->chunk.count); + + /* write line info */ + writeVector(dstate, obj->chunk.lineInfo, sizeof(int) * obj->chunk.count); + + /* write constants */ + for (int i = 0; i < obj->chunk.constants.count; i++) { + writeCValue(dstate, obj->chunk.constants.values[i]); + } +} + +#define WRITE_VAR(dstate, type, expression) \ + { \ + type _tmp = expression; \ + writeBlock(dstate, &_tmp, sizeof(_tmp)); \ + break; \ + } + +static void writeCObj(DumpState *dstate, CObj *obj) +{ + /* + we can kind of cheat here since our parser only emits a few very limited CObjs... + CChunks will only ever have the following CObj's in their constant table: + - COBJ_STRING + - COBJ_FUNCTION + + the rest of the objects are created during runtime. yay! + */ + CObjType t = cosmoO_readType(obj); + + /* write cobj type */ + writeu8(dstate, t); + + /* write object payload/body */ + switch (t) { + case COBJ_STRING: + writeCObjString(dstate, (CObjString *)obj); + break; + case COBJ_FUNCTION: + writeCObjFunction(dstate, (CObjFunction *)obj); + break; + default: + break; + } +} + +static void writeCValue(DumpState *dstate, CValue val) +{ + CosmoType t = GET_TYPE(val); + + /* write value type */ + writeu8(dstate, t); + + /* write value payload/body */ + switch (t) { + case COSMO_TNUMBER: + WRITE_VAR(dstate, cosmo_Number, cosmoV_readNumber(val)) + case COSMO_TBOOLEAN: + WRITE_VAR(dstate, bool, cosmoV_readBoolean(val)) + case COSMO_TREF: + writeCObj(dstate, cosmoV_readRef(val)); + break; + case COSMO_TNIL: /* fallthrough, no body */ + default: + break; + } +} + +#undef WRITE_VAR + +bool cosmoD_isBigEndian() +{ + union + { + uint32_t i; + uint8_t c[4]; + } _indxint = {0xDEADB33F}; + + return _indxint.c[0] == 0xDE; +} + +int cosmoD_dump(CState *state, CObjFunction *func, cosmo_Writer writer, const void *userData) +{ + DumpState dstate; + initDumpState(state, &dstate, writer, userData); + + writeHeader(&dstate); + writeCObjFunction(&dstate, func); + + return dstate.writerStatus; +} diff --git a/src/cdump.h b/src/cdump.h new file mode 100644 index 0000000..a914e0b --- /dev/null +++ b/src/cdump.h @@ -0,0 +1,18 @@ +#ifndef COSMO_DUMP_H +#define COSMO_DUMP_H + +#include "cobj.h" +#include "cosmo.h" + +#include + +#define COSMO_MAGIC "COS\x12" +#define COSMO_MAGIC_LEN 4 + +typedef int (*cosmo_Writer)(CState *state, const void *data, size_t size, const void *ud); + +bool cosmoD_isBigEndian(); + +int cosmoD_dump(CState *state, CObjFunction *func, cosmo_Writer writer, const void *userData); + +#endif \ No newline at end of file