diff options
-rw-r--r-- | cgen.c | 21 | ||||
-rw-r--r-- | copy.c | 2 | ||||
-rw-r--r-- | eval.c | 103 | ||||
-rw-r--r-- | foreign.c | 10 | ||||
-rw-r--r-- | infer.c | 1 | ||||
-rw-r--r-- | instance_table.c | 10 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | parse.c | 27 | ||||
-rw-r--r-- | test.toc | 10 | ||||
-rw-r--r-- | toc.c | 3 | ||||
-rw-r--r-- | types.c | 170 | ||||
-rw-r--r-- | types.h | 9 |
12 files changed, 188 insertions, 182 deletions
@@ -169,7 +169,6 @@ static void cgen_defs_decl(CGenerator *g, Declaration *d); case TYPE_PTR: \ f(g, type->ptr); \ break; \ - case TYPE_VOID: \ case TYPE_BUILTIN: \ case TYPE_UNKNOWN: \ break; \ @@ -286,7 +285,6 @@ static bool cgen_uses_ptr(Type *t) { case TYPE_PTR: case TYPE_FN: case TYPE_SLICE: - case TYPE_VOID: case TYPE_UNKNOWN: return false; case TYPE_EXPR: @@ -326,16 +324,14 @@ static void cgen_type_pre(CGenerator *g, Type *t) { case BUILTIN_BOOL: cgen_write(g, "bool"); break; case BUILTIN_F32: cgen_write(g, "f32"); break; case BUILTIN_F64: cgen_write(g, "f64"); break; + case BUILTIN_VOID: cgen_write(g, "void"); break; case BUILTIN_NMS: case BUILTIN_TYPE: case BUILTIN_VARARGS: assert(0); break; } break; case TYPE_PTR: - if (t->ptr->kind == TYPE_UNKNOWN) - cgen_write(g, "void"); /* #C &"foo", for example */ - else - cgen_type_pre(g, t->ptr); + cgen_type_pre(g, t->ptr); cgen_write(g, "(*"); break; case TYPE_ARR: @@ -353,7 +349,6 @@ static void cgen_type_pre(CGenerator *g, Type *t) { case TYPE_SLICE: cgen_write(g, "slice_"); break; - case TYPE_VOID: cgen_write(g, "void"); break; case TYPE_STRUCT: cgen_write(g, "struct "); cgen_struct_name(g, t->struc); @@ -416,7 +411,6 @@ static void cgen_type_post(CGenerator *g, Type *t) { cgen_type_post(g, &t->fn.types[0]); } break; case TYPE_BUILTIN: - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_TUPLE: case TYPE_SLICE: @@ -543,7 +537,6 @@ static void cgen_val_ptr_pre(CGenerator *g, void *v, Type *t) { case TYPE_FN: case TYPE_UNKNOWN: case TYPE_TUPLE: - case TYPE_VOID: case TYPE_BUILTIN: case TYPE_PTR: case TYPE_STRUCT: @@ -559,7 +552,6 @@ static void cgen_val_ptr(CGenerator *g, void *v, Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { case TYPE_TUPLE: - case TYPE_VOID: case TYPE_EXPR: case TYPE_UNKNOWN: assert(0); @@ -612,6 +604,7 @@ static void cgen_val_ptr(CGenerator *g, void *v, Type *t) { case BUILTIN_TYPE: case BUILTIN_NMS: case BUILTIN_VARARGS: + case BUILTIN_VOID: assert(0); break; } @@ -829,7 +822,6 @@ static void cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E assert(set_expr->kind == EXPR_TUPLE); cgen_set_tuple(g, set_expr->tuple, NULL, NULL, to_expr); break; - case TYPE_VOID: case TYPE_EXPR: assert(0); break; @@ -1003,7 +995,7 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { cgen_ident_id_to_str(ret_name, id); char *p = ret_name + strlen(ret_name); - if (e->type.kind != TYPE_VOID) { + if (!type_is_void(&e->type)) { if (e->type.kind == TYPE_TUPLE) { for (unsigned long i = 0; i < arr_len(e->type.tuple); ++i) { sprintf(p, "%lu", i); @@ -1665,7 +1657,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { } break; case EXPR_BLOCK: case EXPR_IF: - if (e->type.kind != TYPE_VOID) + if (!type_is_void(&e->type)) cgen_ident_id(g, e->cgen.id); break; case EXPR_CALL: @@ -1850,7 +1842,6 @@ static void cgen_zero_value(CGenerator *g, Type *t) { case TYPE_STRUCT: cgen_write(g, "{0}"); break; - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_TUPLE: case TYPE_EXPR: @@ -2104,7 +2095,7 @@ static void cgen_ret(CGenerator *g, Block *returning_from, Expression *ret_expr) ret.type = f->ret_type; #endif cgen_writeln(g, " return;"); - } else if (f->ret_type.kind == TYPE_VOID) { + } else if (type_is_void(&f->ret_type)) { cgen_writeln(g, "return;"); } else { cgen_writeln(g, "return ret_;"); @@ -53,7 +53,6 @@ static void copy_val(Allocator *a, Value *out, Value in, Type *t) { case TYPE_FN: case TYPE_PTR: case TYPE_SLICE: - case TYPE_VOID: case TYPE_UNKNOWN: *out = in; break; @@ -122,7 +121,6 @@ static void copy_type(Copier *c, Type *out, Type *in) { *out = *in; switch (in->kind) { case TYPE_BUILTIN: - case TYPE_VOID: case TYPE_UNKNOWN: break; case TYPE_EXPR: @@ -37,6 +37,7 @@ static bool builtin_truthiness(Value v, BuiltinType b) { case BUILTIN_BOOL: return v.boolv; case BUILTIN_CHAR: return v.charv != 0; case BUILTIN_VARARGS: return arr_len(v.varargs) != 0; + case BUILTIN_VOID: case BUILTIN_TYPE: case BUILTIN_NMS: break; @@ -47,7 +48,6 @@ static bool builtin_truthiness(Value v, BuiltinType b) { static bool val_truthiness(Value v, Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { - case TYPE_VOID: return false; case TYPE_UNKNOWN: assert(0); return false; case TYPE_BUILTIN: return builtin_truthiness(v, t->builtin); case TYPE_PTR: return v.ptr != NULL; @@ -146,7 +146,6 @@ static void *val_get_ptr(Value *v, Type *t) { switch (t->kind) { case TYPE_PTR: case TYPE_BUILTIN: - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_FN: case TYPE_SLICE: @@ -165,9 +164,6 @@ static void *val_get_ptr(Value *v, Type *t) { static void fprint_val_ptr(FILE *f, void *p, Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { - case TYPE_VOID: - fprintf(f, "(void)"); - break; case TYPE_UNKNOWN: fprintf(f, "???"); break; @@ -185,6 +181,7 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) { case BUILTIN_F64: fprintf(f, F64_FMT, *(F64 *)p); break; case BUILTIN_CHAR: fprint_char_literal(f, *(char *)p); break; case BUILTIN_BOOL: fprintf(f, "%s", *(bool *)p ? "true" : "false"); break; + case BUILTIN_VOID: fprintf(f, "(void)"); break; case BUILTIN_VARARGS: fprintf(f, "...("); arr_foreach(*(VarArg **)p, VarArg, varg) { @@ -278,7 +275,6 @@ static void *val_ptr_to_free(Value *v, Type *t) { case TYPE_FN: case TYPE_PTR: case TYPE_SLICE: - case TYPE_VOID: case TYPE_UNKNOWN: return NULL; case TYPE_ARR: @@ -302,53 +298,55 @@ static inline void val_free_ptr(Value *v, Type *t) { free(v); } -#define builtin_casts_to_int(x) \ - case BUILTIN_I8: \ - vout->i8 = (I8)(I64)vin->x; break; \ - case BUILTIN_I16: \ - vout->i16 = (I16)(I64)vin->x; break; \ - case BUILTIN_I32: \ - vout->i32 = (I32)(I64)vin->x; break; \ - case BUILTIN_I64: \ - vout->i64 = (I64)vin->x; break; \ - case BUILTIN_U8: \ - vout->u8 = (U8)(U64)vin->x; break; \ - case BUILTIN_U16: \ - vout->u16 = (U16)(U64)vin->x; break; \ - case BUILTIN_U32: \ - vout->u32 = (U32)(U64)vin->x; break; \ - case BUILTIN_U64: \ +#define builtin_casts_to_int(x) \ + case BUILTIN_I8: \ + vout->i8 = (I8)(I64)vin->x; break; \ + case BUILTIN_I16: \ + vout->i16 = (I16)(I64)vin->x; break; \ + case BUILTIN_I32: \ + vout->i32 = (I32)(I64)vin->x; break; \ + case BUILTIN_I64: \ + vout->i64 = (I64)vin->x; break; \ + case BUILTIN_U8: \ + vout->u8 = (U8)(U64)vin->x; break; \ + case BUILTIN_U16: \ + vout->u16 = (U16)(U64)vin->x; break; \ + case BUILTIN_U32: \ + vout->u32 = (U32)(U64)vin->x; break; \ + case BUILTIN_U64: \ vout->u64 = (U64)vin->x; break -#define builtin_casts_to_num(x) \ - builtin_casts_to_int(x); \ - case BUILTIN_F32: \ - vout->f32 = (F32)vin->x; break; \ - case BUILTIN_F64: \ +#define builtin_casts_to_num(x) \ + builtin_casts_to_int(x); \ + case BUILTIN_F32: \ + vout->f32 = (F32)vin->x; break; \ + case BUILTIN_F64: \ vout->f64 = (F64)vin->x; break -#define builtin_int_casts(low, up) \ - case BUILTIN_##up: \ - switch (to) { \ - builtin_casts_to_num(low); \ - case BUILTIN_CHAR: vout->charv = (char)vin->low; break; \ - case BUILTIN_BOOL: vout->boolv = vin->low != 0; break; \ - case BUILTIN_NMS: \ - case BUILTIN_TYPE: \ - case BUILTIN_VARARGS: \ - assert(0); break; \ +#define builtin_int_casts(low, up) \ + case BUILTIN_##up: \ + switch (to) { \ + builtin_casts_to_num(low); \ + case BUILTIN_CHAR: vout->charv = (char)vin->low; break; \ + case BUILTIN_BOOL: vout->boolv = vin->low != 0; break; \ + case BUILTIN_NMS: \ + case BUILTIN_VOID: \ + case BUILTIN_TYPE: \ + case BUILTIN_VARARGS: \ + assert(0); break; \ } break -#define builtin_float_casts(low, up) \ - case BUILTIN_##up: \ - switch (to) { \ - builtin_casts_to_num(low); \ - case BUILTIN_BOOL: vout->boolv = vin->low != 0.0f; break; \ - case BUILTIN_CHAR: \ - case BUILTIN_TYPE: \ - case BUILTIN_NMS: \ - case BUILTIN_VARARGS: \ - assert(0); break; \ +#define builtin_float_casts(low, up) \ + case BUILTIN_##up: \ + switch (to) { \ + builtin_casts_to_num(low); \ + case BUILTIN_BOOL: vout->boolv = vin->low != 0.0f; break; \ + case BUILTIN_CHAR: \ + case BUILTIN_TYPE: \ + case BUILTIN_NMS: \ + case BUILTIN_VARARGS: \ + case BUILTIN_VOID: \ + assert(0); break; \ } break static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinType to) { @@ -378,6 +376,7 @@ static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinT case BUILTIN_BOOL: case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VOID: case BUILTIN_VARARGS: assert(0); break; } @@ -385,6 +384,7 @@ static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinT case BUILTIN_TYPE: case BUILTIN_NMS: case BUILTIN_VARARGS: + case BUILTIN_VOID: assert(0); break; } @@ -400,7 +400,6 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { } switch (from->kind) { - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_TUPLE: case TYPE_STRUCT: @@ -427,7 +426,6 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_EXPR: case TYPE_STRUCT: case TYPE_SLICE: - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_TUPLE: case TYPE_FN: @@ -462,6 +460,7 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case BUILTIN_TYPE: case BUILTIN_NMS: case BUILTIN_VARARGS: + case BUILTIN_VOID: assert(0); break; } break; @@ -537,6 +536,7 @@ static void eval_deref(Value *v, void *ptr, Type *type) { case BUILTIN_TYPE: v->type = *(Type **)ptr; break; + case BUILTIN_VOID: case BUILTIN_VARARGS: assert(0); break; @@ -545,7 +545,6 @@ static void eval_deref(Value *v, void *ptr, Type *type) { case TYPE_SLICE: v->slice = *(Slice *)ptr; break; - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_EXPR: assert(0); @@ -579,6 +578,7 @@ static void eval_deref_set(void *set, Value *to, Type *type) { case BUILTIN_TYPE: *(Type **)set = to->type; break; + case BUILTIN_VOID: case BUILTIN_VARARGS: assert(0); break; @@ -587,7 +587,6 @@ static void eval_deref_set(void *set, Value *to, Type *type) { case TYPE_SLICE: *(Slice *)set = to->slice; break; - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_EXPR: assert(0); @@ -1521,7 +1520,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { } } if (ev->returning) { - if (fn->ret_type.kind != TYPE_VOID && !fn->ret_decls) + if (!type_is_void(&fn->ret_type) && !fn->ret_decls) *v = ev->ret_val; ev->returning = NULL; } @@ -102,9 +102,6 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val, warn_print(where, "Foreign function returns function pointer. If it returns a C-style function pointer, it won't be called properly by toc."); av_start_ptr(*arg_list, fn, FnExpr *, &return_val->fn); break; - case TYPE_VOID: - av_start_void(*arg_list, fn); - break; case TYPE_PTR: av_start_ptr(*arg_list, fn, void *, &return_val->ptr); break; @@ -153,6 +150,9 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val, case BUILTIN_NMS: av_start_ptr(*arg_list, fn, Namespace *, &return_val->nms); break; + case BUILTIN_VOID: + av_start_void(*arg_list, fn); + break; case BUILTIN_VARARGS: assert(0); break; @@ -197,7 +197,6 @@ static bool arg_list_start(av_alist *arg_list, void (*fn)(), Value *return_val, static bool arg_list_add(av_alist *arg_list, Value val, Type *type, Location where) { switch (type->kind) { - case TYPE_VOID: case TYPE_TUPLE: case TYPE_UNKNOWN: case TYPE_ARR: { /* @TODO: maybe just pass pointer for arr? */ @@ -262,6 +261,9 @@ static bool arg_list_add(av_alist *arg_list, Value val, Type *type, Location whe arg_list_add(arg_list, arg->val, arg->type, where); } break; + case BUILTIN_VOID: + err_print(where, "Cannot pass type void to foreign function."); + return false; } break; case TYPE_SLICE: @@ -81,7 +81,6 @@ static bool infer_from_type(Typer *tr, Type *match, Type *to, Identifier *idents } } switch (match->kind) { - case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_BUILTIN: break; /* nothing we can do here */ diff --git a/instance_table.c b/instance_table.c index 924ac1d..870ff60 100644 --- a/instance_table.c +++ b/instance_table.c @@ -83,15 +83,13 @@ static U64 type_hash(Type *t) { 0x8191b5178d728e8c, 0x50da97f1211b2423, 0xc3977306abd0ae6c, - 0x87ea684427e1c521, - 0xcee5fd6d6cbdfe23 + 0x87ea684427e1c521 }; U64 hash = starters[t->kind]; assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { case TYPE_BUILTIN: return hash + (U64)t->builtin * 0x1307787dfff73417; - case TYPE_VOID: case TYPE_UNKNOWN: return hash; case TYPE_TUPLE: @@ -124,7 +122,6 @@ static U64 type_hash(Type *t) { static U64 val_ptr_hash(void *v, Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { - case TYPE_VOID: return 0; case TYPE_UNKNOWN: return 0; case TYPE_BUILTIN: switch (t->builtin) { @@ -152,6 +149,8 @@ static U64 val_ptr_hash(void *v, Type *t) { return type_hash(*(Type **)v); case BUILTIN_NMS: return (U64)*(Namespace **)v; + case BUILTIN_VOID: + return 0; } assert(0); return 0; @@ -224,6 +223,7 @@ static bool val_ptr_eq(void *u, void *v, Type *t) { case BUILTIN_F64: return *(F64 *)u == *(F64 *)v; case BUILTIN_BOOL: return *(bool *)u == *(bool *)v; case BUILTIN_CHAR: return *(char *)u == *(char *)v; + case BUILTIN_VOID: return true; case BUILTIN_VARARGS: { VarArg *us = *(VarArg **)u, *vs = *(VarArg **)v; size_t n = arr_len(us); @@ -243,8 +243,6 @@ static bool val_ptr_eq(void *u, void *v, Type *t) { return *(Namespace **)u == *(Namespace **)v; } break; - case TYPE_VOID: - return true; case TYPE_UNKNOWN: return false; case TYPE_FN: @@ -8,11 +8,12 @@ /* @TODO: -&void null +fix eval pointer arithmetic - we're not multiplying by the size? fix including something twice - just use the non-namespacey version if it exists or pick one namespace to use everywhere otherwise - maybe store info about namespaces which are secretly the same as inline blocks/other namespaces in the Typer &&, || +#no_warn start making a standard library... (printf; stringbuilder would be nice to have) improve type_to_str: Foo ::= struct(t::Type) {} @@ -23,6 +24,7 @@ enums unions --- switch to / add as an alternative: libffi + - better yet, inline assembly don't bother generating ret_ if nothing's deferred X ::= newtype(int); or something any odd number of "s for a string @@ -170,6 +170,7 @@ static int kw_to_builtin_type(Keyword kw) { case KW_BOOL: return BUILTIN_BOOL; case KW_CHAR: return BUILTIN_CHAR; case KW_TYPE: return BUILTIN_TYPE; + case KW_VOID: return BUILTIN_VOID; case KW_NAMESPACE: return BUILTIN_NMS; /* don't allow .. => varargs because it's not a normal type */ default: return -1; @@ -192,6 +193,7 @@ static Keyword builtin_type_to_kw(BuiltinType t) { case BUILTIN_BOOL: return KW_BOOL; case BUILTIN_CHAR: return KW_CHAR; case BUILTIN_TYPE: return KW_TYPE; + case BUILTIN_VOID: return KW_VOID; case BUILTIN_NMS: return KW_NAMESPACE; case BUILTIN_VARARGS: return KW_DOTDOT; } @@ -203,8 +205,6 @@ static Keyword builtin_type_to_kw(BuiltinType t) { static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) { bool resolved = (t->flags & TYPE_IS_RESOLVED) != 0; switch (t->kind) { - case TYPE_VOID: - return str_copy(buffer, bufsize, "void"); case TYPE_UNKNOWN: return str_copy(buffer, bufsize, "???"); case TYPE_BUILTIN: { @@ -234,7 +234,7 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) { written += type_to_str_(¶m_types[i], buffer + written, bufsize - written); } written += str_copy(buffer + written, bufsize - written, ")"); - if (ret_type->kind != TYPE_VOID) { + if (!type_is_builtin(ret_type, BUILTIN_VOID)) { written += str_copy(buffer + written, bufsize - written, " "); written += type_to_str_(ret_type, buffer + written, bufsize - written); } @@ -550,7 +550,8 @@ static Status parse_type(Parser *p, Type *type, Location *where) { && t->token->kw != KW_LPAREN && t->token->kw != KW_AMPERSAND) || t->token->kw == KW_AS) { - ret_type->kind = TYPE_VOID; + ret_type->kind = TYPE_BUILTIN; + ret_type->builtin = BUILTIN_VOID; ret_type->flags = 0; } else { if (!parse_type(p, ret_type, NULL)) @@ -930,7 +931,8 @@ static Status parse_fn_expr(Parser *p, FnExpr *f) { if (token_is_kw(t->token, KW_LBRACE)) { /* void function */ - f->ret_type.kind = TYPE_VOID; + f->ret_type.kind = TYPE_BUILTIN; + f->ret_type.builtin = BUILTIN_VOID; f->ret_type.flags = 0; } else if (is_decl(t)) { if (!parse_decl_list(p, &f->ret_decls, DECL_CAN_END_WITH_LBRACE | DECL_CAN_END_WITH_COMMA)) @@ -943,7 +945,8 @@ static Status parse_fn_expr(Parser *p, FnExpr *f) { } --t->token; /* move back to { */ /* just set return type to void. the actual return type will be set by types.c:type_of_fn */ - f->ret_type.kind = TYPE_VOID; + f->ret_type.kind = TYPE_BUILTIN; + f->ret_type.builtin = BUILTIN_VOID; f->ret_type.flags = 0; } else { if (!parse_type(p, &f->ret_type, NULL)) { @@ -1088,11 +1091,12 @@ static Status ctype_to_type(Allocator *a, CType *ctype, Type *type, Location whe case CTYPE_DOUBLE: type->builtin = BUILTIN_F64; break; - case CTYPE_PTR: + case CTYPE_PTR: { type->kind = TYPE_PTR; - type->ptr = allocr_calloc(a, 1, sizeof *type->ptr); - type->ptr->kind = TYPE_VOID; - break; + Type *p = type->ptr = allocr_calloc(a, 1, sizeof *type->ptr); + p->kind = TYPE_BUILTIN; + p->builtin = BUILTIN_VOID; + } break; case CTYPE_UNSIGNED: assert(0); break; } if (size != 0) { @@ -1537,7 +1541,8 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { if (t->token == end) { /* void */ ret_ctype->kind = CTYPE_NONE; - ret_type->kind = TYPE_VOID; + ret_type->kind = TYPE_BUILTIN; + ret_type->builtin = BUILTIN_VOID; ret_type->flags = 0; } else { if (!parse_c_type(p, ret_ctype, ret_type)) @@ -1,11 +1,7 @@ #include "std/io.toc"; main ::= fn() { - #if "hello" { - x := 5; - } else { - x : FOOTYPE = 6.3 + "foo"; - _+3=bar; - } - puti(x); + x : &void = 18 as &&char; + puti(x as int); + } @@ -81,6 +81,9 @@ static void fprint_char_literal(FILE *f, char c) { static inline bool type_is_builtin(Type *t, BuiltinType b) { return t->kind == TYPE_BUILTIN && t->builtin == b; } +static inline bool type_is_void(Type *t) { + return t->kind == TYPE_BUILTIN && t->builtin == BUILTIN_VOID; +} static inline bool type_is_slicechar(Type *t) { return t->kind == TYPE_SLICE && type_is_builtin(t->slice, BUILTIN_CHAR); @@ -59,6 +59,7 @@ static size_t compiler_sizeof_builtin(BuiltinType b) { case BUILTIN_TYPE: return sizeof(Type *); case BUILTIN_NMS: return sizeof(Namespace *); case BUILTIN_VARARGS: return sizeof(VarArg *); + case BUILTIN_VOID: return 1; /* void ptr arithmetic */ } assert(0); return 0; @@ -80,6 +81,7 @@ static size_t compiler_alignof_builtin(BuiltinType b) { case BUILTIN_TYPE: return toc_alignof(Type *); case BUILTIN_NMS: return toc_alignof(Namespace *); case BUILTIN_VARARGS: return toc_alignof(VarArg *); + case BUILTIN_VOID: return 1; } assert(0); return 0; @@ -227,8 +229,6 @@ static size_t compiler_alignof(Type *t) { switch (t->kind) { case TYPE_BUILTIN: return compiler_alignof_builtin(t->builtin); - case TYPE_VOID: - return 1; case TYPE_FN: return toc_alignof(FnExpr *); case TYPE_PTR: @@ -277,7 +277,6 @@ static size_t compiler_sizeof(Type *t) { return SIZE_MAX; return t->struc->size; } break; - case TYPE_VOID: case TYPE_UNKNOWN: return 0; case TYPE_EXPR: @@ -359,7 +358,6 @@ static bool type_eq_exact(Type *a, Type *b) { if (a->kind != b->kind) return false; switch (a->kind) { - case TYPE_VOID: return true; case TYPE_UNKNOWN: return true; case TYPE_BUILTIN: return a->builtin == b->builtin; @@ -429,7 +427,7 @@ static bool type_eq_implicit(Type *a, Type *b) { } if (a->kind == TYPE_PTR) { /* &void casts to &anything */ - if (a->ptr->kind == TYPE_VOID || b->ptr->kind == TYPE_VOID) + if (type_is_builtin(a->ptr, BUILTIN_VOID) || type_is_builtin(b->ptr, BUILTIN_VOID)) return true; } return type_eq_exact(a, b); @@ -447,8 +445,13 @@ static Type *overriding_type(Type *a, Type *b) { } return b; } + if (b->flags & TYPE_IS_FLEXIBLE) return a; + + if (a->kind == TYPE_PTR && type_is_builtin(a->ptr, BUILTIN_VOID)) + return b; + /* doesn't matter */ return a; } @@ -530,7 +533,6 @@ static Status expr_must_lval(Expression *e, const char *purpose) { static bool type_is_compileonly(Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { - case TYPE_VOID: case TYPE_UNKNOWN: return false; case TYPE_BUILTIN: @@ -708,7 +710,7 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { } } - if (f->ret_decls && !generic && f->ret_type.kind == TYPE_VOID /* haven't found return type yet */) { + if (f->ret_decls && !generic && type_is_builtin(&f->ret_type, BUILTIN_VOID) /* haven't found return type yet */) { /* find return type */ arr_foreach(f->ret_decls, Declaration, d) { @@ -980,7 +982,6 @@ static Status type_resolve(Typer *tr, Type *t, Location where) { } } break; case TYPE_UNKNOWN: - case TYPE_VOID: case TYPE_BUILTIN: break; } @@ -993,7 +994,6 @@ static Status type_resolve(Typer *tr, Type *t, Location where) { static bool type_can_be_truthy(Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { - case TYPE_VOID: case TYPE_TUPLE: case TYPE_ARR: case TYPE_STRUCT: @@ -1007,6 +1007,7 @@ static bool type_can_be_truthy(Type *t) { switch (t->builtin) { case BUILTIN_TYPE: case BUILTIN_NMS: + case BUILTIN_VOID: return false; case BUILTIN_I8: case BUILTIN_U8: @@ -1045,7 +1046,6 @@ static CastStatus type_cast_status(Type *from, Type *to) { switch (from->kind) { case TYPE_UNKNOWN: return CAST_STATUS_NONE; case TYPE_STRUCT: - case TYPE_VOID: return CAST_STATUS_ERR; case TYPE_BUILTIN: switch (from->builtin) { @@ -1076,6 +1076,7 @@ static CastStatus type_cast_status(Type *from, Type *to) { case BUILTIN_TYPE: case BUILTIN_NMS: case BUILTIN_VARARGS: + case BUILTIN_VOID: return CAST_STATUS_ERR; } assert(0); @@ -1108,6 +1109,7 @@ static CastStatus type_cast_status(Type *from, Type *to) { case BUILTIN_TYPE: case BUILTIN_NMS: case BUILTIN_VARARGS: + case BUILTIN_VOID: return CAST_STATUS_ERR; } assert(0); @@ -1121,6 +1123,7 @@ static CastStatus type_cast_status(Type *from, Type *to) { case BUILTIN_TYPE: case BUILTIN_NMS: case BUILTIN_VARARGS: + case BUILTIN_VOID: return CAST_STATUS_ERR; } break; @@ -1206,7 +1209,7 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { success = false; goto ret; } - } else if (ret_type->kind != TYPE_VOID && !has_named_ret_vals) { + } else if (!type_is_builtin(ret_type, BUILTIN_VOID) && !has_named_ret_vals) { Statement *stmts = f->body.stmts; if (arr_len(stmts)) { Statement *last_stmt = (Statement *)stmts + (arr_len(stmts) - 1); @@ -2019,7 +2022,8 @@ static Status types_expr(Typer *tr, Expression *e) { goto for_fail; } - t->kind = TYPE_VOID; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_VOID; typer_block_exit(tr); }break; @@ -2173,7 +2177,7 @@ static Status types_expr(Typer *tr, Expression *e) { if (curr->body.ret_expr) { *t = curr->body.ret_expr->type; } else { - t->kind = TYPE_VOID; + t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_VOID; t->flags |= TYPE_IS_RESOLVED; } while (1) { @@ -2199,7 +2203,7 @@ static Status types_expr(Typer *tr, Expression *e) { if (nexti->body.ret_expr) { *next_type = nexti->body.ret_expr->type; } else { - next_type->kind = TYPE_VOID; + next_type->kind = TYPE_BUILTIN; next_type->builtin = BUILTIN_VOID; next_type->flags = TYPE_IS_RESOLVED; } if (!type_eq_implicit(next_type, curr_type)) { @@ -2217,7 +2221,7 @@ static Status types_expr(Typer *tr, Expression *e) { } } - if (!has_else && t->kind != TYPE_VOID) { + if (!has_else && !type_is_builtin(t, BUILTIN_VOID)) { err_print(e->where, "Non-void if block with no else."); return false; } @@ -2235,7 +2239,8 @@ static Status types_expr(Typer *tr, Expression *e) { err_print(w->body.ret_expr->where, "while loops can't return values -- you're missing a semicolon (;)"); return false; } - t->kind = TYPE_VOID; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_VOID; } break; case EXPR_CALL: { CallExpr *c = &e->call; @@ -2829,7 +2834,8 @@ static Status types_expr(Typer *tr, Expression *e) { if (b->ret_expr) { *t = b->ret_expr->type; } else { - t->kind = TYPE_VOID; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_VOID; } } break; case EXPR_C: { @@ -2931,10 +2937,6 @@ static Status types_expr(Typer *tr, Expression *e) { assert(0); /* types_expr is what makes things UNARY_LEN */ break; case UNARY_TYPEOF: { - if (of->type.kind == TYPE_VOID) { - err_print(of->where, "This has type void, but you're trying to apply typeof to it."); - return false; - } if (type_is_builtin(&of->type, BUILTIN_VARARGS)) { err_print(of->where, "You can't apply typeof to varargs."); return false; @@ -3061,7 +3063,8 @@ static Status types_expr(Typer *tr, Expression *e) { switch (o) { case BINARY_SET: /* type of x = y is always void */ - t->kind = TYPE_VOID; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_VOID; break; case BINARY_LT: case BINARY_GT: @@ -3094,7 +3097,7 @@ static Status types_expr(Typer *tr, Expression *e) { o == BINARY_SET_SUB || o == BINARY_SET_MUL || o == BINARY_SET_DIV) { - t->kind = TYPE_VOID; /* actually, it's just void */ + t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_VOID; /* actually, it's just void */ } break; @@ -3241,7 +3244,8 @@ static Status types_expr(Typer *tr, Expression *e) { /* allow access of slice pointer */ t->kind = TYPE_PTR; t->ptr = typer_calloc(tr, 1, sizeof *t->ptr); - t->ptr->kind = TYPE_VOID; + t->ptr->kind = TYPE_BUILTIN; + t->ptr->builtin = BUILTIN_VOID; t->ptr->flags = TYPE_IS_RESOLVED; break; } @@ -3396,7 +3400,7 @@ static Status types_block(Typer *tr, Block *b) { if (s->kind == STMT_EXPR && (s->flags & STMT_EXPR_NO_SEMICOLON)) { /* not voided */ Expression *e = s->expr; - if (e->type.kind == TYPE_VOID) { + if (type_is_builtin(&e->type, BUILTIN_VOID)) { if (!(e->kind == EXPR_BLOCK || e->kind == EXPR_IF || e->kind == EXPR_WHILE @@ -3427,6 +3431,7 @@ static Status types_block(Typer *tr, Block *b) { } static Status types_decl(Typer *tr, Declaration *d) { + Type *dtype = &d->type; if (d->flags & DECL_FOUND_TYPE) return true; bool success = true; @@ -3438,15 +3443,14 @@ static Status types_decl(Typer *tr, Declaration *d) { } if (d->flags & DECL_INFER) { - d->type.kind = TYPE_UNKNOWN; - d->type.flags = 0; + dtype->kind = TYPE_UNKNOWN; + dtype->flags = 0; return true; } typer_arr_add(tr, tr->in_decls, d); if (d->flags & DECL_ANNOTATES_TYPE) { /* type supplied */ - assert(d->type.kind != TYPE_VOID); /* there's no way to annotate void */ - if (!type_resolve(tr, &d->type, d->where)) { + if (!type_resolve(tr, dtype, d->where)) { success = false; goto ret; } @@ -3458,8 +3462,8 @@ static Status types_decl(Typer *tr, Declaration *d) { } assert(d->expr.type.flags & TYPE_IS_RESOLVED); if (d->flags & DECL_ANNOTATES_TYPE) { - if (!type_eq_implicit(&d->expr.type, &d->type)) { - char *decl_type = type_to_str(&d->type), + if (!type_eq_implicit(&d->expr.type, dtype)) { + char *decl_type = type_to_str(dtype), *expr_type = type_to_str(&d->expr.type); err_print(d->expr.where, "Declaration type %s does not match expression type %s.", decl_type, expr_type); free(decl_type); free(expr_type); @@ -3467,14 +3471,14 @@ static Status types_decl(Typer *tr, Declaration *d) { goto ret; } } else { - if (d->expr.type.kind == TYPE_VOID) { + if (type_is_void(&d->expr.type)) { /* e.g. x := (fn(){})(); */ err_print(d->expr.where, "Use of void value."); success = false; goto ret; } - d->type = d->expr.type; - d->type.flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; /* x := 5; => x is not flexible */ + *dtype = d->expr.type; + dtype->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; /* x := 5; => x is not flexible */ } bool need_value = (d->flags & DECL_IS_CONST) || !tr->block || tr->block->kind == BLOCK_NMS; if (need_value) { @@ -3484,26 +3488,62 @@ static Status types_decl(Typer *tr, Declaration *d) { success = false; goto ret; } - copy_val(tr->allocr, &d->val, val, &d->type); + copy_val(tr->allocr, &d->val, val, dtype); d->flags |= DECL_FOUND_VAL; } } } + + size_t n_idents; n_idents = arr_len(d->idents); + + if (type_is_compileonly(dtype)) { + if (!(d->flags & DECL_IS_CONST)) { + char *s = type_to_str(dtype); + err_print(d->where, "Declarations with type %s must be constant.", s); + free(s); + success = false; + goto ret; + } + } - for (size_t i = 0; i < arr_len(d->idents); ++i) { - Type *t = d->type.kind == TYPE_TUPLE ? &d->type.tuple[i] : &d->type; - if (type_is_compileonly(&d->type)) { - if (!(d->flags & DECL_IS_CONST)) { - char *s = type_to_str(&d->type); - err_print(d->where, "Declarations with type %s must be constant.", s); - free(s); - success = false; - goto ret; - } + if (dtype->kind == TYPE_TUPLE) { + if (n_idents != arr_len(dtype->tuple)) { + err_print(d->where, "Expected to have %lu things declared in declaration, but got %lu.", (unsigned long)arr_len(dtype->tuple), (unsigned long)n_idents); + success = false; + goto ret; + } + } + if (dtype->kind == TYPE_UNKNOWN) { + if (!d->where.file->ctx->have_errored) /* don't do an error if we haven't already done one, because it might be because of that */ + err_print(d->where, "Can't determine type of declaration."); + success = false; + goto ret; + } + if (dtype->kind == TYPE_BUILTIN) { + if (dtype->builtin == BUILTIN_VARARGS && !(d->flags & DECL_IS_PARAM)) { + err_print(d->where, "Only parameters can be varargs."); + success = false; + goto ret; + } else if (dtype->builtin == BUILTIN_VOID) { + err_print(d->where, "The type of a declaration can't be void."); + success = false; + goto ret; } + } + if (d->flags & DECL_IS_CONST) { + if (dtype->kind == TYPE_PTR) { + err_print(d->where, "You can't have a constant pointer."); + success = false; + goto ret; + } + } + + + for (int i = 0, len = (int)n_idents; i < len; ++i) { + Type *t = decl_type_at_index(d, i); if (type_is_builtin(t, BUILTIN_TYPE)) { if (d->flags & DECL_HAS_EXPR) { - Value *val = d->type.kind == TYPE_TUPLE ? &d->val.tuple[i] : &d->val; + Value *val = decl_val_at_index(d, i); if (val->type->kind == TYPE_STRUCT && val->type->struc->params) { /* don't resolve it because it's not really complete */ } else { @@ -3522,34 +3562,7 @@ static Status types_decl(Typer *tr, Declaration *d) { t->fn.constness = NULL; } } - - size_t n_idents; n_idents = arr_len(d->idents); - if (d->type.kind == TYPE_TUPLE) { - if (n_idents != arr_len(d->type.tuple)) { - err_print(d->where, "Expected to have %lu things declared in declaration, but got %lu.", (unsigned long)arr_len(d->type.tuple), (unsigned long)n_idents); - success = false; - goto ret; - } - } - if (d->type.kind == TYPE_UNKNOWN) { - if (!d->where.file->ctx->have_errored) /* don't do an error if we haven't already done one, because it might be because of that */ - err_print(d->where, "Can't determine type of declaration."); - success = false; - goto ret; - } - if (type_is_builtin(&d->type, BUILTIN_VARARGS) && !(d->flags & DECL_IS_PARAM)) { - err_print(d->where, "Only parameters can be varargs."); - success = false; - goto ret; - } - if (d->flags & DECL_IS_CONST) { - if (d->type.kind == TYPE_PTR) { - err_print(d->where, "You can't have a constant pointer."); - success = false; - goto ret; - } - } - + if (d->flags & DECL_USE) { int idx = 0; if (arr_len(d->idents) > 1) { @@ -3585,8 +3598,8 @@ static Status types_decl(Typer *tr, Declaration *d) { d->flags |= DECL_FOUND_TYPE; if (!success) { /* use unknown type if we didn't get the type */ - d->type.flags = TYPE_IS_RESOLVED; - d->type.kind = TYPE_UNKNOWN; + dtype->flags = TYPE_IS_RESOLVED; + dtype->kind = TYPE_UNKNOWN; } arr_remove_lasta(tr->in_decls, tr->allocr); return success; @@ -3700,7 +3713,7 @@ static Status types_stmt(Typer *tr, Statement *s) { } r->referring_to = &tr->fn->body; if (r->flags & RET_HAS_EXPR) { - if (tr->fn->ret_type.kind == TYPE_VOID) { + if (type_is_void(&tr->fn->ret_type)) { err_print(s->where, "Return value in a void function."); return false; } @@ -3717,8 +3730,7 @@ static Status types_stmt(Typer *tr, Statement *s) { return false; } } else { - if (tr->fn->ret_type.kind != TYPE_VOID - && !tr->fn->ret_decls) { + if (type_is_void(&tr->fn->ret_type) && !tr->fn->ret_decls) { err_print(s->where, "No return value in non-void function."); return false; } @@ -303,6 +303,7 @@ typedef enum { KW_FLOAT, KW_F32, KW_F64, + KW_VOID, KW_TYPE, KW_NAMESPACE, KW_CHAR, @@ -326,8 +327,8 @@ static const char *const keywords[KW_COUNT] = { "if", "elif", "else", "while", "for", "return", "break", "continue", "defer", "fn", "as", "struct", "int", "i8", "i16", "i32", "i64", - "u8", "u16", "u32", "u64", "float", "f32", "f64", "Type", - "Namespace", "char", "bool", "true", "false", "nms", "use", + "u8", "u16", "u32", "u64", "float", "f32", "f64", "void", + "Type", "Namespace", "char", "bool", "true", "false", "nms", "use", "typeof", "sizeof", "alignof" }; @@ -398,7 +399,6 @@ typedef struct Tokenizer { typedef enum { TYPE_UNKNOWN, - TYPE_VOID, TYPE_BUILTIN, TYPE_FN, TYPE_TUPLE, @@ -426,7 +426,8 @@ typedef enum { BUILTIN_BOOL, BUILTIN_TYPE, BUILTIN_VARARGS, - BUILTIN_NMS + BUILTIN_NMS, + BUILTIN_VOID } BuiltinType; |