aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parse.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-05 05:35:57 +0200
committerlemon <lsof@mailbox.org>2022-08-05 05:35:57 +0200
commitfc29f3f2b0c3a7c5ef1c75d910cf0815d2edbba2 (patch)
treeeef251348f3e1b3a30a3a6296fa05e36971f3140 /bootstrap/parse.c
parentb0d95956fcade40a2d608ccea79e2e989f97b72f (diff)
better diagnostics
Diffstat (limited to 'bootstrap/parse.c')
-rw-r--r--bootstrap/parse.c190
1 files changed, 113 insertions, 77 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index e473f23..822212e 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -195,6 +195,7 @@ readnumber(struct tok *res, const char *s) {
else if (!strcasecmp(suffix, "f")) res->flit.ty = ty_f32;
else if (!strcasecmp(suffix, "f32")) res->flit.ty = ty_f32;
else if (!strcasecmp(suffix, "f64")) res->flit.ty = ty_f64;
+ else return 0;
} else {
res->t = TKintlit;
res->ilit.i = acc;
@@ -213,6 +214,7 @@ readnumber(struct tok *res, const char *s) {
else if (!strcasecmp(suffix, "zs")) res->ilit.ty = ty_isize;
else if (!strcasecmp(suffix, "p")) res->ilit.ty = ty_uptrint;
else if (!strcasecmp(suffix, "ps")) res->ilit.ty = ty_iptrint;
+ else return 0;
}
return 1;
}
@@ -320,7 +322,7 @@ lex(struct parser *P) {
if (readtilsep(P, s, sizeof s, 1) < 0)
fatal(P, P->tokspan, "number literal too long");
if (!readnumber(&tok, s))
- fatal(P, P->tokspan, "invalid number literal");
+ fatal(P, P->tokspan, "invalid number literal %q", s);
tok.span = P->tokspan;
return tok;
} else if (aisalpha(c) || c == '_' || c == '#' || c == '$') {
@@ -485,8 +487,8 @@ static struct tok
lexexpects(struct parser *P, int t, const char *what) {
struct tok tok;
if (!lexmatch(P, &tok, t))
- fatal(P, tok.span, "expected %s (near %s)",
- what ? what : tokt2str(t), tok2str(tok));
+ fatal(P, tok.span, "expected %s (near %T)",
+ what ? what : tokt2str(t), tok);
return tok;
}
#define lexexpect(P, t) lexexpects(P, t, NULL)
@@ -548,7 +550,7 @@ parsetype(struct parser *P) {
}
child = parsetype(P);
if (!completetype(child))
- fatal(P, tok.span, "array of incomplete type");
+ fatal(P, tok.span, "array of incomplete type (%t)", child);
return interntype((struct type) {
TYarr, length * child->size, child->align,
.child = child, .length = length
@@ -556,13 +558,15 @@ parsetype(struct parser *P) {
} else if (lexmatch(P, &tok, TKkw_const)) {
return constify(parsetype(P));
} else if (lexmatch(P, &tok, TKkw_typeof)) {
- const struct type *ty = NULL, *ty2;
+ const struct type *ty = NULL, *ty2, *ty0;
lexexpect(P, '(');
do {
ty2 = parseexpr(P).ty;
+ ty0 = ty;
ty = ty ? typeof2(ty, ty2) : ty2;
if (!ty)
- fatal(P, tok.span, "incompatible types in typeof(...)");
+ fatal(P, tok.span, "incompatible types in typeof(...): %t and %t",
+ ty0, ty2);
if (!lexmatch(P, &tok, ',')) {
lexexpect(P, ')');
break;
@@ -572,12 +576,12 @@ parsetype(struct parser *P) {
} else if (lexmatch(P, &tok, TKident)) {
const struct decl *decl = finddecl(P, tok.str);
if (!decl)
- fatal(P, P->tokspan, "%s is not defined", tok2str(tok));
+ fatal(P, P->tokspan, "%T is not defined", tok);
if (decl->t != Dtype)
- fatal(P, P->tokspan, "%s is not a type", tok2str(tok));
+ fatal(P, P->tokspan, "%T is not a type", tok);
return decl->ty;
}
- fatal(P, P->tokspan, "expected type (near %s)", tok2str(tok));
+ fatal(P, P->tokspan, "expected type (near %T)", tok);
}
static const struct type *
@@ -662,7 +666,7 @@ parsestructini(struct parser *P, const struct type *ty) {
lexexpect(P, ':');
idx = structfldnam2idx(ty, fnam);
if (idx < 0)
- fatal(P, tok.span, "struct has no field `%s'", fnam);
+ fatal(P, tok.span, "struct %t has no field `%s'", ty, fnam);
}
fld = structidx2fld(ty, idx++);
@@ -672,7 +676,9 @@ parsestructini(struct parser *P, const struct type *ty) {
fatal(P, e.span,
"excess elements in struct initializer");
if (!typeof2(e.ty, fld->ty))
- fatal(P, e.span, "incompatible element type in struct initializer");
+ fatal(P, e.span,
+ "incompatible element `%s` type in struct initializer (%t, expected %t)",
+ fld->name, e.ty, fld->ty);
vec_push(&args, ((struct iniarg) {
.fld = fld->name,
@@ -717,7 +723,9 @@ parsearrini(struct parser *P, const struct type *ty) {
P->targty = ty->child;
e = parseexpr(P);
if (!typeof2(ty->child, e.ty))
- fatal(P, e.span, "incompatible element type in array initializer");
+ fatal(P, e.span,
+ "incompatible element type in array initializer (%t, expected %t)",
+ e.ty, ty->child);
if (ty->length >= 0 && iota >= ty->length)
fatal(P, e.span,
"excess elements in array initializer");
@@ -780,7 +788,7 @@ pexprimary(struct parser *P) {
decl = finddecl(P, tok.str);
if (!decl)
- fatal(P, tok.span, "%s is not defined", tok2str(tok));
+ fatal(P, tok.span, "%T is not defined", tok);
if (decl->t == Dtype) {
const struct type *ty = decl->ty;
if (ty->t == TYenum) {
@@ -840,8 +848,7 @@ pexprimary(struct parser *P) {
for (i = 0; i < ex.ty->enu.vals.n; ++i)
if (!strcmp(ex.ty->enu.vals.d[i].name, vname))
goto found;
- fatal(P, tok.span, "enum `%s' contains no variant `%s'",
- ex.ty->enu.name, vname);
+ fatal(P, tok.span, "enum %t contains no variant `%s'", ex.ty, vname);
found:
P->used_targty = 1;
ex.t = Eenumval;
@@ -879,17 +886,19 @@ pexpostfix(struct parser *P) {
int i = 0, n = ex.ty->fn.params.n;
if (ex.ty->t != TYfn)
- fatal(P, ex.span, "callee is not a function");
+ fatal(P, ex.span, "callee is not a function (is %t)", ex.ty);
while (!lexmatch(P, NULL, ')')) {
struct expr arg;
if (i == n && ! ex.ty->fn.variadic)
- fatal(P, arg.span, "too many args for call");
+ fatal(P, arg.span, "too many args for call: (expected %d)", n);
if (i < n)
P->targty = ex.ty->fn.params.d[i];
arg = parseexpr(P);
if (i < n && !typeof2(arg.ty, ex.ty->fn.params.d[i++]))
- fatal(P, arg.span, "call argument #%d type mismatch", i);
+ fatal(P, arg.span,
+ "call argument #%d type mismatch (%t, expected %t)",
+ i, arg.ty, ex.ty->fn.params.d[i - 1]);
vec_push(&args, arg);
if (!lexmatch(P, NULL, ',')) {
@@ -907,24 +916,26 @@ pexpostfix(struct parser *P) {
rhs = parseexpr(P);
lexexpect(P, ']');
if (lhs.ty->t != TYarr && lhs.ty->t != TYptr)
- fatal(P, lhs.span, "indexee is not array or pointer type");
+ 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");
+ 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);
} else if (lexmatch(P, &tok, '++') || lexmatch(P, &tok, '--')) {
- if (!isnumtype(ex.ty))
- fatal(P, ex.span, "invalid operand to unary operator %s: not numeric",
- tok2str(tok));
+ if (!isnumtype(ex.ty) && ex.ty->t != TYptr)
+ fatal(P, ex.span, "invalid %t operand to postfix operator %T: not numeric",
+ ex.ty, tok);
if (!islvalue(&ex))
- fatal(P, ex.span, "left operand to postfix %s operator is not lvalue",
- tok2str(tok));
+ fatal(P, ex.span, "left operand to postfix %T operator is not lvalue",
+ tok);
if (ex.ty->konst)
- fatal(P, ex.span, "left operand to postfix %s operator is const",
- tok2str(tok));
+ fatal(P, ex.span, "left operand to postfix %T operator is const",
+ tok);
ex = (struct expr) {
Epostfix, tok.span, ex.ty, .unop = {
tok.t, exprdup(ex)
@@ -936,7 +947,7 @@ pexpostfix(struct parser *P) {
int idx = structfldnam2idx(ex.ty, fnam);
struct aggfield *fld = &ex.ty->agg.flds.d[idx];
if (idx < 0)
- fatal(P, tok.span, "no such field `%s'", fnam);
+ fatal(P, tok.span, "%t has no such field `%s'", ex.ty, fnam);
ex.get.lhs = exprdup(ex);
ex.t = Eget;
@@ -944,8 +955,8 @@ pexpostfix(struct parser *P) {
ex.ty = fld->ty;
ex.get.fld = fnam;
} else {
- fatal(P, tok.span, "cannot acces `%s': left-hand-side is not an aggregate",
- fnam);
+ fatal(P, tok.span, "cannot acces `%s': left-hand-side is not an aggregate (%t)",
+ fnam, ex.ty);
}
} else {
break;
@@ -963,11 +974,11 @@ pexprefix(struct parser *P) {
const struct type *ty = numpromote(ex.ty);
if (!ty)
- fatal(P, ex.span, "invalid operand to unary operator %s: not numeric",
- tok2str(tok));
+ fatal(P, ex.span, "invalid %t operand to unary operator %T: not numeric",
+ ex.ty, tok);
if (ty->t != TYint && tok.t == '~')
- fatal(P, ex.span, "invalid operand to unary operator %s: not integral",
- tok2str(tok));
+ fatal(P, ex.span, "invalid %t operand to unary operator %T: not integral",
+ ty, tok);
return (struct expr) {
Eprefix, tok.span, ty, .unop = {
tok.t, exprdup(ex)
@@ -976,15 +987,15 @@ pexprefix(struct parser *P) {
} else if (lexmatch(P, &tok, '++') || lexmatch(P, &tok, '--')) {
struct expr ex = pexprefix(P);
- if (!isnumtype(ex.ty))
- fatal(P, ex.span, "invalid operand to unary operator %s: not numeric",
- tok2str(tok));
+ if (!isnumtype(ex.ty) && ex.ty->t != TYptr)
+ fatal(P, ex.span, "invalid %t operand to unary operator %T: not numeric",
+ ex.ty, tok);
if (!islvalue(&ex))
- fatal(P, ex.span, "left operand to prefix %s operator is not lvalue",
- tok2str(tok));
+ fatal(P, ex.span, "left operand to prefix %T operator is not lvalue",
+ ex.ty, tok);
if (ex.ty->konst)
- fatal(P, ex.span, "left operand to prefix %s operator is const",
- tok2str(tok));
+ fatal(P, ex.span, "left operand to prefix %T operator is const",
+ ex.ty, tok);
return (struct expr) {
Eprefix, tok.span, ex.ty, .unop = {
tok.t, exprdup(ex)
@@ -994,8 +1005,8 @@ pexprefix(struct parser *P) {
struct expr ex = pexprefix(P);
if (ex.ty->t != TYbool)
- fatal(P, ex.span, "invalid operand to unary operator %s: not boolean",
- tok2str(tok));
+ fatal(P, ex.span, "invalid %t operand to unary operator %T: not boolean",
+ ex.ty, tok);
return (struct expr) {
Eprefix, tok.span, ty_bool, .unop = {
'not', exprdup(ex)
@@ -1004,9 +1015,9 @@ pexprefix(struct parser *P) {
} else if (lexmatch(P, &tok, '*')) {
struct expr ex = pexprefix(P);
if (ex.ty->t != TYptr)
- fatal(P, ex.span, "invalid operand type to dereference, not pointer");
+ fatal(P, ex.span, "invalid %t operand to dereference, not pointer", ex.ty);
if (!completetype(ex.ty->child) && ex.ty->child->t != TYfn)
- fatal(P, ex.span, "invalid operand type to dereference, incomplete");
+ fatal(P, ex.span, "invalid %t operand to dereference, incomplete", ex.ty);
return (struct expr) {
Eprefix, tok.span, ex.ty->child, .unop = {
'*', exprdup(ex)
@@ -1016,7 +1027,7 @@ pexprefix(struct parser *P) {
struct expr ex = pexprefix(P);
struct type ty2 = { TYptr, g_targ.ptrsize, .child = ex.ty};
if (!islvalue(&ex) && !(ex.t == Ename && ex.ref->t == Dfn))
- fatal(P, ex.span, "invalid operand type to address-of, not an lvalue");
+ fatal(P, ex.span, "invalid operand to `&': not an lvalue");
return (struct expr) {
Eprefix, tok.span, interntype(ty2), .unop = {
'&', exprdup(ex)
@@ -1040,7 +1051,7 @@ pexprefix(struct parser *P) {
else if (from->t == TYenum && to->t == TYint) ;
else if (from->t == TYint && to->t == TYenum) ;
else
- fatal(P, tok.span, "invalid cast"); // TODO better diagnostics...
+ fatal(P, tok.span, "invalid cast from %t to %t", from, to);
P->targty = to;
return (struct expr) {
@@ -1098,12 +1109,13 @@ pexbitarith(struct parser *P) {
ty = ty_isize;
} else if (tokt != '##' && !isnumtype(ty)) {
err:
- fatal(P, tok.span, "invalid operands to binary operator %s",
- tokt2str(tokt));
+ fatal(P, tok.span, "invalid operands %t and %t to binary operator %k",
+ ex.ty, rhs.ty, tokt);
}
if (oret == 2 && ty->t == TYfloat)
- fatal(P, tok.span, "invalid operands to bitwise operator: not integral",
- tokt2str(tokt));
+ fatal(P, tok.span,
+ "invalid operands %t and %t to bitwise operator %k: not integral",
+ ex.ty, rhs.ty, tokt);
if (tokt != '##') {
ex = (struct expr) {
Ebinop, tok.span, ty, .binop = {
@@ -1157,11 +1169,12 @@ pexcmp(struct parser *P) {
if (matchcmpop(P, &tok)) {
struct expr rhs = pexbitarith(P);
if (!typeof2(ex.ty, rhs.ty))
- fatal(P, tok.span, "incompatible operands to binary operator %s",
- tok2str(tok));
+ fatal(P, tok.span, "incompatible operands %t and %t to binary operator %T",
+ ex.ty, rhs.ty, tok);
if (tok.t != '==' && !isnumtype(typeof2(ex.ty, rhs.ty)))
- fatal(P, tok.span, "invalid operands to relational operator %s: not numeric",
- tok2str(tok));
+ fatal(P, tok.span,
+ "invalid operands %t and %t to relational operator %T: not numeric",
+ ex.ty, rhs.ty, tok);
ex = (struct expr) {
Ebinop, tok.span, ty_bool, .binop = {
tok.t, exprdup(ex), exprdup(rhs)
@@ -1187,8 +1200,9 @@ pexlog(struct parser *P) {
while (lexmatch(P, &tok, tokt)) {
struct expr rhs = pexcmp(P);
if (ex.ty->t != TYbool || rhs.ty->t != TYbool)
- fatal(P, tok.span, "invalid operands to binary operator %s: not boolean",
- tokt2str(tok.t));
+ fatal(P, tok.span,
+ "invalid operands %t and %t to binary operator %k",
+ ex.ty, rhs.ty, tok.t);
ex = (struct expr) {
Ebinop, tok.span, ty_bool, .binop = {
tokt == TKkw_and ? 'and' : 'or', exprdup(ex), exprdup(rhs)
@@ -1212,10 +1226,15 @@ pexcond(struct parser *P) {
struct expr ex3;
const struct type *ty;
+ if (ex.ty->t != TYbool)
+ fatal(P, ex.span, "invalid test operand %t to conditional operator", ex.ty);
+
lexexpect(P, ':');
ex3 = pexcond(P);
if (!(ty = typeof2(ex2.ty, ex3.ty)))
- fatal(P, tok.span, "conditional operator branches have incompatible types");
+ fatal(P, tok.span,
+ "conditional operator branches have incompatible types %t and %t",
+ ex2.ty, ex3.ty);
ex = (struct expr) {
Econd, tok.span, ty, .cond = {
exprdup(ex), exprdup(ex2), exprdup(ex3)
@@ -1256,16 +1275,18 @@ pexassign(struct parser *P) {
struct expr rhs = pexcond(P);
if (!islvalue(&ex))
fatal(P, ex.span,
- "left operand to assignment operator %s is not an lvalue",
- tok2str(tok));
- if (!typeof2(ex.ty, rhs.ty))
+ "left operand to assignment operator %T is not an lvalue",
+ tok);
+ if (!typeof2(ex.ty, rhs.ty)
+ && !(ex.ty->t == TYptr && rhs.ty->t == TYint
+ && (tok.t == '+=' || tok.t == '-=')))
fatal(P, ex.span,
- "operands to assignment operator %s have incompatible types",
- tok2str(tok));
+ "operands %t and %t to assignment operator %T have incompatible types",
+ ex.ty, rhs.ty, tok);
if (ex.ty->konst)
fatal(P, ex.span,
- "left operand to assignment operator %s is const",
- tok2str(tok));
+ "left operand to assignment operator %T is const",
+ tok);
ex = (struct expr) {
Ebinop, tok.span, ex.ty, .binop = {
tok.t, exprdup(ex), exprdup(rhs)
@@ -1311,7 +1332,7 @@ parsevardecl(struct parser *P, struct decl *decl) {
P->targty = ty;
ini = exprdup(parseexpr(P));
} else if (decl->t == Dlet) {
- fatal(P, tok.span, "variable must be initialized");
+ fatal(P, tok.span, "variable %T must be initialized", tok);
}
}
@@ -1320,10 +1341,12 @@ parsevardecl(struct parser *P, struct decl *decl) {
// fatal(P, ini->span, "static initializer isn't constant");
if (ini && !typeof2(ty, ini->ty))
- fatal(P, tok.span, "incompatible initializer type");
+ fatal(P, tok.span, "incompatible initializer type (%t, expected %t)",
+ ini->ty, ty);
if (!completetype(ty))
- fatal(P, tok.span, "let `%s': variable type is incomplete", name);
+ fatal(P, tok.span, "let `%s': variable type %t is incomplete",
+ name, ty);
if (konst)
ty = constify(ty);
@@ -1351,7 +1374,8 @@ pstifelse(struct parser *P) {
st.ifelse.test = parseexpr(P);
if (st.ifelse.test.ty->t != TYbool && st.ifelse.test.ty->t != TYptr)
fatal(P, st.ifelse.test.span,
- "if statement condition must be bool or pointer");
+ "if statement condition must be bool or pointer (%t)",
+ st.ifelse.test.ty);
lexexpect(P, '{');
st.ifelse.t = parseblock(P).block;
if (lexmatch(P, NULL, TKkw_else)) {
@@ -1393,7 +1417,8 @@ pstfor(struct parser *P) {
if (st.loop.test.ty->t != TYbool && st.loop.test.ty->t != TYptr)
fatal(P, st.loop.test.span,
- "for statement condition must be bool or pointer");
+ "for statement condition must be bool or pointer (%t)",
+ st.loop.test.ty);
if (!lexmatch(P, &tok, '{')) {
st.loop.next = exprdup(parseexpr(P));
@@ -1432,7 +1457,8 @@ pstiswitch(struct parser *P, const struct expr *test) {
if (!fold(&ex))
fatal(P, ex.span, "case expression is not constant");
if (!typeof2(ex.ty, test->ty))
- fatal(P, ex.span, "case expression has incorrect type");
+ fatal(P, ex.span, "case expression has incorrect type (%t, expected %t)",
+ ex.ty, test->ty);
vec_push(&es, ex);
if (!lexmatch(P, &tok, ',')) {
lexexpect(P, ';');
@@ -1531,7 +1557,7 @@ parseexpandmacro(struct parser *P, const struct macro *macro) {
goto arg_done;
break;
case TKeof:
- fatal(P, espan, "unterminated macro invokation");
+ fatal(P, espan, "unterminated macro `%s' invokation", macro->name);
}
vec_push(&toks, tok);
}
@@ -1598,7 +1624,8 @@ parsestmt(struct parser *P) {
st.loop.test = parseexpr(P);
if (st.loop.test.ty->t != TYbool && st.loop.test.ty->t != TYptr)
fatal(P, st.loop.test.span,
- "while statement condition must be bool or pointer");
+ "while statement condition must be bool or pointer (%t)",
+ st.loop.test.ty);
lexexpect(P, '{');
st.loop.body = parseblock(P).block;
} else if (lexmatch(P, &tok, TKkw_for)) {
@@ -1618,7 +1645,8 @@ parsestmt(struct parser *P) {
lexexpect(P, ';');
if (!typeof2(st.retex->ty, P->curfn->retty))
fatal(P, st.retex->span,
- "incompatible type in return statement");
+ "incompatible type in return statement (%t, expected %t)",
+ st.retex->ty, P->curfn->retty);
} else if (P->curfn->retty != ty_void) {
fatal(P, tok.span,
"return statement in non-void function must return a value");
@@ -1726,7 +1754,8 @@ parsefn(struct decl *decl, struct parser *P) {
vec_slice_cpy(&fn->params, &params);
fn->retty = unconstify(parsetype(P));
if (fn->retty != ty_void && !completetype(fn->retty)) {
- fatal(P, tok.span, "return type is incomplette");
+ fatal(P, tok.span, "return type is incomplette (%t)",
+ fn->retty);
}
fn->selfty = fntype(fn);
if (!lexmatch(P, &tok, ';')) {
@@ -1880,7 +1909,8 @@ parseenum(struct parser *P, const char *name) {
if (lexmatch(P, &tok, ':')) {
ty.enu.intty = unconstify(parsetype(P));
if (ty.enu.intty->t != TYint)
- fatal(P, tok.span, "enum backing type is not integral");
+ fatal(P, tok.span, "enum backing type is not integral (%t)",
+ ty.enu.intty);
}
lexexpect(P, '{');
@@ -1947,8 +1977,14 @@ parseagg(struct parser *P, const char *name, int kind) {
const struct type *ty = parsetype(P);
size_t off = kind == TYunion ? 0 : ALIGNUP(size, ty->align);
+ int i; struct aggfield fld;
+ vec_foreach(&flds, fld, i)
+ if (!strcmp(fnam, fld.name))
+ fatal(P, tok.span, "duplicate field %T", tok);
+
if (!completetype(ty))
- fatal(P, tok.span, "aggregate field `%s' is of incomplete type", fnam);
+ fatal(P, tok.span, "aggregate field `%s' is of incomplete type (%t)",
+ fnam, ty);
align = MAX(align, ty->align);
if (kind == TYstruct)