diff options
Diffstat (limited to 'bootstrap')
| -rw-r--r-- | bootstrap/all.h | 17 | ||||
| -rw-r--r-- | bootstrap/cgen.c | 19 | ||||
| -rw-r--r-- | bootstrap/fold.c | 210 | ||||
| -rw-r--r-- | bootstrap/parse.c | 152 | ||||
| -rw-r--r-- | bootstrap/test.cff | 73 | ||||
| -rw-r--r-- | bootstrap/types.c | 122 |
6 files changed, 381 insertions, 212 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index 6b5fd7d..762e978 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -237,8 +237,11 @@ struct expr { struct span span; const struct type *ty; union { - u64 i; // also for bool lit - double f; + union { + i64 i; // also for bool lit + u64 u; + double f; + }; struct { const char *d; u64 n; @@ -405,6 +408,13 @@ bool typeeql(const struct type *lhs, const struct type *rhs); bool completetype(const struct type *); void putprimtypes(struct env *); void visittypes(void (*visitor)(const struct type *, void *), void *arg); +const struct type *constify(const struct type *ty); +const struct type *unconstify(const struct type *ty); +const struct type *constifychild(const struct type *ty); +int numtype2rank(const struct type *a); +const struct type * rank2numtype(int r); +bool isnumtype(const struct type *a); +const struct type *typeof2(const struct type *a, const struct type *b); /** env.c **/ struct decl *envfind(const struct env *, const char *name); @@ -419,3 +429,6 @@ void pritoktree(struct toktree); /** cgen.c **/ void cgen(FILE *, const struct transunit *); + +/** fold.c **/ +int fold(struct expr *); diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index 938e8f3..4bc6280 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -87,6 +87,9 @@ pri(const char *fmt, ...) { case 'U': fprintf(outfp, "%llu", (unsigned long long)va_arg(ap, u64)); break; + case 'I': + fprintf(outfp, "%lld", (long long)va_arg(ap, u64)); + break; case 'z': fprintf(outfp, "%zu", va_arg(ap, size_t)); break; @@ -124,13 +127,15 @@ static void genblock(struct blockstmt block); static void genexpr(struct expr *ex) { - const struct type *ty = ex->ty; + const struct type *ty = unconstify(ex->ty); switch (ex->t) { case Eintlit: if (ty == ty_int) - pri("%U", ex->i); + pri("%I", ex->i); + else if (ty == ty_u64) + pri("((uint64_t)%U)", ex->i); else - pri("((%t)%U)", ty, ex->i); + pri("((%t)%I)", ty, ex->i); break; case Eflolit: pri("%f%s", ex->f, ty->size == 4 ? "f" : ""); @@ -378,7 +383,8 @@ liftnested(struct stmt *stmt) { liftnested(blocktostmt(*stmt->iswitch.f)); break; case Sreturn: - liftnestedex(stmt->retex); + if (stmt->retex) + liftnestedex(stmt->retex); break; } } @@ -488,7 +494,10 @@ defctype(const struct type *ty, void *_) { static void prelude() { pri("#include <stdint.h>\n" - "#include <stddef.h>\n"); + "#include <stddef.h>\n" + "#define not !\n" + "#define and &&\n" + "#define or ||\n"); } void diff --git a/bootstrap/fold.c b/bootstrap/fold.c new file mode 100644 index 0000000..8f080a0 --- /dev/null +++ b/bootstrap/fold.c @@ -0,0 +1,210 @@ +#include "all.h" +#include <stdint.h> + +int fold(struct expr *ex); + +static void +numcast(struct expr *ex, const struct type *to) { + enum typetype t0 = ex->ty->t; + enum typetype t1 = to->t; + const struct type *from = ex->ty; + const struct type *uto = unconstify(to); + const struct type *ufrom = unconstify(from); + int size = to->size; + bool sgn = to->int_signed; + assert(t0 == TYint || t0 == TYfloat || t0 == TYbool); + assert(t1 == TYint || t1 == TYfloat || t1 == TYbool); + + if (ufrom == uto) + /* pass */; + else if (t1 == TYint && t0 == TYfloat) + ex->i = from->size == 4 ? (float)ex->f : ex->f; + else if (t0 == TYfloat && t1 == TYfloat && size == 4) + ex->f = (float)ex->f; + else if (t0 == TYfloat && t1 == TYfloat && size == 8) + ex->f = (double)ex->f; + else if (t0 == TYbool) + ex->i = !!ex->i; + #define intint(siz,sgnd,Ty) \ + else if (t0 == TYint && t1 == TYint && size == (siz) && sgn == (sgnd)) \ + ex->i = (Ty)ex->i; + intint(1,0,uint8_t) + intint(1,1,int8_t) + intint(2,0,uint16_t) + intint(2,1,int16_t) + intint(4,0,uint32_t) + intint(4,1,int32_t) + intint(8,0,uint64_t) + intint(8,1,int64_t) + else if (uto == ty_f64 && ufrom == ty_u64) + ex->f = (u64)ex->i; + else if (uto == ty_f32 && ufrom == ty_u64) + ex->f = (float)(u64)ex->i; + else if (uto == ty_f64) + ex->f = ex->i; + else if (uto == ty_f32) + ex->f = (float)ex->i; + else if (uto == ty_bool && t0 == TYint) + ex->i = !!ex->i; + else if (ufrom == ty_bool && t1 == TYint) + ex->i = !!ex->i; + else + assert(0); + + ex->ty = to; + ex->t = to->t == TYfloat ? Eflolit + : to->t == TYint ? Eintlit + : Eboolit; +} + +static void +unary(struct expr *ex) { + struct expr *r = ex->unop.child; + const struct type *ty = ex->ty; + + if (!fold(r)) + return; + + switch (ex->unop.op) { + case '-': + *ex = *r; + ex->ty = ty; + if (r->ty->t == TYint) + ex->i = -ex->i; + else if (r->ty->t == TYfloat) + ex->f = -ex->f; + else assert(0); + free(r); + numcast(ex, ty); + break; + case '~': + *ex = *r; + ex->ty = ty; + assert(r->ty->t == TYint); + ex->i = ~ex->i; + numcast(ex, ty); + free(r); + break; + case 'not': + *ex = *r; + ex->ty = ty; + assert(ty->t == TYbool); + ex->i = !ex->i; + free(r); + break; + } +} + +static void +binop(struct expr *ex) { + struct expr *l = ex->binop.lhs; + struct expr *r = ex->binop.rhs; + const struct type *ty = ex->ty, + *uty = unconstify(ty); + int op = ex->binop.op; + + if (!fold(l) || !fold(r)) + return; + + if (uty == ty_bool) + ty = typeof2(l->ty, r->ty); + numcast(l, ty); + numcast(r, ty); + if (op == '/' && r->ty->t == TYint && r->i == 0) // div/0 + return; + + if (op == '+' && ty->t == TYint) ex->i = l->i + r->i; + else if (op == '+' && ty->t == TYfloat) ex->i = l->f + r->f; + else if (op == '-' && ty->t == TYint) ex->i = l->i - r->i; + else if (op == '-' && ty->t == TYfloat) ex->i = l->f - r->f; + else if (op == '*' && uty == ty_u64) ex->i = (u64)l->i * (u64)r->i; + else if (op == '*' && ty->t == TYint) ex->i = l->i * r->i; + else if (op == '*' && ty->t == TYfloat) ex->i = l->f * r->f; + else if (op == '/' && uty == ty_u64) ex->i = (u64)l->i / (u64)r->i; + else if (op == '/' && ty->t == TYint) ex->i = l->i / r->i; + else if (op == '/' && ty->t == TYfloat) ex->i = l->f / r->f; + else if (op == '%' && uty == ty_u64) ex->i = (u64)l->i % (u64)r->i; + else if (op == '%' && ty->t == TYint) ex->i = l->i % r->i; + else if (op == '&' && ty->t == TYint) ex->i = l->i & r->i; + else if (op == '|' && ty->t == TYint) ex->i = l->i | r->i; + else if (op == '^' && ty->t == TYint) ex->i = l->i ^ r->i; + else if (op == '<<' && ty->t == TYint) ex->i = l->i << r->i; + else if (op == '>>' && ty->t == TYint && !ty->int_signed) + ex->i = (u64)l->i >> r->i; + else if (op == '>>' && ty->t == TYint) ex->i = l->i >> r->i; + else if (op == '==' && ty->t == TYfloat) ex->i = l->f == r->f; + else if (op == '==' && ty->t == TYint) ex->i = l->i == r->i; + else if (op == '<' && ty->t == TYfloat) ex->i = l->f < r->f; + else if (op == '<' && uty == ty_u64) ex->i = (u64)l->i < (u64)r->i; + else if (op == '<' && ty->t == TYint) ex->i = l->i < r->i; + else if (op == '>' && ty->t == TYfloat) ex->i = l->f > r->f; + else if (op == '>' && uty == ty_u64) ex->i = (u64)l->i > (u64)r->i; + else if (op == '>' && ty->t == TYint) ex->i = l->i > r->i; + else if (op == '<=' && ty->t == TYfloat) ex->i = l->f <= r->f; + else if (op == '<=' && uty == ty_u64) ex->i = (u64)l->i <= (u64)r->i; + else if (op == '<=' && ty->t == TYint) ex->i = l->i <= r->i; + else if (op == '>=' && ty->t == TYfloat) ex->i = l->f >= r->f; + else if (op == '>=' && uty == ty_u64) ex->i = (u64)l->i >= (u64)r->i; + else if (op == '>=' && ty->t == TYint) ex->i = l->i >= r->i; + else if (op == 'and') ex->i = l->i && r->i; + else if (op == 'or') ex->i = l->i || r->i; + else assert(0); + + free(l); + free(r); + if (uty != ty_bool) + numcast(ex, ty); + else + ex->t = Eboolit; +} + +static void +cond(struct expr *ex) { + struct expr *test = ex->cond.test, + *t = ex->cond.t, + *f = ex->cond.f; + const struct type *ty = ex->ty; + + if (!fold(test) || !fold(f) || !fold(t)) + return; + assert(test->ty->t == TYbool); + numcast(f, ty); + numcast(t, ty); + if (test->i) + ex->i = t->i; + else + ex->i = f->i; + numcast(ex, ty); + free(test); + free(t); + free(f); +} + +int +fold(struct expr *ex) { + switch (ex->t) { + case Eintlit: case Eflolit: case Eboolit: + numcast(ex, ex->ty); + return 1; + case Estrlit:case Enullit: + return 1; + case Eprefix: + unary(ex); + break; + case Ebinop: + binop(ex); + break; + case Econd: + cond(ex); + default: + break; + } + + switch (ex->t) { + case Eintlit: case Eflolit: case Estrlit: + case Eboolit: case Enullit: + return 1; + default: + return 0; + } +} diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 3d609c4..3cb6924 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -502,38 +502,6 @@ finddecl(struct parser *P, const char *name) { static struct expr parseexpr(struct parser *P); static const struct type * -constify(const struct type *ty) { - struct type ty2 = *ty; - if (ty->konst) - return ty; - if (ty2.t != TYfn) - ty2.konst = 1; - return interntype(ty2); -} - -static const struct type * -unconstify(const struct type *ty) { - struct type ty2 = *ty; - if (!ty->konst) - return ty; - ty2.konst = 0; - return interntype(ty2); -} - -static const struct type * -constifychild(const struct type *ty) { - struct type ty2 = *ty; - const struct type *child = constify(ty->child); - if (child == ty->child) - return ty; - ty2.child = child; - return interntype(ty2); -} - - -static const struct type * typeof2(const struct type *, const struct type *); - -static const struct type * parsetype(struct parser *P) { struct tok tok; if (lexmatch(P, &tok, '*')) { @@ -545,8 +513,12 @@ parsetype(struct parser *P) { } else if (lexmatch(P, &tok, '[')) { i64 length = -1; if (!lexmatch(P, &tok, ']')) { - length = lexexpect(P, TKintlit).ilit.i; - assert(length >= 0); + struct expr ex = parseexpr(P); + if (!fold(&ex) || ex.t != Eintlit) + fatal(P, ex.span, + "array length should be a compile-time integral expression"); + if ((length = ex.i) < 0) + fatal(P, ex.span, "negative array length"); lexexpect(P, ']'); } return interntype((struct type) { @@ -583,42 +555,16 @@ parsetype(struct parser *P) { } static const struct type * -ilittype(struct parser *P, u64 i) { - if (i <= INT_MAX) +ilittype(struct parser *P, u64 n) { + if (n <= INT_MAX) return ty_int; - if (i <= INT32_MAX) + if (n <= INT32_MAX) return ty_i32; - if (i <= INT64_MAX) + if (n <= INT64_MAX) return ty_i64; return ty_u64; } -static int -numtype2rank(const struct type *a) { - if (a->t == TYint) { - if (a->size < g_targ.intsize || a == ty_int) - return 0; - if (a == ty_uint) return 1; - if (a == ty_i32) return 2; - if (a == ty_u32) return 3; - if (a == ty_i64) return 4; - if (a == ty_u64) return 5; - } - if (a == ty_f32) return 6; - if (a == ty_f64) return 7; - return -1; -} - -static const struct type * -rank2numtype(int r) { - static const struct type **types[] = { - &ty_int, &ty_uint, &ty_i32, &ty_u32, - &ty_i64, &ty_u64, &ty_f32, &ty_f64, - }; - assert(r >= 0 && r < ARRAY_LENGTH(types)); - return *types[r]; -} - static const struct type * numpromote(const struct type *ty) { int r = numtype2rank(ty); @@ -628,73 +574,6 @@ numpromote(const struct type *ty) { } static bool -isnumtype(const struct type *a) { - return a->t == TYint || a->t == TYfloat; -} - -static const struct type * -arraydecay(const struct type *ty) { - struct type ty2 = *ty; - - if (ty->t != TYarr) - return ty; - - ty2.t = TYptr; - return interntype(ty2); -} - -// peer type resolution -static const struct type * -typeof2(const struct type *a, const struct type *b) { - if (isnumtype(a) && isnumtype(b)) { - int ra = numtype2rank(a), rb = numtype2rank(b); - return rank2numtype(MAX(ra, rb)); - } - if (a == b) - return a; - if (unconstify(a) == b) - return a; - if (a == unconstify(b)) - return b; - if (a->t == TYarr && b->t == TYarr) - a = arraydecay(a); - if (a->t == TYptr && b->t == TYarr) - b = arraydecay(b); - if (a->t == TYarr && b->t == TYptr) - a = arraydecay(a); - if (a->t == TYptr && b->t == TYptr) { - bool akonst = a->child->konst, - bkonst = b->child->konst; - const struct type *uac = unconstify(a->child), - *ubc = unconstify(b->child); - if (uac == ubc) - return akonst ? a : b; - if (uac == ty_void) { - if (bkonst && !akonst) - return constifychild(a); - return a; - } - if (ubc == ty_void) { - if (akonst && !bkonst) - return constifychild(b); - return b; - } - if (uac == ty_u8) { - if (bkonst && !akonst) - return constifychild(a); - return a; - } - if (ubc == ty_u8) { - if (akonst && !bkonst) - return constifychild(b); - return b; - } - - } - return NULL; -} - -static bool islvalue(const struct expr *ex) { if (ex->t == Ename) return 1; @@ -731,7 +610,7 @@ pexprimary(struct parser *P) { ex.t = Eintlit; ex.span = tok.span; ex.i = tok.ilit.i; - ex.ty = tok.ilit.ty ? tok.ilit.ty : ilittype(P, ex.i); + ex.ty = tok.ilit.ty ? tok.ilit.ty : ilittype(P, ex.u); } else if (lexmatch(P, &tok, TKflolit)) { ex.t = Eflolit; ex.span = tok.span; @@ -957,9 +836,10 @@ peeksbitarithop(struct parser *P, struct tok* tokp) { if (tokp) *tokp = tok; switch (tok.t) { - case '+': case '-': case '*': case '/': case '%': + case '+': case '-': case '*': case '/': return 1; - case '&': case '|': case '^': case '<<': case '>>': + case '%': case '&': case '|': + case '^': case '<<': case '>>': return 2; case '##': return 3; @@ -1206,6 +1086,10 @@ parsevardecl(struct parser *P, struct decl *decl) { fatal(P, tok.span, "variable must be initialized"); } } + + if (ini && decl->t == Dstatic && !fold(ini)) + fatal(P, ini->span, "static initializer isn't constant"); + if (ini && !typeof2(ty, ini->ty)) fatal(P, tok.span, "incompatible initializer type"); diff --git a/bootstrap/test.cff b/bootstrap/test.cff index 61fcbf3..1f426b8 100644 --- a/bootstrap/test.cff +++ b/bootstrap/test.cff @@ -1,76 +1,7 @@ - -defmacro MAX(x, y) [ ((x) < (y) ? (y) : (x)) ] - -defmacro fmt(fmt, ...args) [ printf(fmt, args) ] -defmacro add { -(x) [ (x) ], -(x, y, ...rest) [ (x) + add(y, rest) ] -} - -defmacro swap(x, y) [ - (do - let $x = &(x); - let $y = &(y); - let $z = *$x; - *$x = *$y; - *$y = $z;) -] - -defmacro map { -(f, x) [ f(x) ], -(f, x, ...rest) [ f(x) map(f, rest) ] -} - -defmacro printints_s(x) [ "%d " ## ] -defmacro printints(...rest) [ printf(map(printints_s, rest) "\n", rest) ] - - -fn fact(x usize) usize { - fn f(acc usize, n usize) usize { - return n == 0 ? acc : f(acc * n, n - 1); - } - return f(1, x); -} - -defmacro lambda(tys, body) [ - (do - fn $lam tys body - &$lam;) -] - -fn counter() int { - static xs int = 0; - extern static glob int; - glob; - return xs++; -} - -extern static glob int = 42; +typedef v3f [-(-1 * 2) + -(-8/~~5)]f32; extern fn main (argc int, argv **u8) void { extern fn printf(fmt *const u8, ...) int; - fmt("%d\n", add(1, 2, 3, 4)); - - let x = 0; - let y = 7; - switch y { - case 0, 1 do - printf("wow\n"); - case else - printf("p\n"); - } - printf("x: %d; y: %d\n", x, y); - swap(x, y); - printf("x: %d; y: %d\n", x, y); - printf("fact(6) = %zu\n", fact(6)); - - printints(1, 7, 8 + 9, x, x / (++y ^ 2)); - let z = (do - printf("hi"); - x + 1;); - - let fo = lambda((x int) void, {}); - - return (*fo)(0); + return; } diff --git a/bootstrap/types.c b/bootstrap/types.c index 8e735d0..401f9e6 100644 --- a/bootstrap/types.c +++ b/bootstrap/types.c @@ -206,3 +206,125 @@ visittypes(void (*visitor)(const struct type *, void *), void *arg) { for (struct typesnode *n = types.buckets[i]; n; n = n->next) visitor(&n->ty, arg); } + +const struct type * +constify(const struct type *ty) { + struct type ty2 = *ty; + if (ty->konst) + return ty; + if (ty2.t != TYfn) + ty2.konst = 1; + return interntype(ty2); +} + +const struct type * +unconstify(const struct type *ty) { + struct type ty2 = *ty; + if (!ty->konst) + return ty; + ty2.konst = 0; + return interntype(ty2); +} + +const struct type * +constifychild(const struct type *ty) { + struct type ty2 = *ty; + const struct type *child = constify(ty->child); + if (child == ty->child) + return ty; + ty2.child = child; + return interntype(ty2); +} + +static const struct type * +arraydecay(const struct type *ty) { + struct type ty2 = *ty; + + if (ty->t != TYarr) + return ty; + + ty2.t = TYptr; + return interntype(ty2); +} + +int +numtype2rank(const struct type *a) { + if (a->t == TYint) { + if (a->size < g_targ.intsize || a == ty_int) + return 0; + if (a == ty_uint) return 1; + if (a == ty_i32) return 2; + if (a == ty_u32) return 3; + if (a == ty_i64) return 4; + if (a == ty_u64) return 5; + } + if (a == ty_f32) return 6; + if (a == ty_f64) return 7; + return -1; +} + +const struct type * +rank2numtype(int r) { + static const struct type **types[] = { + &ty_int, &ty_uint, &ty_i32, &ty_u32, + &ty_i64, &ty_u64, &ty_f32, &ty_f64, + }; + assert(r >= 0 && r < ARRAY_LENGTH(types)); + return *types[r]; +} + +bool +isnumtype(const struct type *a) { + return a->t == TYint || a->t == TYfloat; +} + +// peer type resolution +const struct type * +typeof2(const struct type *a, const struct type *b) { + if (isnumtype(a) && isnumtype(b)) { + int ra = numtype2rank(a), rb = numtype2rank(b); + return rank2numtype(MAX(ra, rb)); + } + if (a == b) + return a; + if (unconstify(a) == b) + return a; + if (a == unconstify(b)) + return b; + if (a->t == TYarr && b->t == TYarr) + a = arraydecay(a); + if (a->t == TYptr && b->t == TYarr) + b = arraydecay(b); + if (a->t == TYarr && b->t == TYptr) + a = arraydecay(a); + if (a->t == TYptr && b->t == TYptr) { + bool akonst = a->child->konst, + bkonst = b->child->konst; + const struct type *uac = unconstify(a->child), + *ubc = unconstify(b->child); + if (uac == ubc) + return akonst ? a : b; + if (uac == ty_void) { + if (bkonst && !akonst) + return constifychild(a); + return a; + } + if (ubc == ty_void) { + if (akonst && !bkonst) + return constifychild(b); + return b; + } + if (uac == ty_u8) { + if (bkonst && !akonst) + return constifychild(a); + return a; + } + if (ubc == ty_u8) { + if (akonst && !bkonst) + return constifychild(b); + return b; + } + + } + return NULL; +} |