aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-03-17 22:06:55 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-03-17 22:06:55 -0400
commit6905f759e5cdbbfa7e16cf183d01ca1f8a858f71 (patch)
tree40915c44938daa8e1acec1e0ecb204fae4db97a1
parent146d3542d5f626099f4c30a0190b6e1d963e70f4 (diff)
Empty enums use a singleton instead of a constructor
-rw-r--r--enums.c41
-rw-r--r--test/enums.tm6
-rw-r--r--typecheck.c8
3 files changed, 33 insertions, 22 deletions
diff --git a/enums.c b/enums.c
index 9917d2ca..a7d38eda 100644
--- a/enums.c
+++ b/enums.c
@@ -115,25 +115,32 @@ void compile_enum_def(env_t *env, ast_t *ast)
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));
enum_def = CORD_all(enum_def, full_name, "$", tag->name, "_t ", tag->name, ";\n");
- // Constructor:
- 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(env, field_t, field->name));
- if (field->next) arg_sig = CORD_cat(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");
- env->code->fndefs = CORD_cat(env->code->fndefs, constructor_def);
+ if (tag->fields) {
+ // Constructor:
+ 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(env, field_t, field->name));
+ if (field->next) arg_sig = CORD_cat(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");
+ env->code->fndefs = CORD_cat(env->code->fndefs, constructor_def);
- CORD constructor_impl = CORD_all("public inline ", full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ") { return (",
- full_name, "_t){.$tag=$tag$", full_name, "$", 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, ", ");
+ CORD constructor_impl = CORD_all("public inline ", full_name, "_t ", full_name, "$tagged$", tag->name, "(", arg_sig, ") { return (",
+ full_name, "_t){.$tag=$tag$", full_name, "$", 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);
+ } else { // Empty tagged data:
+ CORD singleton = CORD_all("extern const ", full_name, "_t ", full_name, "$tagged$", tag->name, ";\n");
+ env->code->fndefs = CORD_cat(env->code->fndefs, singleton);
+ CORD value = CORD_all("public const ", full_name, "_t ", full_name, "$tagged$", tag->name, " = {$tag$", full_name, "$", tag->name, "};\n");
+ env->code->funcs = CORD_cat(env->code->funcs, value);
}
- constructor_impl = CORD_cat(constructor_impl, "}}; }\n");
- env->code->funcs = CORD_cat(env->code->funcs, constructor_impl);
}
enum_def = CORD_cat(enum_def, "};\n};\n");
env->code->typecode = CORD_cat(env->code->typecode, enum_def);
diff --git a/test/enums.tm b/test/enums.tm
index 6dde3601..1b02686d 100644
--- a/test/enums.tm
+++ b/test/enums.tm
@@ -1,6 +1,6 @@
enum Foo(Zero, One(x:Int), Two(x,y:Int))
->> Foo.Zero()
+>> Foo.Zero
= Foo.Zero()
>> Foo.One(123)
= Foo.One(x=123)
@@ -10,7 +10,7 @@ enum Foo(Zero, One(x:Int), Two(x,y:Int))
>> Foo.One(10) == Foo.One(10)
= yes
->> Foo.One(10) == Foo.Zero()
+>> Foo.One(10) == Foo.Zero
= no
>> Foo.One(10) == Foo.One(-1)
@@ -23,7 +23,7 @@ enum Foo(Zero, One(x:Int), Two(x,y:Int))
>> t := {x=>"found"; default="missing"}
>> t[x]
= "found"
->> t[Foo.Zero()]
+>> t[Foo.Zero]
= "missing"
when x is o:One
diff --git a/typecheck.c b/typecheck.c
index 6c26dc43..4a73b32d 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -165,8 +165,12 @@ void bind_statement(env_t *env, ast_t *statement)
type->__data.EnumType.opaque = false;
for (tag_t *tag = tags; tag; tag = tag->next) {
- type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type);
- set_binding(ns_env, tag->name, new(binding_t, .type=constructor_t, .code=CORD_all(env->file_prefix, def->name, "$tagged$", tag->name)));
+ 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, new(binding_t, .type=constructor_t, .code=CORD_all(env->file_prefix, def->name, "$tagged$", tag->name)));
+ } else { // Empty singleton value:
+ set_binding(ns_env, tag->name, new(binding_t, .type=type, .code=CORD_all(env->file_prefix, def->name, "$tagged$", tag->name)));
+ }
Table_str_set(env->types, heap_strf("%s$%s", def->name, tag->name), tag->type);
}