aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-05-25 16:41:43 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-05-25 16:41:43 -0400
commitb2033f6d6d8918ed9ac72468aaa5faf96f8157dd (patch)
tree94d8697b8d664d716feeaa3831fa494c1eedcb6f
parentf2f43f2e239890847c2f1833ad2e7baf07108145 (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.
-rw-r--r--lib/time/time.tm2
-rw-r--r--src/compile.c54
-rw-r--r--src/enums.c41
-rw-r--r--src/structs.c2
-rw-r--r--src/typecheck.c7
-rw-r--r--src/types.c9
-rw-r--r--src/types.h1
7 files changed, 81 insertions, 35 deletions
diff --git a/lib/time/time.tm b/lib/time/time.tm
index db0b9538..456b5f08 100644
--- a/lib/time/time.tm
+++ b/lib/time/time.tm
@@ -140,7 +140,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
@ret.minute = I(info.tm_min);
@ret.second = I(info.tm_sec);
@ret.nanosecond = I(@t.tv_usec);
- @ret.weekday.$tag = info.tm_wday + 1;
+ @ret.weekday = info.tm_wday + 1;
@ret.day_of_year = I(info.tm_yday);
@ret.timezone = @timezone;
}
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