summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c21
-rw-r--r--copy.c2
-rw-r--r--eval.c103
-rw-r--r--foreign.c10
-rw-r--r--infer.c1
-rw-r--r--instance_table.c10
-rw-r--r--main.c4
-rw-r--r--parse.c27
-rw-r--r--test.toc10
-rw-r--r--toc.c3
-rw-r--r--types.c170
-rw-r--r--types.h9
12 files changed, 188 insertions, 182 deletions
diff --git a/cgen.c b/cgen.c
index 5927858..188a16e 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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_;");
diff --git a/copy.c b/copy.c
index 05b1eea..e34036c 100644
--- a/copy.c
+++ b/copy.c
@@ -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:
diff --git a/eval.c b/eval.c
index cda97da..1a2451d 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
}
diff --git a/foreign.c b/foreign.c
index 788f87b..65de87b 100644
--- a/foreign.c
+++ b/foreign.c
@@ -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:
diff --git a/infer.c b/infer.c
index 8367dce..0bf5e0f 100644
--- a/infer.c
+++ b/infer.c
@@ -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:
diff --git a/main.c b/main.c
index 704b534..0b2fd5c 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/parse.c b/parse.c
index 3780b40..b06e0e1 100644
--- a/parse.c
+++ b/parse.c
@@ -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_(&param_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))
diff --git a/test.toc b/test.toc
index 822084b..891b513 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
+
}
diff --git a/toc.c b/toc.c
index 6089c20..954f357 100644
--- a/toc.c
+++ b/toc.c
@@ -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);
diff --git a/types.c b/types.c
index 22126a0..a3fb651 100644
--- a/types.c
+++ b/types.c
@@ -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;
}
diff --git a/types.h b/types.h
index f3fff36..8ceaa32 100644
--- a/types.h
+++ b/types.h
@@ -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;