Aria

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

commit ed3b745b91673943b102e11097e57c7289448601
parent 084b3befcf98c7e9ff9642197025075f4d4b4538
Author: m21c <ho*******@gmail.com>
Date:   Fri, 27 Jun 2025 21:14:06 +0200

worked on declaration + bundle + record

Diffstat:
Mcompiler.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(&param->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: