Optional structs
This commit is contained in:
parent
bba9f1b141
commit
dee3742b48
@ -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);
|
||||
|
58
compile.c
58
compile.c
@ -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);
|
||||
|
18
structs.c
18
structs.c
@ -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
|
||||
|
@ -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
|
||||
|
7
types.c
7
types.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user