commit 82b27b67550b5b5d715db6f17b24cfca4cead61b
parent ed3b745b91673943b102e11097e57c7289448601
Author: m21c <ho*******@gmail.com>
Date: Fri, 27 Jun 2025 21:19:00 +0200
worked on reccord + loops + dispatch
Diffstat:
| M | compiler.c | | | 453 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
1 file changed, 448 insertions(+), 5 deletions(-)
diff --git a/compiler.c b/compiler.c
@@ -215,7 +215,10 @@ struct Block Block;
entry(ASTMT , SASTMT , 0 , 0 , 0) \
entry(ADECL , SADECL , 0 , 0 , 0) \
entry(ADECLREF , SADECLREF , 0 , 0 , 0) \
+ entry(AENV , "env" , 0 , 0 , 0) \
entry(ALOOPUNTIL , SALOOPUNTIL , 0 , 0 , 0) \
+ entry(AFOREACH , "for-each" , 0 , 0 , 0) \
+ entry(AFORSTEP , "for-step" , 0 , 0 , 0) \
entry(ASCOPE , "scope" , 0 , 0 , 0) \
entry(ALABEL , "label" , 0 , 0 , 0) \
entry(ASWITCH , SASWITCH , 0 , 0 , 0) \
@@ -388,6 +391,8 @@ enum EnvKind {
SPARAMLIST,
SFUNCTION,
SSCOPE,
+ SIFHEADER,
+ SLOOPHEADER,
SDO,
SLOOP,
SWHILE,
@@ -1141,6 +1146,7 @@ redo:
goto redo;
}
+int auxthen, auxin, auxto, auxstep;
int auxself;
static int
@@ -2194,6 +2200,18 @@ deferfuncenv(Source *source, int keydeclinfunc)
return true;
}
+
+static Node *
+wrapenv(Node *node, Env *env)
+{
+ Node *aenv = makenode(node, node);
+
+ aenv->kind = AENV;
+ aenv->u.env = env;
+
+ return aenv;
+}
+
static void
deleteenv(Env *env)
{
@@ -3138,7 +3156,7 @@ skipnewlineontok(Source *source, Kind kind, int neededindent)
if (getkind(source) == LINEDELIM) {
savedtok = source->tok;
- if (gettok(source) == kind &&
+ if (gettok(source) == (int) kind &&
source->lastindent >= neededindent)
return true;
@@ -3149,6 +3167,51 @@ skipnewlineontok(Source *source, Kind kind, int neededindent)
}
static Node *
+readrecordinitfield(Source *source, Type *recordtype)
+{
+ Node *fieldinit = NULL;
+ Node savedtok = {0};
+
+ /* @todo add init-env */
+
+ skipnewline(source);
+
+ fieldinit = tokennode(source, NULL);
+ fieldinit->kind = AFIELDINIT;
+ if (getkind(source) == IDENT) {
+ savedtok = source->tok;
+ gettok(source);
+ if (getkind(source) == COLONDELIM) {
+ gettok(source);
+ /* @todo associate field name with field in record type */
+ fieldinit->lhs = makenode(&savedtok, NULL);
+ } else {
+ pushbacktok(source, &savedtok);
+ }
+ }
+
+ fieldinit->rhs = readexpr(source, PASSIGN);
+ return fieldinit;
+}
+
+static Node *
+readrecordinitfieldlist(Source *source, Type *recordtype)
+{
+ /* @todo add init-env */
+ /* @todo check for missing field-initializers */
+ Node *init = readrecordinitfield(source, recordtype);
+
+ while (skipnewline(source), getkind(source) == COMMADELIM) {
+ init = tokennode(source, init);
+ init->kind = ACOMMA;
+ gettok(source);
+ init->rhs = readrecordinitfield(source, recordtype);
+ }
+
+ return init;
+}
+
+static Node *
readatom(Source *source, int flags)
{
Node *lhs = NULL, *savedis = source->lastis;
@@ -3386,6 +3449,7 @@ readatom(Source *source, int flags)
indent = source->lastindent;
lhs = tokennode(source, NULL);
gettok(source);
+ pushenv(source, SLOOPHEADER);
lhs->lhs = stmtlist(source, indent, SLOOP, NULL, false);
if (skipnewlineontok(source, KUNTIL, indent)) {
@@ -3396,14 +3460,67 @@ readatom(Source *source, int flags)
if (lhs->kind != KLOOP)
goto joinelse;
- else
- /* skip postfix-operators */
- return lhs;
+
+ /* skip postfix-operators */
+ return wrapenv(lhs, popenv(source));
+
+ case KFOR:
+ indent = source->lastindent;
+ lhs = tokennode(source, NULL);
+ gettok(source);
+
+ pushenv(source, SLOOPHEADER);
+ lhs->u.payload = readexpr(source, POR);
+ if (getkind(source) == IDENT) {
+ if (source->tok.u.key == auxin) {
+ Node *aux = tokennode(source, NULL);
+ aux->lhs = lhs->u.payload;
+ aux->kind = AFOREACH;
+ lhs->u.payload = aux;
+ gettok(source);
+ aux->rhs = readexpr(source, POR);
+ } else if (source->tok.u.key == auxto) {
+ Node *aux = tokennode(source, NULL);
+ aux->lhs = lhs->u.payload;
+ aux->kind = AFORSTEP;
+ lhs->u.payload = aux;
+ gettok(source);
+ aux->rhs = readexpr(source, POR);
+ if (getkind(source) == IDENT
+ && source->tok.u.key == auxstep) {
+ gettok(source);
+ aux->u.payload = readexpr(source, POR);
+ } else {
+ aux->u.payload = tokennode(source, NULL);
+ aux->u.payload->kind = NUMBER;
+ aux->u.payload->type = primitive(TINFER);
+ aux->u.payload->u.s = 1;
+ }
+ } else if (source->tok.u.key == auxstep) {
+ Node *aux = tokennode(source, NULL);
+ aux->lhs = lhs->u.payload;
+ aux->kind = AFORSTEP;
+ lhs->u.payload = aux;
+ gettok(source);
+ aux->u.payload = readexpr(source, POR);
+
+ /* @note is this even correct? */
+ aux->rhs = tokennode(source, NULL);
+ aux->rhs->kind = NUMBER;
+ aux->rhs->type = primitive(TINFER);
+ aux->rhs->u.s = INTMAX_MAX;
+ }
+ }
+
+ /* @todo maybe use SFOR instead of SLOOP */
+ lhs->lhs = stmtlist(source, indent, SLOOP, NULL, false);
+ goto joinelse;
case KWHILE:
indent = source->lastindent;
lhs = tokennode(source, NULL);
gettok(source);
+ pushenv(source, SLOOPHEADER);
lhs->u.payload = readexpr(source, POR);
lhs->lhs = stmtlist(source, indent, SWHILE, NULL, false);
goto joinelse;
@@ -3412,6 +3529,7 @@ readatom(Source *source, int flags)
indent = source->lastindent;
lhs = tokennode(source, NULL);
gettok(source);
+ pushenv(source, SIFHEADER);
lhs->u.payload = readexpr(source, POR);
/* skipnewline(source); */
@@ -3426,7 +3544,7 @@ readatom(Source *source, int flags)
}
/* skip postfix-operators */
- return lhs;
+ return wrapenv(lhs, popenv(source));
default:
/* joinerror: */
@@ -3446,6 +3564,7 @@ readatom(Source *source, int flags)
gettok(source);
// source->lastindent = nextindent(source, source->lastindent);
+ lhs->rhs = readrecordinitfieldlist(source, lhs->type);
expect(source, RCURLDELIM, "expected '}'");
}
@@ -3513,6 +3632,18 @@ readatom(Source *source, int flags)
lhs->rhs = readexpr(source, PRELAT);
}
+ /* skip funtion-call without parentheses when next token is an
+ * auxiliary keyword */
+ if (getkind(source) == IDENT) {
+ if (source->tok.u.key == auxthen
+ || source->tok.u.key == auxin
+ || source->tok.u.key == auxto
+ || source->tok.u.key == auxstep) {
+ return lhs;
+ }
+ }
+
+
return lhs;
}
@@ -4036,6 +4167,93 @@ typecheckdecl(Env *env, Decl *decl)
}
static Node *
+substitutedispatch(Env *env, Node *expr)
+{
+#if 0
+ /* This is wrong (tuple != comma-operator)*/
+ assert(expr->u.declref);
+ assert(expr->type == expr->u.declref->type);
+
+ expr->kind = ACOMMA;
+ expr->type = maketype(&expr->loc, primitive(TTUPLE), expr->lhs->type);
+
+ expr->rhs->kind = ADECLREF;
+ expr->rhs->u.declref = expr->u.declref;
+ expr->rhs->type = expr->type;
+
+ expr->type->u.rtarget = expr->lhs->type;
+ return expr;
+#else
+ Node *result = makenode(expr, NULL);
+ result->kind = ADECLREF;
+ result->u.declref = expr->u.declref;
+ result->type = expr->type;
+
+ /* @fixme delete doesnt work (self is used multiple times) */
+ /* deletenode(expr); */
+ return result;
+#endif
+}
+
+static Node *
+substitutedispatchcall(Env *env, Node *expr)
+{
+ expr->lhs = substitutedispatch(env, expr->lhs);
+
+ return expr;
+}
+
+static Node *
+selfdispatchcall(Env *env, Node *expr)
+{
+ Node *self, *probe, *insert;
+
+ assert(expr && expr->kind == OCALL);
+
+ if (expr->lhs->kind != ASELFDISP)
+ return expr;
+
+ self = expr->lhs->lhs;
+ assert(self);
+ assert(self->type);
+
+ if (self->type->kind == TSTRUCT || self->type->kind == TUNION) {
+ self = makenode(self, self);
+ self->kind = OADDR;
+ self->type = maketype(&self->loc, primitive(TINT), self->type);
+ } else if (self->type->kind != TPTR) {
+ error(&self->loc, "expected struct or union or pointer type");
+ } else if (self->type->target->kind != TSTRUCT &&
+ self->type->target->kind != TUNION) {
+ error(&self->loc, "expected pointer to struct or union type");
+ }
+
+ if (!expr->rhs) {
+ expr->rhs = self;
+ return substitutedispatchcall(env, expr);
+ }
+
+ if (expr->rhs->kind != ACOMMA) {
+ insert = makenode(expr->rhs, self);
+ insert->kind = ACOMMA;
+ insert->rhs = expr->rhs;
+ expr->rhs = insert;
+
+ return substitutedispatchcall(env, expr);
+ }
+
+ probe = expr->rhs;
+ while (probe->lhs && probe->lhs->kind == ACOMMA)
+ probe = probe->lhs;
+
+ insert = makenode(probe, self);
+ insert->rhs = probe->lhs;
+ probe->lhs = insert;
+
+ return substitutedispatchcall(env, expr);
+}
+
+static Node *
resolvepending(Env *env, Node *expr)
{
Decl *decl;
@@ -4066,6 +4284,134 @@ resolvepending(Env *env, Node *expr)
}
static Node *
+dispatch(Node *expr, Node *parent)
+{
+ Type *type;
+ Decl *field;
+
+ /* @note might change in future */
+ assert(expr->lhs);
+ type = expr->lhs->type;
+ assert(type);
+
+ /* @todo maybe do implicit dereference */
+ if (type->kind == TPTR) {
+ Node *lhs = makenode(expr->lhs, expr->lhs);
+ lhs->kind = ADEREF;
+ lhs->type = type->target;
+
+ type = type->target;
+ expr->lhs = lhs;
+ }
+
+ if (type->kind != TSTRUCT && type->kind != TUNION) {
+ error(&expr->lhs->loc, "expected struct or union type");
+ return expr;
+ }
+
+ /* @note might change in future */
+ assert(expr->rhs);
+ assert(expr->rhs->kind == IDENT);
+
+ /* @note improvised for now */
+ assert(type->module->contentenv);
+ field = finddeclinenv(expr->rhs->u.key, type->module->contentenv);
+
+ if (!field) {
+ const char *typekind = type->kind == TSTRUCT ? "struct" : "union";
+ const char *modulename = getstring(idents, type->module->key);
+ const char *fieldname = getstring(idents, expr->rhs->u.key);
+ error(&expr->rhs->loc, "%s '%s' has no field '%s'",
+ typekind, modulename, fieldname);
+ expr->type = primitive(TERRTYPE);
+ return expr;
+ }
+
+ expr->type = field->type;
+ expr->u.declref = field;
+
+ return expr;
+}
+
+static void
+forloop(Env *env, Node *expr, Node *header)
+{
+ if (header->kind == AFORSTEP) {
+ Node *init = header->lhs;
+ if (init->kind == ADECL) {
+ Decl *it = init->u.declref;
+ if (!it->u.content) {
+ if (!isarithtype(it->type)) {
+ error(&it->loc, "for loop variable must be initialized");
+ return;
+ }
+ it->u.content = makenode(header, NULL);
+ it->u.content->kind = NUMBER;
+ it->u.content->type = it->type;
+ it->u.content->u.u = 0;
+ }
+
+ header->lhs = conv(typecheck(env, header->lhs));
+ }
+
+ /* @todo do proper typechecking */
+ header->rhs = wrap(header->lhs->type, typecheck(env, header->rhs));
+ header->u.payload = wrap(header->lhs->type, typecheck(env, header->u.payload));
+ return;
+ }
+
+ if (header->kind == AFOREACH) {
+
+ return;
+ }
+
+ header = expr->u.payload = conv(typecheck(env, header));
+
+ if (isarithtype(header->type)) {
+ Decl *it;
+ Node *forstep;
+
+
+ it = makedecl2(&header->loc, env,
+ getstringkey(&idents, "it", 2), DVAR);
+ it->type = header->type;
+ it->u.content = makenode(header, NULL);
+ it->u.content->kind = NUMBER;
+ it->u.content->type = header->type;
+ it->u.content->u.u = 0;
+
+ forstep = makenode(header, NULL);
+ forstep->kind = AFORSTEP;
+ forstep->type = header->type;
+
+ forstep->lhs = makenode(header, NULL);
+ forstep->lhs->kind = ADECL;
+ forstep->lhs->u.declref = it;
+
+ forstep->rhs = header;
+
+ forstep->u.payload = makenode(header, NULL);
+ forstep->u.payload->kind = NUMBER;
+ forstep->u.payload->type = header->type;
+ /* @todo handle negative step when possible
+ * (i.e. when header is signed and constant) */
+ if (isfloattype(header->type))
+ forstep->u.payload->u.d = 1.0;
+ else
+ forstep->u.payload->u.u = 1;
+
+ expr->u.payload = forstep;
+ return;
+ }
+
+ /* @todo handle other cases (e.g. arrays/strings/lists/iterators) */
+ error(&expr->loc, "invalid loop header");
+}
+
+Node *parentnodes[1024];
+int parenttop = 0;
+
+static Node *
typecheck(Env *env, Node *expr)
{
#define return return --parenttop,
@@ -4314,6 +4660,22 @@ typecheck(Env *env, Node *expr)
expr->type = primitive(TVOID);
return expr;
+ case KFOR:
+ assert(expr->u.payload);
+ forloop(env, expr, expr->u.payload);
+
+ if (lhs)
+ expr->lhs = typecheck(env, lhs);
+
+ if (rhs)
+ expr->rhs = typecheck(env, rhs);
+
+ /* @todo infer type of the for-loop like in the case above. */
+
+ expr->type = primitive(TVOID);
+ return expr;
+
+ case AENV:
case ASCOPE:
assert(lhs);
assert(expr->u.env);
@@ -4351,6 +4713,20 @@ typecheck(Env *env, Node *expr)
expr->lhs = conv(lhs);
return expr;
+ case ACOMPOUND:
+ assert(lhs);
+ assert(rhs);
+
+ expr->lhs = typecheck(env, lhs);
+ expr->type = lhs->type;
+ expr->rhs = typecheck(env, rhs);
+ return expr;
+
+ case AFIELDINIT:
+ assert(expr->rhs);
+ expr->rhs = typecheck(env, rhs);
+ return expr;
+
case IDENT:
return resolvepending(env, expr);
@@ -4453,6 +4829,7 @@ typecheck(Env *env, Node *expr)
#undef errortype
#undef reporton
+ #undef return
}
static Node *
@@ -5842,11 +6219,23 @@ printexpr(FILE *out, Node *expr, int indent)
break;
+ case CHAR:
+ /* @todo print chars correctly */
+ n += highlight(out, HLCHAR);
+ n += fprintf(out, "'%c'", (uchar) expr->u.u);
+ break;
+
case STRING:
n += highlight(out, HLSTRING);
n += printstring(out, expr);
break;
+ case TYPE:
+ /* @note might be unnecessary (only used for ACOMPOUND) */
+ n += highlight(out, HLTYPE);
+ n += printtype(out, expr->type, indent);
+ break;
+
case ADECLREF:
printdeclname(out, expr->u.declref, false);
break;
@@ -5915,6 +6304,31 @@ printexpr(FILE *out, Node *expr, int indent)
n += fprintf(out, "while ");
goto joinifbody;
+ case KFOR:
+ n += highlight(out, HLKEYWORD);
+ n += fprintf(out, "for ");
+ goto joinifbody;
+
+ case AFORSTEP:
+ n += printexpr(out, expr->lhs, indent);
+ n += highlight(out, HLKEYWORD);
+ n += fprintf(out, " to ");
+ n += printexpr(out, expr->rhs, indent);
+
+ assert(expr->u.payload);
+ if (expr->u.payload->kind == NUMBER && false) {
+ if (isfloattype(expr->u.payload->type)
+ && expr->u.payload->u.d == 1.0)
+ break;
+ if (isinttype(expr->u.payload->type)
+ && expr->u.payload->u.u == 1)
+ break;
+ }
+ n += highlight(out, HLKEYWORD);
+ n += fprintf(out, " step ");
+ n += printexpr(out, expr->u.payload, indent);
+ break;
+
case KIF:
n += highlight(out, HLKEYWORD);
n += fprintf(out, "if ");
@@ -6028,6 +6442,10 @@ printexpr(FILE *out, Node *expr, int indent)
n += printexpr(out, expr->lhs, indent);
n += fprintf(out, "\n"); /* blank line */
break;
+
+ case AENV:
+ n += printexpr(out, expr->lhs, indent);
+ break;
case ACONV:
n += highlight(out, HLNUMBER);
@@ -6057,6 +6475,31 @@ printexpr(FILE *out, Node *expr, int indent)
n += fputs("}", out);
break;
+ case ACOMPOUND:
+ n += highlight(out, HLTYPE);
+ n += printtype(out, expr->type, indent);
+ n += highlight(out, HLDELIM);
+ n += fputs("{", out);
+ n += printexpr(out, expr->rhs, indent);
+ n += highlight(out, HLDELIM);
+ n += fputs("}", out);
+ break;
+
+ case AFIELDINIT:
+ if (expr->lhs) {
+ n += highlight(out, HLDELIM);
+ n += fprintf(out, "%s: ", getstring(idents, expr->u.key));
+ }
+ n += printexpr(out, expr->rhs, indent);
+ break;
+
+ case ASELFDISP:
+ n += printexpr(out, expr->lhs, indent);
+ n += highlight(out, HLNONE);
+ /* @todo use printexpr when typechecked */
+ n += fprintf(out, ":%s", getstring(idents, expr->rhs->u.key));
+ break;
+
default:
n += highlight(out, HLINFO);
n += fprintf(out, "node(%u)", expr->kind);