Created
May 2, 2016 00:09
-
-
Save pervognsen/5a64f252a5bd95525faa123c1cb75453 to your computer and use it in GitHub Desktop.
This file contains 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
// 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