commit ed3b745b91673943b102e11097e57c7289448601
parent 084b3befcf98c7e9ff9642197025075f4d4b4538
Author: m21c <ho*******@gmail.com>
Date: Fri, 27 Jun 2025 21:14:06 +0200
worked on declaration + bundle + record
Diffstat:
| M | compiler.c | | | 247 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
1 file changed, 222 insertions(+), 25 deletions(-)
diff --git a/compiler.c b/compiler.c
@@ -132,6 +132,7 @@ struct Block Block;
entry(KTRUE , "true" , 0 , 0 , 0) \
entry(KNULL , "null" , 0 , 0 , 0) \
entry(KUSE , "use" , 0 , 0 , 0) \
+ entry(KBUNDLE , "bundle" , 0 , 0 , 0) \
entry(KNOT , "not" , 0 , 0 , 0) \
entry(KAND , "and" , 0 , 0 , 0) \
entry(KOR , "or" , 0 , 0 , 0) \
@@ -222,6 +223,9 @@ struct Block Block;
entry(ACONV , SACONV , 0 , 0 , 0) \
entry(ADEREF , "*" , 0 , 0 , 0) \
entry(AADDR , "&" , 0 , 0 , 0) \
+ entry(ACOMPOUND , "{...}" , 0 , 0 , 0) \
+ entry(AFIELDINIT , ":" , 0 , 0 , 0) \
+ entry(ASELFDISP , ":" , 0 , 0 , 0) \
/* endof NODETAB */
#define isbinaryop(kind) ((kind) >= OMUL && (kind) < ACOMMA)
@@ -364,7 +368,8 @@ enum DeclKind {
DVAR,
DPARAM,
DFUNCTION,
- DFIELDALIAS
+ DFIELDALIAS,
+ DBUNDLE,
/*
DMACRO,
DENFOLD
@@ -372,6 +377,12 @@ enum DeclKind {
} DeclKind;
typedef
+enum DeclFlags {
+ MSPECIAL = 0x0001,
+ /* MINPORT = 0x0002, ... */
+} DeclFlags;
+
+typedef
enum EnvKind {
STOPLEVEL = 0,
SPARAMLIST,
@@ -512,11 +523,10 @@ struct Decl {
SrcLoc loc;
Type *type;
- Type *typemodule; /* the parent module type (is needed to associate a
- variable declaration inside a module to the parent
- module type) */
+ Decl *module; /* module or bundle */
int key;
+ DeclFlags flags;
Env *parentenv, *contentenv;
union {
@@ -539,6 +549,10 @@ struct Env {
Node *stmts;
Decl *envdecl; /* for SFUNCTION, SSTRUCT, SUNION */
+ /* for toplevel declarations. it will be assigned to decl->module
+ * if decl->module is null (in declaration()). */
+ Decl *bundle;
+
Env *below;
bool pending;
@@ -758,12 +772,12 @@ Source testsource;
#define defaultloc {0, 1, "<builtin>"}
+#define entry(tag, size, align) \
+ {(tag), defaultloc, NULL, (size), (align), {{0}}, NULL},
Type prim[] = {
- #define entry(tag, size, align) \
- {tag, defaultloc, NULL, size, align, {0}, NULL},
TYPETAB
- #undef entry
};
+#undef entry
#define primitive(typetag) (prim + typetag)
@@ -1127,7 +1141,7 @@ redo:
goto redo;
}
-int auxthen;
+int auxself;
static int
getstringkey(StringMap *map, const char *str, int n)
@@ -1837,6 +1851,7 @@ getunarysuffix(Source *source)
return 0;
switch (kind) {
+ case COLONDELIM: return ASELFDISP;
case LPARDELIM: return OCALL;
case LSQRDELIM: return OARRAY;
default:
@@ -2279,6 +2294,7 @@ makedecl(Source *source, int key, DeclKind kind)
decl->key = key;
decl->type = primitive(TVOID);
decl->contentenv = NULL;
+ decl->module = NULL;
appenddecltoenv(decl, currenv);
@@ -2286,6 +2302,69 @@ makedecl(Source *source, int key, DeclKind kind)
}
static Decl *
+makebundle(Source *source, int key, Decl *parentbundle)
+{
+ /* Env *currenv = source->currenv; */
+ Decl *decl;
+
+ /* assert(currenv); */
+
+ decl = declbuf + decltop++;
+
+ decl->kind = DBUNDLE;
+ /* TODO(m21c): make sure that source->tok.loc is the correct
+ * source-location. */
+ /* TODO(m21c): maybe use getloc(source) instead of
+ * &source->tok.loc and move the declaration of
+ * getloc() up in the source-code. */
+ decl->loc = source->tok.loc;
+ decl->key = key;
+ decl->type = primitive(TVOID);
+ decl->contentenv = NULL;
+ decl->module = parentbundle;
+
+ return decl;
+}
+
+static Decl *
+makedecl2(SrcLoc *loc, Env *env, int key, DeclKind kind)
+{
+ Decl *decl;
+
+ assert(env);
+
+ /* TODO(m21c): maybe remove check if already declared,
+ * since many functions that call makedecl
+ * already try to obtain a declaration for
+ * other reasons. So the check if it is
+ * already declared can be done by those
+ * functions */
+
+ decl = finddeclinenv(key, env);
+ if (decl) {
+ /* @todo maybe check also for implicit declarations */
+ error(loc, "'%s' already declared", getstring(idents, key));
+ }
+
+ decl = declbuf + decltop++;
+
+ decl->kind = kind;
+ /* TODO(m21c): make sure that source->tok.loc is the correct
+ * source-location. */
+ /* TODO(m21c): maybe use getloc(source) instead of
+ * &source->tok.loc and move the declaration of
+ * getloc() up in the source-code. */
+ decl->loc = *loc;
+ decl->key = key;
+ decl->type = primitive(TVOID);
+ decl->contentenv = NULL;
+
+ appenddecltoenv(decl, env);
+
+ return decl;
+}
+
+static Decl *
defertypedeclaration(Source *source, int key)
{
Env *savedcurrenv = source->currenv;
@@ -2777,9 +2856,15 @@ redodeclaration:
/* variable name */
if (getkind(source) == IDENT) {
- decl = makedecl(source, source->tok.u.key, DVAR);
+ Env *moduleenv = NULL;
+ assert(module->module);
+ assert(module->module->contentenv);
+ moduleenv = module->module->contentenv;
+
+ decl = makedecl2(&source->tok.loc,
+ moduleenv, source->tok.u.key, DVAR);
decl->type = ty;
- decl->typemodule = module;
+ decl->module = module->module;
gettok(source);
} else {
error(getloc(source), "expected identifier");
@@ -2793,6 +2878,9 @@ redodeclaration:
return result;
}
+ if (!decl->module)
+ decl->module = source->currenv->bundle;
+
/* function declaration */
if (getkind(source) == LPARDELIM) {
Type *paramtype = NULL;
@@ -2804,11 +2892,24 @@ redodeclaration:
if (getkind(source) != RPARDELIM) {
Decl *param;
Node *paramlist;
+ Type *paramtype = NULL;
functionenv = pushenv(source, SPARAMLIST);
functionenv->envdecl = decl;
- paramlist = exprlist(source, true, NULL);
+ if (selfparam) {
+ param = makedecl(source, auxself, DVAR);
+ param->type = maketype(¶m->loc,
+ prim + TPTR, module);
+ param->flags |= MSPECIAL;
+ /* @note param doesn't need to be added to
+ * paramlist. since paramlist will be
+ * deleted anyway and param is already
+ * present in env. */
+ paramtype = param->type;
+ }
+
+ paramlist = exprlist(source, true, paramtype);
paramlist = typecheck(functionenv, paramlist);
paramtype = paramlist->type;
deletenode(paramlist);
@@ -2819,6 +2920,17 @@ redodeclaration:
assert(param->kind == DVAR);
param->kind = DPARAM;
}
+ } else if (selfparam) {
+ Type *selftype = maketype(&decl->loc,
+ primitive(TPTR), module);
+ Decl *selfdecl;
+
+ functionenv = pushenv(source, SPARAMLIST);
+ functionenv->envdecl = decl;
+
+ selfdecl = makedecl(source, auxself, DPARAM);
+ selfdecl->type = selftype;
+ selfdecl->flags |= MSPECIAL;
}
expect(source, RPARDELIM, "expected ')'");
@@ -2830,6 +2942,7 @@ redodeclaration:
}
decl->type = maketype(&decl->loc, primitive(TFUNCTION), paramtype);
+ decl->kind = DFUNCTION;
decl->type->u.rtarget = ty;
ty = decl->type;
@@ -2855,16 +2968,12 @@ redodeclaration:
popenv(source);
}
-
- assert(decl);
assert(decl->contentenv == NULL);
decl->contentenv = functionenv;
assert(decl->u.content == NULL);
decl->u.content = body;
- assert(decl->kind == DVAR);
- decl->kind = DFUNCTION;
/* TODO(m21c): maybe add function-declaration to its type and
* add the paramlist to the type-info */
@@ -2997,14 +3106,20 @@ readrecord(Source *source, bool isunion)
module->type->module = module;
recordnode->type = module->type;
+ if (!module->module) /* @note currently module->module == NULL always */
+ module->module = source->currenv->bundle;
+
/* read record body */
- /* NOTE(m21c): we will stmtlist() for parsing the record body,
+ /* NOTE(m21c): maybe we will use stmtlist() for parsing the record body,
since we have to parse statements or expressions beside
field declarations */
/* TODO(m21c): check for new-line and only then read body */
recordnode->rhs = stmtlist(source, indent, envkind, module, false);
+ if (recordnode->rhs) {
+ module->contentenv = recordnode->rhs->u.env;
+ }
/* TODO(m21c): validate record body, extract declarations,
* compute size and align, resolve aliases */
@@ -3326,12 +3441,11 @@ readatom(Source *source, int flags)
/* compound-literal */
if (getkind(source) == LCURLDELIM && lhs->kind == TYPE) {
lhs = tokennode(source, lhs);
- lhs->kind = 'A'; /* FIXME(m21c): add kind for compound literals */
+ lhs->kind = ACOMPOUND;
lhs->type = lhs->lhs->type;
- gettok(source);
-
- lhs->rhs = exprlist(source, false, NULL);
+ gettok(source);
+ // source->lastindent = nextindent(source, source->lastindent);
expect(source, RCURLDELIM, "expected '}'");
}
@@ -3351,6 +3465,15 @@ readatom(Source *source, int flags)
lhs->rhs = tokennode(source, NULL);
+ } else if (getkind(source) == COLONDELIM) {
+ gettok(source);
+ skipnewline(source);
+
+ if (getkind(source) != IDENT)
+ error(getloc(source), "expected identifier");
+
+ lhs->rhs = tokennode(source, NULL);
+
} else if (getkind(source) == LPARDELIM) {
gettok(source);
@@ -3483,12 +3606,12 @@ exprlist(Source *source, bool isparam, Type *paramtype)
lhs = readexpr(source, PASSIGN);
}
- if (isparam && lhs->kind != ADECL)
- error(getloc(source), "expected declaration");
+ isdeclaration = lhs->kind == ADECL;
- if ((isdeclaration = lhs->kind == ADECL)) {
+ if (isdeclaration)
paramtype = lhs->type;
- }
+ else if (isparam)
+ error(getloc(source), "expected declaration");
typetuple = lhs->kind == TYPE;
@@ -3681,6 +3804,7 @@ islvalue(Node *node)
case ADECLREF:
case ADEREF:
case ADECL:
+ case ODISP: /* only for member fields. @todo evaluate for properties. */
case TERRTYPE: /* avoiding error-reporting on error-type */
return true;
@@ -3731,6 +3855,12 @@ wrap(Type *type, Node *node)
Type *nodetype = node->type;
assert(type);
+
+ // @todo add error-reporting | refactor
+ if (!nodetype) {
+ printf("node has no type\n");
+ }
+
assert(nodetype);
/* TODO(m21c): do proper type-check */
@@ -3938,8 +4068,12 @@ resolvepending(Env *env, Node *expr)
static Node *
typecheck(Env *env, Node *expr)
{
+ #define return return --parenttop,
+
Node *lhs = expr->lhs, *rhs = expr->rhs;
+ parentnodes[parenttop++] = expr;
+
#define errortype(condition) do { \
if (condition) { \
expr->type = primitive(TERRTYPE); \
@@ -3974,6 +4108,48 @@ typecheck(Env *env, Node *expr)
return expr;
switch (expr->kind) {
+ case ODISP:
+ case ASELFDISP:
+ lhs = typecheck(env, lhs);
+ expr->lhs = conv(lhs);
+
+ if (parenttop > 1)
+ return dispatch(expr, parentnodes[parenttop - 2]);
+
+ return dispatch(expr, NULL);
+
+ case OCALL:
+ reporton(lhs->type->kind == TPTR && lhs->type->target->kind != TFUNCTION,
+ &expr->loc, "operand is not a pointer to function");
+
+ reporton(lhs->type->kind != TPTR && lhs->type->kind != TFUNCTION,
+ &expr->loc, "operand is not a function");
+
+ if (lhs->type->kind == TFUNCTION)
+ expr->type = lhs->type->u.rtarget;
+ else
+ expr->type = lhs->type->target->u.rtarget;
+
+ expr = selfdispatchcall(env, expr);
+ expr->rhs = typecheck(env, expr->rhs);
+ return expr;
+
+ case OARRAY:
+ expr->lhs = conv(lhs);
+ reporton(lhs->type->kind != TARRAY && lhs->type->kind != TPTR,
+ &expr->loc, "operand is not an array or pointer");
+
+ expr->rhs = typecheck(env, rhs);
+
+ /* @todo handle negative indices when possible (use unsigned) */
+ reporton(!isinttype(rhs->type),
+ &rhs->loc, "array index is not an integer");
+
+ expr->rhs = wrap(primitive(TUSIZE), expr->rhs);
+
+ expr->type = lhs->type->target;
+ return expr;
+
case OINC: case ODEC: case OSUFINC: case OSUFDEC:
reporton(!islvalue(lhs),
&expr->loc, "operand is not an lvalue");
@@ -4161,6 +4337,11 @@ typecheck(Env *env, Node *expr)
case ADECL:
expr->type = typecheckdecl(env, expr->u.declref);
return expr;
+
+ case ADECLREF:
+ /* @note propagate type changes from ADECL to ADECLREF */
+ expr->type = expr->u.declref->type;
+ return expr;
case AADDR:
case ADEREF:
@@ -4803,6 +4984,15 @@ fetchblocks(Block *block, Node *expr)
appendconduct(block, CSCOPE, NULL);
return;
+ case ACOMMA:
+ assert(lhs);
+ assert(rhs);
+
+ /* @note is this correct? */
+ fetchblocks(block, lhs);
+ fetchblocks(block, rhs);
+ return;
+
case KIF:
assert(lhs);
assert(expr->u.payload);
@@ -5553,7 +5743,14 @@ printexpr(FILE *out, Node *expr, int indent)
case ODISP:
n += highlight(out, HLDELIM);
n += fprintf(out, ".");
- n += printexpr(out, expr->rhs, indent);
+ if (expr->rhs && expr->rhs->kind == IDENT) {
+ n += highlight(out, HLIDENT);
+ n += fprintf(out, "%s",
+ getstring(idents, expr->rhs->u.key));
+ } else {
+ /* @note this might be unnecessary */
+ n += printexpr(out, expr->rhs, indent);
+ }
break;
default: