aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap/parse.c')
-rw-r--r--bootstrap/parse.c178
1 files changed, 147 insertions, 31 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index 381cfcc..025e061 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -413,6 +413,7 @@ lex(struct parser *P) {
case '-':
if (chrmatch(P, '=')) tok.t = '-=';
else if (chrmatch(P, '-')) tok.t = '--';
+ else if (chrmatch(P, '>')) tok.t = '->';
else tok.t = '-';
return tok;
case '&':
@@ -511,13 +512,15 @@ popenv(struct parser *P) {
assert(P->curenv);
}
-static void
+static struct decl *
putdecl(struct parser *P, struct span espan, const struct decl *decl) {
+ struct decl *ret;
if (envfind(P->primenv, decl->name))
fatal(P, espan, "cannot shadow primitive `%s'", decl->name);
- if (!envput(P->curenv, decl))
+ if (!(ret = envput(P->curenv, decl)))
fatal(P, decl->span,
"cannot shadow earlier incompatible declaration of `%s'", decl->name);
+ return ret;
}
static const struct decl *
@@ -652,6 +655,8 @@ islvalue(const struct expr *ex) {
return 1;
if (ex->t == Eprefix && ex->unop.op == '*')
return 1;
+ if (ex->t == Eindex || ex->t == Eget)
+ return 1;
return 0;
}
@@ -683,14 +688,22 @@ structidx2fld(const struct type *ty, int idx) {
static int
structfldnam2idx(const struct type *ty, const char *name) {
- int i;
assert(name);
- for (i = 0; i < ty->agg.flds.n; ++i)
+ for (int i = 0; i < ty->agg.flds.n; ++i)
if (!strcmp(name, ty->agg.flds.d[i].name))
return i;
return -1;
}
+static struct decl *
+findaggdecl(const struct type *ty, const char *name) {
+ assert(name);
+ for (int i = 0; i < ty->agg.decls.n; ++i)
+ if (!strcmp(name, ty->agg.decls.d[i].name))
+ return &ty->agg.decls.d[i];
+ return NULL;
+}
+
static struct expr
parsestructini(struct parser *P, const struct type *ty) {
struct expr ex = {Eini};
@@ -788,6 +801,8 @@ parsearrini(struct parser *P, const struct type *ty) {
static const struct type *
fntype(const struct fn *fn) {
struct type ty = { TYfn, 0, g_targ.sizesize };
+ if (fn->selfty)
+ return fn->selfty;
vec_t(const struct type *) params = {0};
ty.fn.retty = fn->retty;
for (int i = 0; i < fn->params.n; ++i)
@@ -946,6 +961,7 @@ static struct expr
pexpostfix(struct parser *P) {
struct expr ex = pexprimary(P);
struct tok tok;
+ struct fn *met = NULL;
if (P->used_targty) return ex;
@@ -954,6 +970,12 @@ pexpostfix(struct parser *P) {
const struct type *ty = ex.ty;
int i = 0;
+ if (met) {
+ ++i;
+ ty = met->selfty = fntype(met);
+ vec_push(&args, ex);
+ }
+
if (ty->t == TYptr)
ty = ty->child;
@@ -979,11 +1001,17 @@ pexpostfix(struct parser *P) {
break;
}
}
- ex.call.callee = exprdup(ex);
- ex.t = Ecall;
- ex.span = tok.span;
- ex.ty = ty->fn.retty;
- vec_slice_cpy(&ex.call.args, &args);
+ if (met) {
+ ex.t = Emcall;
+ ex.mcall.met = met;
+ vec_slice_cpy(&ex.mcall.args, &args);
+ } else {
+ ex.call.callee = exprdup(ex);
+ ex.t = Ecall;
+ ex.span = tok.span;
+ ex.ty = ty->fn.retty;
+ vec_slice_cpy(&ex.call.args, &args);
+ }
} else if (lexmatch(P, &tok, '[')) {
struct expr lhs = ex,
rhs = parseexpr(P);
@@ -1023,7 +1051,7 @@ pexpostfix(struct parser *P) {
int idx = structfldnam2idx(ty, fnam);
struct aggfield *fld = &ty->agg.flds.d[idx];
if (idx < 0)
- fatal(P, tok.span, "%t has no such field `%s'", ex.ty, fnam);
+ fatal(P, tok.span, "%t has no such field `%s'", ty, fnam);
ex.get.lhs = exprdup(ex);
ex.t = Eget;
@@ -1034,6 +1062,62 @@ pexpostfix(struct parser *P) {
fatal(P, tok.span, "cannot access `%s': left-hand-side is not an aggregate (%t)",
fnam, ex.ty);
}
+ } else if (lexmatch(P, &tok, '->')) {
+ const char *fnam = (tok = lexexpect(P, TKident)).str;
+ const struct type *ty = ex.ty;
+ bool exptr = 0, metptr = 0;
+
+ if ((exptr = ty->t == TYptr))
+ ty = ty->child;
+ if (ty->t == TYstruct || ty->t == TYunion) {
+ struct decl *decl = findaggdecl(ty, fnam);
+ if (!decl)
+ fatal(P, tok.span, "%t has no such method `%s'", ty, fnam);
+ if (decl->t != Dfn)
+ fatal(P, tok.span, "%t:%bs is not a function", ty, fnam);
+ met = &decl->fn;
+ if (met->params.n == 0)
+ fatal(P, tok.span,
+ "cannot call `->%s', it takes zero arguments",
+ fnam);
+
+ const struct type *recv0 = met->params.d[0].ty,
+ *recv = recv0;
+ if ((metptr = recv->t == TYptr))
+ recv = recv->child;
+ if (unconstify(ty) != unconstify(recv))
+ fatal(P, tok.span,
+ "method receiver type mismatch for `->%s' (%t vs %t)",
+ fnam, ty, recv);
+ if (!exptr && !metptr) {
+ ;
+ } else if (exptr && !metptr) {
+ ex = (struct expr) {
+ Eprefix, ex.span, ty, .unop = { '*', exprdup(ex) }
+ };
+ } else if (!exptr && metptr) {
+ struct type pty = {TYptr, g_targ.ptrsize, 0, 0, .child = ty};
+ if (!islvalue(&ex))
+ fatal(P, tok.span, "cannot call `->%s' by reference: left-hand-side is not"
+ "an lvalue", fnam);
+ else if (ty->konst && !recv->konst)
+ fatal(P, tok.span, "constness mismatch: method takes %t but subject is %t",
+ recv0, ex.ty);
+ ex = (struct expr) {
+ Eprefix, ex.span, interntype(pty), .unop = { '&', exprdup(ex) }
+ };
+ } else if (exptr && metptr) {
+ if (ty->konst && !recv->konst)
+ fatal(P, tok.span, "constness mismatch: method takes %t but subject is %t",
+ recv0, ex.ty);
+ }
+
+ if (lexpeek(P).t != '(')
+ lexexpect(P, '(');
+ } else {
+ fatal(P, tok.span, "cannot call `->%s': left-hand-side is not an aggregate (%t)",
+ fnam, ex.ty);
+ }
} else {
break;
}
@@ -2076,7 +2160,6 @@ parseenum(struct parser *P, const char *name) {
if (min >= INT32_MIN && max <= INT32_MAX) ty.enu.intty = ty_int;
if (min >= INT64_MIN && max <= INT64_MAX) ty.enu.intty = ty_int;
}
- assert(ty.enu.intty);
}
ty.size = ty.enu.intty->size;
@@ -2088,18 +2171,24 @@ parseenum(struct parser *P, const char *name) {
}
static const struct type *
-parseagg(struct parser *P, const char *name, int kind) {
+parseagg(struct parser *P, const char *name, int kind, bool *put) {
struct tok tok;
struct type ty = {kind};
+ const struct type *pty = NULL;
static int id = 0;
size_t size = 0, align = 1;
vec_t(struct aggfield) flds = {0};
+ *put = 1;
+
if (lexmatch(P, &tok, ';')) {
ty.agg.fwd = 1;
} else {
lexexpect(P, '{');
while (!lexmatch(P, &tok, '}')) {
+ if (isdecltokt(lexpeek(P).t))
+ goto decls;
+
const char *fnam = (tok = lexexpect(P, TKident)).str;
const struct type *ty = parsetype(P);
size_t off = kind == TYunion ? 0 : ALIGNUP(size, ty->align);
@@ -2129,6 +2218,41 @@ parseagg(struct parser *P, const char *name, int kind) {
}
}
}
+ if (0)
+decls: {
+ vec_t(struct decl) decls = {0};
+ struct env env = {.parent = P->curenv};
+ struct decl *decl;
+
+ ty.size = ALIGNUP(size, align);
+ ty.align = align;
+ ty.agg.name = name;
+ vec_slice_cpy(&ty.agg.flds, &flds);
+ ty.agg.id = id++;
+ pty = interntype(ty);
+ 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;
+
+ pushenv(P, &env);
+ while (!lexmatch(P, &tok, '}'))
+ parsedecl(NULL, NULL, P, 0);
+ for (struct decls *ds = env.decls, *next; ds; ds = next) {
+ if (ds->decl.t == Dtype && ds->decl.ty == pty)
+ ;
+ else
+ vec_push(&decls, ds->decl);
+ next = ds->next;
+ free(ds);
+ }
+ vec_slice_cpy(&((struct type *)decl->ty)->agg.decls, &decls);
+ popenv(P);
+ *put = 0;
+ return decl->ty;
+ }
ty.size = ALIGNUP(size, align);
ty.align = align;
@@ -2184,7 +2308,8 @@ staticvaryield(struct decl *decl, void *arg) {
if (a->P->is_header && a->externp && decl->var.ini)
fatal(a->P, decl->span,
"cannot define extern variable in header");
- a->yield(decl, a->yarg);
+ if (a->yield)
+ a->yield(decl, a->yarg);
}
static void
@@ -2234,25 +2359,13 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) {
decl.name = lexexpects(P, TKident, "enum name").str;
decl.ty = parseenum(P, decl.name);
} else if (lexmatch(P, &tok, TKkw_struct)) {
- struct decl *d2;
+ bool put;
kind = TYstruct;
if (externp) fatal(P, tok.span, "struct cannot be `extern'");
agg:
decl.name = lexexpects(P, TKident, "struct name").str;
- decl.ty = parseagg(P, decl.name, kind);
- d2 = (struct decl *)finddecl(P, decl.name);
- if (d2 && d2->t == Dtype && d2->ty->t == kind && d2->ty->agg.fwd) {
- // modify existing forward declaration
- *(size_t *)&d2->ty->size = decl.ty->size;
- *(size_t *)&d2->ty->align = decl.ty->align;
- *(bool *)&d2->ty->agg.fwd = 0;
- memcpy((void *)&d2->ty->agg.flds, &decl.ty->agg.flds,
- sizeof d2->ty->agg.flds);
- uninterntype(decl.ty);
- d2->span = tok.span;
- envput(P->curenv, d2);
- return;
- }
+ decl.ty = parseagg(P, decl.name, kind, &put);
+ if (!put) goto noput;
} else if (lexmatch(P, &tok, TKkw_union)) {
if (externp) fatal(P, tok.span, "union cannot be `extern'");
kind = TYunion;
@@ -2265,7 +2378,8 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) {
cf = doimport(P, path);
for (int i = 0; i < cf.decls.n; ++i) {
putdecl(P, tok.span, &cf.decls.d[i]);
- yield(&cf.decls.d[i], yarg);
+ if (yield)
+ yield(&cf.decls.d[i], yarg);
}
free(cf.decls.d);
lexexpect(P, ';');
@@ -2276,8 +2390,10 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) {
}
decl.span = tok.span;
- putdecl(P, tok.span, &decl);
- yield(&decl, yarg);
+ decl = *putdecl(P, tok.span, &decl);
+noput:
+ if (yield)
+ yield(&decl, yarg);
}
static void