diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-03-17 22:06:55 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-03-17 22:06:55 -0400 |
| commit | 6905f759e5cdbbfa7e16cf183d01ca1f8a858f71 (patch) | |
| tree | 40915c44938daa8e1acec1e0ecb204fae4db97a1 | |
| parent | 146d3542d5f626099f4c30a0190b6e1d963e70f4 (diff) | |
Empty enums use a singleton instead of a constructor
| -rw-r--r-- | enums.c | 41 | ||||
| -rw-r--r-- | test/enums.tm | 6 | ||||
| -rw-r--r-- | typecheck.c | 8 |
3 files changed, 33 insertions, 22 deletions
@@ -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); } |
