diff options
| -rw-r--r-- | ast.c | 2 | ||||
| -rw-r--r-- | ast.h | 1 | ||||
| -rw-r--r-- | builtins/functions.c | 20 | ||||
| -rw-r--r-- | builtins/nextline.c | 2 | ||||
| -rw-r--r-- | builtins/optionals.c | 5 | ||||
| -rw-r--r-- | builtins/types.c | 4 | ||||
| -rw-r--r-- | builtins/types.h | 6 | ||||
| -rw-r--r-- | compile.c | 8 | ||||
| -rw-r--r-- | enums.c | 7 | ||||
| -rw-r--r-- | parse.c | 21 | ||||
| -rw-r--r-- | structs.c | 6 | ||||
| -rw-r--r-- | test/optionals.tm | 21 | ||||
| -rw-r--r-- | typecheck.c | 3 |
13 files changed, 58 insertions, 48 deletions
@@ -74,7 +74,7 @@ CORD when_clauses_to_xml(when_clause_t *clauses) { CORD tags_to_xml(tag_ast_t *tags) { CORD c = CORD_EMPTY; for (; tags; tags = tags->next) { - c = CORD_all(c, "<tag name=\"", tags->name, "\" value=\"", CORD_asprintf("%ld", tags->value), "\">", arg_list_to_xml(tags->fields), "</tag>"); + c = CORD_all(c, "<tag name=\"", tags->name, "\">", arg_list_to_xml(tags->fields), "</tag>"); } return c; } @@ -67,7 +67,6 @@ typedef enum { typedef struct tag_ast_s { const char *name; arg_ast_t *fields; - int64_t value; bool secret:1; struct tag_ast_s *next; } tag_ast_t; diff --git a/builtins/functions.c b/builtins/functions.c index d6778d4c..ed0889d4 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -117,8 +117,8 @@ PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo *type) case OptionalInfo: { errx(1, "Optional hash not implemented"); } - case EmptyStruct: return 0; - case CustomInfo: + case EmptyStructInfo: return 0; + case CustomInfo: case StructInfo: case EnumInfo: // These all share the same info if (!type->CustomInfo.hash) goto hash_data; return type->CustomInfo.hash(obj, type); @@ -142,8 +142,8 @@ PUREFUNC public int32_t generic_compare(const void *x, const void *y, const Type case OptionalInfo: { errx(1, "Optional compare not implemented"); } - case EmptyStruct: return 0; - case CustomInfo: + case EmptyStructInfo: return 0; + case CustomInfo: case StructInfo: case EnumInfo: // These all share the same info if (!type->CustomInfo.compare) goto compare_data; return type->CustomInfo.compare(x, y, type); @@ -163,11 +163,11 @@ PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo case ArrayInfo: return Array$equal(x, y, type); case ChannelInfo: return Channel$equal((const channel_t**)x, (const channel_t**)y, type); case TableInfo: return Table$equal(x, y, type); - case EmptyStruct: return true; + case EmptyStructInfo: return true; case OptionalInfo: { errx(1, "Optional equal not implemented"); } - case CustomInfo: + case CustomInfo: case StructInfo: case EnumInfo: // These all share the same info if (!type->CustomInfo.equal) goto use_generic_compare; return type->CustomInfo.equal(x, y, type); @@ -188,10 +188,10 @@ public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo *ty case TableInfo: return Table$as_text(obj, colorize, type); case TypeInfoInfo: return Type$as_text(obj, colorize, type); case OptionalInfo: return Optional$as_text(obj, colorize, type); - case EmptyStruct: return colorize ? - Text$concat(Text("\x1b[0;1m"), Text$from_str(type->EmptyStruct.name), Text("\x1b[m()")) - : Text$concat(Text$from_str(type->EmptyStruct.name), Text("()")); - case CustomInfo: + case EmptyStructInfo: return colorize ? + Text$concat(Text("\x1b[0;1m"), Text$from_str(type->EmptyStructInfo.name), Text("\x1b[m()")) + : Text$concat(Text$from_str(type->EmptyStructInfo.name), Text("()")); + case CustomInfo: case StructInfo: case EnumInfo: // These all share the same info if (!type->CustomInfo.as_text) fail("No text function provided for type!\n"); return type->CustomInfo.as_text(obj, colorize, type); diff --git a/builtins/nextline.c b/builtins/nextline.c index 3fa37412..b7928939 100644 --- a/builtins/nextline.c +++ b/builtins/nextline.c @@ -91,7 +91,7 @@ static uint64_t NextLine$hash(const NextLine_t *obj, const TypeInfo *info) return siphash24((void *) &hashes, sizeof(hashes)); } -public const TypeInfo NextLine$Done = { 0, 0, {.tag = EmptyStruct,.EmptyStruct.name = +public const TypeInfo NextLine$Done = { 0, 0, {.tag = EmptyStructInfo,.EmptyStructInfo.name = "NextLine$Done" } }; public const TypeInfo NextLine$Next = { 24, 8, {.tag = CustomInfo,.CustomInfo = {.as_text = diff --git a/builtins/optionals.c b/builtins/optionals.c index f58c8134..88f08097 100644 --- a/builtins/optionals.c +++ b/builtins/optionals.c @@ -36,12 +36,15 @@ static inline bool is_null(const void *obj, const TypeInfo *non_optional_type) case ArrayInfo: return ((Array_t*)obj)->length < 0; case TableInfo: return ((Table_t*)obj)->entries.length < 0; case FunctionInfo: return *(void**)obj == NULL; - case CustomInfo: { + case StructInfo: { int64_t offset = non_optional_type->size; if (offset % non_optional_type->align) offset += non_optional_type->align - (offset % non_optional_type->align); return *(bool*)(obj + offset); } + case EnumInfo: { + return (*(int*)obj) == 0; // NULL tag + } default: { Text_t t = generic_as_text(NULL, false, non_optional_type); errx(1, "is_null() not implemented for: %k", &t); diff --git a/builtins/types.c b/builtins/types.c index 79f65f71..512fdfc3 100644 --- a/builtins/types.c +++ b/builtins/types.c @@ -32,8 +32,8 @@ public const TypeInfo TypeInfo$info = { .TypeInfoInfo.type_str="TypeInfo", }; -public const TypeInfo Void$info = {.size=0, .align=0, .tag=EmptyStruct}; -public const TypeInfo Abort$info = {.size=0, .align=0, .tag=EmptyStruct}; +public const TypeInfo Void$info = {.size=0, .align=0, .tag=EmptyStructInfo}; +public const TypeInfo Abort$info = {.size=0, .align=0, .tag=EmptyStructInfo}; public Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo *type) { diff --git a/builtins/types.h b/builtins/types.h index a6cc40c6..38d8bdc5 100644 --- a/builtins/types.h +++ b/builtins/types.h @@ -17,8 +17,8 @@ typedef Text_t (*text_fn_t)(const void*, bool, const struct TypeInfo*); typedef struct TypeInfo { int64_t size, align; struct { // Anonymous tagged union for convenience - enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo, - OptionalInfo, TypeInfoInfo, OpaqueInfo, EmptyStruct } tag; + enum { CustomInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo, + OptionalInfo, TypeInfoInfo, OpaqueInfo, EmptyStructInfo } tag; union { struct { equal_fn_t equal; @@ -52,7 +52,7 @@ typedef struct TypeInfo { struct {} OpaqueInfo; struct { const char *name; - } EmptyStruct; + } EmptyStructInfo; }; }; } TypeInfo; @@ -222,7 +222,7 @@ CORD compile_type(type_t *t) switch (nonnull->tag) { case BoolType: case CStringType: case BigIntType: case NumType: case TextType: case ArrayType: case SetType: case TableType: case FunctionType: case ClosureType: - case PointerType: + case PointerType: case EnumType: return compile_type(nonnull); case IntType: return CORD_all("Optional", compile_type(nonnull)); @@ -348,6 +348,8 @@ static CORD compile_optional_check(env_t *env, ast_t *ast) return CORD_all("!(", compile(env, ast), ").is_null"); else if (t->tag == StructType) return CORD_all("!(", compile(env, ast), ").is_null"); + else if (t->tag == EnumType) + return CORD_all("((", compile(env, ast), ").tag != 0)"); errx(1, "Optional check not implemented for: %T", t); } @@ -1707,6 +1709,10 @@ CORD compile(env_t *env, ast_t *ast) case ClosureType: return "NULL_CLOSURE"; case NumType: return "nan(\"null\")"; case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_null=true})"); + case EnumType: { + env_t *enum_env = Match(t, EnumType)->env; + return CORD_all("((", compile_type(t), "){", namespace_prefix(enum_env->libname, enum_env->namespace), "null})"); + } default: code_err(ast, "Nil isn't implemented for this type: %T", t); } } @@ -171,7 +171,7 @@ void compile_enum_def(env_t *env, ast_t *ast) } type_t *t = Table$str_get(*env->types, def->name); - CORD typeinfo = CORD_asprintf("public const TypeInfo %s = {%zu, %zu, {.tag=CustomInfo, .CustomInfo={", + CORD typeinfo = CORD_asprintf("public const TypeInfo %s = {%zu, %zu, {.tag=EnumInfo, .CustomInfo={", full_name, type_size(t), type_align(t)); env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast)); @@ -202,9 +202,10 @@ CORD compile_enum_typedef(env_t *env, ast_t *ast) CORD full_name = CORD_cat(namespace_prefix(env->libname, env->namespace), def->name); CORD all_defs = CORD_all("typedef struct ", full_name, "_s ", full_name, "_t;\n"); CORD enum_def = CORD_all("struct ", full_name, "_s {\n" - "\tenum {"); + "\tenum { ", full_name, "$null=0, "); + for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { - CORD_appendf(&enum_def, "%r$tag$%s = %ld", full_name, tag->name, tag->value); + enum_def = CORD_all(enum_def, full_name, "$tag$", tag->name); if (tag->next) enum_def = CORD_cat(enum_def, ", "); } enum_def = CORD_cat(enum_def, "} tag;\n" @@ -2028,12 +2028,8 @@ ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) { if (!match(&pos, "(")) return NULL; tag_ast_t *tags = NULL; - int64_t next_value = 0; - whitespace(&pos); for (;;) { - const char *tag_start = pos; - spaces(&pos); const char *tag_name = get_id(&pos); if (!tag_name) break; @@ -2055,22 +2051,7 @@ ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) { fields = NULL; } - spaces(&pos); - if (match(&pos, "=")) { - ast_t *val = expect(ctx, tag_start, &pos, parse_int, "I expected an integer literal after this '='"); - Int_t i = Int$from_text(Text$from_str(Match(val, Int)->str), NULL); - // TODO check for overflow - next_value = (i.small >> 2); - } - - // Check for duplicate values: - for (tag_ast_t *t = tags; t; t = t->next) { - if (t->value == next_value) - parser_err(ctx, tag_start, pos, "This tag value (%ld) is a duplicate of an earlier tag value", next_value); - } - - tags = new(tag_ast_t, .name=tag_name, .value=next_value, .fields=fields, .secret=secret, .next=tags); - ++next_value; + tags = new(tag_ast_t, .name=tag_name, .fields=fields, .secret=secret, .next=tags); if (!match_separator(&pos)) break; @@ -121,7 +121,7 @@ void compile_struct_def(env_t *env, ast_t *ast) assert(t && t->tag == StructType); auto struct_ = Match(t, StructType); if (def->fields) { - CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=CustomInfo, .CustomInfo={", + CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=StructInfo, .CustomInfo={", full_name, type_size(t), type_align(t)); typeinfo = CORD_all(typeinfo, ".as_text=(void*)", full_name, "$as_text, "); @@ -156,8 +156,8 @@ void compile_struct_def(env_t *env, ast_t *ast) typeinfo = CORD_cat(typeinfo, "}}};\n"); env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo); } else { - // If there are no fields, we can use an EmptyStruct typeinfo, which generates less code: - CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=EmptyStruct, .EmptyStruct.name=%r}};\n", + // If there are no fields, we can use an EmptyStructInfo typeinfo, which generates less code: + CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=EmptyStructInfo, .EmptyStructInfo.name=%r}};\n", full_name, type_size(t), type_align(t), CORD_quoted(def->name)); env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo); } diff --git a/test/optionals.tm b/test/optionals.tm index b80fbab0..a721deaa 100644 --- a/test/optionals.tm +++ b/test/optionals.tm @@ -1,11 +1,17 @@ struct Struct(x:Int, y:Text): - func maybe(should_i:Bool)-> Struct?: + func maybe(should_i:Bool)->Struct?: if should_i: return Struct(123, "hello") else: return !Struct +enum Enum(X, Y(y:Int)): + func maybe(should_i:Bool)->Enum?: + if should_i: + return Enum.Y(123) + else: + return !Enum func maybe_int(should_i:Bool)->Int?: if should_i: @@ -143,6 +149,19 @@ func main(): fail("Truthy: $nope") else: !! Falsey: $nope + do: + !! ... + !! Enums: + >> yep := Enum.maybe(yes) + = Enum.Y(y=123)? + >> nope := Enum.maybe(no) + = !Enum + >> if yep: >> yep + else: fail("Falsey: $yep") + >> if nope: + fail("Truthy: $nope") + else: !! Falsey: $nope + if yep := maybe_int(yes): >> yep = 123 : Int diff --git a/typecheck.c b/typecheck.c index 5d0e2b48..dabd5532 100644 --- a/typecheck.c +++ b/typecheck.c @@ -324,6 +324,7 @@ void bind_statement(env_t *env, ast_t *statement) type_t *type = Table$str_get(*env->types, def->name); assert(type); tag_t *tags = NULL; + int64_t next_tag = 1; for (tag_ast_t *tag_ast = def->tags; tag_ast; tag_ast = tag_ast->next) { arg_t *fields = NULL; for (arg_ast_t *field_ast = tag_ast->fields; field_ast; field_ast = field_ast->next) { @@ -342,7 +343,7 @@ void bind_statement(env_t *env, ast_t *statement) REVERSE_LIST(fields); env_t *member_ns = namespace_env(env, heap_strf("%s$%s", def->name, tag_ast->name)); type_t *tag_type = Type(StructType, .name=heap_strf("%s$%s", def->name, tag_ast->name), .fields=fields, .env=member_ns); - tags = new(tag_t, .name=tag_ast->name, .tag_value=tag_ast->value, .type=tag_type, .next=tags); + tags = new(tag_t, .name=tag_ast->name, .tag_value=(next_tag++), .type=tag_type, .next=tags); } REVERSE_LIST(tags); type->__data.EnumType.tags = tags; |
