commit 042c933eb160930b2971aa46316764aef44923cf
parent 5d3f81f553dc602164529513bf8b76831fbe3560
Author: m21c <ho*******@gmail.com>
Date: Sat, 5 Feb 2022 13:19:39 +0100
worked on typechecking
Diffstat:
| M | compiler.c | | | 467 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
1 file changed, 255 insertions(+), 212 deletions(-)
diff --git a/compiler.c b/compiler.c
@@ -2952,6 +2952,39 @@ isinttype(Type *ty)
case TS64: case TU64:
return true;
+ /* FIXME(m21c): This *just* tests wether a tuple only contains types of
+ * certain kinds. In order to check wether two tuple-types
+ * are compatible (for casting), another function has to
+ * be implemented. */
+ case TTUPLE:
+ return isinttype(ty->target)
+ && isinttype(ty->u.rtarget);
+
+ default:
+ return false;
+ }
+}
+
+static bool
+isintorbooltype(Type *ty)
+{
+ switch (ty->kind) {
+ case TBOOL:
+ case TINFER: case TUINFER:
+ case TS8: case TU8:
+ case TS16: case TU16:
+ case TS32: case TU32:
+ case TS64: case TU64:
+ return true;
+
+ /* FIXME(m21c): This *just* tests wether a tuple only contains types of
+ * certain kinds. In order to check wether two tuple-types
+ * are compatible (for casting), another function has to
+ * be implemented. */
+ case TTUPLE:
+ return isintorbooltype(ty->target)
+ && isintorbooltype(ty->u.rtarget);
+
default:
return false;
}
@@ -2964,6 +2997,14 @@ isfloattype(Type *ty)
case TF32: case TF64:
return true;
+ /* FIXME(m21c): This *just* tests wether a tuple only contains types of
+ * certain kinds. In order to check wether two tuple-types
+ * are compatible (for casting), another function has to
+ * be implemented. */
+ case TTUPLE:
+ return isfloattype(ty->target)
+ && isfloattype(ty->u.rtarget);
+
default:
return false;
}
@@ -2982,6 +3023,14 @@ isarithtype(Type *ty)
case TF32: case TF64:
return true;
+ /* FIXME(m21c): This *just* tests wether a tuple only contains types of
+ * certain kinds. In order to check wether two tuple-types
+ * are compatible (for casting), another function has to
+ * be implemented. */
+ case TTUPLE:
+ return isarithtype(ty->target)
+ && isarithtype(ty->u.rtarget);
+
default:
return false;
}
@@ -2991,11 +3040,39 @@ static bool
isunsignedtype(Type *ty)
{
switch (ty->kind) {
- case TBOOL: case TUINFER:
+ case TBOOL:
+ case TUINFER:
case TU8: case TU16:
case TU32: case TU64:
return true;
+ /* FIXME(m21c): This *just* tests wether a tuple only contains types of
+ * certain kinds. In order to check wether two tuple-types
+ * are compatible (for casting), another function has to
+ * be implemented. */
+ case TTUPLE:
+ return isunsignedtype(ty->target)
+ && isunsignedtype(ty->u.rtarget);
+
+ default:
+ return false;
+ }
+}
+
+static bool
+islvalue(Node *node)
+{
+ assert(node);
+
+ switch (node->kind) {
+ case ADECLREF:
+ case ADEREF:
+ case ADECL:
+ return true;
+
+ case ACOMMA:
+ return islvalue(node->lhs) && islvalue(node->rhs);
+
default:
return false;
}
@@ -3055,13 +3132,13 @@ wrap(Type *type, Node *node)
node->u.d
);
- } else if (isinttype(type)) {
+ } else if (isintorbooltype(type)) {
node->u.u = maskint(
type->size,
(int64_t) node->u.d
);
}
- } else if (isinttype(nodetype)) {
+ } else if (isintorbooltype(nodetype)) {
if (isfloattype(type)) {
node->u.d = maskfloat(
type->size, (double)
@@ -3071,7 +3148,7 @@ wrap(Type *type, Node *node)
)
);
- } else if (isinttype(type)) {
+ } else if (isintorbooltype(type)) {
node->u.u = maskint(
type->size,
convint(
@@ -3198,6 +3275,15 @@ typecheckdecl(Env *env, Decl *decl)
} else {
decl->u.content = wrap(decl->type, decl->u.content);
}
+ } else if (decl->kind == DFUNCTION) {
+ if (!decl->u.content)
+ return decl->type;
+
+ assert(decl->contentenv);
+ if (decl->contentenv->pending)
+ return decl->type;
+
+ decl->u.content = typecheck(env, decl->u.content);
}
return decl->type;
@@ -3238,23 +3324,31 @@ typecheck(Env *env, Node *expr)
{
Node *lhs = expr->lhs, *rhs = expr->rhs;
+ #define errortype(condition) do { \
+ if (condition) { \
+ expr->type = primitive(TERRTYPE); \
+ return expr; \
+ } \
+ } while (0)
+
+ #define reporton(condition, loc, errormsg) do { \
+ if (condition) { \
+ error((loc), (errormsg)); \
+ expr->type = primitive(TERRTYPE); \
+ return expr; \
+ } \
+ } while (0)
+
switch (getnumops(expr->kind)) {
case 2:
assert(rhs);
- if (rhs->type->kind == TERRTYPE) {
- expr->type = prim + TERRTYPE;
- return expr;
- } else {
- rhs = typecheck(env, rhs);
- }
+ errortype(rhs->type->kind == TERRTYPE);
+ rhs = typecheck(env, rhs);
+ /* FALLTHROUGH */
case 1:
assert(lhs);
- if (lhs->type->kind == TERRTYPE) {
- expr->type = prim + TERRTYPE;
- return expr;
- } else {
- lhs = typecheck(env, lhs);
- }
+ errortype(lhs->type->kind == TERRTYPE);
+ lhs = typecheck(env, lhs);
if (arithtuplereorder(env, expr, getnumops(expr->kind)))
goto joincomma;
@@ -3264,60 +3358,55 @@ typecheck(Env *env, Node *expr)
return expr;
switch (expr->kind) {
+ case OINC: case ODEC: case OSUFINC: case OSUFDEC:
+ reporton(!islvalue(lhs),
+ &expr->loc, "operand is not an lvalue");
+
+ expr->lhs = conv(lhs);
+ expr->type = lhs->type;
+ return expr;
+
case ODEREF:
- expr->type = expr->lhs->type;
+ expr->type = lhs->type;
- if (expr->type->kind != TPTR) {
- error(&expr->loc, "operand is not a pointer");
- } else {
- expr->type = expr->type->target;
- }
+ reporton(expr->type->kind != TPTR,
+ &expr->loc, "operand is not a pointer");
+ expr->type = expr->type->target;
return expr;
case OADDR:
- expr->type = maketype(&expr->loc, prim + TPTR, expr->lhs->type);
+ reporton(!islvalue(lhs),
+ &expr->loc, "operand is not an lvalue");
+
+ expr->type = maketype(&expr->loc, primitive(TPTR), lhs->type);
return expr;
case OPLUS: case OMINUS:
/*
- if (!isarithtype(lhs->type)) {
- error(&lhs->loc, "expression is not of arithmentic type");
- expr->type = prim + TERRTYPE;
- break;
- }
+ reporton(!isarithtype(lhs->type),
+ &lhs->loc, "expression is not of arithmentic type");
*/
+ expr->lhs = conv(lhs);
expr->type = lhs->type;
- goto joinunaryconv;
+ return expr;
case OBNOT:
- if (!isinttype(lhs->type)) {
- error(
- &lhs->loc,
- "expression is not of integer type"
- );
-
- expr->type = prim + TERRTYPE;
- return expr;
- }
+ reporton(!isintorbooltype(lhs->type),
+ &lhs->loc, "expression is not of integer type");
+ expr->lhs = conv(lhs);
expr->type = lhs->type;
- goto joinunaryconv;
+ return expr;
case OLNOT:
- if (!isarithtype(lhs->type)) {
- error(
- &lhs->loc,
- "expression is not of arithmentic type"
- );
-
- expr->type = prim + TERRTYPE;
- return expr;
- }
+ reporton(!isarithtype(lhs->type),
+ &lhs->loc, "expression is not of arithmentic type");
- expr->type = prim + TBOOL;
- goto joinunaryconv;
+ expr->type = primitive(TBOOL);
+ expr->lhs = conv(lhs); /* cannot be wrap(expr->type, lhs) */
+ return expr;
case OCAST:
/*
@@ -3333,145 +3422,91 @@ typecheck(Env *env, Node *expr)
case OMUL: case ODIV: case OMOD:
case OADD: case OSUB:
- /* usual arithmetic conversion */
- if (isarithtype(lhs->type) && isarithtype(rhs->type)) {
- if (lhs->type->kind < rhs->type->kind)
- expr->type = rhs->type;
- else
- expr->type = lhs->type;
- } else {
- error(
- &expr->loc,
- "expression is not of arithmentic type"
- );
+ reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type),
+ &expr->loc, "expression is not of arithmentic type");
- expr->type = prim + TERRTYPE;
- return expr;
- }
+ /* usual arithmetic conversion */
+ if (lhs->type->kind < rhs->type->kind)
+ expr->type = rhs->type;
+ else
+ expr->type = lhs->type;
- goto joinbinarywrap;
+ expr->lhs = wrap(expr->type, lhs);
+ expr->rhs = wrap(expr->type, rhs);
+ return expr;
case OBAND: case OBOR: case OXOR:
- if (isinttype(lhs->type) && isinttype(rhs->type)) {
- if (lhs->type->kind < rhs->type->kind) {
- expr->type = rhs->type;
- } else {
- expr->type = lhs->type;
- }
- } else {
- error(
- &expr->loc,
- "expression is not of integer type"
- );
+ reporton(!isintorbooltype(lhs->type) || !isintorbooltype(rhs->type),
+ &expr->loc, "expression is not of integer type");
- expr->type = prim + TERRTYPE;
- }
+ /* usual arithmetic conversion */
+ if (lhs->type->kind < rhs->type->kind)
+ expr->type = rhs->type;
+ else
+ expr->type = lhs->type;
- goto joinbinarywrap;
+ expr->lhs = wrap(expr->type, lhs);
+ expr->rhs = wrap(expr->type, rhs);
+ return expr;
case OLSH: case ORSH: case OARSH:
- if (isinttype(lhs->type) && isinttype(rhs->type)) {
- expr->type = lhs->type;
- } else {
- error(
- &expr->loc,
- "expression is not of integer type"
- );
-
- expr->type = prim + TERRTYPE;
- }
+ reporton(!isinttype(lhs->type) || !isinttype(rhs->type),
+ &expr->loc, "expression is not of integer type");
- /* should be only wrap rhs */
- goto joinbinarywrap;
+ expr->lhs = conv(lhs);
+ expr->rhs = wrap(primitive(TINT), rhs);
+ expr->type = lhs->type;
+ return expr;
case OEQU: case ONEQ:
case OLET: case OLEQ:
case OGRT: case OGEQ:
- if (isarithtype(lhs->type) && isarithtype(rhs->type)) {
- expr->type = prim + TBOOL;
- } else {
- error(
- &expr->loc,
- "expression is not of integer type"
- );
+ reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type),
+ &expr->loc, "expression is not of arithmentic type");
- expr->type = prim + TERRTYPE;
- }
-
- goto joinbinaryconv;
+ expr->lhs = conv(lhs);
+ expr->rhs = conv(rhs);
+ expr->type = primitive(TBOOL);
+ return expr;
case OLAND: case OLOR:
- if (isarithtype(lhs->type) && isarithtype(rhs->type)) {
- expr->type = prim + TBOOL;
- } else {
- error(
- &expr->loc,
- "expression is not of integer type"
- );
-
- expr->type = prim + TERRTYPE;
- }
+ reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type),
+ &expr->loc, "expression is not of arithmentic type");
- goto joinbinaryconv;
+ expr->type = primitive(TBOOL);
+ expr->lhs = wrap(expr->type, lhs);
+ expr->rhs = wrap(expr->type, rhs);
+ return expr;
- case OASS:
case OMULA: case ODIVA: case OMODA:
- case OLSHA: case ORSHA: case OARSHA:
case OADDA: case OSUBA:
+ reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type),
+ &expr->loc, "expression is not of arithmentic type");
+ goto joinassign;
+
+ case OLSHA: case ORSHA: case OARSHA:
case OANDA:
case OORA: case OXORA:
- switch ((int) expr->kind) {
- case OASS:
- expr->type = lhs->type;
- break;
-
- case OMULA: case ODIVA: case OMODA:
- case OADDA: case OSUBA:
- if (isarithtype(lhs->type) &&
- isarithtype(rhs->type))
- {
- expr->type = lhs->type;
- } else {
- error(
- &expr->loc,
- "expression is not of arithmetic type"
- );
-
- expr->type = prim + TERRTYPE;
- }
-
- break;
-
- case OLSHA: case ORSHA: case OARSHA:
- case OANDA:
- case OORA: case OXORA:
- if (isinttype(lhs->type) &&
- isinttype(rhs->type))
- {
- expr->type = lhs->type;
- } else {
- error(
- &expr->loc,
- "expression is not of integer type"
- );
-
- expr->type = prim + TERRTYPE;
- }
+ reporton(!isinttype(lhs->type) || !isinttype(rhs->type),
+ &expr->loc, "expression is not of integer type");
+ /* FALLTHROUGH */
- break;
- }
+ case OASS:
+ joinassign:
+ reporton(!islvalue(lhs),
+ &expr->loc, "left-hand-side is not an lvalue");
expr->lhs = conv(lhs);
+ expr->type = lhs->type;
expr->rhs = wrap(expr->type, rhs);
return expr;
case KIF:
- lhs = expr->lhs;
- rhs = expr->rhs;
-
+ case KWHILE:
+ case KUNTIL:
assert(expr->u.payload);
expr->u.payload = typecheck(env, expr->u.payload);
- expr->u.payload = wrap(prim + TBOOL, expr->u.payload);
+ expr->u.payload = wrap(primitive(TBOOL), expr->u.payload);
if (lhs)
expr->lhs = typecheck(env, lhs);
@@ -3484,15 +3519,14 @@ typecheck(Env *env, Node *expr)
* might be needed by the enclosed statement-list
*/
- expr->type = prim + TVOID;
+ expr->type = primitive(TVOID);
return expr;
case ASCOPE:
- assert(expr->lhs);
+ assert(lhs);
assert(expr->u.env);
- expr->lhs = typecheck(expr->u.env, expr->lhs);
-
+ expr->lhs = typecheck(expr->u.env, lhs);
return expr;
case ASTMT:
@@ -3506,20 +3540,18 @@ typecheck(Env *env, Node *expr)
rhs = rhs->rhs, lhs = rhs->lhs;
goto advancestmt;
}
-
return expr;
case ADECL:
expr->type = typecheckdecl(env, expr->u.declref);
-
return expr;
case AADDR:
case ADEREF:
- assert(expr->lhs);
- expr->lhs = typecheck(env, expr->lhs);
- expr->lhs = conv(expr->lhs);
+ assert(lhs);
+ lhs = typecheck(env, lhs);
+ expr->lhs = conv(lhs);
return expr;
case IDENT:
@@ -3540,11 +3572,8 @@ typecheck(Env *env, Node *expr)
* the same node.
* - check wether the resulting type
* does account for nesting on rhs */
-
- if (lhs->type->kind == TERRTYPE || rhs->type->kind == TERRTYPE) {
- expr->type = prim + TERRTYPE;
- return expr;
- }
+ errortype(lhs->type->kind == TERRTYPE);
+ errortype(rhs->type->kind == TERRTYPE);
lhs = typecheck(env, lhs);
rhs = typecheck(env, rhs);
@@ -3553,7 +3582,7 @@ typecheck(Env *env, Node *expr)
expr->lhs = conv(lhs);
expr->rhs = conv(rhs);
- expr->type = maketype(&expr->loc, prim + TTUPLE, lhs->type);
+ expr->type = maketype(&expr->loc, primitive(TTUPLE), lhs->type);
expr->type->u.rtarget = rhs->type;
return expr;
@@ -3563,17 +3592,9 @@ typecheck(Env *env, Node *expr)
expr->lhs = lhs = typecheck(env, lhs);
- if (lhs->type->kind == TERRTYPE)
- return expr->type = prim + TERRTYPE, expr;
-
- if (rhs->type->kind == TERRTYPE)
- return expr->type = prim + TERRTYPE, expr;
-
- if (rhs->kind != TYPE) {
- error(&rhs->loc, "expected type");
- expr->type = prim + TERRTYPE;
- return expr;
- }
+ errortype(lhs->type->kind == TERRTYPE);
+ errortype(rhs->type->kind == TERRTYPE);
+ reporton(rhs->kind != TYPE, &rhs->loc, "expected type");
expr->type = rhs->type;
return expr;
@@ -3582,28 +3603,58 @@ typecheck(Env *env, Node *expr)
case KALIGNOF:
case KLENGTHOF:
assert(lhs);
+
expr->lhs = lhs = typecheck(env, lhs);
+ errortype(lhs->type->kind == TERRTYPE);
+
+ expr->type = primitive(TUSIZE);
+ return expr;
+
+ case KRETURN:
+ rhs = expr->rhs;
+
+ if (rhs) {
+ expr->rhs = rhs = typecheck(env, rhs);
+ errortype(rhs->type->kind == TERRTYPE);
+ }
+
+ do {
+ Env *funcenv = getfuncenv(env);
+ Type *functype;
+
+ reporton(!funcenv,
+ &expr->loc, "return statement is not inside a function");
+
+ assert(funcenv->envdecl);
+ assert(funcenv->envdecl->type);
- if (lhs->type->kind == TERRTYPE)
- return expr->type = prim + TERRTYPE, expr;
+ functype = funcenv->envdecl->type;
+
+ assert(functype->kind == TFUNCTION);
+ assert(functype->u.rtarget);
+
+ expr->type = functype->u.rtarget;
+ } while (0);
+
+ reporton(expr->type->kind == TVOID &&
+ rhs && rhs->type->kind != TVOID,
+ &expr->loc, "expected no return value");
+
+ reporton(expr->type->kind != TVOID &&
+ (!rhs || rhs->type->kind == TVOID),
+ &expr->loc, "expected return value");
+
+ if (rhs)
+ expr->lhs = wrap(expr->type, rhs);
- expr->type = prim + TUSIZE;
return expr;
default:
return expr;
}
-joinbinaryconv:
- expr->rhs = conv(rhs);
-joinunaryconv:
- expr->lhs = conv(lhs);
- return expr;
-
-joinbinarywrap:
- expr->rhs = wrap(expr->type, rhs);
- expr->lhs = wrap(expr->type, lhs);
- return expr;
+ #undef errortype
+ #undef reporton
}
static Node *
@@ -3620,7 +3671,7 @@ foldexpr(Env *env, Node *expr)
maskfloat(ty->size, lhs->u.d) op \
maskfloat(ty->size, rhs->u.d) \
); \
- else if (isinttype(ty)) \
+ else if (isintorbooltype(ty)) \
expr->u.u = maskint(ty->size, \
maskint(ty->size, lhs->u.u) op \
maskint(ty->size, rhs->u.u) \
@@ -3630,7 +3681,7 @@ foldexpr(Env *env, Node *expr)
} while (0)
#define isvalue(expr, value) (expr->kind == NUMBER && \
- ((expr->u.u == value && isinttype(ty)) || \
+ ((expr->u.u == value && isintorbooltype(ty)) || \
(expr->u.d == value && isarithtype(ty))))
/* TODO(m21c): maybe modify getnumops() in such a way, that it
@@ -3669,7 +3720,7 @@ foldexpr(Env *env, Node *expr)
if (expr->kind == OMUL) {
evalbinary(*);
} else {
- if (rhs->u.u == 0 && isinttype(ty)) {
+ if (rhs->u.u == 0 && isintorbooltype(ty)) {
error(
&expr->loc,
"division by zero"
@@ -3689,7 +3740,7 @@ foldexpr(Env *env, Node *expr)
deletenode(lhs);
deletenode(rhs);
} else if (isvalue(rhs, 0)) {
- if (rhs->u.u == 0 && isinttype(ty))
+ if (rhs->u.u == 0 && isintorbooltype(ty))
error(&expr->loc, "division by zero");
*expr = *rhs;
deletenode(lhs);
@@ -3718,7 +3769,7 @@ foldexpr(Env *env, Node *expr)
expr->kind = NUMBER;
expr->u.d = maskfloat(ty->size, -lhs->u.d);
deletenode(lhs);
- } else if (isinttype(ty)) {
+ } else if (isintorbooltype(ty)) {
expr->kind = NUMBER;
expr->u.u = maskint(ty->size, -lhs->u.u);
deletenode(lhs);
@@ -3732,16 +3783,8 @@ foldexpr(Env *env, Node *expr)
case OBAND: case OBOR: case OXOR:
if (lhs->kind == NUMBER && rhs->kind == NUMBER) {
- assert(
- isinttype(lhs->type) ||
- lhs->type->kind == TBOOL
- );
-
- assert(
- isinttype(rhs->type) ||
- rhs->type->kind == TBOOL
- );
-
+ assert(isintorbooltype(lhs->type));
+ assert(isintorbooltype(rhs->type));
lhs->u.u = maskint(ty->size, lhs->u.u);
rhs->u.u = maskint(ty->size, rhs->u.u);
if (expr->kind == OBAND)