aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parse.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-06 22:12:59 +0200
committerlemon <lsof@mailbox.org>2022-08-06 22:30:45 +0200
commita522d6c89067aa2b560ccab3eed9b4e00e89b100 (patch)
tree59d0ce39a20864d780781607e45c1f9572eae831 /bootstrap/parse.c
parent09baa8201a5422b8fa3d9d96bbfe7ceb3e12736b (diff)
slices
Diffstat (limited to 'bootstrap/parse.c')
-rw-r--r--bootstrap/parse.c110
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);
}