diff options
-rw-r--r-- | README.html | 2 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rwxr-xr-x | build.sh | 2 | ||||
-rw-r--r-- | cgen.c | 69 | ||||
-rw-r--r-- | copy.c | 6 | ||||
-rw-r--r-- | decls_cgen.c | 2 | ||||
-rw-r--r-- | err.c | 3 | ||||
-rw-r--r-- | eval.c | 73 | ||||
-rw-r--r-- | infer.c | 5 | ||||
-rw-r--r-- | instance_table.c | 29 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | package.c | 28 | ||||
-rw-r--r-- | parse.c | 18 | ||||
-rwxr-xr-x | test-build.sh | 2 | ||||
-rw-r--r-- | test.toc | 7 | ||||
-rw-r--r-- | toc.c | 8 | ||||
-rw-r--r-- | tokenizer.c | 3 | ||||
-rw-r--r-- | typedefs_cgen.c | 4 | ||||
-rw-r--r-- | types.c | 183 | ||||
-rw-r--r-- | types.h | 9 |
20 files changed, 254 insertions, 203 deletions
diff --git a/README.html b/README.html index 3b4bc57..32673e4 100644 --- a/README.html +++ b/README.html @@ -74,7 +74,7 @@ it is nearly as fast in theory.</p> <ul> <li>Anonymous structures/unions</li> -<li><code>max_align_t</code> and <code>alignof</code> - It can still compile without these but it won’t technically be standard-compliant</li> +<li><code>max_align_t</code> - It can still compile without this, and will almost definitely work, but it won’t technically be standard-compliant</li> </ul> @@ -64,7 +64,7 @@ Here are all the C99 features which `toc` depends on (I might have forgotten som And here are all of its C11 features: - Anonymous structures/unions -- `max_align_t` and `alignof` - It can still compile without these but it won't technically be standard-compliant +- `max_align_t` - It can still compile without this, and will almost definitely work, but it won't technically be standard-compliant #### More @@ -27,7 +27,7 @@ RELEASE_FLAGS="-O3 -s -DNDEBUG $WARNINGS -std=c11" if [ "$1" = "release" ]; then FLAGS="$RELEASE_FLAGS $ADDITIONAL_FLAGS" - COMMAND="$CC compatibility.c -Wall -Wextra -std=c99 -Wpedantic -o compatibility" + COMMAND="$CC compatibility.c -Wall -Wextra -o compatibility" echo $COMMAND $COMMAND || exit 1 FLAGS="$FLAGS $(./compatibility)" @@ -187,8 +187,6 @@ static bool cgen_defs_decl(CGenerator *g, Declaration *d); break; \ case TYPE_VOID: \ case TYPE_BUILTIN: \ - case TYPE_PKG: \ - case TYPE_TYPE: \ case TYPE_UNKNOWN: \ break; \ case TYPE_EXPR: assert(0); \ @@ -278,10 +276,8 @@ static bool cgen_uses_ptr(Type *t) { case TYPE_SLICE: case TYPE_VOID: case TYPE_UNKNOWN: - case TYPE_TYPE: return false; case TYPE_EXPR: - case TYPE_PKG: break; } assert(0); @@ -332,6 +328,9 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { 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_TYPE: + case BUILTIN_PKG: + assert(0); break; } break; case TYPE_PTR: if (!cgen_type_pre(g, t->ptr, where)) @@ -370,9 +369,7 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { } break; case TYPE_TUPLE: - case TYPE_TYPE: case TYPE_EXPR: - case TYPE_PKG: /* We should never try to generate this type */ assert(0); return false; @@ -441,12 +438,10 @@ static bool cgen_type_post(CGenerator *g, Type *t, Location where) { case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_TUPLE: - case TYPE_TYPE: case TYPE_SLICE: case TYPE_STRUCT: break; case TYPE_EXPR: - case TYPE_PKG: assert(0); break; } @@ -465,53 +460,15 @@ static inline void cgen_fn_instance_number(CGenerator *g, U64 instance) { cgen_write(g, U64_FMT"_", instance); } -/* does this type have a Type or a Package in it? (e.g. [5]Type, &&Package) */ -static bool type_contains_compileonly_type(Type *t) { - assert(t->flags & TYPE_IS_RESOLVED); - switch (t->kind) { - case TYPE_BUILTIN: - case TYPE_VOID: - case TYPE_UNKNOWN: - return false; - case TYPE_PKG: - case TYPE_TYPE: - return true; - case TYPE_PTR: - return type_contains_compileonly_type(t->ptr); - case TYPE_SLICE: - return type_contains_compileonly_type(t->slice); - case TYPE_ARR: - return type_contains_compileonly_type(t->arr.of); - case TYPE_FN: - arr_foreach(t->fn.types, Type, sub) - if (type_contains_compileonly_type(sub)) - return true; - return false; - case TYPE_TUPLE: - arr_foreach(t->tuple, Type, sub) - if (type_contains_compileonly_type(sub)) - return true; - return false; - case TYPE_STRUCT: - arr_foreach(t->struc->fields, Field, f) - if (type_contains_compileonly_type(f->type)) - return true; - return false; - case TYPE_EXPR: break; - } - assert(0); - return false; -} - /* should we generate this function? (or is it just meant for compile time) */ static bool cgen_should_gen_fn(FnExpr *f) { if (f->ret_decls) { arr_foreach(f->ret_decls, Declaration, decl) - if (type_contains_compileonly_type(&decl->type)) + if (type_is_compileonly(&decl->type)) return false; return true; } else { - return !type_contains_compileonly_type(&f->ret_type); + return !type_is_compileonly(&f->ret_type); } } @@ -669,9 +626,7 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E return false; break; case TYPE_VOID: - case TYPE_TYPE: case TYPE_EXPR: - case TYPE_PKG: assert(0); return false; } @@ -1567,12 +1522,10 @@ static void cgen_zero_value(CGenerator *g, Type *t) { case TYPE_STRUCT: cgen_write(g, "{0}"); break; - case TYPE_TYPE: case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_TUPLE: case TYPE_EXPR: - case TYPE_PKG: assert(0); break; } @@ -1605,7 +1558,7 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, U64 instance, Valu Type *type = param->type.kind == TYPE_TUPLE ? ¶m->type.tuple[i] : ¶m->type; Value arg = compile_time_args[carg_idx]; - if (type->kind == TYPE_TYPE) { + if (type_is_builtin(type, BUILTIN_TYPE)) { /* don't need to do anything; we'll just use the type's id */ } else { if (!cgen_val_pre(g, arg, type, where)) @@ -1708,7 +1661,6 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) { } break; case TYPE_FN: - case TYPE_TYPE: case TYPE_UNKNOWN: case TYPE_TUPLE: case TYPE_VOID: @@ -1717,7 +1669,6 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) { case TYPE_STRUCT: break; case TYPE_EXPR: - case TYPE_PKG: assert(0); return false; } @@ -1731,8 +1682,6 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { case TYPE_TUPLE: case TYPE_VOID: case TYPE_EXPR: - case TYPE_TYPE: - case TYPE_PKG: assert(0); return false; case TYPE_UNKNOWN: @@ -1779,6 +1728,10 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { case BUILTIN_F64: cgen_write(g, F64_FMT, *(F64 *)v); break; case BUILTIN_CHAR: cgen_write(g, "'\\x%02x'", *(char *)v); break; case BUILTIN_BOOL: cgen_write(g, "%s", *(bool *)v ? "true" : "false"); break; + case BUILTIN_TYPE: + case BUILTIN_PKG: + assert(0); + break; } break; } @@ -1804,7 +1757,7 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { Identifier i = d->idents[idx]; Type *type = decl_type_at_index(d, idx); Value *val = decl_val_at_index(d, idx); - if (type_contains_compileonly_type(type)) { + if (type_is_compileonly(type)) { continue; } if (g->block == NULL && g->fn == NULL && !i->export_name) @@ -38,8 +38,6 @@ static void copy_val(Allocator *a, Value *out, Value *in, Type *t) { case TYPE_SLICE: case TYPE_VOID: case TYPE_UNKNOWN: - case TYPE_PKG: - case TYPE_TYPE: *out = *in; break; case TYPE_ARR: { @@ -63,7 +61,7 @@ static void copy_val(Allocator *a, Value *out, Value *in, Type *t) { } static void copy_val_full(Copier *c, Value *out, Value *in, Type *t) { - if (t->kind == TYPE_TYPE) { + if (type_is_builtin(t, BUILTIN_TYPE)) { Type *new_type = allocr_malloc(c->allocr, sizeof *new_type); copy_type(c, new_type, in->type); out->type = new_type; @@ -77,8 +75,6 @@ static void copy_type(Copier *c, Type *out, Type *in) { *out = *in; switch (in->kind) { case TYPE_BUILTIN: - case TYPE_TYPE: - case TYPE_PKG: case TYPE_VOID: case TYPE_UNKNOWN: break; diff --git a/decls_cgen.c b/decls_cgen.c index 728d83e..e8f7cca 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -152,7 +152,7 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) { for (int i = 0, n_idents = (int)arr_len(d->idents); i < n_idents; ++i) { Identifier ident = d->idents[i]; Type *type = decl_type_at_index(d, i); - if (!type_contains_compileonly_type(type)) { + if (!type_is_compileonly(type)) { if (ident->export_name) cgen_write(g, "extern "); else @@ -187,6 +187,9 @@ static void err_print_footer_(Location where) { static void err_vprint(Location where, const char *fmt, va_list args) { if (location_is_ctx_disabled(where)) return; + if (where.start) { + where.start->pos.ctx->have_errored = true; + } err_print_header_(where); err_vfprint(fmt, args); err_print_footer_(where); @@ -50,6 +50,8 @@ static size_t compiler_sizeof_builtin(BuiltinType b) { case BUILTIN_F64: return sizeof(F64); case BUILTIN_CHAR: return sizeof(char); /* = 1 */ case BUILTIN_BOOL: return sizeof(bool); + case BUILTIN_TYPE: return sizeof(Type *); + case BUILTIN_PKG: return sizeof(Package *); } assert(0); return 0; @@ -101,10 +103,6 @@ static size_t compiler_alignof(Type *t) { return sizeof(void *); else return sizeof(size_t); - case TYPE_TYPE: - return sizeof v.type; - case TYPE_PKG: - return sizeof v.pkg; case TYPE_STRUCT: { /* assume the align of a struct is (at most) the greatest align out of its children's */ eval_struct_find_offsets(t); @@ -135,10 +133,6 @@ static size_t compiler_sizeof(Type *t) { return sizeof v.tuple; case TYPE_SLICE: return sizeof v.slice; - case TYPE_TYPE: - return sizeof v.type; - case TYPE_PKG: - return sizeof v.pkg; case TYPE_STRUCT: { eval_struct_find_offsets(t); return t->struc->size; @@ -167,6 +161,9 @@ static bool builtin_truthiness(Value *v, BuiltinType b) { case BUILTIN_F64: return v->f64 != 0; case BUILTIN_BOOL: return v->boolv; case BUILTIN_CHAR: return v->charv != 0; + case BUILTIN_TYPE: + case BUILTIN_PKG: + break; } assert(0); return false; } @@ -181,11 +178,9 @@ static bool val_truthiness(Value *v, Type *t) { case TYPE_FN: return v->fn != NULL; case TYPE_ARR: return t->arr.n > 0; case TYPE_SLICE: return v->slice.n > 0; - case TYPE_TYPE: case TYPE_TUPLE: case TYPE_STRUCT: case TYPE_EXPR: - case TYPE_PKG: break; } assert(0); @@ -256,9 +251,7 @@ static void *val_get_ptr(Value *v, Type *t) { case TYPE_UNKNOWN: case TYPE_FN: case TYPE_SLICE: - case TYPE_TYPE: case TYPE_TUPLE: - case TYPE_PKG: return v; case TYPE_ARR: return v->arr; @@ -293,6 +286,13 @@ 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_PKG: { + Package *pkg = *(Package **)p; + fprintf(f, "<package at %p>", (void *)pkg); + } break; + case BUILTIN_TYPE: + fprint_type(f, *(Type **)p); + break; } break; case TYPE_FN: @@ -323,10 +323,6 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) { case TYPE_PTR: fprintf(f, "<pointer: %p>", *(void **)p); break; - case TYPE_PKG: { - Package *pkg = *(Package **)p; - fprintf(f, "<package at %p>", (void *)pkg); - } break; case TYPE_SLICE: { fprintf(f, "["); /* TODO: change? when slice initializers are added */ Slice slice = *(Slice *)p; @@ -341,9 +337,6 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) { } fprintf(f, "]"); } break; - case TYPE_TYPE: - fprint_type(f, *(Type **)p); - break; case TYPE_STRUCT: fprintf(f, "["); /* TODO: change? when struct initializers are added */ arr_foreach(t->struc->fields, Field, fi) { @@ -378,8 +371,6 @@ static void *val_ptr_to_free(Value *v, Type *t) { case TYPE_PTR: case TYPE_SLICE: case TYPE_VOID: - case TYPE_TYPE: - case TYPE_PKG: case TYPE_UNKNOWN: return NULL; case TYPE_ARR: @@ -429,6 +420,7 @@ static void val_free(Value *v, Type *t) { 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_PKG: case BUILTIN_TYPE: assert(0); break; \ } break #define builtin_float_casts(low, up) \ @@ -437,6 +429,7 @@ static void val_free(Value *v, Type *t) { builtin_casts_to_num(low); \ case BUILTIN_BOOL: vout->boolv = vin->low != 0.0f; break; \ case BUILTIN_CHAR: \ + case BUILTIN_PKG: case BUILTIN_TYPE: \ assert(0); break; \ } break @@ -465,9 +458,15 @@ static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinT case BUILTIN_F32: case BUILTIN_F64: case BUILTIN_BOOL: + case BUILTIN_TYPE: + case BUILTIN_PKG: assert(0); break; } break; + case BUILTIN_TYPE: + case BUILTIN_PKG: + assert(0); + break; } } @@ -484,10 +483,8 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_TUPLE: - case TYPE_TYPE: case TYPE_STRUCT: case TYPE_EXPR: - case TYPE_PKG: assert(0); break; case TYPE_BUILTIN: switch (to->kind) { @@ -515,8 +512,6 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_TUPLE: case TYPE_FN: case TYPE_ARR: - case TYPE_TYPE: - case TYPE_PKG: assert(0); break; } @@ -544,6 +539,8 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case BUILTIN_CHAR: case BUILTIN_F32: case BUILTIN_F64: + case BUILTIN_TYPE: + case BUILTIN_PKG: assert(0); break; } break; @@ -615,17 +612,17 @@ static void eval_deref(Value *v, void *ptr, Type *type) { case BUILTIN_F64: v->f64 = *(F64 *)ptr; break; case BUILTIN_CHAR: v->charv = *(char *)ptr; break; case BUILTIN_BOOL: v->boolv = *(bool *)ptr; break; + case BUILTIN_TYPE: + v->type = *(Type **)ptr; + break; + case BUILTIN_PKG: + v->pkg = *(Package **)ptr; + break; } break; case TYPE_SLICE: v->slice = *(Slice *)ptr; break; - case TYPE_TYPE: - v->type = *(Type **)ptr; - break; - case TYPE_PKG: - v->pkg = *(Package **)ptr; - break; case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_EXPR: @@ -656,17 +653,17 @@ static void eval_deref_set(void *set, Value *to, Type *type) { case BUILTIN_F64: *(F64 *)set = to->f64; break; case BUILTIN_CHAR: *(char *)set = to->charv; break; case BUILTIN_BOOL: *(bool *)set = to->boolv; break; + case BUILTIN_TYPE: + *(Type **)set = to->type; + break; + case BUILTIN_PKG: + *(Package **)set = to->pkg; + break; } break; case TYPE_SLICE: *(Slice *)set = to->slice; break; - case TYPE_TYPE: - *(Type **)set = to->type; - break; - case TYPE_PKG: - *(Package **)set = to->pkg; - break; case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_EXPR: @@ -1030,7 +1027,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { switch (e->unary.op) { case UNARY_ADDRESS: { Expression *o = e->unary.of; - if (o->type.kind == TYPE_TYPE) { + if (type_is_builtin(&o->type, BUILTIN_TYPE)) { if (!eval_expr(ev, e->unary.of, &of)) return false; /* "address" of type (pointer to type) */ v->type = evalr_malloc(ev, sizeof *v->type); /* TODO: this might be bad in the future; should free this at some point */ @@ -83,8 +83,6 @@ static bool infer_from_type(Typer *tr, Type *match, Type *to, Identifier *idents case TYPE_VOID: case TYPE_UNKNOWN: case TYPE_BUILTIN: - case TYPE_TYPE: - case TYPE_PKG: break; /* nothing we can do here */ case TYPE_TUPLE: { if (to->kind != TYPE_TUPLE) return true; @@ -137,7 +135,8 @@ static bool infer_from_type(Typer *tr, Type *match, Type *to, Identifier *idents e.flags = EXPR_FOUND_TYPE; Type *type = &e.type; type->flags = TYPE_IS_RESOLVED; - type->kind = TYPE_TYPE; + type->kind = TYPE_BUILTIN; + type->builtin = BUILTIN_TYPE; if (!to_expr) { to_expr = &e; } diff --git a/instance_table.c b/instance_table.c index b2a4c01..0e5827f 100644 --- a/instance_table.c +++ b/instance_table.c @@ -85,8 +85,7 @@ static U64 type_hash(Type *t) { 0x50da97f1211b2423, 0xc3977306abd0ae6c, 0x87ea684427e1c521, - 0xcee5fd6d6cbdfe23, - 0xd80dd2469d6e7c1b + 0xcee5fd6d6cbdfe23 }; U64 hash = starters[t->kind]; assert(t->flags & TYPE_IS_RESOLVED); @@ -95,8 +94,6 @@ static U64 type_hash(Type *t) { return hash + (U64)t->builtin * 0x1307787dfff73417; case TYPE_VOID: case TYPE_UNKNOWN: - case TYPE_TYPE: - case TYPE_PKG: return hash; case TYPE_TUPLE: arr_foreach(t->tuple, Type, sub) @@ -144,6 +141,12 @@ static U64 val_ptr_hash(void *v, Type *t) { case BUILTIN_F64: return f64_hash(*(F64 *)v); case BUILTIN_CHAR: return (U64)*(char *)v; case BUILTIN_BOOL: return (U64)*(bool *)v; + case BUILTIN_TYPE: + return type_hash(*(Type **)v); + case BUILTIN_PKG: { + Package *pkg = *(Package **)v; + return (U64)pkg; + } break; } assert(0); return 0; @@ -159,8 +162,6 @@ static U64 val_ptr_hash(void *v, Type *t) { return hash; } case TYPE_PTR: return (U64)*(void **)v; - case TYPE_TYPE: - return type_hash(*(Type **)v); case TYPE_ARR: { U32 x = 1; U64 hash = 0; @@ -191,10 +192,6 @@ static U64 val_ptr_hash(void *v, Type *t) { } return hash; } - case TYPE_PKG: { - Package *pkg = *(Package **)v; - return (U64)pkg; - } break; case TYPE_EXPR: break; } assert(0); @@ -222,6 +219,12 @@ 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_TYPE: { + bool ret = type_eq(*(Type **)u, *(Type **)v); + return ret; + } + case BUILTIN_PKG: + return *(Package **)u == *(Package **)v; } break; case TYPE_VOID: @@ -232,10 +235,6 @@ static bool val_ptr_eq(void *u, void *v, Type *t) { return *(FnExpr **)u == *(FnExpr **)v; case TYPE_PTR: return *(void **)u == *(void **)v; - case TYPE_TYPE: { - bool ret = type_eq(*(Type **)u, *(Type **)v); - return ret; - } case TYPE_TUPLE: { Value *us = *(Value **)u; Value *vs = *(Value **)v; @@ -276,8 +275,6 @@ static bool val_ptr_eq(void *u, void *v, Type *t) { return false; } return true; - case TYPE_PKG: - return *(Package **)u == *(Package **)v; case TYPE_EXPR: break; } assert(0); @@ -117,7 +117,7 @@ int main(int argc, char **argv) { Evaluator ev; Exporter exptr; evalr_create(&ev, &tr, &main_allocr); - typer_create(&tr, &ev, &main_allocr, &idents); + typer_create(&tr, &ev, &err_ctx, &main_allocr, &idents); tr.exptr = &exptr; if (!block_enter(NULL, f.stmts, SCOPE_CHECK_REDECL)) /* enter global scope */ @@ -226,18 +226,18 @@ static bool import_pkg(Allocator *allocr, Package *p, FILE *f, const char *fname static bool export_type(Exporter *ex, Type *type, Location where) { assert(type->flags & TYPE_IS_RESOLVED); - export_u8(ex, (U8)type->kind); + if (type->kind == TYPE_BUILTIN) { + export_u8(ex, (U8)(type->builtin + TYPE_COUNT)); + } else { + export_u8(ex, (U8)type->kind); + } switch (type->kind) { case TYPE_VOID: - case TYPE_TYPE: - case TYPE_PKG: case TYPE_UNKNOWN: + case TYPE_BUILTIN: break; case TYPE_PTR: export_type(ex, type->ptr, where); break; case TYPE_SLICE: export_type(ex, type->slice, where); break; - case TYPE_BUILTIN: - export_u8(ex, (U8)type->builtin); - break; case TYPE_TUPLE: export_len(ex, arr_len(type->tuple)); arr_foreach(type->tuple, Type, sub) @@ -316,6 +316,14 @@ static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where) case BUILTIN_F64: export_f64(ex, *(F64 *)val); break; case BUILTIN_BOOL: export_bool(ex, *(bool *)val); break; case BUILTIN_CHAR: export_char(ex, *(char *)val); break; + case BUILTIN_TYPE: + if (!export_type(ex, *(Type **)val, where)) + return false; + break; + case BUILTIN_PKG: { + Package *pkg = *(Package **)val; + export_ident(ex, pkg->name); + } break; } break; case TYPE_TUPLE: { @@ -326,10 +334,6 @@ static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where) return false; } } break; - case TYPE_TYPE: - if (!export_type(ex, *(Type **)val, where)) - return false; - break; case TYPE_PTR: err_print(where, "Cannot export pointer."); return false; @@ -365,10 +369,6 @@ static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where) if (!export_fn_ptr(ex, *(FnExpr **)val, where)) return false; break; - case TYPE_PKG: { - Package *pkg = *(Package **)val; - export_ident(ex, pkg->name); - } break; case TYPE_UNKNOWN: case TYPE_EXPR: assert(0); @@ -151,6 +151,8 @@ static int kw_to_builtin_type(Keyword kw) { case KW_F64: return BUILTIN_F64; case KW_BOOL: return BUILTIN_BOOL; case KW_CHAR: return BUILTIN_CHAR; + case KW_PACKAGE: return BUILTIN_PKG; + case KW_TYPE: return BUILTIN_TYPE; default: return -1; } return -1; @@ -170,6 +172,8 @@ static Keyword builtin_type_to_kw(BuiltinType t) { case BUILTIN_F64: return KW_F64; case BUILTIN_BOOL: return KW_BOOL; case BUILTIN_CHAR: return KW_CHAR; + case BUILTIN_PKG: return KW_PACKAGE; + case BUILTIN_TYPE: return KW_TYPE; } assert(0); return KW_COUNT; @@ -265,10 +269,6 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) { written += type_to_str_(t->ptr, buffer + written, bufsize - written); return written; } - case TYPE_TYPE: - return str_copy(buffer, bufsize, "Type"); - case TYPE_PKG: - return str_copy(buffer, bufsize, "pkg"); case TYPE_EXPR: /* TODO: improve this... we're gonna need expr_to_str ): */ return str_copy(buffer, bufsize, "<type expression>"); @@ -455,10 +455,6 @@ static bool parse_type(Parser *p, Type *type) { } /* Not a builtin */ switch (t->token->kw) { - case KW_TYPE: - type->kind = TYPE_TYPE; - ++t->token; - break; case KW_FN: { /* function type */ type->kind = TYPE_FN; @@ -1875,6 +1871,12 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 fla } d->where.end = t->token; + switch (ends_with) { + case DECL_END_RPAREN_COMMA: + case DECL_END_LBRACE_COMMA: + --d->where.end; /* don't include the ) / { as part of the declaration */ + case DECL_END_SEMICOLON: break; + } return true; diff --git a/test-build.sh b/test-build.sh index d03eff1..38f667a 100755 --- a/test-build.sh +++ b/test-build.sh @@ -1,8 +1,8 @@ #!/bin/sh -./build.sh release || exit 1 for CC in tcc gcc clang g++ ; do CC="$CC" ./build.sh || exit 1 CC="$CC" ./build.sh release || exit 1 done +./build.sh release || exit 1 ./build.sh || exit 1 @@ -7,9 +7,8 @@ putf ::= fn(x: float) { "); }; point ::= pkg "point"; -main ::= fn() { - x := fahfsdkjahksjdfh; -fahfsdkjahksjdfh := -5; +main ::= fn() { +f::=fn(t::Type)Type {t}; +x:f(int) = 5; };
\ No newline at end of file @@ -45,6 +45,13 @@ 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_slicechar(Type *t) { + return t->kind == TYPE_SLICE && type_is_builtin(t->slice, BUILTIN_CHAR); +} /* utilities */ #include "allocator.c" @@ -57,6 +64,7 @@ static void fprint_char_literal(FILE *f, char c) { #include "copy.c" #include "binfile.c" + #include "identifiers.c" #include "tokenizer.c" #include "parse.c" diff --git a/tokenizer.c b/tokenizer.c index 5c46ec8..d7a7b1e 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -3,7 +3,7 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -static const char *keywords[KW_COUNT] = +static const char *const keywords[KW_COUNT] = {";", ":", ",", "(", ")", "{", "}", "[", "]", "==", "+=", "-=", "*=", "/=", "!=", "<=", "<", ">=", ">", @@ -13,6 +13,7 @@ static const char *keywords[KW_COUNT] = "new", "del", "struct", "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "f32", "f64", "Type", + "Package", "char", "bool", "true", "false", "pkg"}; diff --git a/typedefs_cgen.c b/typedefs_cgen.c index 884d61e..3f7d8f1 100644 --- a/typedefs_cgen.c +++ b/typedefs_cgen.c @@ -83,7 +83,7 @@ static bool typedefs_decl(CGenerator *g, Declaration *d) { Identifier i = d->idents[idx]; Type *type = decl_type_at_index(d, idx); Value *val = decl_val_at_index(d, idx); - if (type->kind == TYPE_TYPE) { + if (type_is_builtin(type, BUILTIN_TYPE)) { /* generate typedef */ typedefs_type(g, val->type, i); @@ -91,7 +91,7 @@ static bool typedefs_decl(CGenerator *g, Declaration *d) { IdentID id = 0; if (g->block != NULL || g->fn != NULL) id = ++g->ident_counter; - if (val->type->kind != TYPE_TYPE) { + if (!type_is_compileonly(val->type)) { cgen_write(g, "typedef "); if (!cgen_type_pre(g, val->type, d->where)) return false; cgen_write(g, " "); @@ -20,14 +20,6 @@ static inline void *typer_arr_add_(Typer *tr, void **arr, size_t sz) { return arr_adda_(arr, sz, tr->allocr); } -static inline bool type_is_builtin(Type *t, BuiltinType b) { - return t->kind == TYPE_BUILTIN && t->builtin == b; -} - -static inline bool type_is_slicechar(Type *t) { - return t->kind == TYPE_SLICE && type_is_builtin(t->slice, BUILTIN_CHAR); -} - #define typer_arr_add(tr, a) typer_arr_add_(tr, (void **)(a), sizeof **(a)) static bool type_eq(Type *a, Type *b) { @@ -56,8 +48,6 @@ static bool type_eq(Type *a, Type *b) { switch (a->kind) { case TYPE_VOID: return true; case TYPE_UNKNOWN: assert(0); return false; - case TYPE_TYPE: return true; - case TYPE_PKG: return true; case TYPE_BUILTIN: return a->builtin == b->builtin; case TYPE_STRUCT: return a->struc == b->struc; @@ -193,6 +183,48 @@ static bool expr_must_lval(Expression *e) { return false; } + +/* does this type have a Type or a Package in it? (e.g. [5]Type, &&Package) */ +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: + return t->builtin == BUILTIN_PKG || t->builtin == BUILTIN_TYPE; + case TYPE_PTR: + return type_is_compileonly(t->ptr); + case TYPE_SLICE: + return type_is_compileonly(t->slice); + case TYPE_ARR: + return type_is_compileonly(t->arr.of); + case TYPE_FN: + arr_foreach(t->fn.types, Type, sub) { + if (sub->flags & TYPE_IS_RESOLVED) /* for templates */ { + if (type_is_compileonly(sub)) + return true; + } else { + return true; + } + } + return false; + case TYPE_TUPLE: + arr_foreach(t->tuple, Type, sub) + if (type_is_compileonly(sub)) + return true; + return false; + case TYPE_STRUCT: + arr_foreach(t->struc->fields, Field, f) + if (type_is_compileonly(f->type)) + return true; + return false; + case TYPE_EXPR: break; + } + assert(0); + return false; +} + enum { /* is f an instance? (changes behaviour a bit) */ TYPE_OF_FN_IS_INSTANCE = 0x01 @@ -327,21 +359,23 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { success = false; goto ret; } - } - *ret_type = f->ret_type; - - if (ret_type->kind == TYPE_TYPE) { - /* - a function which returns a type but has non-constant parameters is weird... - but might be useful, so let's warn - */ - arr_foreach(f->params, Declaration, param) { - if (!(param->flags & DECL_IS_CONST)) { - warn_print(param->where, "Non-constant parameter in function which returns Type. (You can't call functions which return types at run-time, y'know)"); - break; + if (type_is_compileonly(&f->ret_type)) { + /* + a function which returns a compile-only type but has non-constant parameters is weird... + but might be useful, so let's warn + */ + arr_foreach(f->params, Declaration, param) { + if (!(param->flags & DECL_IS_CONST)) { + char *s = type_to_str(ret_type); + warn_print(param->where, "Non-constant parameter in function which returns %s (which is a type which can only be used at run time).", s); + free(s); + break; + } } } + } + *ret_type = f->ret_type; ret: arr_remove_lasta(&tr->blocks, tr->allocr); @@ -521,7 +555,9 @@ static bool type_resolve(Typer *tr, Type *t, Location where) { Value typeval; if (!types_expr(tr, t->expr)) return false; - if (t->expr->type.kind != TYPE_TYPE) { + if (t->expr->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored) + return false; /* silently fail (e.g. if a function couldn't be typed) */ + if (!type_is_builtin(&t->expr->type, BUILTIN_TYPE)) { err_print(where, "This expression is not a type, but it's being used as one."); return false; } @@ -534,8 +570,6 @@ static bool type_resolve(Typer *tr, Type *t, Location where) { } break; case TYPE_UNKNOWN: case TYPE_VOID: - case TYPE_TYPE: - case TYPE_PKG: case TYPE_BUILTIN: break; } @@ -552,16 +586,32 @@ static bool type_can_be_truthy(Type *t) { case TYPE_VOID: case TYPE_TUPLE: case TYPE_ARR: - case TYPE_TYPE: case TYPE_STRUCT: - case TYPE_PKG: return false; case TYPE_FN: case TYPE_UNKNOWN: - case TYPE_BUILTIN: case TYPE_PTR: case TYPE_SLICE: return true; + case TYPE_BUILTIN: + switch (t->builtin) { + case BUILTIN_TYPE: + case BUILTIN_PKG: + return false; + case BUILTIN_I8: + case BUILTIN_U8: + case BUILTIN_I16: + case BUILTIN_U16: + case BUILTIN_I32: + case BUILTIN_U32: + case BUILTIN_I64: + case BUILTIN_U64: + case BUILTIN_F32: + case BUILTIN_F64: + case BUILTIN_CHAR: + case BUILTIN_BOOL: + return true; + } case TYPE_EXPR: break; } @@ -584,9 +634,7 @@ static Status type_cast_status(Type *from, Type *to) { switch (from->kind) { case TYPE_UNKNOWN: return STATUS_NONE; case TYPE_STRUCT: - case TYPE_TYPE: case TYPE_VOID: - case TYPE_PKG: return STATUS_ERR; case TYPE_BUILTIN: switch (from->builtin) { @@ -600,6 +648,26 @@ static Status type_cast_status(Type *from, Type *to) { case BUILTIN_U64: switch (to->kind) { case TYPE_BUILTIN: + switch (to->builtin) { + case BUILTIN_I8: + case BUILTIN_U8: + case BUILTIN_I16: + case BUILTIN_U16: + case BUILTIN_I32: + case BUILTIN_U32: + case BUILTIN_I64: + case BUILTIN_U64: + case BUILTIN_F32: + case BUILTIN_F64: + case BUILTIN_BOOL: + case BUILTIN_CHAR: + return STATUS_NONE; + case BUILTIN_PKG: + case BUILTIN_TYPE: + return STATUS_ERR; + } + assert(0); + break; case TYPE_UNKNOWN: return STATUS_NONE; case TYPE_PTR: @@ -610,15 +678,36 @@ static Status type_cast_status(Type *from, Type *to) { break; case BUILTIN_F32: case BUILTIN_F64: - if (to->kind == TYPE_BUILTIN && to->builtin != BUILTIN_CHAR) + if (to->kind == TYPE_BUILTIN) return STATUS_ERR; + switch (to->builtin) { + case BUILTIN_I8: + case BUILTIN_U8: + case BUILTIN_I16: + case BUILTIN_U16: + case BUILTIN_I32: + case BUILTIN_U32: + case BUILTIN_I64: + case BUILTIN_U64: + case BUILTIN_F32: + case BUILTIN_F64: + case BUILTIN_BOOL: return STATUS_NONE; - return STATUS_ERR; + case BUILTIN_CHAR: + case BUILTIN_TYPE: + case BUILTIN_PKG: + return STATUS_ERR; + } + assert(0); + break; case BUILTIN_CHAR: if (to->kind == TYPE_BUILTIN && type_builtin_is_int(to->builtin)) return STATUS_NONE; return STATUS_ERR; case BUILTIN_BOOL: return type_can_be_truthy(to) ? STATUS_NONE : STATUS_ERR; + case BUILTIN_TYPE: + case BUILTIN_PKG: + return STATUS_ERR; } break; case TYPE_TUPLE: return STATUS_ERR; @@ -855,7 +944,8 @@ static bool types_expr(Typer *tr, Expression *e) { t->builtin = BUILTIN_CHAR; break; case EXPR_PKG: { - t->kind = TYPE_PKG; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_PKG; Expression *name_expr = e->pkg.name_expr; if (!types_expr(tr, name_expr)) return false; if (!type_is_slicechar(&name_expr->type)) { @@ -1357,7 +1447,7 @@ static bool types_expr(Typer *tr, Expression *e) { Value *val = &inferred_vals[i]; Type *type = &inferred_types[i]; /* if we have an inferred type argument, it shouldn't be flexible */ - if (type->kind == TYPE_TYPE) + if (type_is_builtin(type, BUILTIN_TYPE)) val->type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; param->val = *val; param->type = *type; @@ -1544,7 +1634,7 @@ static bool types_expr(Typer *tr, Expression *e) { Expression *of = e->kind == EXPR_DSIZEOF ? e->dsizeof.of : e->dalignof.of; if (!types_expr(tr, of)) return false; - if (of->type.kind == TYPE_TYPE) { + if (type_is_builtin(&of->type, BUILTIN_TYPE)) { Value val; if (!eval_expr(tr->evalr, of, &val)) return false; @@ -1579,9 +1669,10 @@ static bool types_expr(Typer *tr, Expression *e) { *t = *of_type; break; case UNARY_ADDRESS: - if (of_type->kind == TYPE_TYPE) { + if (type_is_builtin(of_type, BUILTIN_TYPE)) { /* oh it's a type! */ - t->kind = TYPE_TYPE; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_TYPE; break; } if (!expr_must_lval(of)) { @@ -1678,10 +1769,6 @@ static bool types_expr(Typer *tr, Expression *e) { if (o == BINARY_SET) { valid = type_eq(lhs_type, rhs_type); - if (lhs_type->kind == TYPE_TYPE) { - err_print(e->where, "Cannot set type."); - return false; - } } else { /* numerical binary ops */ if (lhs_type->kind == TYPE_BUILTIN && type_eq(lhs_type, rhs_type)) { @@ -1925,7 +2012,8 @@ static bool types_expr(Typer *tr, Expression *e) { case EXPR_TYPE: if (!type_resolve(tr, &e->typeval, e->where)) return false; - t->kind = TYPE_TYPE; + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_TYPE; break; case EXPR_VAL: assert(0); @@ -2043,12 +2131,16 @@ static bool types_decl(Typer *tr, Declaration *d) { } 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 (t->kind == TYPE_TYPE) { + if (type_is_compileonly(&d->type)) { if (!(d->flags & DECL_IS_CONST)) { - err_print(d->where, "Cannot declare non-constant type."); + 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 (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; if (!type_resolve(tr, val->type, d->where)) return false; @@ -2154,11 +2246,12 @@ static bool types_stmt(Typer *tr, Statement *s) { return true; } -static void typer_create(Typer *tr, Evaluator *ev, Allocator *allocr, Identifiers *idents) { +static void typer_create(Typer *tr, Evaluator *ev, ErrCtx *err_ctx, Allocator *allocr, Identifiers *idents) { tr->block = NULL; tr->blocks = NULL; tr->fn = NULL; tr->evalr = ev; + tr->err_ctx = err_ctx; tr->exptr = NULL; /* by default, don't set an exporter */ tr->in_decls = NULL; tr->in_expr_decls = NULL; @@ -86,6 +86,7 @@ typedef struct ErrCtx { char *str; /* file contents */ bool enabled; bool color_enabled; + bool have_errored; struct Location *instance_stack; /* stack of locations which generate the instances we're dealing with */ } ErrCtx; @@ -269,6 +270,7 @@ typedef enum { KW_F32, KW_F64, KW_TYPE, + KW_PACKAGE, KW_CHAR, KW_BOOL, KW_TRUE, @@ -344,8 +346,6 @@ typedef enum { TYPE_ARR, TYPE_PTR, TYPE_SLICE, - TYPE_TYPE, - TYPE_PKG, TYPE_EXPR, /* just use this expression as the type. this kind of type doesn't exist after resolving. */ TYPE_STRUCT #define TYPE_COUNT (TYPE_STRUCT+1) @@ -364,7 +364,9 @@ typedef enum { BUILTIN_F32, BUILTIN_F64, BUILTIN_CHAR, - BUILTIN_BOOL + BUILTIN_BOOL, + BUILTIN_TYPE, + BUILTIN_PKG } BuiltinType; /* field of a struct */ @@ -774,6 +776,7 @@ typedef struct Typer { Block **blocks; /* dyn array of all the block's we're in ([0] = NULL for global scope) */ FnExpr *fn; /* the function we're currently parsing. */ char *pkg_name; + ErrCtx *err_ctx; } Typer; typedef struct Package { |