Fixing up enums
This commit is contained in:
parent
d2aeee16e6
commit
f9cc44f145
@ -44,6 +44,17 @@ typedef struct TypeInfo {
|
||||
};
|
||||
} TypeInfo;
|
||||
|
||||
#define $PointerInfo(sigil_expr, pointed_info) &((TypeInfo){.size=sizeof(void*), .align=__alignof__(void*), \
|
||||
.tag=PointerInfo, .PointerInfo.sigil=sigil_expr, .PointerInfo.pointed=pointed_info})
|
||||
#define $ArrayInfo(item_info) &((TypeInfo){.size=sizeof(array_t), .align=__alignof__(array_t), \
|
||||
.tag=ArrayInfo, .ArrayInfo.item=item_info})
|
||||
#define $TableInfo(key_expr, value_expr) &((TypeInfo){.size=sizeof(table_t), .align=__alignof__(table_t), \
|
||||
.tag=TableInfo, .TableInfo.key=key_expr, .TableInfo.value=value_expr})
|
||||
#define $FunctionInfo(typestr) &((TypeInfo){.size=sizeof(void*), .align=__alignof__(void*), \
|
||||
.tag=FunctionInfo, .FunctionInfo.type_str=typestr})
|
||||
#define $TypeInfoInfo(typestr) &((TypeInfo){.size=sizeof(TypeInfo), .align=__alignof__(TypeInfo), \
|
||||
.tag=TypeInfoInfo, .TypeInfoInfo.type_str=typestr})
|
||||
|
||||
typedef struct {
|
||||
TypeInfo type;
|
||||
} TypeInfo_namespace_t;
|
||||
|
113
compile.c
113
compile.c
@ -90,7 +90,7 @@ CORD compile_string(env_t *env, ast_t *ast, CORD color)
|
||||
return expr_as_string(env, expr, t, color);
|
||||
}
|
||||
|
||||
static CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth)
|
||||
static CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool allow_optional)
|
||||
{
|
||||
CORD val = compile(env, ast);
|
||||
type_t *t = get_type(env, ast);
|
||||
@ -115,6 +115,15 @@ static CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_dept
|
||||
--depth;
|
||||
}
|
||||
}
|
||||
if (!allow_optional) {
|
||||
while (t->tag == PointerType) {
|
||||
auto ptr = Match(t, PointerType);
|
||||
if (ptr->is_optional)
|
||||
code_err(ast, "You can't dereference this value, since it's not guaranteed to be non-null");
|
||||
t = ptr->pointed;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -136,24 +145,24 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
type_t *t = get_type(env, expr);
|
||||
switch (value_type(t)->tag) {
|
||||
case StringType: {
|
||||
CORD str = compile_to_pointer_depth(env, expr, 0);
|
||||
CORD str = compile_to_pointer_depth(env, expr, 0, false);
|
||||
return CORD_all("CORD_len(", str, ")");
|
||||
}
|
||||
case ArrayType: {
|
||||
if (t->tag == PointerType) {
|
||||
CORD arr = compile_to_pointer_depth(env, expr, 1);
|
||||
CORD arr = compile_to_pointer_depth(env, expr, 1, false);
|
||||
return CORD_all("I64((", arr, ")->length)");
|
||||
} else {
|
||||
CORD arr = compile_to_pointer_depth(env, expr, 0);
|
||||
CORD arr = compile_to_pointer_depth(env, expr, 0, false);
|
||||
return CORD_all("I64((", arr, ").length)");
|
||||
}
|
||||
}
|
||||
case TableType: {
|
||||
if (t->tag == PointerType) {
|
||||
CORD table = compile_to_pointer_depth(env, expr, 1);
|
||||
CORD table = compile_to_pointer_depth(env, expr, 1, false);
|
||||
return CORD_all("I64((", table, ")->entries.length)");
|
||||
} else {
|
||||
CORD table = compile_to_pointer_depth(env, expr, 0);
|
||||
CORD table = compile_to_pointer_depth(env, expr, 0, false);
|
||||
return CORD_all("I64((", table, ").entries.length)");
|
||||
}
|
||||
}
|
||||
@ -649,29 +658,28 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
case EnumDef: {
|
||||
auto def = Match(ast, EnumDef);
|
||||
CORD_appendf(&env->code->typedefs, "typedef struct %s_s %s_t;\n", def->name, def->name);
|
||||
CORD_appendf(&env->code->typecode, "struct %s_s {\nenum {", def->name);
|
||||
CORD enum_def = CORD_all("struct ", def->name, "_s {\n"
|
||||
"\tenum {");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
CORD_appendf(&env->code->typecode, "%s$%s = %ld, ", def->name, tag->name, tag->value);
|
||||
CORD_appendf(&enum_def, "$tag$%s$%s = %ld", def->name, tag->name, tag->value);
|
||||
if (tag->next) enum_def = CORD_cat(enum_def, ", ");
|
||||
}
|
||||
env->code->typecode = CORD_cat(env->code->typecode, "} $tag;\nunion {\n");
|
||||
enum_def = CORD_cat(enum_def, "} $tag;\n"
|
||||
"union {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
env->code->typecode = CORD_cat(env->code->typecode, "struct {\n");
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
CORD type = compile_type_ast(field->type);
|
||||
CORD_appendf(&env->code->typecode, "%r %s%s;\n", type, field->name,
|
||||
CORD_cmp(type, "Bool_t") ? "" : ":1");
|
||||
}
|
||||
CORD_appendf(&env->code->typecode, "} %s;\n", tag->name);
|
||||
CORD_appendf(&env->code->typedefs, "#define %s__%s(...) ((%s_t){%s$%s, .%s={__VA_ARGS__}})\n",
|
||||
(void)compile(env, WrapAST(ast, StructDef, .name=heap_strf("%s$%s", def->name, tag->name), .fields=tag->fields));
|
||||
enum_def = CORD_all(enum_def, def->name, "$", tag->name, "_t ", tag->name, ";\n");
|
||||
CORD_appendf(&env->code->typedefs, "#define %s__%s(...) ((%s_t){$tag$%s$%s, .%s={__VA_ARGS__}})\n",
|
||||
def->name, tag->name, def->name, def->name, tag->name, tag->name);
|
||||
}
|
||||
env->code->typecode = CORD_cat(env->code->typecode, "};\n};\n");
|
||||
enum_def = CORD_cat(enum_def, "};\n};\n");
|
||||
env->code->typecode = CORD_cat(env->code->typecode, enum_def);
|
||||
|
||||
CORD cord_func = CORD_all("static CORD ", def->name, "__as_str(", def->name, "_t *obj, bool use_color) {\n",
|
||||
"\tif (!obj) return \"", def->name, "\";\n",
|
||||
"\tswitch (obj->$tag) {\n");
|
||||
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
|
||||
cord_func = CORD_all(cord_func, "\tcase ", def->name, "$", tag->name, ": return CORD_all(use_color ? \"\\x1b[36;1m",
|
||||
cord_func = CORD_all(cord_func, "\tcase $tag$", def->name, "$", tag->name, ": return CORD_all(use_color ? \"\\x1b[36;1m",
|
||||
def->name, ".", tag->name, "\\x1b[m(\" : \"", def->name, ".", tag->name, "(\"");
|
||||
|
||||
for (arg_ast_t *field = tag->fields; field; field = field->next) {
|
||||
@ -733,14 +741,18 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
return CORD_cat(code, "\n}");
|
||||
} else if (expr_t->tag == VoidType || expr_t->tag == AbortType) {
|
||||
return CORD_asprintf(
|
||||
"__doctest((%r, NULL), NULL, NULL, %r, %ld, %ld);",
|
||||
"%r;\n"
|
||||
"__doctest(NULL, NULL, NULL, %r, %ld, %ld);",
|
||||
compile(env, test->expr),
|
||||
compile(env, WrapAST(test->expr, StringLiteral, .cord=test->expr->file->filename)),
|
||||
(int64_t)(test->expr->start - test->expr->file->text),
|
||||
(int64_t)(test->expr->end - test->expr->file->text));
|
||||
} else {
|
||||
return CORD_asprintf(
|
||||
"__doctest($stack(%r), %r, %r, %r, %ld, %ld);",
|
||||
"{\n%r $expr = %r;\n"
|
||||
"__doctest(&$expr, %r, %r, %r, %ld, %ld);\n"
|
||||
"}",
|
||||
compile_type(expr_t),
|
||||
compile(env, test->expr),
|
||||
compile_type_info(env, expr_t),
|
||||
compile(env, WrapAST(test->expr, StringLiteral, .cord=test->output)),
|
||||
@ -752,13 +764,35 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
case FieldAccess: {
|
||||
auto f = Match(ast, FieldAccess);
|
||||
type_t *fielded_t = get_type(env, f->fielded);
|
||||
CORD fielded = compile(env, f->fielded);
|
||||
while (fielded_t->tag == PointerType) {
|
||||
if (Match(fielded_t, PointerType)->is_optional)
|
||||
code_err(ast, "You can't dereference this value, since it's not guaranteed to be non-null");
|
||||
fielded = CORD_all("*(", fielded, ")");
|
||||
type_t *value_t = value_type(fielded_t);
|
||||
switch (value_t->tag) {
|
||||
case StructType: {
|
||||
for (arg_t *field = Match(value_t, StructType)->fields; field; field = field->next) {
|
||||
if (streq(field->name, f->field)) {
|
||||
if (fielded_t->tag == PointerType) {
|
||||
CORD fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
|
||||
return CORD_asprintf("(%r)->%s", fielded, f->field);
|
||||
} else {
|
||||
CORD fielded = compile(env, f->fielded);
|
||||
return CORD_asprintf("(%r).%s", fielded, f->field);
|
||||
}
|
||||
}
|
||||
}
|
||||
code_err(ast, "The field '%s' is not a valid field name of %T", f->field, value_t);
|
||||
}
|
||||
case EnumType: {
|
||||
auto enum_ = Match(value_t, EnumType);
|
||||
for (tag_t *tag = enum_->tags; tag; tag = tag->next) {
|
||||
if (streq(tag->name, f->field)) {
|
||||
CORD fielded = compile_to_pointer_depth(env, f->fielded, 0, false);
|
||||
return CORD_asprintf("$tagged(%r, %s, %s)", fielded, enum_->name, f->field);
|
||||
}
|
||||
}
|
||||
code_err(ast, "The field '%s' is not a valid field name of %T", f->field, value_t);
|
||||
}
|
||||
default:
|
||||
code_err(ast, "Field accesses are only supported on struct and enum values");
|
||||
}
|
||||
return CORD_asprintf("(%r).%s", fielded, f->field);
|
||||
}
|
||||
case Index: {
|
||||
auto indexing = Match(ast, Index);
|
||||
@ -769,7 +803,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
if (index_t->tag != IntType)
|
||||
code_err(indexing->index, "Arrays can only be indexed by integers, not %T", index_t);
|
||||
type_t *item_type = Match(container_t, ArrayType)->item_type;
|
||||
CORD arr = compile_to_pointer_depth(env, indexing->indexed, 1);
|
||||
CORD arr = compile_to_pointer_depth(env, indexing->indexed, 1, false);
|
||||
CORD index = compile(env, indexing->index);
|
||||
file_t *f = indexing->index->file;
|
||||
if (indexing->unchecked)
|
||||
@ -785,7 +819,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
type_t *value_t = Match(container_t, TableType)->value_type;
|
||||
if (!can_promote(index_t, key_t))
|
||||
code_err(indexing->index, "This value has type %T, but this table can only be index with keys of type %T", index_t, key_t);
|
||||
CORD table = compile_to_pointer_depth(env, indexing->indexed, 1);
|
||||
CORD table = compile_to_pointer_depth(env, indexing->indexed, 1, false);
|
||||
CORD key = compile(env, indexing->index);
|
||||
file_t *f = indexing->index->file;
|
||||
return CORD_all("$Table_get(", table, ", ", compile_type(key_t), ", ", compile_type(value_t), ", ",
|
||||
@ -797,8 +831,6 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
default: code_err(ast, "Indexing is not supported for type: %T", container_t);
|
||||
}
|
||||
}
|
||||
// Index
|
||||
// DocTest,
|
||||
// Use,
|
||||
// LinkerDirective,
|
||||
case Unknown: code_err(ast, "Unknown AST");
|
||||
@ -818,32 +850,21 @@ CORD compile_type_info(env_t *env, type_t *t)
|
||||
case EnumType: return CORD_all("&", Match(t, EnumType)->name, ".type");
|
||||
case ArrayType: {
|
||||
type_t *item_t = Match(t, ArrayType)->item_type;
|
||||
return CORD_asprintf(
|
||||
"&((TypeInfo){.size=%zu, .align=%zu, .tag=ArrayInfo, .ArrayInfo.item=%r})",
|
||||
sizeof(array_t), __alignof__(array_t),
|
||||
compile_type_info(env, item_t));
|
||||
return CORD_asprintf("$ArrayInfo(%r)", compile_type_info(env, item_t));
|
||||
}
|
||||
case TableType: {
|
||||
type_t *key_type = Match(t, TableType)->key_type;
|
||||
type_t *value_type = Match(t, TableType)->value_type;
|
||||
return CORD_asprintf(
|
||||
"&((TypeInfo){.size=%zu, .align=%zu, .tag=TableInfo, .TableInfo.key=%r, .TableInfo.value=%r})",
|
||||
sizeof(table_t), __alignof__(table_t),
|
||||
compile_type_info(env, key_type),
|
||||
compile_type_info(env, value_type));
|
||||
return CORD_asprintf("$TableInfo(%r, %r)", compile_type_info(env, key_type), compile_type_info(env, value_type));
|
||||
}
|
||||
case PointerType: {
|
||||
auto ptr = Match(t, PointerType);
|
||||
CORD sigil = ptr->is_stack ? "&" : (ptr->is_optional ? "?" : "@");
|
||||
if (ptr->is_readonly) sigil = CORD_cat(sigil, "(readonly)");
|
||||
return CORD_asprintf(
|
||||
"&((TypeInfo){.size=%zu, .align=%zu, .tag=PointerInfo, .PointerInfo.sigil=\"%r\", .PointerInfo.pointed=%r})",
|
||||
sizeof(void*), __alignof__(void*),
|
||||
sigil, compile_type_info(env, ptr->pointed));
|
||||
return CORD_asprintf("$PointerInfo(%r, %r)", Str__quoted(sigil, false), compile_type_info(env, ptr->pointed));
|
||||
}
|
||||
case FunctionType: {
|
||||
return CORD_asprintf("((TypeInfo){.size=%zu, .align=%zu, .tag=FunctionInfo, .FunctionInfo.type_str=\"%r\"})",
|
||||
sizeof(void*), __alignof__(void*), type_to_cord(t));
|
||||
return CORD_asprintf("$FunctionInfo(%r)", Str__quoted(type_to_cord(t), false));
|
||||
}
|
||||
case ClosureType: {
|
||||
errx(1, "No typeinfo for closures yet");
|
||||
|
@ -40,7 +40,9 @@ env_t *new_compilation_unit(void)
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(global_vars)/sizeof(global_vars[0]); i++) {
|
||||
Table_str_set(env->globals, global_vars[i].name, &global_vars[i].binding);
|
||||
binding_t *b = new(binding_t);
|
||||
*b = global_vars[i].binding;
|
||||
Table_str_set(env->globals, global_vars[i].name, b);
|
||||
}
|
||||
|
||||
struct {
|
||||
|
@ -40,6 +40,9 @@ CORD as_cord(void *x, bool use_color, const char *fmt, ...);
|
||||
default: "???")
|
||||
#define $heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x))
|
||||
#define $stack(x) (__typeof(x)*)((__typeof(x)[1]){x})
|
||||
#define $tagged(obj_expr, type_name, tag_name) ({ __typeof(obj_expr) $obj = obj_expr; \
|
||||
$obj.$tag == $tag$##type_name##$##tag_name ? &$obj.tag_name : NULL; })
|
||||
|
||||
|
||||
#define not(x) _Generic(x, bool: (bool)!(x), default: ~(x))
|
||||
#define and(x, y) _Generic(x, bool: (bool)((x) && (y)), default: ((x) & (y)))
|
||||
|
@ -287,7 +287,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
type_t *fielded_t = get_type(env, access->fielded);
|
||||
type_t *field_t = get_field_type(fielded_t, access->field);
|
||||
if (!field_t)
|
||||
code_err(ast, "I can't find anything called %s on the type %T", access->field, fielded_t);
|
||||
code_err(ast, "%T objects don't have a field called '%s'", fielded_t, access->field);
|
||||
return field_t;
|
||||
}
|
||||
case Index: {
|
||||
@ -329,6 +329,10 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
if (call->extern_return_type)
|
||||
return parse_type_ast(env, call->extern_return_type);
|
||||
type_t *fn_type_t = get_type(env, call->fn);
|
||||
if (!fn_type_t)
|
||||
code_err(call->fn, "I couldn't find this function");
|
||||
if (fn_type_t->tag != FunctionType)
|
||||
code_err(call->fn, "This isn't a function, it's a %T", fn_type_t);
|
||||
auto fn_type = Match(fn_type_t, FunctionType);
|
||||
return fn_type->ret;
|
||||
}
|
||||
|
2
types.c
2
types.c
@ -486,7 +486,7 @@ type_t *get_field_type(type_t *t, const char *field_name)
|
||||
auto e = Match(t, EnumType);
|
||||
for (tag_t *tag = e->tags; tag; tag = tag->next) {
|
||||
if (streq(field_name, tag->name))
|
||||
return tag->type;
|
||||
return Type(PointerType, .pointed=tag->type, .is_optional=true, .is_readonly=true);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user