diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-05-25 16:41:43 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-05-25 16:41:43 -0400 |
| commit | b2033f6d6d8918ed9ac72468aaa5faf96f8157dd (patch) | |
| tree | 94d8697b8d664d716feeaa3831fa494c1eedcb6f /src | |
| parent | f2f43f2e239890847c2f1833ad2e7baf07108145 (diff) | |
Optimize codegen for enums: no longer bother with a struct wrapper, but
just use a C enum type instead. This will make it easier to use
externally defined enums in the future.
Diffstat (limited to 'src')
| -rw-r--r-- | src/compile.c | 54 | ||||
| -rw-r--r-- | src/enums.c | 41 | ||||
| -rw-r--r-- | src/structs.c | 2 | ||||
| -rw-r--r-- | src/typecheck.c | 7 | ||||
| -rw-r--r-- | src/types.c | 9 | ||||
| -rw-r--r-- | src/types.h | 1 |
6 files changed, 80 insertions, 34 deletions
diff --git a/src/compile.c b/src/compile.c index ebd7b6ba..8671592e 100644 --- a/src/compile.c +++ b/src/compile.c @@ -1004,8 +1004,12 @@ CORD check_none(type_t *t, CORD value) return CORD_all("({(", value, ").length < 0;})"); else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType) return CORD_all("(", value, ").is_none"); - else if (t->tag == EnumType) - return CORD_all("({(", value, ").$tag == 0;})"); + else if (t->tag == EnumType) { + if (enum_has_fields(t)) + return CORD_all("({(", value, ").$tag == 0;})"); + else + return CORD_all("((", value, ") == 0)"); + } print_err("Optional check not implemented for: ", type_to_str(t)); return CORD_EMPTY; } @@ -1066,7 +1070,13 @@ static CORD _compile_statement(env_t *env, ast_t *ast) } DeclareMatch(enum_t, subject_t, EnumType); - CORD code = CORD_all("WHEN(", compile_type(subject_t), ", ", compile(env, when->subject), ", _when_subject, {\n"); + + CORD code; + if (enum_has_fields(subject_t)) + code = CORD_all("WHEN(", compile_type(subject_t), ", ", compile(env, when->subject), ", _when_subject, {\n"); + else + code = CORD_all("switch(", compile(env, when->subject), ") {\n"); + for (when_clause_t *clause = when->clauses; clause; clause = clause->next) { if (clause->pattern->tag == Var) { const char *clause_tag_name = Match(clause->pattern, Var)->name; @@ -1148,7 +1158,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) } else { code = CORD_all(code, "default: errx(1, \"Invalid tag!\");\n"); } - code = CORD_all(code, "\n})\n"); + code = CORD_all(code, "\n}", enum_has_fields(subject_t) ? ")" : CORD_EMPTY, "\n"); return code; } case DocTest: { @@ -2669,8 +2679,10 @@ CORD compile_empty(type_t *t) assert(tag->type); if (Match(tag->type, StructType)->fields) return CORD_all("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=", compile_empty(tag->type), "})"); - else + else if (enum_has_fields(t)) return CORD_all("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})"); + else + return CORD_all("((", compile_type(t), ")", String(tag->tag_value), ")"); } default: return CORD_EMPTY; } @@ -3825,9 +3837,12 @@ CORD compile(env_t *env, ast_t *ast) if (fielded_t->tag == PointerType) { CORD fielded = compile_to_pointer_depth(env, f->fielded, 1, false); return CORD_all("((", fielded, ")->$tag == ", tag_name, ")"); - } else { + } else if (enum_has_fields(value_t)) { CORD fielded = compile(env, f->fielded); return CORD_all("((", fielded, ").$tag == ", tag_name, ")"); + } else { + CORD fielded = compile(env, f->fielded); + return CORD_all("((", fielded, ") == ", tag_name, ")"); } } } @@ -4708,15 +4723,26 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) *info->header = CORD_all(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n"); } else if (ast->tag == EnumDef) { DeclareMatch(def, ast, EnumDef); - CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct")); - CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")); - *info->header = CORD_all(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n"); - + bool has_any_tags_with_fields = false; for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { - if (!tag->fields) continue; - CORD tag_struct = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$struct")); - CORD tag_type = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$type")); - *info->header = CORD_all(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n"); + has_any_tags_with_fields = has_any_tags_with_fields || (tag->fields != NULL); + } + + if (has_any_tags_with_fields) { + CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct")); + CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")); + *info->header = CORD_all(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n"); + + for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { + if (!tag->fields) continue; + CORD tag_struct = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$struct")); + CORD tag_type = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$type")); + *info->header = CORD_all(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n"); + } + } else { + CORD enum_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$enum")); + CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")); + *info->header = CORD_all(*info->header, "typedef enum ", enum_name, " ", type_name, ";\n"); } } else if (ast->tag == LangDef) { DeclareMatch(def, ast, LangDef); diff --git a/src/enums.c b/src/enums.c index e391086e..2ff64ad3 100644 --- a/src/enums.c +++ b/src/enums.c @@ -86,32 +86,37 @@ CORD compile_enum_header(env_t *env, ast_t *ast) { DeclareMatch(def, ast, EnumDef); CORD all_defs = CORD_EMPTY; - CORD struct_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$struct")); CORD none_name = namespace_name(env, env->namespace, CORD_all(def->name, "$none")); - CORD enum_def = CORD_all("struct ", struct_name, " {\n" - "\tenum { ", none_name, "=0, "); + CORD enum_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$enum")); + CORD enum_tags = CORD_all("{ ", none_name, "=0, "); bool has_any_tags_with_fields = false; for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { CORD tag_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)); - enum_def = CORD_all(enum_def, tag_name); - if (tag->next) enum_def = CORD_all(enum_def, ", "); + enum_tags = CORD_all(enum_tags, tag_name); + if (tag->next) enum_tags = CORD_all(enum_tags, ", "); has_any_tags_with_fields = has_any_tags_with_fields || (tag->fields != NULL); } - 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); - CORD tag_type = namespace_name(env, env->namespace, CORD_all(def->name, "$", tag->name, "$$type")); - enum_def = CORD_all(enum_def, tag_type, " ", tag->name, ";\n"); - } - enum_def = CORD_all(enum_def, "};\n"); + enum_tags = CORD_all(enum_tags, " }"); + + if (!has_any_tags_with_fields) { + CORD enum_def = CORD_all("enum ", enum_name, " ", enum_tags, ";\n"); + CORD info = namespace_name(env, env->namespace, CORD_all(def->name, "$$info")); + return CORD_all(enum_def, "extern const TypeInfo_t ", info, ";\n"); + } + + CORD struct_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$struct")); + CORD enum_def = CORD_all("struct ", struct_name, " {\n" + "enum ", enum_tags, " $tag;\n" + "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); + CORD tag_type = namespace_name(env, env->namespace, CORD_all(def->name, "$", tag->name, "$$type")); + enum_def = CORD_all(enum_def, tag_type, " ", tag->name, ";\n"); } - enum_def = CORD_all(enum_def, "};\n"); + enum_def = CORD_all(enum_def, "};\n};\n"); all_defs = CORD_all(all_defs, enum_def); CORD info = namespace_name(env, env->namespace, CORD_all(def->name, "$$info")); diff --git a/src/structs.c b/src/structs.c index b398b871..88de7aac 100644 --- a/src/structs.c +++ b/src/structs.c @@ -69,7 +69,7 @@ CORD compile_struct_header(env_t *env, ast_t *ast) CORD typeinfo_code = CORD_all("extern const TypeInfo_t ", typeinfo_name, ";\n"); CORD optional_code = CORD_EMPTY; if (!def->opaque) { - optional_code = CORD_all("DEFINE_OPTIONAL_TYPE(", compile_type(t), ", ", unpadded_size, ",", + optional_code = CORD_all("DEFINE_OPTIONAL_TYPE(", compile_type(t), ", ", unpadded_size, ", ", namespace_name(env, env->namespace, CORD_all("$Optional", def->name, "$$type")), ");\n"); } return CORD_all(struct_code, optional_code, typeinfo_code); diff --git a/src/typecheck.c b/src/typecheck.c index b98cb84b..6fdfb1d8 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -397,7 +397,9 @@ void bind_statement(env_t *env, ast_t *statement) assert(type); tag_t *tags = NULL; int64_t next_tag = 1; + bool has_any_tags_with_fields = false; for (tag_ast_t *tag_ast = def->tags; tag_ast; tag_ast = tag_ast->next) { + has_any_tags_with_fields = has_any_tags_with_fields || tag_ast->fields; arg_t *fields = NULL; for (arg_ast_t *field_ast = tag_ast->fields; field_ast; field_ast = field_ast->next) { type_t *field_t = get_arg_ast_type(env, field_ast); @@ -437,10 +439,13 @@ void bind_statement(env_t *env, ast_t *statement) if (Match(tag->type, StructType)->fields) { // Constructor: type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type); set_binding(ns_env, tag->name, constructor_t, namespace_name(env, env->namespace, CORD_all(def->name, "$tagged$", tag->name))); - } else { // Empty singleton value: + } else if (has_any_tags_with_fields) { // Empty singleton value: CORD code = CORD_all("((", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), "){", namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)), "})"); set_binding(ns_env, tag->name, type, code); + } else { + CORD code = namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)); + set_binding(ns_env, tag->name, type, code); } Table$str_set(env->types, String(def->name, "$", tag->name), tag->type); } diff --git a/src/types.c b/src/types.c index 91848bef..1a2405d4 100644 --- a/src/types.c +++ b/src/types.c @@ -836,4 +836,13 @@ type_t *_make_function_type(type_t *ret, int n, arg_t args[n]) return Type(FunctionType, .ret=ret, .args=&arg_pointers[0]); } +PUREFUNC bool enum_has_fields(type_t *t) +{ + for (tag_t *e_tag = Match(t, EnumType)->tags; e_tag; e_tag = e_tag->next) { + if (e_tag->type != NULL && Match(e_tag->type, StructType)->fields) + return true; + } + return false; +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/types.h b/src/types.h index 33e54ff5..3b789560 100644 --- a/src/types.h +++ b/src/types.h @@ -157,5 +157,6 @@ PUREFUNC type_t *non_optional(type_t *t); type_t *get_field_type(type_t *t, const char *field_name); PUREFUNC type_t *get_iterated_type(type_t *t); type_t *_make_function_type(type_t *ret, int n, arg_t args[n]); +PUREFUNC bool enum_has_fields(type_t *t); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 |
