aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/all.h7
-rw-r--r--bootstrap/cgen.c25
-rw-r--r--bootstrap/parse.c110
-rw-r--r--bootstrap/test.cff11
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);