Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Created May 2, 2016 00:09
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pervognsen/5a64f252a5bd95525faa123c1cb75453 to your computer and use it in GitHub Desktop.
Save pervognsen/5a64f252a5bd95525faa123c1cb75453 to your computer and use it in GitHub Desktop.
// Xeno
enum Xeno_Kind {
XENO_POINTER,
XENO_AGGREGATE,
XENO_FIRST_PRIMITIVE_TYPE,
XENO_UINT8 = XENO_FIRST_PRIMITIVE_TYPE,
XENO_UINT16,
XENO_UINT32,
XENO_UINT64,
XENO_INT8,
XENO_INT16,
XENO_INT32,
XENO_INT64,
XENO_FLOAT,
XENO_DOUBLE,
XENO_KINDS_COUNT,
XENO_LAST_PRIMITIVE_TYPE = XENO_KINDS_COUNT - 1,
XENO_UINT = XENO_UINT32,
XENO_CHAR = XENO_UINT8
};
struct Xeno_Type;
struct Xeno_Field {
Xeno_Type *type;
char *name;
size_t offset;
};
struct Xeno_Type {
Xeno_Kind kind;
char *name;
size_t size;
size_t count;
union {
Xeno_Type *pointee;
struct {
size_t count;
Xeno_Field *array;
} fields;
};
};
struct Xeno_Data {
void *pointer;
Xeno_Type *type;
};
Xeno_Type xeno_uint8 = {XENO_UINT8, "uint8", sizeof(uint8_t), 1};
Xeno_Type xeno_uint16 = {XENO_UINT16, "uint16", sizeof(uint16_t), 1};
Xeno_Type xeno_uint32 = {XENO_UINT32, "uint32", sizeof(uint32_t), 1};
Xeno_Type xeno_uint64 = {XENO_UINT64, "uint64", sizeof(uint64_t), 1};
Xeno_Type xeno_int8 = {XENO_INT8, "int8", sizeof(int8_t), 1};
Xeno_Type xeno_int16 = {XENO_INT8, "int16", sizeof(int16_t), 1};
Xeno_Type xeno_int32 = {XENO_INT32, "int32", sizeof(int32_t), 1};
Xeno_Type xeno_int64 = {XENO_INT64, "int64", sizeof(int64_t), 1};
Xeno_Type xeno_float = {XENO_FLOAT, "float", sizeof(float), 1};
Xeno_Type xeno_double = {XENO_DOUBLE, "double", sizeof(double), 1};
Xeno_Type xeno_uint8_pointer = {XENO_POINTER, "uint8*", sizeof(void *), 1, &xeno_uint8};
const Xeno_Type *xeno_types[XENO_KINDS_COUNT] = {
0, // XENO_POINTER
0, // XENO_AGGREGATE
&xeno_uint8,
&xeno_uint16,
&xeno_uint32,
&xeno_uint64,
&xeno_int8,
&xeno_int16,
&xeno_int32,
&xeno_int64,
&xeno_float,
&xeno_double
};
size_t Xeno_GetFieldIndex(Xeno_Type *type, char *name) {
Assert(type->kind == XENO_AGGREGATE);
size_t index;
for (index = 0; index < type->fields.count; index++) {
if (strcmp(type->fields.array[index].name, name) == 0) {
break;
}
}
return index;
}
void Xeno_GetElement(Xeno_Data *element, Xeno_Data data, size_t index) {
element->pointer = (char *)data.pointer + index * data.type->size;
element->type = data.type;
}
void Xeno_GetField(Xeno_Data *field, Xeno_Data data, size_t index) {
Assert(data.type->kind == XENO_AGGREGATE);
Assert(index < data.type->fields.count);
field->pointer = (char *)data.pointer + data.type->fields.array[index].offset;
field->type = data.type->fields.array[index].type;
}
void Xeno_Dereference(Xeno_Data *pointee, Xeno_Data pointer) {
Assert(pointer.type->kind == XENO_POINTER);
pointee->pointer = *(void **)pointer.pointer;
pointee->type = pointer.type->pointee;
}
void Xeno_Copy(Xeno_Data destination, Xeno_Data source) {
memcpy(destination.pointer, source.pointer, source.type->size * source.type->count);
}
void Xeno_Cast(Xeno_Data destination, Xeno_Data source) {
uint8_t uint8_t_value;
uint16_t uint16_t_value;
uint32_t uint32_t_value;
uint64_t uint64_t_value;
int8_t int8_t_value;
int16_t int16_t_value;
int32_t int32_t_value;
int64_t int64_t_value;
float float_value;
double double_value;
#define CASE(kind, type) \
case kind: { \
type source_t_value = *(type *)source.pointer; \
uint8_t_value = (uint8_t)source_t_value; \
uint16_t_value = (uint16_t)source_t_value; \
uint32_t_value = (uint32_t)source_t_value; \
uint64_t_value = (uint64_t)source_t_value; \
int8_t_value = (int8_t)source_t_value; \
int16_t_value = (int16_t)source_t_value; \
int32_t_value = (int32_t)source_t_value; \
int64_t_value = (int64_t)source_t_value; \
float_value = (float)source_t_value; \
double_value = (double)source_t_value; \
break; \
}
switch (source.type->kind) {
CASE(XENO_UINT8, uint8_t)
CASE(XENO_UINT16, uint16_t)
CASE(XENO_UINT32, uint32_t)
CASE(XENO_UINT64, uint64_t)
CASE(XENO_INT8, int8_t)
CASE(XENO_INT16, int16_t)
CASE(XENO_INT32, int32_t)
CASE(XENO_INT64, int64_t)
CASE(XENO_FLOAT, float)
CASE(XENO_DOUBLE, double)
default:
Assert(0);
break;
}
#undef CASE
#define CASE(kind, type) \
case kind: \
*(type *)destination.pointer = type##_value; \
break;
switch (destination.type->kind) {
CASE(XENO_UINT8, uint8_t)
CASE(XENO_UINT16, uint16_t)
CASE(XENO_UINT32, uint32_t)
CASE(XENO_UINT64, uint64_t)
CASE(XENO_INT8, int8_t)
CASE(XENO_INT16, int16_t)
CASE(XENO_INT32, int32_t)
CASE(XENO_INT64, int64_t)
CASE(XENO_FLOAT, float)
CASE(XENO_DOUBLE, double)
default:
Assert(0);
break;
}
#undef CASE
}
// Xeno diagnostics
void Xeno_AssertTypeInvariants(Xeno_Type *type) {
Assert(type);
Assert(type->kind < XENO_KINDS_COUNT);
Assert(type->size > 0);
Assert(type->count > 0);
if (type->kind == XENO_POINTER) {
Assert(type->size == sizeof(void *));
Xeno_AssertTypeInvariants(type->pointee);
} else if (type->kind == XENO_AGGREGATE) {
for (size_t index = 0; index < type->fields.count; index++) {
Xeno_Field *field = type->fields.array + index;
Xeno_AssertTypeInvariants(field->type);
Assert(field->offset + field->type->size <= type->size);
}
} else {
Assert(type->size == xeno_types[type->kind]->size);
}
}
void Xeno_PrintType(Xeno_Type *type) {
switch (type->kind) {
case XENO_POINTER:
Printf("(:%s * ", type->name);
Xeno_PrintType(type->pointee);
Printf(")");
break;
case XENO_AGGREGATE:
Printf("(:%s {", type->name);
for (size_t index = 0; index < type->fields.count; index++) {
Xeno_Field *field = type->fields.array + index;
if (index != 0) {
Printf(" ");
}
Printf("(%s %llu ", field->name, field->offset);
Xeno_PrintType(field->type);
Printf(")");
}
Printf("})");
break;
default:
Printf("%s", xeno_types[type->kind]->name);
break;
}
}
void Xeno_PrintNested(Xeno_Data data, int nesting) {
Xeno_Type *type = data.type;
PrintIndentation(nesting);
if (type->count > 1) {
Printf("[");
}
for (size_t index = 0; index < type->count; index++) {
if (index != 0) {
Printf("\n");
PrintIndentation(nesting);
}
switch (type->kind) {
case XENO_POINTER:
Printf("0x%p", *(void **)data.pointer);
break;
case XENO_AGGREGATE:
Printf("{\n");
nesting += 2;
for (size_t field_index = 0; field_index < type->fields.count; field_index++) {
Xeno_Field *field = type->fields.array + field_index;
PrintIndentation(nesting);
Printf("%s:\n", field->name);
Xeno_Data field_data;
Xeno_GetField(&field_data, data, field_index);
Xeno_PrintNested(field_data, nesting + 2);
Printf("\n");
}
nesting -= 2;
PrintIndentation(nesting);
Printf("}");
break;
case XENO_UINT8:
Printf("%u", *(uint8_t *)data.pointer);
break;
case XENO_UINT16:
Printf("%u", *(uint16_t *)data.pointer);
break;
case XENO_UINT32:
Printf("%u", *(uint32_t *)data.pointer);
break;
case XENO_UINT64:
Printf("%llu", *(uint64_t *)data.pointer);
break;
case XENO_INT8:
Printf("%d", *(int8_t *)data.pointer);
break;
case XENO_INT16:
Printf("%d", *(int16_t *)data.pointer);
break;
case XENO_INT32:
Printf("%d", *(int32_t *)data.pointer);
break;
case XENO_INT64:
Printf("%lld", *(int64_t *)data.pointer);
break;
case XENO_FLOAT:
Printf("%f", *(float *)data.pointer);
break;
case XENO_DOUBLE:
Printf("%g", *(double *)data.pointer);
break;
default:
Assert(0);
break;
}
Xeno_GetElement(&data, data, 1);
}
if (type->count > 1) {
Printf("]");
}
}
void Xeno_Print(Xeno_Data data) {
Xeno_PrintNested(data, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment