diff options
| -rw-r--r-- | bootstrap/all.h | 7 | ||||
| -rw-r--r-- | bootstrap/cgen.c | 25 | ||||
| -rw-r--r-- | bootstrap/parse.c | 110 | ||||
| -rw-r--r-- | bootstrap/test.cff | 11 |
4 files changed, 121 insertions, 32 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index 8b57d94..2f7f070 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -265,6 +265,8 @@ enum exprtype { Eini, Eget, Emcall, + Eslice, + Elen, }; struct blockstmt { @@ -306,7 +308,7 @@ struct expr { struct expr *lhs, *rhs; } index; struct blockstmt block; - struct expr *child; // cast + struct expr *child; // cast, len struct { i64 i; const char *vname; @@ -323,6 +325,9 @@ struct expr { struct fn *met; slice_t(struct expr) args; } mcall; + struct { + struct expr *lhs, *start, *end; + } slice; }; }; diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index 8a01e09..7315876 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -209,7 +209,8 @@ genexpr(struct expr *ex) { pri(")"); break; case Eindex: - pri("%e[%e]", ex->index.lhs, ex->index.rhs); + pri("%e%s[%e]", ex->index.lhs, + ex->index.lhs->ty->t == TYslice ? ".ptr" : "", ex->index.rhs); break; case Eblock: pri("(\n"); @@ -247,6 +248,17 @@ genexpr(struct expr *ex) { } pri(")"); break; + case Eslice: + ;static int id; + // TODO range assertions + pri("({ %t __start%d = %e; ", ex->slice.start->ty, id, ex->slice.start); + pri("(%t) { %e%s + __start%d, %e - __start%d }; })", + ex->ty, ex->slice.lhs, ex->slice.lhs->ty->t == TYslice ? ".ptr" : "", id, ex->slice.end, id); + ++id; + break; + case Elen: + pri("%e.len", ex->child); + break; } } @@ -360,7 +372,7 @@ static void liftdecl(struct decl *decl); static void liftnestedex(struct expr *ex) { - switch (ex->t) { + if (ex) switch (ex->t) { case Eintlit: case Eflolit: case Estrlit: case Eboolit: case Enullit: case Ename: case Ezeroini: @@ -393,7 +405,7 @@ liftnestedex(struct expr *ex) { case Eblock: liftnested(blocktostmt(ex->block)); break; - case Eas: + case Eas: case Elen: liftnestedex(ex->child); break; case Eini: @@ -403,11 +415,16 @@ liftnestedex(struct expr *ex) { case Eget: liftnestedex(ex->get.lhs); break; - case Emcall: + case Emcall: liftdecl(container_of(ex->mcall.met, struct decl, fn)); for (int i = 0; i < ex->call.args.n; ++i) liftnestedex(&ex->mcall.args.d[i]); break; + case Eslice: + liftnestedex(ex->slice.lhs); + liftnestedex(ex->slice.start); + liftnestedex(ex->slice.end); + break; } } diff --git a/bootstrap/parse.c b/bootstrap/parse.c index c48d1eb..3233e84 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -431,8 +431,9 @@ lex(struct parser *P) { else tok.t = '^'; return tok; case ':': - if (chrmatch(P, '=')) tok.t = ':='; - else tok.t = ':'; + if (chrmatch(P, '=')) tok.t = ':='; + else if (chrmatch(P, ':')) tok.t = '::'; + else tok.t = ':'; return tok; case '=': if (chrmatch(P, '=')) tok.t = '=='; @@ -575,6 +576,15 @@ parsefntype(struct parser *P) { } static const struct type * +mkslicetype(const struct type *child) { + int align = MAX(g_targ.ptrsize, g_targ.sizesize); + return interntype((struct type) { + TYslice, ALIGNUP(g_targ.ptrsize + g_targ.sizesize, align), align, + .child = child + }); +} + +static const struct type * parsetype(struct parser *P) { struct tok tok; if (lexmatch(P, &tok, '*')) { @@ -584,8 +594,13 @@ parsetype(struct parser *P) { }); } else if (lexmatch(P, &tok, '[')) { i64 length = -1; + bool slice = 0; const struct type *child; - if (!lexmatch(P, &tok, ']')) { + + if (lexmatch(P, &tok, '#')) { + slice = 1; + lexexpect(P, ']'); + } else if (!lexmatch(P, &tok, ']')) { struct expr ex = parseexpr(P); if (!fold(&ex) || ex.t != Eintlit) fatal(P, ex.span, @@ -596,11 +611,14 @@ parsetype(struct parser *P) { } child = parsetype(P); if (!completetype(child)) - fatal(P, tok.span, "array of incomplete type (%t)", child); - return interntype((struct type) { - TYarr, length * child->size, child->align, - .child = child, .length = length - }); + fatal(P, tok.span, "%s of incomplete type (%t)", slice ? "slice" : "array", child); + if (slice) + return mkslicetype(child); + else + return interntype((struct type) { + TYarr, length * child->size, child->align, + .child = child, .length = length + }); } else if (lexmatch(P, &tok, TKkw_const)) { return constify(parsetype(P)); } else if (lexmatch(P, &tok, TKkw_typeof)) { @@ -1017,19 +1035,47 @@ pexpostfix(struct parser *P) { } } else if (lexmatch(P, &tok, '[')) { struct expr lhs = ex, - rhs = parseexpr(P); - lexexpect(P, ']'); - if (lhs.ty->t != TYarr && lhs.ty->t != TYptr) + rhs = parseexpr(P), + *end = NULL; + bool slice = 0; + if (lhs.ty->t != TYarr && lhs.ty->t != TYptr && lhs.ty->t != TYslice) fatal(P, lhs.span, "indexee is not array or pointer type (%t)", lhs.ty); if (rhs.ty->t != TYint) fatal(P, lhs.span, "index expression type is not integral (%t)", rhs.ty); - ex.t = Eindex; - ex.span = tok.span; - ex.ty = lhs.ty->child; - ex.index.lhs = exprdup(lhs); - ex.index.rhs = exprdup(rhs); + if (lexmatch(P, NULL, '::')) { + slice = 1; + if (!lexmatch(P, NULL, ']')) { + end = exprdup(parseexpr(P)); + if (end->ty->t != TYint) + fatal(P, lhs.span, + "slice range end expression type is not integral (%t)", end->ty); + lexexpect(P, ']'); + } else if (lhs.ty->t == TYarr) { + end = exprdup((struct expr) { + Eintlit, .ty = ty_usize, .i = lhs.ty->length + }); + } else { + fatal(P, tok.span, "missing end of slice range"); + } + } else { + lexexpect(P, ']'); + } + if (slice) { + ex.t = Eslice; + ex.span = tok.span; + ex.ty = mkslicetype(lhs.ty->child); + ex.slice.lhs = exprdup(lhs); + ex.slice.start = exprdup(rhs); + ex.slice.end = end; + } else { + ex.t = Eindex; + ex.span = tok.span; + ex.ty = lhs.ty->child; + ex.index.lhs = exprdup(lhs); + ex.index.rhs = exprdup(rhs); + } } else if (lexmatch(P, &tok, '++') || lexmatch(P, &tok, '--')) { if (!isnumtype(ex.ty) && ex.ty->t != TYptr) fatal(P, ex.span, "invalid %t operand to postfix operator %T: not numeric", @@ -1050,13 +1096,20 @@ pexpostfix(struct parser *P) { const struct type *ty = ex.ty; if (ty->t == TYptr) ty = ty->child; - if (ty->t != TYarr) + if (ty->t == TYarr) { + assert(ty->length >= 0); + ex.t = Eintlit; + ex.ty = ty_usize; + ex.span = tok.span; + ex.i = ty->length; + } else if (ty->t == TYslice) { + ex.child = exprdup(ex); + ex.t = Elen; + ex.ty = ty_usize; + ex.span = tok.span; + } else { fatal(P, ex.span, "invalid operand to `.#len' (%t)", ex.ty); - assert(ty->length >= 0); - ex.t = Eintlit; - ex.ty = ty_usize; - ex.span = tok.span; - ex.i = ty->length; + } } else { const char *fnam = (tok = lexexpect(P, TKident)).str; const struct type *ty = ex.ty; @@ -2263,12 +2316,13 @@ decls: { vec_slice_cpy(&ty.agg.flds, &flds); ty.agg.id = id++; pty = interntype(ty); - if (name) + if (name) { decl = putdecl(P, tok.span, &(struct decl){Dtype, name, .span = tok.span, .ty = pty}); - if (decl->ty != pty) - uninterntype(pty); - pty = decl->ty; + if (decl->ty != pty) + uninterntype(pty); + pty = decl->ty; + } pushenv(P, &env); while (!lexmatch(P, &tok, '}')) @@ -2276,8 +2330,10 @@ decls: { for (struct decls *ds = env.decls, *next; ds; ds = next) { if (ds->decl.t == Dtype && ds->decl.ty == pty) ; - else + else if (ds->decl.t == Dfn && !ds->decl.externp && ds->decl.fn.body) vec_push(&decls, ds->decl); + else + fatal(P, ds->decl.span, "this kind of declaration is disallowed inside aggregates"); next = ds->next; free(ds); } diff --git a/bootstrap/test.cff b/bootstrap/test.cff index 95ee7bf..e466bba 100644 --- a/bootstrap/test.cff +++ b/bootstrap/test.cff @@ -48,6 +48,11 @@ struct Vec2f { } } +fn spanz(cstr *const u8) [#]const u8 { + extern fn strlen(s *const u8) usize; + return cstr[0::strlen(cstr)]; +} + extern fn main (argc int, argv **u8) int { let colors [3]Color = { :Red, :Green, :Blue } ; @@ -63,6 +68,12 @@ extern fn main (argc int, argv **u8) int { each(i, x, is, printf("%d\n", x); ) + let slice [#]int = is[3::5]; + + printf("sl %d\n", slice[0]); + slice = slice[1::4]; + printf("sl %d\n", slice[0]); + slice.#len; printf("sizeof(is) = %zu\n", sizeof(is)); printf("sizeof *void = %zu\n", sizeof *void); |