diff options
| -rw-r--r-- | builtins/optionals.c | 6 | ||||
| -rw-r--r-- | compile.c | 58 | ||||
| -rw-r--r-- | structs.c | 18 | ||||
| -rw-r--r-- | test/optionals.tm | 21 | ||||
| -rw-r--r-- | types.c | 7 |
5 files changed, 85 insertions, 25 deletions
diff --git a/builtins/optionals.c b/builtins/optionals.c index 27ab8ec6..f58c8134 100644 --- a/builtins/optionals.c +++ b/builtins/optionals.c @@ -36,6 +36,12 @@ 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: { + 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); + } default: { Text_t t = generic_as_text(NULL, false, non_optional_type); errx(1, "is_null() not implemented for: %k", &t); @@ -23,7 +23,24 @@ static CORD compile_string(env_t *env, ast_t *ast, CORD color); static CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args); static CORD compile_maybe_incref(env_t *env, ast_t *ast); static CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target); +static CORD promote_to_optional(type_t *t, CORD code); +CORD promote_to_optional(type_t *t, CORD code) +{ + if (t->tag == IntType) { + switch (Match(t, IntType)->bits) { + case TYPE_IBITS8: return CORD_all("((OptionalInt8_t){.i=", code, "})"); + case TYPE_IBITS16: return CORD_all("((OptionalInt16_t){.i=", code, "})"); + case TYPE_IBITS32: return CORD_all("((OptionalInt32_t){.i=", code, "})"); + case TYPE_IBITS64: return CORD_all("((OptionalInt64_t){.i=", code, "})"); + default: errx(1, "Unsupported in type: %T", t); + } + } else if (t->tag == StructType) { + return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.value=", code, "})"); + } else { + return code; + } +} static bool promote(env_t *env, CORD *code, type_t *actual, type_t *needed) { if (type_eq(actual, needed)) @@ -62,8 +79,10 @@ static bool promote(env_t *env, CORD *code, type_t *actual, type_t *needed) } // Optional promotion: - if (needed->tag == OptionalType && type_eq(actual, Match(needed, OptionalType)->type)) + if (needed->tag == OptionalType && type_eq(actual, Match(needed, OptionalType)->type)) { + *code = promote_to_optional(actual, *code); return true; + } // Stack ref promotion: if (actual->tag == PointerType && needed->tag == PointerType) @@ -189,9 +208,9 @@ CORD compile_type(type_t *t) case ClosureType: return "closure_t"; case PointerType: return CORD_cat(compile_type(Match(t, PointerType)->pointed), "*"); case StructType: { - auto s = Match(t, StructType); if (t == THREAD_TYPE) return "pthread_t*"; + auto s = Match(t, StructType); return CORD_all("struct ", namespace_prefix(s->env->libname, s->env->namespace->parent), s->name, "_s"); } case EnumType: { @@ -200,11 +219,22 @@ CORD compile_type(type_t *t) } case OptionalType: { type_t *nonnull = Match(t, OptionalType)->type; - if (nonnull->tag == IntType) + 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: + return compile_type(nonnull); + case IntType: return CORD_all("Optional", compile_type(nonnull)); - if (!supports_optionals(nonnull)) + case StructType: { + if (nonnull == THREAD_TYPE) + return "pthread_t*"; + auto s = Match(nonnull, StructType); + return CORD_all(namespace_prefix(s->env->libname, s->env->namespace->parent), "$Optional", s->name, "_t"); + } + default: compiler_err(NULL, NULL, NULL, "Optional types are not supported for: %T", t); - return compile_type(nonnull); + } } case TypeInfoType: return "TypeInfo"; default: compiler_err(NULL, NULL, NULL, "Compiling type is not implemented for type with tag %d", t->tag); @@ -287,6 +317,8 @@ static CORD optional_var_into_nonnull(binding_t *b) switch (b->type->tag) { case IntType: return CORD_all(b->code, ".i"); + case StructType: + return CORD_all(b->code, ".value"); default: return b->code; } @@ -314,6 +346,8 @@ static CORD compile_optional_check(env_t *env, ast_t *ast) return CORD_all("((", compile(env, ast), ").length >= 0)"); else if (t->tag == IntType) return CORD_all("!(", compile(env, ast), ").is_null"); + else if (t->tag == StructType) + return CORD_all("!(", compile(env, ast), ").is_null"); errx(1, "Optional check not implemented for: %T", t); } @@ -1672,6 +1706,7 @@ CORD compile(env_t *env, ast_t *ast) case PointerType: return CORD_all("((", compile_type(t), ")NULL)"); case ClosureType: return "NULL_CLOSURE"; case NumType: return "nan(\"null\")"; + case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_null=true})"); default: code_err(ast, "Nil isn't implemented for this type: %T", t); } } @@ -1779,18 +1814,7 @@ CORD compile(env_t *env, ast_t *ast) case Optional: { ast_t *value = Match(ast, Optional)->value; CORD value_code = compile(env, value); - type_t *t = get_type(env, value); - if (t->tag == IntType) { - switch (Match(t, IntType)->bits) { - case TYPE_IBITS8: return CORD_all("((OptionalInt8_t){.i=", value_code, "})"); - case TYPE_IBITS16: return CORD_all("((OptionalInt16_t){.i=", value_code, "})"); - case TYPE_IBITS32: return CORD_all("((OptionalInt32_t){.i=", value_code, "})"); - case TYPE_IBITS64: return CORD_all("((OptionalInt64_t){.i=", value_code, "})"); - default: errx(1, "Unsupported in type: %T", t); - } - } else { - return value_code; - } + return promote_to_optional(get_type(env, value), value_code); } case BinaryOp: { auto binop = Match(ast, BinaryOp); @@ -169,18 +169,24 @@ CORD compile_struct_typedef(env_t *env, ast_t *ast) { auto def = Match(ast, StructDef); CORD full_name = CORD_cat(namespace_prefix(env->libname, env->namespace), def->name); - CORD code = CORD_all("typedef struct ", full_name, "_s ", full_name, "_t;\n"); - CORD struct_code = CORD_all("struct ", full_name, "_s {\n"); + CORD fields = CORD_EMPTY; for (arg_ast_t *field = def->fields; field; field = field->next) { type_t *field_t = get_arg_ast_type(env, field); CORD type_code = compile_type(field_t); - CORD_appendf(&struct_code, "%r $%s%s;\n", type_code, field->name, - CORD_cmp(type_code, "Bool_t") ? "" : ":1"); + fields = CORD_all(fields, type_code, " $", field->name, field_t->tag == BoolType ? ":1" : CORD_EMPTY, ";\n"); } + CORD struct_code = CORD_all("struct ", full_name, "_s {\n"); struct_code = CORD_all(struct_code, "};\n"); - code = CORD_all(code, struct_code); - return code; + return CORD_all( + "typedef struct ", full_name, "_s ", full_name, "_t;\n", + "struct ", full_name, "_s {\n", + fields, + "};\n", + "typedef struct {\n", + full_name, "_t value;\n" + "Bool_t is_null:1;\n" + "} ", namespace_prefix(env->libname, env->namespace), "$Optional", def->name, "_t;\n"); } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/test/optionals.tm b/test/optionals.tm index 8e24f66d..b80fbab0 100644 --- a/test/optionals.tm +++ b/test/optionals.tm @@ -1,3 +1,12 @@ + +struct Struct(x:Int, y:Text): + func maybe(should_i:Bool)-> Struct?: + if should_i: + return Struct(123, "hello") + else: + return !Struct + + func maybe_int(should_i:Bool)->Int?: if should_i: return 123 @@ -121,6 +130,18 @@ func main(): fail("Truthy: $nope") else: !! Falsey: $nope + do: + !! ... + !! Structs: + >> yep := Struct.maybe(yes) + = Struct(x=123, y="hello")? + >> nope := Struct.maybe(no) + = !Struct + >> if yep: >> yep + else: fail("Falsey: $yep") + >> if nope: + fail("Truthy: $nope") + else: !! Falsey: $nope if yep := maybe_int(yes): >> yep @@ -1,9 +1,10 @@ // Logic for handling type_t types #include <gc/cord.h> -#include <stdint.h> -#include <signal.h> #include <limits.h> #include <math.h> +#include <signal.h> +#include <stdint.h> +#include <sys/param.h> #include "builtins/integers.h" #include "builtins/table.h" @@ -418,6 +419,7 @@ PUREFUNC size_t type_size(type_t *t) case TYPE_IBITS8: return sizeof(OptionalInt8_t); default: errx(1, "Invalid integer bit size"); } + case StructType: return padded_type_size(nonnull) + 1; default: return type_size(nonnull); } } @@ -495,6 +497,7 @@ PUREFUNC size_t type_align(type_t *t) case TYPE_IBITS8: return __alignof__(OptionalInt8_t); default: errx(1, "Invalid integer bit size"); } + case StructType: return MAX(1, type_align(nonnull)); default: return type_align(nonnull); } } |
