diff options
Diffstat (limited to 'bootstrap/parse.c')
| -rw-r--r-- | bootstrap/parse.c | 110 |
1 files changed, 83 insertions, 27 deletions
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); } |