Simplify enum/struct codegen by using reusable general-purpose
metamethods for structs/enums instead of metamethod codegen for each struct/enum defined.
This commit is contained in:
parent
6b9055db7c
commit
954ed42934
10
compile.c
10
compile.c
@ -1461,9 +1461,7 @@ CORD expr_as_text(env_t *env, CORD expr, type_t *t, CORD color)
|
||||
case FunctionType: case ClosureType: return CORD_asprintf("Func$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
|
||||
case PointerType: return CORD_asprintf("Pointer$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
|
||||
case OptionalType: return CORD_asprintf("Optional$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
|
||||
case StructType: case EnumType:
|
||||
return CORD_asprintf("(%r)->CustomInfo.as_text(stack(%r), %r, %r)",
|
||||
compile_type_info(env, t), expr, color, compile_type_info(env, t));
|
||||
case StructType: case EnumType: return CORD_asprintf("generic_as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
|
||||
default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for %T", t);
|
||||
}
|
||||
}
|
||||
@ -1952,6 +1950,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
code_err(ast, "I don't know how to get the negative value of type %T", t);
|
||||
|
||||
}
|
||||
// TODO: for constructors, do new(T, ...) instead of heap((T){...})
|
||||
case HeapAllocate: return CORD_asprintf("heap(%r)", compile(env, Match(ast, HeapAllocate)->value));
|
||||
case StackReference: {
|
||||
ast_t *subject = Match(ast, StackReference)->value;
|
||||
@ -3464,7 +3463,8 @@ CORD compile_type_info(env_t *env, type_t *t)
|
||||
return CORD_asprintf("Closure$info(%r)", CORD_quoted(type_to_cord(t)));
|
||||
}
|
||||
case OptionalType: {
|
||||
return CORD_asprintf("Optional$info(%r)", compile_type_info(env, Match(t, OptionalType)->type));
|
||||
type_t *non_optional = Match(t, OptionalType)->type;
|
||||
return CORD_asprintf("Optional$info(%zu, %zu, %r)", type_size(t), type_align(t), compile_type_info(env, non_optional));
|
||||
}
|
||||
case TypeInfoType: return CORD_all("TypeInfo$info(", CORD_quoted(type_to_cord(Match(t, TypeInfoType)->type)), ")");
|
||||
case MemoryType: return "&Memory$info";
|
||||
@ -3656,9 +3656,9 @@ CORD compile_file(env_t *env, ast_t *ast)
|
||||
"#include <tomo/tomo.h>\n"
|
||||
"#include \"", name, ".tm.h\"\n\n",
|
||||
env->code->local_typedefs, "\n",
|
||||
env->code->typeinfos, "\n",
|
||||
env->code->staticdefs, "\n",
|
||||
env->code->funcs, "\n",
|
||||
env->code->typeinfos, "\n",
|
||||
"public void $", env->namespace->name, "$$initialize(void) {\n",
|
||||
"static bool initialized = false;\n",
|
||||
"if (initialized) return;\n",
|
||||
|
253
enums.c
253
enums.c
@ -13,193 +13,53 @@
|
||||
#include "typecheck.h"
|
||||
#include "stdlib/util.h"
|
||||
|
||||
PUREFUNC static bool has_extra_data(tag_ast_t *tags)
|
||||
{
|
||||
for (tag_ast_t *tag = tags; tag; tag = tag->next) {
|
||||
if (tag->fields) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static CORD compile_str_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
CORD str_func = CORD_all("static Text_t ", full_name, "$as_text(", full_name, "_t *obj, bool use_color) {\n"
|
||||
"\tif (!obj) return Text(\"", def->name, "\");\n"
|
||||
"switch (obj->tag) {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (!tag->fields) {
|
||||
str_func = CORD_all(str_func, "\tcase ", full_name, "$tag$", tag->name, ": return use_color ? Text(\"\\x1b[36;1m",
|
||||
def->name, ".", tag->name, "\\x1b[m\") : Text(\"", def->name, ".", tag->name, "\");\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
str_func = CORD_all(str_func, "\tcase ", full_name, "$tag$", tag->name, ": return Text$concat(use_color ? Text(\"\\x1b[36;1m",
|
||||
def->name, ".", tag->name, "\\x1b[m(\") : Text(\"", def->name, ".", tag->name, "(\")");
|
||||
|
||||
if (tag->secret) {
|
||||
str_func = CORD_cat(str_func, ", use_color ? Text(\"\\x1b[2m...\\x1b[m\") : Text(\"...\", \")\"));\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag->fields && !tag->fields->next) { // Single-member tags don't need to print member names:
|
||||
type_t *field_t = get_arg_ast_type(env, tag->fields);
|
||||
CORD field_str = expr_as_text(env, CORD_all("obj->$", tag->name, ".$", tag->fields->name), field_t, "use_color");
|
||||
str_func = CORD_all(str_func, ", ", field_str);
|
||||
} else {
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
type_t *field_t = get_arg_ast_type(env, field);
|
||||
CORD field_str = expr_as_text(env, CORD_all("obj->$", tag->name, ".$", field->name), field_t, "use_color");
|
||||
str_func = CORD_all(str_func, ", Text(\"", field->name, "=\"), ", field_str);
|
||||
if (field->next) str_func = CORD_cat(str_func, ", Text(\", \")");
|
||||
}
|
||||
}
|
||||
str_func = CORD_cat(str_func, ", Text(\")\"));\n");
|
||||
}
|
||||
str_func = CORD_cat(str_func, "\tdefault: return (Text_t){.length=0};\n\t}\n}\n");
|
||||
return str_func;
|
||||
}
|
||||
|
||||
static CORD compile_compare_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
if (!has_extra_data(def->tags)) {
|
||||
// Comparisons are simpler if there is only a tag, no tagged data:
|
||||
return CORD_all("static int ", full_name, "$compare(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n"
|
||||
"return (x->tag - y->tag);\n"
|
||||
"}\n");
|
||||
}
|
||||
CORD cmp_func = CORD_all("static int ", full_name, "$compare(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n"
|
||||
"int diff = x->tag - y->tag;\n"
|
||||
"if (diff) return diff;\n"
|
||||
"switch (x->tag) {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (tag->fields) {
|
||||
type_t *tag_type = Table$str_get(*env->types, CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)));
|
||||
cmp_func = CORD_all(cmp_func, "\tcase ", full_name, "$tag$", tag->name, ": "
|
||||
"return generic_compare(&x->$", tag->name, ", &y->$", tag->name, ", ", compile_type_info(env, tag_type), ");\n");
|
||||
} else {
|
||||
cmp_func = CORD_all(cmp_func, "\tcase ", full_name, "$tag$", tag->name, ": return 0;\n");
|
||||
}
|
||||
}
|
||||
cmp_func = CORD_all(cmp_func, "default: return 0;\n}\n}\n");
|
||||
return cmp_func;
|
||||
}
|
||||
|
||||
static CORD compile_equals_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
if (!has_extra_data(def->tags)) {
|
||||
// Equality is simpler if there is only a tag, no tagged data:
|
||||
return CORD_all("static bool ", full_name, "$equal(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n"
|
||||
"return (x->tag == y->tag);\n"
|
||||
"}\n");
|
||||
}
|
||||
CORD eq_func = CORD_all("static bool ", full_name, "$equal(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n"
|
||||
"if (x->tag != y->tag) return no;\n"
|
||||
"switch (x->tag) {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (tag->fields) {
|
||||
type_t *tag_type = Table$str_get(*env->types, CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)));
|
||||
eq_func = CORD_all(eq_func, "\tcase ", full_name, "$tag$", tag->name, ": "
|
||||
"return generic_equal(&x->$", tag->name, ", &y->$", tag->name, ", ", compile_type_info(env, tag_type), ");\n");
|
||||
} else {
|
||||
eq_func = CORD_all(eq_func, "\tcase ", full_name, "$tag$", tag->name, ": return yes;\n");
|
||||
}
|
||||
}
|
||||
eq_func = CORD_all(eq_func, "default: return 0;\n}\n}\n");
|
||||
return eq_func;
|
||||
}
|
||||
|
||||
static CORD compile_hash_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
if (!has_extra_data(def->tags)) {
|
||||
// Hashing is simpler if there is only a tag, no tagged data:
|
||||
return CORD_all("static uint64_t ", full_name, "$hash(const ", full_name, "_t *obj, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n"
|
||||
"return siphash24((void*)&obj->tag, sizeof(obj->tag));\n"
|
||||
"\n}\n");
|
||||
}
|
||||
CORD hash_func = CORD_all("static uint64_t ", full_name, "$hash(const ", full_name, "_t *obj, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n"
|
||||
"uint64_t hashes[2] = {(uint64_t)obj->tag, 0};\n"
|
||||
"switch (obj->tag) {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (tag->fields) {
|
||||
type_t *tag_type = Table$str_get(*env->types, CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)));
|
||||
hash_func = CORD_all(hash_func, "\tcase ", full_name, "$tag$", tag->name, ": "
|
||||
"hashes[1] = generic_hash(&obj->$", tag->name, ", ", compile_type_info(env, tag_type), ");\n"
|
||||
"break;\n");
|
||||
} else {
|
||||
hash_func = CORD_all(hash_func, "\tcase ", full_name, "$tag$", tag->name, ": break;\n");
|
||||
}
|
||||
}
|
||||
hash_func = CORD_all(hash_func, "}\n"
|
||||
"return siphash24((void*)&hashes, sizeof(hashes));\n}\n");
|
||||
return hash_func;
|
||||
}
|
||||
|
||||
void compile_enum_def(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
|
||||
// Compile member types and constructors:
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
compile_struct_def(env, WrapAST(ast, StructDef, .name=CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)), .fields=tag->fields));
|
||||
if (tag->fields) { // Constructor macros:
|
||||
CORD arg_sig = CORD_EMPTY;
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
type_t *field_t = get_arg_ast_type(env, field);
|
||||
arg_sig = CORD_all(arg_sig, compile_declaration(field_t, CORD_all("$", field->name)));
|
||||
if (field->next) arg_sig = CORD_cat(arg_sig, ", ");
|
||||
}
|
||||
if (arg_sig == CORD_EMPTY) arg_sig = "void";
|
||||
CORD constructor_impl = CORD_all("public inline ", full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ") { return (",
|
||||
full_name, "_t){.tag=", full_name, "$tag$", tag->name, ", .$", tag->name, "={");
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
constructor_impl = CORD_all(constructor_impl, "$", field->name);
|
||||
if (field->next) constructor_impl = CORD_cat(constructor_impl, ", ");
|
||||
}
|
||||
constructor_impl = CORD_cat(constructor_impl, "}}; }\n");
|
||||
env->code->funcs = CORD_cat(env->code->funcs, constructor_impl);
|
||||
if (!tag->fields) continue;
|
||||
|
||||
const char *tag_name = heap_strf("%s$%s", def->name, tag->name);
|
||||
compile_struct_def(env, WrapAST(ast, StructDef, .name=tag_name, .fields=tag->fields, .secret=tag->secret));
|
||||
CORD arg_sig = CORD_EMPTY;
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
type_t *field_t = get_arg_ast_type(env, field);
|
||||
arg_sig = CORD_all(arg_sig, compile_declaration(field_t, CORD_all("$", field->name)));
|
||||
if (field->next) arg_sig = CORD_cat(arg_sig, ", ");
|
||||
}
|
||||
if (arg_sig == CORD_EMPTY) arg_sig = "void";
|
||||
CORD constructor_impl = CORD_all("public inline ", full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ") { return (",
|
||||
full_name, "_t){.tag=", full_name, "$tag$", tag->name, ", .$", tag->name, "={");
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
constructor_impl = CORD_all(constructor_impl, "$", field->name);
|
||||
if (field->next) constructor_impl = CORD_cat(constructor_impl, ", ");
|
||||
}
|
||||
constructor_impl = CORD_cat(constructor_impl, "}}; }\n");
|
||||
env->code->funcs = CORD_cat(env->code->funcs, constructor_impl);
|
||||
}
|
||||
|
||||
int num_tags = 0;
|
||||
for (tag_ast_t *t = def->tags; t; t = t->next)
|
||||
num_tags += 1;
|
||||
|
||||
type_t *t = Table$str_get(*env->types, def->name);
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %s = {%zu, %zu, {.tag=EnumInfo, .CustomInfo={",
|
||||
full_name, type_size(t), type_align(t));
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {%zu, %zu, {.tag=EnumInfo, .EnumInfo={.name=\"%s\", "
|
||||
".num_tags=%d, .tags=(NamedType_t[]){",
|
||||
full_name, type_size(t), type_align(t), def->name, num_tags);
|
||||
|
||||
env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast));
|
||||
if (has_extra_data(def->tags)) {
|
||||
env->code->funcs = CORD_all(
|
||||
env->code->funcs,
|
||||
compile_equals_method(env, ast), compile_compare_method(env, ast),
|
||||
compile_hash_method(env, ast));
|
||||
typeinfo = CORD_all(
|
||||
typeinfo,
|
||||
".as_text=(void*)", full_name, "$as_text, "
|
||||
".equal=(void*)", full_name, "$equal, "
|
||||
".hash=(void*)", full_name, "$hash, "
|
||||
".compare=(void*)", full_name, "$compare");
|
||||
} else {
|
||||
// No need for custom methods if there is no tagged data
|
||||
typeinfo = CORD_all(typeinfo, ".as_text=(void*)", full_name, "$as_text");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
const char *tag_type_name = heap_strf("%s$%s", def->name, tag->name);
|
||||
type_t *tag_type = Table$str_get(*env->types, tag_type_name);
|
||||
if (tag_type && Match(tag_type, StructType)->fields)
|
||||
typeinfo = CORD_all(typeinfo, "{\"", tag->name, "\", ", compile_type_info(env, tag_type), "}, ");
|
||||
else
|
||||
typeinfo = CORD_all(typeinfo, "{\"", tag->name, "\"}, ");
|
||||
}
|
||||
typeinfo = CORD_cat(typeinfo, "}}};\n");
|
||||
typeinfo = CORD_all(typeinfo, "}}}};\n");
|
||||
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
|
||||
|
||||
compile_namespace(env, def->name, def->namespace);
|
||||
}
|
||||
|
||||
@ -211,35 +71,40 @@ CORD compile_enum_header(env_t *env, ast_t *ast)
|
||||
CORD enum_def = CORD_all("struct ", full_name, "_s {\n"
|
||||
"\tenum { ", full_name, "$null=0, ");
|
||||
|
||||
bool has_any_tags_with_fields = false;
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
enum_def = CORD_all(enum_def, full_name, "$tag$", tag->name);
|
||||
if (tag->next) enum_def = CORD_all(enum_def, ", ");
|
||||
has_any_tags_with_fields = has_any_tags_with_fields || (tag->fields != NULL);
|
||||
}
|
||||
enum_def = CORD_all(enum_def, "} tag;\n"
|
||||
"union {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
CORD field_def = compile_struct_header(env, WrapAST(ast, StructDef, .name=CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)), .fields=tag->fields));
|
||||
all_defs = CORD_all(all_defs, field_def);
|
||||
enum_def = CORD_all(enum_def, full_name, "$", tag->name, "_t $", tag->name, ";\n");
|
||||
enum_def = CORD_all(enum_def, "} tag;\n");
|
||||
|
||||
if (has_any_tags_with_fields) {
|
||||
enum_def = CORD_all(enum_def, "union {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
if (!tag->fields) continue;
|
||||
CORD field_def = compile_struct_header(env, WrapAST(ast, StructDef, .name=CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)), .fields=tag->fields));
|
||||
all_defs = CORD_all(all_defs, field_def);
|
||||
enum_def = CORD_all(enum_def, full_name, "$", tag->name, "_t $", tag->name, ";\n");
|
||||
}
|
||||
enum_def = CORD_all(enum_def, "};\n");
|
||||
}
|
||||
enum_def = CORD_all(enum_def, "};\n};\n");
|
||||
enum_def = CORD_all(enum_def, "};\n");
|
||||
all_defs = CORD_all(all_defs, enum_def);
|
||||
|
||||
all_defs = CORD_all(all_defs, "extern const TypeInfo_t ", full_name, ";\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
all_defs = CORD_all(all_defs,
|
||||
"extern const TypeInfo_t ", namespace_prefix(env, env->namespace), def->name, "$", tag->name, ";\n");
|
||||
if (tag->fields) { // Constructor macros:
|
||||
CORD arg_sig = CORD_EMPTY;
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
type_t *field_t = get_arg_ast_type(env, field);
|
||||
arg_sig = CORD_all(arg_sig, compile_declaration(field_t, CORD_all("$", field->name)));
|
||||
if (field->next) arg_sig = CORD_all(arg_sig, ", ");
|
||||
}
|
||||
if (arg_sig == CORD_EMPTY) arg_sig = "void";
|
||||
CORD constructor_def = CORD_all(full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ");\n");
|
||||
all_defs = CORD_all(all_defs, constructor_def);
|
||||
if (!tag->fields) continue;
|
||||
|
||||
CORD arg_sig = CORD_EMPTY;
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
type_t *field_t = get_arg_ast_type(env, field);
|
||||
arg_sig = CORD_all(arg_sig, compile_declaration(field_t, CORD_all("$", field->name)));
|
||||
if (field->next) arg_sig = CORD_all(arg_sig, ", ");
|
||||
}
|
||||
if (arg_sig == CORD_EMPTY) arg_sig = "void";
|
||||
CORD constructor_def = CORD_all(full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ");\n");
|
||||
all_defs = CORD_all(all_defs, constructor_def);
|
||||
}
|
||||
return CORD_all(all_defs, compile_namespace_header(env, def->name, def->namespace));
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "arrays.h"
|
||||
#include "bools.h"
|
||||
#include "channels.h"
|
||||
#include "functiontype.h"
|
||||
#include "metamethods.h"
|
||||
@ -15,6 +16,7 @@
|
||||
#include "util.h"
|
||||
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wstack-protector"
|
||||
PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
@ -23,8 +25,54 @@ PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type)
|
||||
case ChannelInfo: return Channel$hash((Channel_t**)obj, type);
|
||||
case TableInfo: return Table$hash(obj, type);
|
||||
case OptionalInfo: return is_null(obj, type->OptionalInfo.type) ? 0 : generic_hash(obj, type->OptionalInfo.type);
|
||||
case EmptyStructInfo: return 0;
|
||||
case CustomInfo: case StructInfo: case EnumInfo: case CStringInfo: // These all share the same info
|
||||
case StructInfo: {
|
||||
if (type->StructInfo.num_fields == 0) {
|
||||
return 0;
|
||||
} else if (type->StructInfo.num_fields == 1) {
|
||||
return generic_hash(obj, type->StructInfo.fields[0].type);
|
||||
} else {
|
||||
uint32_t field_hashes[type->StructInfo.num_fields] = {};
|
||||
ptrdiff_t byte_offset = 0;
|
||||
ptrdiff_t bit_offset = 0;
|
||||
for (int i = 0; i < type->StructInfo.num_fields; i++) {
|
||||
NamedType_t field = type->StructInfo.fields[i];
|
||||
if (field.type == &Bool$info) {
|
||||
bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
|
||||
field_hashes[i] = (uint32_t)b;
|
||||
bit_offset += 1;
|
||||
if (bit_offset >= 8) {
|
||||
byte_offset += 1;
|
||||
bit_offset = 0;
|
||||
}
|
||||
} else {
|
||||
if (bit_offset > 0) {
|
||||
byte_offset += 1;
|
||||
bit_offset = 0;
|
||||
}
|
||||
if (field.type->align && byte_offset % field.type->align > 0)
|
||||
byte_offset += field.type->align - (byte_offset % field.type->align);
|
||||
field_hashes[i] = generic_hash(obj + byte_offset, field.type);
|
||||
byte_offset += field.type->size;
|
||||
}
|
||||
}
|
||||
return siphash24((void*)field_hashes, sizeof(field_hashes));
|
||||
}
|
||||
}
|
||||
case EnumInfo: {
|
||||
int32_t tag = *(int32_t*)obj;
|
||||
uint32_t components[2] = {(uint32_t)tag, 0};
|
||||
|
||||
const TypeInfo_t *value = type->EnumInfo.tags[tag-1].type;
|
||||
if (value && value->size > 0) {
|
||||
ptrdiff_t byte_offset = sizeof(int32_t);
|
||||
if (value->align && byte_offset % value->align > 0)
|
||||
byte_offset += value->align - (byte_offset % value->align);
|
||||
components[1] = generic_hash(obj + byte_offset, value);
|
||||
}
|
||||
return siphash24((void*)components, sizeof(components));
|
||||
|
||||
}
|
||||
case CustomInfo: case CStringInfo: // These all share the same info
|
||||
if (!type->CustomInfo.hash)
|
||||
goto hash_data;
|
||||
return type->CustomInfo.hash(obj, type);
|
||||
@ -52,8 +100,52 @@ PUREFUNC public int32_t generic_compare(const void *x, const void *y, const Type
|
||||
else if (x_is_null != y_is_null) return (int32_t)y_is_null - (int32_t)x_is_null;
|
||||
else return generic_compare(x, y, type->OptionalInfo.type);
|
||||
}
|
||||
case EmptyStructInfo: return 0;
|
||||
case CustomInfo: case StructInfo: case EnumInfo: case CStringInfo: // These all share the same info
|
||||
case StructInfo: {
|
||||
ptrdiff_t byte_offset = 0;
|
||||
ptrdiff_t bit_offset = 0;
|
||||
for (int i = 0; i < type->StructInfo.num_fields; i++) {
|
||||
NamedType_t field = type->StructInfo.fields[i];
|
||||
if (field.type == &Bool$info) {
|
||||
bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1;
|
||||
bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1;
|
||||
if (bx != by)
|
||||
return (int32_t)bx - (int32_t)by;
|
||||
bit_offset += 1;
|
||||
if (bit_offset >= 8) {
|
||||
byte_offset += 1;
|
||||
bit_offset = 0;
|
||||
}
|
||||
} else {
|
||||
if (bit_offset > 0) {
|
||||
byte_offset += 1;
|
||||
bit_offset = 0;
|
||||
}
|
||||
if (field.type->align && byte_offset % field.type->align > 0)
|
||||
byte_offset += field.type->align - (byte_offset % field.type->align);
|
||||
int32_t cmp = generic_compare(x + byte_offset, y + byte_offset, field.type);
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
byte_offset += field.type->size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case EnumInfo: {
|
||||
int32_t x_tag = *(int32_t*)x;
|
||||
int32_t y_tag = *(int32_t*)y;
|
||||
if (x_tag != y_tag)
|
||||
return x_tag > y_tag ? 1 : -1;
|
||||
|
||||
const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type;
|
||||
if (value && value->size > 0) {
|
||||
ptrdiff_t byte_offset = sizeof(int32_t);
|
||||
if (value->align && byte_offset % value->align > 0)
|
||||
byte_offset += value->align - (byte_offset % value->align);
|
||||
return generic_compare(x + byte_offset, y + byte_offset, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case CustomInfo: case CStringInfo: // These all share the same info
|
||||
if (!type->CustomInfo.compare)
|
||||
goto compare_data;
|
||||
return type->CustomInfo.compare(x, y, type);
|
||||
@ -73,7 +165,6 @@ PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_
|
||||
case ArrayInfo: return Array$equal(x, y, type);
|
||||
case ChannelInfo: return Channel$equal((Channel_t**)x, (Channel_t**)y, type);
|
||||
case TableInfo: return Table$equal(x, y, type);
|
||||
case EmptyStructInfo: return true;
|
||||
case OptionalInfo: {
|
||||
bool x_is_null = is_null(x, type->OptionalInfo.type);
|
||||
bool y_is_null = is_null(y, type->OptionalInfo.type);
|
||||
@ -81,7 +172,9 @@ PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_
|
||||
else if (x_is_null != y_is_null) return false;
|
||||
else return generic_equal(x, y, type->OptionalInfo.type);
|
||||
}
|
||||
case CustomInfo: case StructInfo: case EnumInfo: case CStringInfo: // These all share the same info
|
||||
case StructInfo: case EnumInfo:
|
||||
return (generic_compare(x, y, type) == 0);
|
||||
case CustomInfo: case CStringInfo: // These all share the same info
|
||||
if (!type->CustomInfo.equal)
|
||||
goto use_generic_compare;
|
||||
return type->CustomInfo.equal(x, y, type);
|
||||
@ -102,15 +195,64 @@ public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *
|
||||
case TableInfo: return Table$as_text(obj, colorize, type);
|
||||
case TypeInfoInfo: return Type$as_text(obj, colorize, type);
|
||||
case OptionalInfo: return Optional$as_text(obj, colorize, type);
|
||||
case EmptyStructInfo: return colorize ?
|
||||
Text$concat(Text("\x1b[0;1m"), Text$from_str(type->EmptyStructInfo.name), Text("\x1b[m()"))
|
||||
: Text$concat(Text$from_str(type->EmptyStructInfo.name), Text("()"));
|
||||
case CustomInfo: case StructInfo: case EnumInfo: case CStringInfo: // These all share the same info
|
||||
case StructInfo: {
|
||||
if (!obj) return Text$from_str(type->StructInfo.name);
|
||||
|
||||
if (type->StructInfo.is_secret)
|
||||
return Text$format(colorize ? "\x1b[0;1m%s\x1b[m(...)" : "%s(...)", type->StructInfo.name);
|
||||
|
||||
Text_t text = Text$format(colorize ? "\x1b[0;1m%s\x1b[m(" : "%s(", type->StructInfo.name);
|
||||
ptrdiff_t byte_offset = 0;
|
||||
ptrdiff_t bit_offset = 0;
|
||||
for (int i = 0; i < type->StructInfo.num_fields; i++) {
|
||||
NamedType_t field = type->StructInfo.fields[i];
|
||||
if (i > 0)
|
||||
text = Text$concat(text, Text(", "));
|
||||
|
||||
if (type->StructInfo.num_fields > 1)
|
||||
text = Text$concat(text, Text$from_str(field.name), Text("="));
|
||||
|
||||
if (field.type == &Bool$info) {
|
||||
bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
|
||||
text = Text$concat(text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no")));
|
||||
bit_offset += 1;
|
||||
if (bit_offset >= 8) {
|
||||
byte_offset += 1;
|
||||
bit_offset = 0;
|
||||
}
|
||||
} else {
|
||||
if (bit_offset > 0) {
|
||||
byte_offset += 1;
|
||||
bit_offset = 0;
|
||||
}
|
||||
if (field.type->align && byte_offset % field.type->align > 0)
|
||||
byte_offset += field.type->align - (byte_offset % field.type->align);
|
||||
text = Text$concat(text, generic_as_text(obj + byte_offset, colorize, field.type));
|
||||
byte_offset += field.type->size;
|
||||
}
|
||||
}
|
||||
return Text$concat(text, Text(")"));
|
||||
}
|
||||
case EnumInfo: {
|
||||
if (!obj) return Text$from_str(type->EnumInfo.name);
|
||||
|
||||
int32_t tag = *(int32_t*)obj;
|
||||
NamedType_t value = type->EnumInfo.tags[tag-1];
|
||||
if (!value.type || value.type->size == 0)
|
||||
return Text$format(colorize ? "\x1b[36;1m%s\x1b[m.\x1b[1m%s\x1b[m" : "%s.%s", type->EnumInfo.name, value.name);
|
||||
|
||||
ptrdiff_t byte_offset = sizeof(int32_t);
|
||||
if (value.type->align && byte_offset % value.type->align > 0)
|
||||
byte_offset += value.type->align - (byte_offset % value.type->align);
|
||||
return Text$concat(Text$format(colorize ? "\x1b[36;1m%s\x1b[m." : "%s.", type->EnumInfo.name),
|
||||
generic_as_text(obj + byte_offset, colorize, value.type));
|
||||
}
|
||||
case CustomInfo: case CStringInfo: // These all share the same info
|
||||
if (!type->CustomInfo.as_text)
|
||||
fail("No text function provided for type!\n");
|
||||
return type->CustomInfo.as_text(obj, colorize, type);
|
||||
case OpaqueInfo: return Text("???");
|
||||
default: errx(1, "Invalid type tag: %d", type->tag);
|
||||
default: fail("Invalid type tag: %d", type->tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ public Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo_t
|
||||
return Text$from_str(type->TypeInfoInfo.type_str);
|
||||
}
|
||||
|
||||
public const TypeInfo_t Void$info = {.size=0, .align=0, .tag=EmptyStructInfo};
|
||||
public const TypeInfo_t Abort$info = {.size=0, .align=0, .tag=EmptyStructInfo};
|
||||
public const TypeInfo_t Void$info = {.size=0, .align=0, .tag=StructInfo};
|
||||
public const TypeInfo_t Abort$info = {.size=0, .align=0, .tag=StructInfo};
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -7,18 +7,23 @@
|
||||
|
||||
#include "datatypes.h"
|
||||
|
||||
struct TypeInfo_t;
|
||||
typedef struct TypeInfo_s TypeInfo_t;
|
||||
|
||||
typedef uint64_t (*hash_fn_t)(const void*, const struct TypeInfo_t*);
|
||||
typedef int32_t (*compare_fn_t)(const void*, const void*, const struct TypeInfo_t*);
|
||||
typedef bool (*equal_fn_t)(const void*, const void*, const struct TypeInfo_t*);
|
||||
typedef Text_t (*text_fn_t)(const void*, bool, const struct TypeInfo_t*);
|
||||
typedef uint64_t (*hash_fn_t)(const void*, const TypeInfo_t*);
|
||||
typedef int32_t (*compare_fn_t)(const void*, const void*, const TypeInfo_t*);
|
||||
typedef bool (*equal_fn_t)(const void*, const void*, const TypeInfo_t*);
|
||||
typedef Text_t (*text_fn_t)(const void*, bool, const TypeInfo_t*);
|
||||
|
||||
typedef struct TypeInfo_t {
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const TypeInfo_t *type;
|
||||
} NamedType_t;
|
||||
|
||||
struct TypeInfo_s {
|
||||
int64_t size, align;
|
||||
struct { // Anonymous tagged union for convenience
|
||||
enum { CustomInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo,
|
||||
OptionalInfo, TypeInfoInfo, OpaqueInfo, EmptyStructInfo, CStringInfo } tag;
|
||||
enum { Invalid, CustomInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo,
|
||||
OptionalInfo, TypeInfoInfo, OpaqueInfo, CStringInfo } tag;
|
||||
union {
|
||||
struct {
|
||||
equal_fn_t equal;
|
||||
@ -28,16 +33,16 @@ typedef struct TypeInfo_t {
|
||||
} CustomInfo;
|
||||
struct {
|
||||
const char *sigil;
|
||||
const struct TypeInfo_t *pointed;
|
||||
const TypeInfo_t *pointed;
|
||||
} PointerInfo;
|
||||
struct {
|
||||
const char *lang;
|
||||
} TextInfo;
|
||||
struct {
|
||||
const struct TypeInfo_t *item;
|
||||
const TypeInfo_t *item;
|
||||
} ArrayInfo, ChannelInfo;
|
||||
struct {
|
||||
const struct TypeInfo_t *key, *value;
|
||||
const TypeInfo_t *key, *value;
|
||||
} TableInfo;
|
||||
struct {
|
||||
const char *type_str;
|
||||
@ -46,16 +51,24 @@ typedef struct TypeInfo_t {
|
||||
const char *type_str;
|
||||
} TypeInfoInfo;
|
||||
struct {
|
||||
const struct TypeInfo_t *type;
|
||||
const TypeInfo_t *type;
|
||||
} OptionalInfo;
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
struct {} OpaqueInfo;
|
||||
struct {
|
||||
const char *name;
|
||||
} EmptyStructInfo;
|
||||
int num_tags;
|
||||
NamedType_t *tags;
|
||||
} EnumInfo;
|
||||
struct {
|
||||
const char *name;
|
||||
int num_fields;
|
||||
bool is_secret:1;
|
||||
NamedType_t *fields;
|
||||
} StructInfo;
|
||||
};
|
||||
};
|
||||
} TypeInfo_t;
|
||||
};
|
||||
|
||||
#define Pointer$info(sigil_expr, pointed_info) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \
|
||||
.tag=PointerInfo, .PointerInfo={.sigil=sigil_expr, .pointed=pointed_info}})
|
||||
@ -73,7 +86,7 @@ typedef struct TypeInfo_t {
|
||||
.tag=FunctionInfo, .FunctionInfo.type_str=typestr})
|
||||
#define Type$info(typestr) &((TypeInfo_t){.size=sizeof(TypeInfo_t), .align=__alignof__(TypeInfo_t), \
|
||||
.tag=TypeInfoInfo, .TypeInfoInfo.type_str=typestr})
|
||||
#define Optional$info(t) &((TypeInfo_t){.size=(t)->size, .align=(t)->align, \
|
||||
#define Optional$info(_size, _align, t) &((TypeInfo_t){.size=_size, .align=_align, \
|
||||
.tag=OptionalInfo, .OptionalInfo.type=t})
|
||||
|
||||
extern const TypeInfo_t Void$info;
|
||||
|
163
structs.c
163
structs.c
@ -12,112 +12,6 @@
|
||||
#include "typecheck.h"
|
||||
#include "stdlib/util.h"
|
||||
|
||||
static CORD compile_str_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, StructDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
const char *name = def->name;
|
||||
const char *dollar = strrchr(name, '$');
|
||||
if (dollar) name = dollar + 1;
|
||||
CORD str_func = CORD_asprintf("static Text_t %r$as_text(%r_t *obj, bool use_color) {\n"
|
||||
"\tif (!obj) return Text(\"%s\");\n", full_name, full_name, name);
|
||||
if (def->secret) {
|
||||
CORD_appendf(&str_func, "\treturn use_color ? Text(\"\\x1b[0;1m%s\\x1b[m(\\x1b[2m...\\x1b[m)\") : Text(\"%s(...)\");\n}",
|
||||
name, name);
|
||||
} else if (def->fields && !def->fields->next) { // Single-member structs don't need to print names:
|
||||
type_t *field_type = get_arg_ast_type(env, def->fields);
|
||||
CORD field_str = expr_as_text(env, CORD_cat("obj->$", def->fields->name), field_type, "use_color");
|
||||
str_func = CORD_all(str_func, "\treturn Text$concat(use_color ? Text(\"\\x1b[0;1m", name, "\\x1b[m(\") : Text(\"", name, "(\"), ",
|
||||
field_str, ", Text(\")\"));\n}\n");
|
||||
} else {
|
||||
CORD_appendf(&str_func, "\treturn Text$concat(use_color ? Text(\"\\x1b[0;1m%s\\x1b[m(\") : Text(\"%s(\")", name, name);
|
||||
for (arg_ast_t *field = def->fields; field; field = field->next) {
|
||||
type_t *field_type = get_arg_ast_type(env, field);
|
||||
CORD field_str = expr_as_text(env, CORD_cat("obj->$", field->name), field_type, "use_color");
|
||||
CORD_appendf(&str_func, ", Text(\"%s=\"), %r", field->name, field_str);
|
||||
if (field->next) CORD_appendf(&str_func, ", Text(\", \")");
|
||||
}
|
||||
CORD_appendf(&str_func, ", Text(\")\"));\n}\n");
|
||||
}
|
||||
return str_func;
|
||||
}
|
||||
|
||||
static CORD compile_compare_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, StructDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
CORD cmp_func = CORD_all("static int ", full_name, "$compare(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n",
|
||||
"int diff;\n");
|
||||
for (arg_ast_t *field = def->fields; field; field = field->next) {
|
||||
type_t *field_type = get_arg_ast_type(env, field);
|
||||
switch (field_type->tag) {
|
||||
case BigIntType:
|
||||
cmp_func = CORD_all(cmp_func, "diff = Int$compare_value(x->$", field->name, ", y->$", field->name, ");");
|
||||
break;
|
||||
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
|
||||
cmp_func = CORD_all(cmp_func, "diff = (x->$", field->name, " > y->$", field->name, ") - (x->$", field->name, " < y->$", field->name, ");");
|
||||
break;
|
||||
default:
|
||||
cmp_func = CORD_all(cmp_func, "diff = generic_compare(&x->$", field->name, ", &y->$", field->name, ", ",
|
||||
compile_type_info(env, field_type), ");\n");
|
||||
break;
|
||||
}
|
||||
cmp_func = CORD_all(cmp_func, "if (diff != 0) return diff;\n");
|
||||
}
|
||||
cmp_func = CORD_all(cmp_func, "return 0;\n}\n");
|
||||
return cmp_func;
|
||||
}
|
||||
|
||||
static CORD compile_equals_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, StructDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
CORD eq_func = CORD_all("static bool ", full_name, "$equal(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n");
|
||||
CORD condition = CORD_EMPTY;
|
||||
for (arg_ast_t *field = def->fields; field; field = field->next) {
|
||||
if (condition != CORD_EMPTY)
|
||||
condition = CORD_all(condition, " && ");
|
||||
type_t *field_type = get_arg_ast_type(env, field);
|
||||
switch (field_type->tag) {
|
||||
case BigIntType:
|
||||
condition = CORD_all(condition, "Int$equal_value(x->$", field->name, ", y->$", field->name, ")");
|
||||
break;
|
||||
case BoolType: case IntType: case NumType: case PointerType: case FunctionType:
|
||||
condition = CORD_all(condition, "(x->$", field->name, " == y->$", field->name, ")");
|
||||
break;
|
||||
default:
|
||||
condition = CORD_all(condition, "generic_equal(&x->$", field->name, ", &y->$", field->name, ", ",
|
||||
compile_type_info(env, field_type), ")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
eq_func = CORD_all(eq_func, "return ", condition, ";\n}\n");
|
||||
return eq_func;
|
||||
}
|
||||
|
||||
static CORD compile_hash_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, StructDef);
|
||||
CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
|
||||
CORD hash_func = CORD_all("static uint64_t ", full_name, "$hash(const ", full_name, "_t *obj, const TypeInfo_t *info) {\n"
|
||||
"(void)info;\n"
|
||||
"uint64_t field_hashes[] = {");
|
||||
for (arg_ast_t *field = def->fields; field; field = field->next) {
|
||||
type_t *field_type = get_arg_ast_type(env, field);
|
||||
if (field_type->tag == BoolType) // Bools can be bit fields, so you can't use *obj->field there:
|
||||
hash_func = CORD_all(hash_func, "\n(uint32_t)(obj->$", field->name, "),");
|
||||
else
|
||||
hash_func = CORD_all(hash_func, "\ngeneric_hash(&obj->$", field->name, ", ", compile_type_info(env, field_type), "),");
|
||||
}
|
||||
hash_func = CORD_all(hash_func, "};\n"
|
||||
"return siphash24((void*)&field_hashes, sizeof(field_hashes));\n}\n");
|
||||
return hash_func;
|
||||
}
|
||||
|
||||
void compile_struct_def(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, StructDef);
|
||||
@ -125,48 +19,25 @@ void compile_struct_def(env_t *env, ast_t *ast)
|
||||
|
||||
type_t *t = Table$str_get(*env->types, def->name);
|
||||
assert(t && t->tag == StructType);
|
||||
auto struct_ = Match(t, StructType);
|
||||
if (def->fields) {
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {%zu, %zu, {.tag=StructInfo, .CustomInfo={",
|
||||
full_name, type_size(t), type_align(t));
|
||||
int num_fields = 0;
|
||||
for (arg_ast_t *f = def->fields; f; f = f->next)
|
||||
num_fields += 1;
|
||||
const char *short_name = def->name;
|
||||
if (strchr(short_name, '$'))
|
||||
short_name = strrchr(short_name, '$') + 1;
|
||||
|
||||
typeinfo = CORD_all(typeinfo, ".as_text=(void*)", full_name, "$as_text, ");
|
||||
env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast));
|
||||
|
||||
if (struct_->fields && !struct_->fields->next) { // Single member, can just use its methods
|
||||
type_t *member_t = struct_->fields->type;
|
||||
switch (member_t->tag) {
|
||||
case IntType: case NumType:
|
||||
typeinfo = CORD_all(typeinfo, ".compare=(void*)", type_to_cord(member_t), "$compare, "
|
||||
".equal=(void*)", type_to_cord(member_t), "$equal, ");
|
||||
goto got_methods;
|
||||
case BigIntType: case TextType:
|
||||
typeinfo = CORD_all(typeinfo, ".hash=(void*)", type_to_cord(member_t), "$hash", ", ",
|
||||
".compare=(void*)", type_to_cord(member_t), "$compare, "
|
||||
".equal=(void*)", type_to_cord(member_t), "$equal, ");
|
||||
goto got_methods;
|
||||
case BoolType: goto got_methods;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (struct_->fields) {
|
||||
env->code->funcs = CORD_all(env->code->funcs, compile_compare_method(env, ast),
|
||||
compile_equals_method(env, ast), compile_hash_method(env, ast));
|
||||
typeinfo = CORD_all(
|
||||
typeinfo,
|
||||
".compare=(void*)", full_name, "$compare, "
|
||||
".equal=(void*)", full_name, "$equal, "
|
||||
".hash=(void*)", full_name, "$hash");
|
||||
}
|
||||
got_methods:;
|
||||
typeinfo = CORD_cat(typeinfo, "}}};\n");
|
||||
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
|
||||
} else {
|
||||
// If there are no fields, we can use an EmptyStructInfo typeinfo, which generates less code:
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {%zu, %zu, {.tag=EmptyStructInfo, .EmptyStructInfo.name=%r}};\n",
|
||||
full_name, type_size(t), type_align(t), CORD_quoted(def->name));
|
||||
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
|
||||
env->code->typeinfos = CORD_all("public const TypeInfo_t ", full_name, ";\n", env->code->typeinfos);
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {%zu, %zu, .tag=StructInfo, .StructInfo.name=\"%s\"%s, "
|
||||
".StructInfo.num_fields=%ld, .StructInfo.fields=(NamedType_t[%d]){",
|
||||
full_name, type_size(t), type_align(t), short_name, def->secret ? ", .StructInfo.is_secret=true" : "",
|
||||
num_fields, num_fields);
|
||||
for (arg_ast_t *f = def->fields; f; f = f->next) {
|
||||
type_t *field_type = get_arg_ast_type(env, f);
|
||||
typeinfo = CORD_all(typeinfo, "{\"", f->name, "\", ", compile_type_info(env, field_type), "}");
|
||||
if (f->next) typeinfo = CORD_all(typeinfo, ", ");
|
||||
}
|
||||
typeinfo = CORD_all(typeinfo, "}};\n");
|
||||
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
|
||||
|
||||
compile_namespace(env, def->name, def->namespace);
|
||||
}
|
||||
|
4
types.c
4
types.c
@ -431,7 +431,7 @@ PUREFUNC size_t type_size(type_t *t)
|
||||
type_t *nonnull = Match(t, OptionalType)->type;
|
||||
switch (nonnull->tag) {
|
||||
case IntType:
|
||||
switch (Match(t, IntType)->bits) {
|
||||
switch (Match(nonnull, IntType)->bits) {
|
||||
case TYPE_IBITS64: return sizeof(OptionalInt64_t);
|
||||
case TYPE_IBITS32: return sizeof(OptionalInt32_t);
|
||||
case TYPE_IBITS16: return sizeof(OptionalInt16_t);
|
||||
@ -511,7 +511,7 @@ PUREFUNC size_t type_align(type_t *t)
|
||||
type_t *nonnull = Match(t, OptionalType)->type;
|
||||
switch (nonnull->tag) {
|
||||
case IntType:
|
||||
switch (Match(t, IntType)->bits) {
|
||||
switch (Match(nonnull, IntType)->bits) {
|
||||
case TYPE_IBITS64: return __alignof__(OptionalInt64_t);
|
||||
case TYPE_IBITS32: return __alignof__(OptionalInt32_t);
|
||||
case TYPE_IBITS16: return __alignof__(OptionalInt16_t);
|
||||
|
Loading…
Reference in New Issue
Block a user