Aria

A low-level systems programming language
git clone git://git.m21c.me/Aria.git
Log | Files | Refs | LICENSE

commit 042c933eb160930b2971aa46316764aef44923cf
parent 5d3f81f553dc602164529513bf8b76831fbe3560
Author: m21c  <ho*******@gmail.com>
Date:   Sat,  5 Feb 2022 13:19:39 +0100

worked on typechecking

Diffstat:
Mcompiler.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)