Created
July 13, 2018 07:57
-
-
Save timruffles/088a2b9de5c4d7eea3abceebf310a91f to your computer and use it in GitHub Desktop.
Representing JsValues for JS -> C compiler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <assert.h> | |
#include <stdint.h> | |
#include <string.h> | |
/** | |
* So, plan is to store the values for the JS compiler | |
* in a union, nicking Lua's idea. That way immediate | |
* values like numbers live inside the JSValue wrapper, | |
* while the compound values lived elsewhere. | |
*/ | |
typedef char* TypeTag; | |
typedef char BooleanValue; | |
static const char TRUE = 'Y'; | |
static char OBJECT[] = "object"; | |
static char BOOLEAN[] = "boolean"; | |
static char NUMBER[] = "number"; | |
typedef union { | |
void* object; | |
double number; | |
BooleanValue boolean; | |
uintptr_t raw; | |
} JsValueContent; | |
typedef struct { | |
// to discriminate the union | |
TypeTag type; | |
JsValueContent value; | |
} JsValue; | |
/** | |
* So I thought I could be clever and have a single | |
* valueGet function that'd return the N bytes of the | |
* union. Now - since then I've decided that's a silly | |
* idea and having the JsValue module expose typed getters | |
* makes more sense - but I'm interested in that it wasn't doable. | |
* | |
* My first though was to both pass in and return the union | |
* as a uintptr_t - as it was going to be as wide as a | |
* pointer. | |
* | |
* I noticed two things: | |
* - this makes for a LOT of ugly casting to make the compiler | |
* stop pointing out it's a bad idea | |
* - it's easy to break things if you do casts that will cause | |
* data conversion (especially double -> uintptr_t) rather than | |
* simply a view of a different type of the same data | |
*/ | |
JsValue* jsValueCreate(TypeTag, uintptr_t); | |
JsValue* jsValueCreate(TypeTag tag, uintptr_t value) { | |
JsValue* val = calloc(sizeof(JsValue), 1); | |
*val = (JsValue) { | |
.type = tag, | |
}; | |
// Although the union elements are of different sizes | |
// unions' elements are all aligned to address of union, | |
// so we can just read the max number of bytes for every | |
// argument. | |
// | |
// Argument that this is ok: char is well defined as a single | |
// byte, so having 7 bytes of garbage after is not a problem. | |
// | |
// Pointers and doubles both take 8 bytes, so we're never | |
// getting any garbage anyway. | |
// | |
// jsValueCreate(.., 'Y') | |
// | |
// jsValueCreate(.., 47.0) | |
// | |
// jsValueCreate(.., somePtr) | |
// | |
//memcpy(&val->value, &value, sizeof(JsValueContent)); | |
val->value.raw = value; | |
return val; | |
} | |
uintptr_t jsValueGet(JsValue*); | |
uintptr_t jsValueGet(JsValue* value) { | |
return (uintptr_t)value->value.object; | |
} | |
int main() { | |
double pretendObject = 4242; | |
double doubleVal = 47; | |
JsValue* val1 = jsValueCreate(NUMBER, *(uintptr_t*)(void*)&doubleVal); | |
JsValue* val2 = jsValueCreate(BOOLEAN, TRUE); | |
JsValue* val3 = jsValueCreate(OBJECT, &pretendObject); | |
// copy out our double value into another double variable | |
uintptr_t r = jsValueGet(val1); | |
double dblRestored = *(double*)(void*)&r; | |
assert(dblRestored - doubleVal < 0.0000000001); | |
printf("val1 %f - \n", dblRestored); | |
// read out the char | |
char readChar = (char)jsValueGet(val2); | |
assert(readChar == TRUE); | |
printf("val2 %c\n", readChar); | |
// read out the pointer value | |
void* restoredPointer = jsValueGet(val3); | |
assert(restoredPointer == &pretendObject); | |
printf("val3 %p\n", restoredPointer); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
clang -Weverything js-values-sketch.c -o demo && ./demo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment