diff --git a/src/ast.c b/src/ast.c index 6fcc8c4..287749b 100644 --- a/src/ast.c +++ b/src/ast.c @@ -10,8 +10,8 @@ const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) }; -void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, void(*handler)(AST**, AST*, AST*, AST*, AST*, void*)) { - handler(nptr, stmt, stmtPrev, chu, tlc, ud); +void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, GenericVisitorHandler preHandler, GenericVisitorHandler postHandler) { + if(preHandler) preHandler(nptr, stmt, stmtPrev, chu, tlc, ud); AST *n = *nptr; @@ -19,51 +19,51 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v AST *sPrev = NULL; AST **s = &n->chunk.statementFirst; while(*s) { - generic_visitor(s, *s, sPrev, n, tlc, ud, handler); + generic_visitor(s, *s, sPrev, n, tlc, ud, preHandler, postHandler); sPrev = *s; s = &sPrev->statement.next; } } else if(n->nodeKind == AST_STMT_ASSIGN) { - generic_visitor(&n->stmtAssign.what, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtAssign.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); if(n->stmtAssign.to) { - generic_visitor(&n->stmtAssign.to, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtAssign.to, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } } else if(n->nodeKind == AST_STMT_IF) { - generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, handler); - generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); + generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else if(n->nodeKind == AST_STMT_LOOP) { - generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else if(n->nodeKind == AST_STMT_BREAK) { } else if(n->nodeKind == AST_STMT_CONTINUE) { } else if(n->nodeKind == AST_STMT_EXT_ALIGN) { } else if(n->nodeKind == AST_STMT_DECL) { if(n->stmtDecl.expression) { - generic_visitor(&n->stmtDecl.expression, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtDecl.expression, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } } else if(n->nodeKind == AST_STMT_EXPR) { - generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else if(n->nodeKind == AST_STMT_EXT_ORG) { } else if(n->nodeKind == AST_STMT_EXT_SECTION) { } else if(n->nodeKind == AST_STMT_RETURN) { if(n->stmtReturn.val) { - generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } } else if(n->nodeKind == AST_EXPR_BINARY_OP) { - generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, handler); - generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); + generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else if(n->nodeKind == AST_EXPR_CALL) { - generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); for(size_t i = 0; i < n->exprCall.what->expression.type->function.argCount; i++) { - generic_visitor(&n->exprCall.args[i], stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprCall.args[i], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } } else if(n->nodeKind == AST_EXPR_CAST) { - generic_visitor(&n->exprCast.what, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprCast.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else if(n->nodeKind == AST_EXPR_FUNC) { - generic_visitor(&n->exprFunc.chunk, NULL, NULL, n->exprFunc.chunk, n->exprFunc.chunk, ud, handler); + generic_visitor(&n->exprFunc.chunk, NULL, NULL, n->exprFunc.chunk, n->exprFunc.chunk, ud, preHandler, postHandler); } else if(n->nodeKind == AST_EXPR_UNARY_OP) { - generic_visitor(&n->exprUnOp.operand, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprUnOp.operand, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else if(n->nodeKind == AST_EXPR_VAR) { } else if(n->nodeKind == AST_EXPR_STACK_POINTER) { } else if(n->nodeKind == AST_EXPR_PRIMITIVE) { @@ -73,18 +73,16 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v assert(n->expression.type->array.length != 0); for(size_t i = 0; i < n->expression.type->array.length; i++) { - generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } } else if(n->nodeKind == AST_EXPR_EXT_SALLOC) { } else if(n->nodeKind == AST_EXPR_DOT) { - generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else { abort(); } -} - -AST *ast_expression_optimize(AST *ast) { - return ast; + + if(postHandler) postHandler(nptr, stmt, stmtPrev, chu, tlc, ud); } int ast_expression_equal(AST *a, AST *b) { @@ -100,9 +98,11 @@ int ast_expression_equal(AST *a, AST *b) { return a->exprBinOp.operator == b->exprBinOp.operator && ast_expression_equal(a->exprBinOp.operands[0], b->exprBinOp.operands[0]) && ast_expression_equal(a->exprBinOp.operands[1], b->exprBinOp.operands[1]); } else if(a->nodeKind == AST_EXPR_STACK_POINTER) { return 1; + } else if(a->nodeKind == AST_EXPR_CAST) { + return ast_expression_equal(a->exprCast.what, b->exprCast.what) && type_equal(a->exprCast.to, b->exprCast.to) && a->exprCast.reinterpretation == b->exprCast.reinterpretation; + } else { + stahp_node(a, "ast_expression_equal: unhandled %s", AST_KIND_STR[a->nodeKind]); } - - return 0; } // This function may return three values: YES (1), NO (0) or UNKNOWN (-1). @@ -231,7 +231,7 @@ static void adduse(VarTableEntry *vte, AST *use, AST *whole) { if(!rd) return; for(size_t d = 0; d < rd->defCount; d++) { - UseDef *ud = malloc(sizeof(*ud)); + UseDef *ud = calloc(1, sizeof(*ud)); ud->def = rd->defs[d]; ud->use = use; ud->stmt = whole; @@ -277,7 +277,7 @@ static void mergedefs(VarTableEntry *vte) { static void pushdefs(VarTableEntry *vte) { assert(vte->kind == VARTABLEENTRY_VAR); - ReachingDefs *rdefs = malloc(sizeof(*rdefs)); + ReachingDefs *rdefs = calloc(1, sizeof(*rdefs)); rdefs->defCount = 0; rdefs->defs = NULL; rdefs->excludeParent = 0; @@ -455,6 +455,20 @@ char *type_to_string(Type *t) { return r; } else if(t->type == TYPE_TYPE_RECORD) { return malp("%s", t->record.name); + } else if(t->type == TYPE_TYPE_GENERIC) { + return malp("%s", t->generic.paramName); + } else if(t->type == TYPE_TYPE_ARRAY) { + char *of = type_to_string(t->array.of); + char *len = NULL; + if(t->array.lengthIsGeneric) { + len = malp(""); + } else { + len = malp("%i", t->array.length); + } + char *r = malp("%s[%s]", of, len); + free(of); + free(len); + return r; } return strdup("@unimp"); @@ -552,6 +566,11 @@ static char *ast_dumpe(AST *e) { } else if(e->nodeKind == AST_EXPR_FUNC) { char *out = NULL; + if(type_is_generic(e->expression.type)) { + out = malp("(generic)"); + return out; + } + { char *rettype = type_to_string(e->expression.type->function.ret); out = malp("%s(", rettype); @@ -660,6 +679,8 @@ static char *ast_dumps(AST *s) { } return malp("%s; /* loop guard */\n", name); + } else if(s->nodeKind == AST_STMT_EXPR) { + return ast_dumpe(s->stmtExpr.expr); } else if(s->nodeKind == AST_STMT_RETURN) { if(s->stmtReturn.val) { char *e = ast_dumpe(s->stmtReturn.val); @@ -677,7 +698,7 @@ static char *ast_dumps(AST *s) { char *ast_dump(AST *tlc) { AST *stmt = tlc->chunk.statementFirst; - char *ret = NULL; + char *ret = strdup(""); #define CAT(s) do { char *b = s; ret = cat(ret, (b)); free(b); } while(0) @@ -712,15 +733,15 @@ AST *ast_cast_expr(AST *what, Type *to) { /* Only exists at parse-time, hence not part of type system and is handled separately */ if(what->nodeKind == AST_EXPR_STRING_LITERAL) { if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && to->array.length == what->exprStrLit.length) { - ASTExprArray *ret = malloc(sizeof(*ret)); + ASTExprArray *ret = calloc(1, sizeof(*ret)); ret->nodeKind = AST_EXPR_ARRAY; - ret->items = malloc(sizeof(*ret->items) * to->array.length); + ret->items = calloc(to->array.length, sizeof(*ret->items)); ret->type = to; for(int i = 0; i < to->array.length; i++) { uint8_t bajt = what->exprStrLit.data[i]; - ASTExprPrimitive *item = malloc(sizeof(*item)); + ASTExprPrimitive *item = calloc(1, sizeof(*item)); item->nodeKind = AST_EXPR_PRIMITIVE; item->type = to->array.of; item->val = bajt; @@ -731,10 +752,10 @@ AST *ast_cast_expr(AST *what, Type *to) { return (AST*) ret; } else if(to->type == TYPE_TYPE_PRIMITIVE) { if(to->primitive.width != what->exprStrLit.length * 8) { - stahp(0, 0, "Size mismatch between string literal and target type"); + stahp_node(what, "Size mismatch between string literal and target type"); } - ASTExprPrimitive *ret = malloc(sizeof(*ret)); + ASTExprPrimitive *ret = calloc(1, sizeof(*ret)); ret->nodeKind = AST_EXPR_PRIMITIVE; ret->type = to; memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val)); @@ -742,6 +763,12 @@ AST *ast_cast_expr(AST *what, Type *to) { } else abort(); } + // Make sure an unparametrized generic int parameter hasn't sneaked its way in + while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_CEXPR && what->exprVar.thing->data.cexpr.concrete) { + what = what->exprVar.thing->data.cexpr.concrete; + } + assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_CEXPR)); + if(type_equal(what->expression.type, to)) return what; if(!type_is_castable(what->expression.type, to)) { @@ -749,7 +776,7 @@ AST *ast_cast_expr(AST *what, Type *to) { } if(what->nodeKind == AST_EXPR_PRIMITIVE && (to->type == TYPE_TYPE_PRIMITIVE || to->type == TYPE_TYPE_POINTER)) { - ASTExprPrimitive *ret = malloc(sizeof(*ret)); + ASTExprPrimitive *ret = calloc(1, sizeof(*ret)); ret->nodeKind = AST_EXPR_PRIMITIVE; ret->type = to; @@ -761,7 +788,7 @@ AST *ast_cast_expr(AST *what, Type *to) { return (AST*) ret; } else { - ASTExprCast *ret = malloc(sizeof(*ret)); + ASTExprCast *ret = calloc(1, sizeof(*ret)); ret->nodeKind = AST_EXPR_CAST; ret->type = to; ret->what = what; @@ -770,7 +797,7 @@ AST *ast_cast_expr(AST *what, Type *to) { } fail: - stahp(0, 0, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to)); + stahp_node(what, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to)); } struct Spill2StackState { @@ -795,23 +822,23 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk if(a->exprVar.thing == this->target) { // DO THE SPILL - ASTExprStackPointer *rsp = malloc(sizeof(*rsp)); + ASTExprStackPointer *rsp = calloc(1, sizeof(*rsp)); rsp->nodeKind = AST_EXPR_STACK_POINTER; rsp->type = primitive_parse("u32"); - ASTExprPrimitive *offset = malloc(sizeof(*offset)); + ASTExprPrimitive *offset = calloc(1, sizeof(*offset)); offset->nodeKind = AST_EXPR_PRIMITIVE; offset->type = rsp->type; offset->val = -this->stackGrowth; // This will be affected by the other part of this pass, so we must reverse - ASTExprBinaryOp *bop = malloc(sizeof(*bop)); + ASTExprBinaryOp *bop = calloc(1, sizeof(*bop)); bop->nodeKind = AST_EXPR_BINARY_OP; bop->type = rsp->type; bop->operator = BINOP_ADD; bop->operands[0] = (AST*) rsp; bop->operands[1] = (AST*) offset; - ASTExprUnaryOp *deref = malloc(sizeof(*deref)); + ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); deref->nodeKind = AST_EXPR_UNARY_OP; deref->type = a->expression.type; deref->operator = UNOP_DEREF; @@ -829,8 +856,11 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk } void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) { - assert(vte != NULL); assert(tlc->nodeKind == AST_CHUNK); + assert(vte != NULL); + assert(vte->kind == VARTABLEENTRY_VAR); + + fprintf(stderr, "Spilling %s to stack...\n", vte->data.var.name); struct Spill2StackState state; memset(&state, 0, sizeof(state)); @@ -838,5 +868,36 @@ void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) { state.targetTLC = tlc; state.stackGrowth = (type_size(vte->type) + 7) & ~7; - generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL); +} + +static void typecheck_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + AST *a = *aptr; + + if(a->nodeKind == AST_EXPR_CALL) { + if(a->exprCall.what->expression.type != TYPE_TYPE_FUNCTION) { + stahp_node(a, "Only function types may be called."); + } + } else if(a->nodeKind == AST_EXPR_BINARY_OP) { + if(!type_is_number(a->exprBinOp.operands[0]) || !type_is_number(a->exprBinOp.operands[1])) { + stahp_node(a, "Operands must be numbers."); + } + + if(type_size(a->exprBinOp.operands[0]->expression.type) < type_size(a->exprBinOp.operands[1]->expression.type)) { + a->exprBinOp.operands[0] = ast_cast_expr(a->exprBinOp.operands[0], a->exprBinOp.operands[1]->expression.type); + } + + if(type_size(a->exprBinOp.operands[1]->expression.type) < type_size(a->exprBinOp.operands[0]->expression.type)) { + a->exprBinOp.operands[1] = ast_cast_expr(a->exprBinOp.operands[1], a->exprBinOp.operands[0]->expression.type); + } + + if(!a->exprBinOp.type) { + a->exprBinOp.type = a->exprBinOp.operands[0]->expression.type; + } + } else if(a->nodeKind == AST_EXPR_UNARY_OP) { + + } +} +void ast_type_check(AST *tlc, VarTableEntry *vte) { + generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, typecheck_visitor); } diff --git a/src/ast.h b/src/ast.h index 2e8d1e4..da55f72 100644 --- a/src/ast.h +++ b/src/ast.h @@ -111,6 +111,12 @@ union AST; typedef struct { ASTKind nodeKind; + uint16_t row; + uint16_t col; +} ASTBase; + +typedef struct { + ASTBase; Type *type; } ASTExpr; @@ -163,10 +169,15 @@ typedef struct { ASTExpr; union AST *chunk; + + // Necessary for when the parser jumps to a generic function + Token *rangeTokens; + size_t startTokI; + size_t endTokI; } ASTExprFunc; typedef struct { - ASTKind nodeKind; + ASTBase; size_t size; } ASTType; @@ -185,7 +196,7 @@ typedef struct { } ASTTypePointer; typedef struct { - ASTKind nodeKind; + ASTBase; union AST *next; } ASTStmt; @@ -198,12 +209,16 @@ typedef struct { } ASTStmtDecl; typedef struct { - ASTKind nodeKind; + ASTBase; /* Flattened variable array for global register allocation */ size_t varCount; VarTableEntry **vars; + /* extern symbol array */ + size_t externCount; + VarTableEntry **externs; + union AST *statementFirst; union AST *statementLast; @@ -301,7 +316,7 @@ typedef struct { } ASTStmtReturn; typedef union AST { - ASTKind nodeKind; + ASTBase; ASTChunk chunk; ASTStmt statement; @@ -332,9 +347,9 @@ typedef union AST { #pragma pack(pop) -void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, void(*handler)(AST**, AST*, AST*, AST*, AST*, void*)); +typedef void(*GenericVisitorHandler)(AST**, AST*, AST*, AST*, AST*, void*); +void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, GenericVisitorHandler preHandler, GenericVisitorHandler postHandler); -AST *ast_expression_optimize(AST*); int ast_expression_equal(AST*, AST*); int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2); @@ -349,6 +364,8 @@ AST *ast_cast_expr(AST *what, Type *to); void ast_spill_to_stack(AST *tlc, VarTableEntry *vte); +void ast_typecheck(AST *tlc); + __attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...); #endif diff --git a/src/cg.c b/src/cg.c index 779901e..4eaeafe 100644 --- a/src/cg.c +++ b/src/cg.c @@ -120,6 +120,10 @@ static AST *is_field_access(AST *e) { return e; } + if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_ADD && e->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR) { + return e; + } + return NULL; } @@ -131,7 +135,8 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { char *ret = bufs[bufidx]; - if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) { + //if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) { + if(e->nodeKind == AST_EXPR_CAST) { e = e->exprCast.what; } @@ -154,10 +159,22 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4)); } else if(is_field_access(e)) { e = is_field_access(e); - snprintf(ret, XOPBUFSZ, "%s [%s + %i]", - spec(sz), - e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, - e->exprBinOp.operands[1]->exprPrim.val); + + if(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP) { + assert(e->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF); + + snprintf(ret, XOPBUFSZ, "%s [%s + %i]", + spec(sz), + e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, + e->exprBinOp.operands[1]->exprPrim.val); + } else { + assert(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR); + + snprintf(ret, XOPBUFSZ, "%s [%s + %i]", + spec(sz), + regs[e->exprBinOp.operands[0]->exprVar.thing->data.var.color][2], + e->exprBinOp.operands[1]->exprPrim.val); + } } else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && p->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && p->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]", spec(sz), @@ -238,7 +255,9 @@ void cg_chunk(CGState *cg, AST *a) { VarTableEntry *v = s->stmtDecl.thing; if(v->data.symbol.isExternal) { - printf("extern %s\n", v->data.symbol.name); + // Do nothing. + // All external symbols are handled at once in the top-level chunk. + //printf("extern %s\n", v->data.symbol.name); } else { if(!v->data.symbol.isLocal) { printf("global %s\n", v->data.symbol.name); @@ -265,9 +284,14 @@ void cg_chunk(CGState *cg, AST *a) { assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC); - dumben_go(s->stmtDecl.expression->exprFunc.chunk); - while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { + // Generic functions have non-NULL code blocks + if(!type_is_generic(s->stmtDecl.expression->expression.type)) { + dumben_go(s->stmtDecl.expression->exprFunc.chunk); + while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { + dumben_go(s->stmtDecl.expression->exprFunc.chunk); + } + } } else abort(); @@ -375,7 +399,7 @@ void cg_chunk(CGState *cg, AST *a) { printf("neg %s\n", xop(cg->tlc, s->stmtAssign.what)); - } else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) { + } else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST && type_size(s->stmtAssign.what->expression.type) > type_size(s->stmtAssign.to->expression.type)) { printf("movzx %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprCast.what)); @@ -448,7 +472,15 @@ void cg_chunk(CGState *cg, AST *a) { /* Loop guard, probably. */ - } else abort(); + } else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_UNARY_OP && s->stmtExpr.expr->exprUnOp.operator == UNOP_DEREF && s->stmtExpr.expr->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) { + + /* Loop guard for a spilled variable, probably. */ + + } else { + + stahp_node(s, "Unknown statement caught by code generator."); + + } s = s->statement.next; } @@ -801,7 +833,7 @@ static void callee_saved(AST *tlc) { state.targetTLC = tlc; state.ebxuser = ebxuser; - generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor, NULL); } } @@ -812,6 +844,15 @@ static int comparator(const void *A, const void *B) { return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority); } int cg_go(AST *a) { + assert(a->nodeKind == AST_CHUNK); + + for(size_t e = 0; e < a->chunk.externCount; e++) { + assert(a->chunk.externs[e]->kind == VARTABLEENTRY_SYMBOL); + assert(a->chunk.externs[e]->data.symbol.isExternal); + + printf("extern %s\n", a->chunk.externs[e]->data.symbol.name); + } + ast_usedef_reset(a); size_t adjCount = 0; diff --git a/src/dumberdowner.c b/src/dumberdowner.c index d5b3fe8..dff0b15 100644 --- a/src/dumberdowner.c +++ b/src/dumberdowner.c @@ -42,13 +42,13 @@ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { ASTExprVar *ev[2]; for(int i = 0; i < 2; i++) { - ev[i] = malloc(sizeof(ASTExprVar)); + ev[i] = calloc(1, sizeof(ASTExprVar)); ev[i]->nodeKind = AST_EXPR_VAR; ev[i]->type = e->expression.type; ev[i]->thing = vte; } - ASTStmtAssign *assign = malloc(sizeof(*assign)); + ASTStmtAssign *assign = calloc(1, sizeof(*assign)); assign->nodeKind = AST_STMT_ASSIGN; assign->what = (AST*) ev[0]; assign->to = e; @@ -187,6 +187,12 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to); this->effective = 1; + + } else if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF && !is_xop(s->stmtAssign.what)) { + + s->stmtAssign.what->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprUnOp.operand); + this->effective = 1; + } else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { ASTExprCall *call = &s->stmtAssign.to->exprCall; @@ -215,7 +221,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * s->stmtAssign.to = negation->exprUnOp.operand; negation->exprUnOp.operand = ev[0]; - AST *assign2 = malloc(sizeof(ASTStmtAssign)); + AST *assign2 = calloc(1, sizeof(ASTStmtAssign)); assign2->nodeKind = AST_STMT_ASSIGN; assign2->stmtAssign.what = ev[1]; assign2->stmtAssign.to = negation; @@ -291,7 +297,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * // a = b // a = a op c - AST *assign2 = malloc(sizeof(ASTStmtAssign)); + AST *assign2 = calloc(1, sizeof(ASTStmtAssign)); assign2->nodeKind = AST_STMT_ASSIGN; assign2->stmtAssign.what = ast_deep_copy(s->stmtAssign.what); assign2->stmtAssign.to = s->stmtAssign.to->exprBinOp.operands[0]; @@ -458,13 +464,19 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *nptr = n->exprBinOp.operands[0]; + *success = true; + } else if(n->nodeKind == AST_EXPR_CAST && n->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && n->exprCast.to->type == TYPE_TYPE_POINTER) { + // Turn (x as A*) into x, since all pointer types are identical in Nectar's AST + + *nptr = n->exprCast.what; + *success = true; } } void dumben_pre(AST *tlc) { - generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor); - generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor, NULL); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access, NULL); for(size_t t = 0; t < tlc->chunk.varCount; t++) { if(tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) { @@ -475,7 +487,7 @@ void dumben_pre(AST *tlc) { bool success; do { success = false; - generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor, NULL); } while(success); } @@ -492,7 +504,7 @@ void dumben_go(AST* tlc) { struct DumbenState state; memset(&state, 0, sizeof(state)); - generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor, NULL); int successful = state.effective; diff --git a/src/lexer.c b/src/lexer.c index 436c424..6b4eb27 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -48,6 +48,7 @@ char *TOKEN_NAMES[] = { "'record'", "'.'", "'as'", + "'use'", }; static int isAlpha(int c) { @@ -290,6 +291,10 @@ Token nct_tokenize(FILE *f) { free(content); tok.type = TOKEN_AS; return tok; + } else if(!strcmp(content, "use")) { + free(content); + tok.type = TOKEN_USE; + return tok; } tok.type = TOKEN_IDENTIFIER; @@ -319,7 +324,7 @@ Token nct_tokenize(FILE *f) { while(c = nextc(f), (isNum(c) || (base > 10 && c >= 'A' && c < ('A' + base - 10)))) { if(i == 31) { - stahp(1, 6180, "Numbers have a maximum size of 31."); + stahp_token(&tok, "Numbers have a maximum size of 31."); } content[i++] = c; diff --git a/src/lexer.h b/src/lexer.h index 587c851..a0485a0 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -48,9 +48,10 @@ typedef enum { TOKEN_RECORD, TOKEN_DOT, TOKEN_AS, + TOKEN_USE, } TokenKind; -typedef struct { +typedef struct Token { TokenKind type; int row, column; diff --git a/src/parse.c b/src/parse.c index f18e85b..b2fa04a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -48,8 +48,18 @@ typedef struct { // Skim mode disables parsing function definitions // This is needed to automatically forward-declare symbols int skimMode; + + // If this parser is for importing an external module, all symbols should become "extern" + int externalify; } Parser; +static void *alloc_node(Parser *P, size_t sz) { + AST *a = calloc(1, sz); + a->row = P->tokens[P->i].row; + a->col = P->tokens[P->i].column; + return a; +} + static Token get(Parser *P) { if(P->tokens[P->i].type == TOKEN_EOF) { return P->tokens[P->i]; @@ -96,7 +106,7 @@ static void pushstat(Parser *P, void *a) { } static ASTExprPrimitive *parse_prim(Parser *P) { - ASTExprPrimitive *ret = malloc(sizeof(*ret)); + ASTExprPrimitive *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_EXPR_PRIMITIVE; Token tok = get(P); @@ -104,11 +114,15 @@ static ASTExprPrimitive *parse_prim(Parser *P) { const char *str = tok.content; int base = 10; if(strchr(str, 'r')) { - base = strtol(str, (char**) &str, 10); + if(!unstupid_strtol(str, (char**) &str, 10, &base)) { + return NULL; + } str++; /* Go past the r. */ } - ret->val = strtol(str, NULL, base); + if(!unstupid_strtol(str, NULL, base, &ret->val)) { + return NULL; + } // Smallest integer type to store number char buf[8]; @@ -119,7 +133,10 @@ static ASTExprPrimitive *parse_prim(Parser *P) { } static AST *exprvar(Parser *P, VarTableEntry *v) { - AST *a = malloc(sizeof(ASTExprVar)); + assert(v->kind != VARTABLEENTRY_TYPE); + + AST *a = alloc_node(P, sizeof(ASTExprVar)); + a->nodeKind = AST_EXPR_VAR; a->exprVar.type = v->type; a->exprVar.thing = v; @@ -145,7 +162,7 @@ static AST *exprvar(Parser *P, VarTableEntry *v) { } if(!alreadyAdded) { - ASTExprVar *ev = malloc(sizeof(*ev)); + ASTExprVar *ev = alloc_node(P, sizeof(*ev)); memcpy(ev, a, sizeof(*ev)); P->guardedVars = realloc(P->guardedVars, sizeof(*P->guardedVars) * (P->guardedVarCount + 1)); @@ -159,6 +176,8 @@ static AST *exprvar(Parser *P, VarTableEntry *v) { ASTChunk *nct_parse_chunk(Parser*, int, int, VarTable*, Type *ft); Type *nct_parse_typename(Parser *P); +static bool parse_parametrization(Parser *P, Parametrizations *parametrizations); +static char *parametrize_function_name(Type *t, const char *original, Parametrization *types, Parametrization *ints); static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) { if(type_size(binop->operands[0]->expression.type) < type_size(binop->operands[1]->expression.type)) { @@ -176,16 +195,33 @@ static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) { AST *nct_parse_expression(Parser *P, int lOP) { if(lOP == 0) { + size_t startTokI = P->i; + // Test if this is an anonymous function Type *ft = nct_parse_typename(P); if(ft) { assert(ft->type == TYPE_TYPE_FUNCTION); - ASTExprFunc *e = malloc(sizeof(*e)); + ASTExprFunc *e = alloc_node(P, sizeof(*e)); e->nodeKind = AST_EXPR_FUNC; e->type = ft; - if(P->skimMode) { + if(type_is_generic(ft)) { + // Don't parse a generic function because the types are unavailable + + size_t depth = 0; + + while(1) { + TokenKind tk = get(P).type; + if(tk == TOKEN_SQUIGGLY_L) depth++; + else if(tk == TOKEN_SQUIGGLY_R) { + if(--depth == 0) { + break; + } + } + } + + } else if(P->skimMode) { // In skim mode, it won't be parsed normally anyway } else { expect(P, TOKEN_ARROW); @@ -202,6 +238,9 @@ AST *nct_parse_expression(Parser *P, int lOP) { expect(P, TOKEN_SQUIGGLY_R); } + e->rangeTokens = P->tokens; + e->startTokI = startTokI; + e->endTokI = P->i; return (AST*) e; } @@ -216,7 +255,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { if(!strcmp(peek(P, 0).content, "@stack")) { get(P); - ASTExprStackPointer *ret = calloc(1, sizeof(*ret)); + ASTExprStackPointer *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_EXPR_STACK_POINTER; ret->type = primitive_parse("u32"); @@ -226,7 +265,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { expect(P, TOKEN_PAREN_L); - ASTExprExtSalloc *ret = calloc(1, sizeof(*ret)); + ASTExprExtSalloc *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_EXPR_EXT_SALLOC; ret->size = nct_parse_typename(P); ret->type = type_pointer_wrap(ret->size); @@ -246,7 +285,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { e = (AST*) exprvar(P, vte); } } else if(peek(P, 0).type == TOKEN_STRING) { - ASTExprStringLiteral *ret = malloc(sizeof(*ret)); + ASTExprStringLiteral *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_EXPR_STRING_LITERAL; Token tok = get(P); @@ -267,7 +306,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { Token fieldTok = expect(P, TOKEN_IDENTIFIER); - ASTExprDot *d = calloc(1, sizeof(*d)); + ASTExprDot *d = alloc_node(P, sizeof(*d)); d->nodeKind = AST_EXPR_DOT; d->a = (AST*) e; @@ -292,7 +331,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { return e; } else if(lOP == 5) { if(maybe(P, TOKEN_STAR)) { - ASTExprUnaryOp *astop = malloc(sizeof(*astop)); + ASTExprUnaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_UNARY_OP; astop->operator = UNOP_DEREF; astop->operand = nct_parse_expression(P, lOP); /* Not +1! */ @@ -300,7 +339,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { return (AST*) astop; } else if(maybe(P, TOKEN_AMPERSAND)) { - ASTExprUnaryOp *astop = malloc(sizeof(*astop)); + ASTExprUnaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_UNARY_OP; astop->operator = UNOP_REF; astop->operand = nct_parse_expression(P, lOP); @@ -314,7 +353,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { operand->exprPrim.val *= -1; return operand; } else { - ASTExprUnaryOp *astop = malloc(sizeof(*astop)); + ASTExprUnaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_UNARY_OP; astop->operator = UNOP_NEGATE; astop->operand = operand; @@ -329,7 +368,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { child->exprPrim.val = ~child->exprPrim.val; return child; } else { - ASTExprUnaryOp *astop = malloc(sizeof(*astop)); + ASTExprUnaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_UNARY_OP; astop->operator = UNOP_BITWISE_NOT; astop->operand = child; @@ -347,7 +386,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types may be called."); } - ASTExprCall *call = malloc(sizeof(*call)); + ASTExprCall *call = alloc_node(P, sizeof(*call)); call->nodeKind = AST_EXPR_CALL; call->type = ret->expression.type->function.ret; call->what = ret; @@ -373,45 +412,73 @@ AST *nct_parse_expression(Parser *P, int lOP) { } ret = (AST*) call; - } else if(maybe(P, TOKEN_SQUAREN_L)) { - ASTExprUnaryOp *ref = malloc(sizeof(*ref)); - ref->nodeKind = AST_EXPR_UNARY_OP; - ref->operator = UNOP_REF; - ref->operand = ret; - ref->type = type_pointer_wrap(ret->expression.type->array.of); - - ASTExprBinaryOp *child = malloc(sizeof(*child)); - child->nodeKind = AST_EXPR_BINARY_OP; - child->operands[0] = (AST*) ref; - child->operands[1] = nct_parse_expression(P, 0); - child->operator = BINOP_ADD; - child->type = ref->type; - - int typesize = type_size(ret->expression.type->array.of); - if(typesize != 1) { - ASTExprPrimitive *scale = malloc(sizeof(*scale)); - scale->nodeKind = AST_EXPR_PRIMITIVE; - scale->type = primitive_parse("u16"); - scale->val = typesize; + } else if(peek(P, 0).type == TOKEN_SQUAREN_L) { + Parametrizations parametrizations = {}; + if(parse_parametrization(P, ¶metrizations)) { + // Generic type parametrization - ASTExprBinaryOp *mul = malloc(sizeof(*mul)); - mul->nodeKind = AST_EXPR_BINARY_OP; - mul->operator = BINOP_MUL; - mul->operands[0] = (AST*) scale; - mul->operands[1] = child->operands[1]; + // Generic functions are not first-class + assert(ret->nodeKind == AST_EXPR_VAR); + assert(ret->exprVar.thing != NULL); + assert(ret->exprVar.thing->kind == VARTABLEENTRY_SYMBOL); - child->operands[1] = (AST*) mul; + char *cname = parametrize_function_name(ret->expression.type, ret->exprVar.thing->data.symbol.name, parametrizations.typeParams, parametrizations.intParams); + + VarTableEntry *cvte = vartable_get(P->scope, cname); + + if(!cvte) { + stahp_token(&P->tokens[P->i], "Parametrization %s not found.", cname); + } + + ret = exprvar(P, cvte); + } else { + // Array access + + expect(P, TOKEN_SQUAREN_L); + + ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref)); + ref->nodeKind = AST_EXPR_UNARY_OP; + ref->operator = UNOP_REF; + ref->operand = ret; + ref->type = type_pointer_wrap(ret->expression.type->array.of); + + ASTExprBinaryOp *child = alloc_node(P, sizeof(*child)); + child->nodeKind = AST_EXPR_BINARY_OP; + child->operands[0] = (AST*) ref; + child->operands[1] = nct_parse_expression(P, 0); + child->operator = BINOP_ADD; + child->type = ref->type; + + if(ret->expression.type->type != TYPE_TYPE_ARRAY) { + stahp_token(&P->tokens[P->i], "Attempt to index a non-array type"); + } + + int typesize = type_size(ret->expression.type->array.of); + if(typesize != 1) { + ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale)); + scale->nodeKind = AST_EXPR_PRIMITIVE; + scale->type = primitive_parse("u16"); + scale->val = typesize; + + ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul)); + mul->nodeKind = AST_EXPR_BINARY_OP; + mul->operator = BINOP_MUL; + mul->operands[0] = (AST*) scale; + mul->operands[1] = child->operands[1]; + + child->operands[1] = (AST*) mul; + } + + ASTExprUnaryOp *unop = alloc_node(P, sizeof(*unop)); + unop->nodeKind = AST_EXPR_UNARY_OP; + unop->type = ret->expression.type->array.of; + unop->operator = UNOP_DEREF; + unop->operand = (AST*) child; + + expect(P, TOKEN_SQUAREN_R); + + ret = (AST*) unop; } - - ASTExprUnaryOp *unop = malloc(sizeof(*unop)); - unop->nodeKind = AST_EXPR_UNARY_OP; - unop->type = ret->expression.type->array.of; - unop->operator = UNOP_DEREF; - unop->operand = (AST*) child; - - ret = (AST*) unop; - - expect(P, TOKEN_SQUAREN_R); } else abort(); } @@ -427,7 +494,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { else if(maybe(P, TOKEN_SLASH)) op = BINOP_DIV; else break; - ASTExprBinaryOp *astop = malloc(sizeof(*astop)); + ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_BINARY_OP; astop->type = ret->expression.type; astop->operator = op; @@ -436,7 +503,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { AST *operand = nct_parse_expression(P, lOP + 1); if(operand->expression.type->type != TYPE_TYPE_PRIMITIVE) { - stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types."); + stahp_token(&P->tokens[P->i], "Invalid combination of operator and operand types."); } astop->operands[1] = operand; @@ -475,7 +542,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { else if(maybe(P, TOKEN_CARET)) op = BINOP_BITWISE_XOR; else break; - ASTExprBinaryOp *astop = malloc(sizeof(*astop)); + ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_BINARY_OP; astop->type = NULL; astop->operator = op; @@ -486,7 +553,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { if(!type_is_number(astop->operands[0]->expression.type) || !type_is_number(astop->operands[1]->expression.type)) { - stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Attempt to perform arithmetic on non-number types."); + stahp_token(&P->tokens[P->i], "Attempt to perform arithmetic on non-number types."); } binop_implicit_cast(astop); @@ -519,7 +586,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { else if(maybe(P, TOKEN_GEQUAL)) op = BINOP_GEQUAL; else break; - ASTExprBinaryOp *astop = malloc(sizeof(*astop)); + ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_BINARY_OP; astop->type = NULL; astop->operator = op; @@ -528,7 +595,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression; if(operand->type->type != TYPE_TYPE_PRIMITIVE) { - stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Invalid combination of operator and operand types."); + stahp_token(&P->tokens[P->i], "Invalid combination of operator and operand types."); } binop_implicit_cast(astop); @@ -537,7 +604,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { } } - ret = ast_expression_optimize(ret); + //ret = ast_expression_optimize(ret); return ret; } @@ -548,10 +615,94 @@ AST *nct_parse_expression(Parser *P, int lOP) { return NULL; } +// This function may backtrack. +static bool parse_parametrization(Parser *P, Parametrizations *parametrizations) { + size_t oldIdx = P->i; + + if(!maybe(P, TOKEN_SQUAREN_L)) { + goto backtrack; + } + + bool integerMode = false; + + Parametrization *head = NULL; + Parametrization *last = NULL; + + while(1) { + if(maybe(P, TOKEN_SQUAREN_R)) { + break; + } + + Parametrization *par = calloc(1, sizeof(*par)); + + if(integerMode) { + AST *n = nct_parse_expression(P, 0); + + if(!n) { + goto backtrack; + } + + par->param = n; + } else { + Type *t = nct_parse_typename(P); + + if(!t) { + goto backtrack; + } + + par->param = t; + } + + if(!par->param) { + goto backtrack; + } + + if(!head) { + head = par; + last = head; + + if(integerMode) { + parametrizations->intParams = head; + } else { + parametrizations->typeParams = head; + } + } else if(last) { + last->next = par; + last = par; + } + + if(maybe(P, TOKEN_SQUAREN_R)) { + break; + } + + if(maybe(P, TOKEN_SEMICOLON)) { + integerMode = true; + head = NULL; + last = NULL; + } else if(!maybe(P, TOKEN_COMMA)) { + goto backtrack; + } + } + + return true; + +backtrack: + P->i = oldIdx; + return false; +} + /* Since this function backtracks, don't use aborting functions like expect. */ Type *nct_parse_typename(Parser *P) { int oldIdx = P->i; + bool generics = peek(P, 0).type == TOKEN_SQUAREN_L; + + if(generics) { + P->scope = vartable_new(P->scope); + + parse_genericization(P); + } + if(peek(P, 0).type != TOKEN_IDENTIFIER) { goto backtrack; } @@ -573,7 +724,7 @@ Type *nct_parse_typename(Parser *P) { while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_STAR || peek(P, 0).type == TOKEN_SQUAREN_L) { if(maybe(P, TOKEN_STAR)) { - TypePointer *ptr = malloc(sizeof(*ptr)); + TypePointer *ptr = calloc(1, sizeof(*ptr)); ptr->type = TYPE_TYPE_POINTER; ptr->of = ret; @@ -593,6 +744,7 @@ Type *nct_parse_typename(Parser *P) { if((fun->args[fun->argCount - 1] = nct_parse_typename(P)) == NULL) { free(fun); + P->scope = P->scope->parent; goto backtrack; } @@ -608,31 +760,81 @@ Type *nct_parse_typename(Parser *P) { ret = (Type*) fun; } else if(maybe(P, TOKEN_SQUAREN_L)) { - TypeArray *arr = malloc(sizeof(*arr)); - arr->type = TYPE_TYPE_ARRAY; - arr->of = ret; + size_t oldIdx = P->i; + Type *t = nct_parse_typename(P); + P->i = oldIdx; - if(peek(P, 0).type == TOKEN_NUMBER) { - ASTExprPrimitive *prim = parse_prim(P); + if(!t) { + TypeArray *arr = calloc(1, sizeof(*arr)); + arr->type = TYPE_TYPE_ARRAY; + arr->of = ret; - arr->length = prim->val; + if(peek(P, 0).type == TOKEN_NUMBER) { + ASTExprPrimitive *prim = parse_prim(P); + + arr->length = prim->val; + + free(prim); + } else if(maybe(P, TOKEN_QUESTION_MARK)) { + arr->length = 0; + } else if(peek(P, 0).type == TOKEN_IDENTIFIER) { + const char *what = expect(P, TOKEN_IDENTIFIER).content; + + VarTableEntry *vte = vartable_find(P->scope, what); + + if(!vte) { + goto backtrack; + } + + if(vte->kind != VARTABLEENTRY_CEXPR) { + stahp_token(&P->tokens[P->i], "Variable '%s' is not constant.", what); + } + + if(vte->data.cexpr.concrete) { + AST *n = vte->data.cexpr.concrete; + + assert(n->nodeKind == AST_EXPR_PRIMITIVE); + + arr->length = n->exprPrim.val; + arr->lengthIsGeneric = false; + } else { + arr->length = 0; + arr->lengthIsGeneric = true; + arr->lengthGenericParamIdx = 0; // TODO: SHIT + arr->lengthGenericParamName = strdup(what); + } + } else { + stahp_token(&P->tokens[P->i], "Array length must be either constant, generic or '?' (1)."); + } - free(prim); - } else if(maybe(P, TOKEN_QUESTION_MARK)) { - arr->length = 0; + ret = (Type*) arr; + + expect(P, TOKEN_SQUAREN_R); } else { - //stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Array size must be either constant or '?'."); - goto backtrack; + assert(ret->type == TYPE_TYPE_RECORD); + + P->i--; + + Parametrizations parametrizations = {}; + assert(parse_parametrization(P, ¶metrizations)); + + Parametrizations renames = {}; + ret = type_parametrize(ret, ¶metrizations, &renames); } - - expect(P, TOKEN_SQUAREN_R); - - ret = (Type*) arr; } } + if(generics) { + P->scope = P->scope->parent; + } + return ret; + backtrack: + if(generics) { + P->scope = P->scope->parent; + } + P->i = oldIdx; return NULL; } @@ -675,7 +877,7 @@ static AST *parse_declaration(Parser *P) { entry->data.var.priority = 1; entry->data.var.color = -1; - ASTStmtAssign *assign = malloc(sizeof(*assign)); + ASTStmtAssign *assign = alloc_node(P, sizeof(*assign)); assign->nodeKind = AST_STMT_ASSIGN; assign->next = NULL; @@ -688,7 +890,7 @@ static AST *parse_declaration(Parser *P) { ret = (AST*) assign; } else { - ASTStmtDecl *decl = calloc(1, sizeof(*ret)); + ASTStmtDecl *decl = alloc_node(P, sizeof(*ret)); decl->nodeKind = AST_STMT_DECL; decl->thing = entry; decl->next = NULL; @@ -701,8 +903,8 @@ static AST *parse_declaration(Parser *P) { } entry->kind = VARTABLEENTRY_SYMBOL; - entry->data.symbol.isLocal = isLocal; - entry->data.symbol.isExternal = isExternal; + entry->data.symbol.isLocal = P->externalify ? false : isLocal; + entry->data.symbol.isExternal = P->externalify ? true : isExternal; entry->data.symbol.name = name.content; decl->expression = nct_parse_expression(P, 0); @@ -714,6 +916,12 @@ static AST *parse_declaration(Parser *P) { } else { entry->type = decl->expression->expression.type; } + + if(decl->expression && decl->expression->nodeKind == AST_EXPR_FUNC && type_is_generic(decl->expression->expression.type)) { + entry->data.symbol.genfunc.rangeTokens = decl->expression->exprFunc.rangeTokens; + entry->data.symbol.genfunc.startTokI = decl->expression->exprFunc.startTokI; + entry->data.symbol.genfunc.endTokI = decl->expression->exprFunc.endTokI; + } } else if(isExternal) { entry->kind = VARTABLEENTRY_SYMBOL; entry->data.symbol.isLocal = isLocal; @@ -740,13 +948,92 @@ backtrack: return NULL; } +static char *plus_underscore(char *s, char *ts) { + size_t strlens = strlen(s); + + s = realloc(s, strlens + strlen(ts) + 2); + memset(s + strlens, 0, strlen(ts) + 2); + + strcat(s, ts); + + s[strlen(s)] = '_'; + + return s; +} + +static char *parametrize_function_name(Type *t, const char *original, Parametrization *types, Parametrization *ints) { + char *s = calloc(1, strlen(original) + 1 + 1); + strcpy(s, original); + s[strlen(original)] = '_'; + + while(types) { + s = plus_underscore(s, type_to_string(types->param)); + + types = types->next; + } + + while(ints) { + char numstr[32]; + snprintf(numstr, sizeof(numstr), "%i", ((AST*) ints->param)->exprPrim.val); + + s = plus_underscore(s, numstr); + + ints = ints->next; + } + + // Remove last underscore + s[strlen(s) - 1] = '\0'; + + return s; +} + +static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametrizations, Parametrizations *renames) { + Parametrization *c = parametrizations->typeParams; + Parametrization *g = renames->typeParams; + while(c && g) { + Type *ct = (Type*) c->param; + Type *gt = (Type*) g->param; + + assert(!!ct == !!gt); + + VarTableEntry *vte = calloc(1, sizeof(*vte)); + vte->kind = VARTABLEENTRY_TYPE; + vte->data.type.ptr = ct; + vartable_set(P->scope, gt->generic.paramName, vte); + + c = c->next; + g = g->next; + } + + size_t idx = 0; + c = parametrizations->intParams; + g = renames->intParams; + while(c && g) { + AST *node = c->param; + char *name = g->param; + + assert(!!node == !!name); + + VarTableEntry *vte = calloc(1, sizeof(*vte)); + vte->kind = VARTABLEENTRY_CEXPR; + vte->data.cexpr.paramIdx = idx; + vte->data.cexpr.paramName = name; + vte->data.cexpr.concrete = node; + vartable_set(P->scope, name, vte); + + c = c->next; + g = g->next; + idx++; + } +} + void nct_parse_statement(Parser *P) { if(maybe(P, TOKEN_IF)) { expect(P, TOKEN_PAREN_L); AST *e = nct_parse_expression(P, 0); expect(P, TOKEN_PAREN_R); - ASTStmtIf *ret = malloc(sizeof(*ret)); + ASTStmtIf *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_IF; ret->next = NULL; @@ -759,7 +1046,7 @@ void nct_parse_statement(Parser *P) { expect(P, TOKEN_SQUIGGLY_R); return; } else if(maybe(P, TOKEN_LOOP)) { - ASTStmtLoop *ret = malloc(sizeof(*ret)); + ASTStmtLoop *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_LOOP; ret->next = NULL; @@ -781,7 +1068,7 @@ void nct_parse_statement(Parser *P) { for(size_t i = 0; i < P->guardedVarCount; i++) { ASTExprVar *ev = P->guardedVars[i]; - AST *es = calloc(1, sizeof(ASTStmtExpr)); + AST *es = alloc_node(P, sizeof(ASTStmtExpr)); es->nodeKind = AST_STMT_EXPR; es->stmtExpr.expr = (AST*) ev; @@ -795,7 +1082,7 @@ void nct_parse_statement(Parser *P) { return; } else if(maybe(P, TOKEN_BREAK)) { - ASTStmtBreak *ret = malloc(sizeof(*ret)); + ASTStmtBreak *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_BREAK; ret->next = NULL; @@ -805,7 +1092,7 @@ void nct_parse_statement(Parser *P) { return; } else if(maybe(P, TOKEN_CONTINUE)) { - ASTStmtContinue *ret = malloc(sizeof(*ret)); + ASTStmtContinue *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_CONTINUE; ret->next = NULL; @@ -815,7 +1102,7 @@ void nct_parse_statement(Parser *P) { return; } else if(maybe(P, TOKEN_RETURN)) { - ASTStmtReturn *ret = malloc(sizeof(*ret)); + ASTStmtReturn *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_RETURN; ret->next = NULL; @@ -832,7 +1119,9 @@ void nct_parse_statement(Parser *P) { // Do nothing. This is handled in nct_parse_chunk. expect(P, TOKEN_IDENTIFIER); - expect(P, TOKEN_SQUIGGLY_L); + + while(get(P).type != TOKEN_SQUIGGLY_L); + size_t depth = 1; while(1) { TokenKind tk = get(P).type; @@ -846,9 +1135,11 @@ void nct_parse_statement(Parser *P) { } } return; + } else if(maybe(P, TOKEN_USE)) { + while(get(P).type != TOKEN_SEMICOLON); } else if(peek(P, 0).type == TOKEN_IDENTIFIER) { if(!strcmp(peek(P, 0).content, "@align")) { - ASTStmtExtAlign *ret = malloc(sizeof(*ret)); + ASTStmtExtAlign *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_EXT_ALIGN; ret->next = NULL; @@ -865,7 +1156,7 @@ void nct_parse_statement(Parser *P) { pushstat(P, ret); return; } else if(!strcmp(peek(P, 0).content, "@org")) { - ASTStmtExtOrg *ret = malloc(sizeof(*ret)); + ASTStmtExtOrg *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_EXT_ORG; ret->next = NULL; @@ -882,7 +1173,7 @@ void nct_parse_statement(Parser *P) { pushstat(P, ret); return; } else if(!strcmp(peek(P, 0).content, "@section")) { - ASTStmtExtSection *ret = malloc(sizeof(*ret)); + ASTStmtExtSection *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_EXT_SECTION; ret->next = NULL; @@ -895,6 +1186,70 @@ void nct_parse_statement(Parser *P) { expect(P, TOKEN_SEMICOLON); pushstat(P, ret); + return; + } else if(!strcmp(peek(P, 0).content, "@instantiate")) { + get(P); + + Token funcname = expect(P, TOKEN_IDENTIFIER); + + VarTableEntry *func = vartable_find(P->scope, funcname.content); + + if(!func) { + stahp_token(&P->tokens[P->i], "Cannot find function %s for parametrization.", funcname.content); + } + + assert(type_is_generic(func->type)); + + Parametrizations parametrizations = {}; + assert(parse_parametrization(P, ¶metrizations)); + + P->scope = vartable_new(P->scope); + + Parametrizations renames = {}; + Type *parametrizedFuncType = type_parametrize(func->type, ¶metrizations, &renames); + + add_parametrizations_to_scope(P, ¶metrizations, &renames); + + size_t oldIdx = P->i; + + P->i = func->data.symbol.genfunc.startTokI; + + size_t depth = 0; + while(1) { + TokenKind tk = get(P).type; + if(tk == TOKEN_SQUAREN_L) { + depth++; + } else if(tk == TOKEN_SQUAREN_R) { + if(--depth == 0) { + break; + } + } + } + + AST *concreteFunction = nct_parse_expression(P, 0); + + assert(concreteFunction->nodeKind == AST_EXPR_FUNC); + + P->i = oldIdx; + + P->scope = P->scope->parent; + + VarTableEntry *vte = calloc(1, sizeof(*vte)); + vte->kind = VARTABLEENTRY_SYMBOL; + vte->type = parametrizedFuncType; + vte->data.symbol.name = parametrize_function_name(func->type, func->data.symbol.name, parametrizations.typeParams, parametrizations.intParams); + vte->data.symbol.isExternal = false; + vte->data.symbol.isLocal = false; + vartable_set(P->scope, vte->data.symbol.name, vte); + + ASTStmtDecl *decl = alloc_node(P, sizeof(*decl)); + decl->nodeKind = AST_STMT_DECL; + decl->thing = vte; + decl->expression = concreteFunction; + pushstat(P, (AST*) decl); + + expect(P, TOKEN_SEMICOLON); + return; } } @@ -902,7 +1257,10 @@ void nct_parse_statement(Parser *P) { { AST *decl = parse_declaration(P); if(decl) { - pushstat(P, decl); + // Don't pass declaration statements for generic functions, because they're useless + if(decl->nodeKind != AST_STMT_DECL || !type_is_generic(decl->stmtDecl.thing->type)) { + pushstat(P, decl); + } return; } } @@ -910,7 +1268,7 @@ void nct_parse_statement(Parser *P) { AST *e = nct_parse_expression(P, 0); if(maybe(P, TOKEN_EQUALS)) { - ASTStmtAssign *ret = malloc(sizeof(*ret)); + ASTStmtAssign *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_ASSIGN; ret->next = NULL; ret->what = e; @@ -925,7 +1283,7 @@ void nct_parse_statement(Parser *P) { pushstat(P, ret); return; } else { - ASTStmtExpr *ret = malloc(sizeof(*ret)); + ASTStmtExpr *ret = alloc_node(P, sizeof(*ret)); ret->nodeKind = AST_STMT_EXPR; ret->next = NULL; ret->expr = e; @@ -937,16 +1295,80 @@ void nct_parse_statement(Parser *P) { } } +/* + * This function inserts VTEs into the *current* scope. + * Make sure to create a child scope before using. + * */ +void parse_genericization(Parser *P) { + expect(P, TOKEN_SQUAREN_L); + + bool integerMode = false; + + size_t nextIdx = 0; + + while(peek(P, 0).type == TOKEN_IDENTIFIER) { + + if(!integerMode) { + + Type *tg = calloc(1, sizeof(TypeGeneric)); + tg->type = TYPE_TYPE_GENERIC; + tg->generic.paramName = strdup(get(P).content); + tg->generic.paramIdx = nextIdx; + + VarTableEntry *vte = calloc(1, sizeof(*vte)); + vte->kind = VARTABLEENTRY_TYPE; + vte->data.type.ptr = tg; + + vartable_set(P->scope, strdup(tg->generic.paramName), vte); + + } else { + + VarTableEntry *vte = calloc(1, sizeof(*vte)); + vte->type = primitive_parse("u32"); + vte->kind = VARTABLEENTRY_CEXPR; + vte->data.cexpr.paramName = strdup(get(P).content); + vte->data.cexpr.paramIdx = nextIdx; + + vartable_set(P->scope, strdup(vte->data.var.name), vte); + + } + + nextIdx++; + + if(maybe(P, TOKEN_SQUAREN_R)) { + break; + } + + if(maybe(P, TOKEN_SEMICOLON)) { + integerMode = true; + nextIdx = 0; + } else { + expect(P, TOKEN_COMMA); + } + + if(maybe(P, TOKEN_SQUAREN_R)) { + break; + } + } +} + Type *nct_parse_record_definition(Parser *P) { expect(P, TOKEN_RECORD); - Token name = expect(P, TOKEN_IDENTIFIER); + P->scope = vartable_new(P->scope); - expect(P, TOKEN_SQUIGGLY_L); + Token name = expect(P, TOKEN_IDENTIFIER); Type *tr = calloc(1, sizeof(TypeRecord)); tr->type = TYPE_TYPE_RECORD; - tr->record.name = strndup(name.content, name.length); + tr->record.name = strdup(name.content); + + if(maybe(P, TOKEN_SQUAREN_L)) { + P->i--; + parse_genericization(P); + } + + expect(P, TOKEN_SQUIGGLY_L); size_t nextOffset = 0; @@ -968,13 +1390,14 @@ Type *nct_parse_record_definition(Parser *P) { Token fieldName = expect(P, TOKEN_IDENTIFIER); tr->record.fieldTypes[fi] = fieldType; - tr->record.fieldNames[fi] = strndup(fieldName.content, fieldName.length); + tr->record.fieldNames[fi] = strdup(fieldName.content); tr->record.fieldOffsets[fi] = nextOffset; - nextOffset += type_size(tr->record.fieldTypes[fi]); - - if(tr->record.size < nextOffset) { - tr->record.size = nextOffset; + if(type_is_generic(tr->record.fieldTypes[fi])) { + // Hope nothing goes wrong. + // Field offsets must be regenerated later + } else { + nextOffset += type_size(tr->record.fieldTypes[fi]); } expect(P, TOKEN_SEMICOLON); @@ -982,29 +1405,12 @@ Type *nct_parse_record_definition(Parser *P) { expect(P, TOKEN_SQUIGGLY_R); + P->scope = P->scope->parent; + return tr; } -ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *toplevelParent, Type *ft) { - AST *ret = calloc(1, sizeof(ASTChunk)); - ret->nodeKind = AST_CHUNK; - ret->chunk.statementFirst = ret->chunk.statementLast = NULL; - ret->chunk.varCount = 0; - ret->chunk.vars = NULL; - ret->chunk.stackReservation = 0; - - AST *oldChunk = (AST*) P->currentChunk; - P->currentChunk = &ret->chunk; - - VarTable *oldScope = P->scope; - - P->scope = isTopLevel ? toplevelParent : vartable_new(oldScope); - - ASTChunk *oldTopLevel = P->topLevel; - if(isTopLevel) { - P->topLevel = &ret->chunk; - } - +static void skim_chunk(Parser *P, int isTopLevel) { /* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */ P->skimMode++; @@ -1047,11 +1453,76 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable vte->data.type.ptr = tr; vartable_set(P->scope, tr->record.name, vte); + } else if(k == TOKEN_USE) { + + char *path = malp("%s", expect(P, TOKEN_IDENTIFIER).content); + + for(;;) { + if(maybe(P, TOKEN_SEMICOLON)) { + break; + } + + expect(P, TOKEN_DOT); + + char *path2 = malp("%s/%s", path, expect(P, TOKEN_IDENTIFIER).content); + free(path); + path = path2; + } + + { + char *path2 = malp("tests/%s.nct", path); + free(path); + path = path2; + } + + FILE *f = fopen(path, "rb"); + + Parser subp = {.tokens = nct_lex(f), .scope = vartable_new(NULL), .externalify = 1}; + skim_chunk(&subp, 1); + + // Copy all extern symbols from the scope into our TLC's externs array + for(size_t i = 0; i < subp.scope->count; i++) { + VarTableEntry *vte = subp.scope->data[i]; + if(vte->kind == VARTABLEENTRY_SYMBOL && vte->data.symbol.isExternal) { + P->topLevel->externs = realloc(P->topLevel->externs, sizeof(*P->topLevel->externs) * (++P->topLevel->externCount)); + P->topLevel->externs[P->topLevel->externCount - 1] = vte; + } + } + + subp.scope->parent = P->scope; + vartable_merge(subp.scope); + + free(subp.tokens); + fclose(f); + } } P->i = oldIdx; } P->skimMode--; +} + +ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *toplevelParent, Type *ft) { + AST *ret = alloc_node(P, sizeof(ASTChunk)); + ret->nodeKind = AST_CHUNK; + ret->chunk.statementFirst = ret->chunk.statementLast = NULL; + ret->chunk.varCount = 0; + ret->chunk.vars = NULL; + ret->chunk.stackReservation = 0; + + AST *oldChunk = (AST*) P->currentChunk; + P->currentChunk = &ret->chunk; + + VarTable *oldScope = P->scope; + + P->scope = isTopLevel ? toplevelParent : vartable_new(oldScope); + + ASTChunk *oldTopLevel = P->topLevel; + if(isTopLevel) { + P->topLevel = &ret->chunk; + } + + skim_chunk(P, isTopLevel); /* Arguments */ if(ft && isTopLevel) { diff --git a/src/reporting.c b/src/reporting.c index 951ed82..5014185 100644 --- a/src/reporting.c +++ b/src/reporting.c @@ -3,17 +3,45 @@ #include #include #include +#include"ast.h" +#include"lexer.h" + +static void stahp_va(int row, int column, const char *error, va_list l) { + fprintf(stderr, "error %i:%i: ", row, column); + vfprintf(stderr, error, l); + fputc('\n', stderr); +} /* Abort immediately on first error (for now) */ void stahp(int row, int column, const char *error, ...) { va_list l; va_start(l, error); - fprintf(stderr, "error %i:%i: ", row, column); - vfprintf(stderr, error, l); - fputc('\n', stderr); + stahp_va(row, column, error, l); va_end(l); exit(1); -} \ No newline at end of file +} + +void stahp_node(union AST *node, const char *error, ...) { + va_list l; + va_start(l, error); + + stahp_va(node->row, node->col, error, l); + + va_end(l); + + exit(1); +} + +void stahp_token(struct Token *tok, const char *error, ...) { + va_list l; + va_start(l, error); + + stahp_va(tok->row, tok->column, error, l); + + va_end(l); + + exit(1); +} diff --git a/src/reporting.h b/src/reporting.h index ead912c..41d9dcc 100644 --- a/src/reporting.h +++ b/src/reporting.h @@ -5,6 +5,11 @@ #define __attribute__(x) #endif +union AST; +struct Token; + void __attribute__((noreturn)) stahp(int, int, const char*, ...); +void __attribute__((noreturn)) stahp_node(union AST*, const char*, ...); +void __attribute__((noreturn)) stahp_token(struct Token*, const char*, ...); #endif diff --git a/src/types.c b/src/types.c index 38c8bec..a490f70 100644 --- a/src/types.c +++ b/src/types.c @@ -4,6 +4,8 @@ #include #include #include +#include"ast.h" +#include"reporting.h" #include"ntc.h" @@ -20,7 +22,7 @@ Type *primitive_parse(const char *src) { } } - TypePrimitive *ret = malloc(sizeof(*ret)); + TypePrimitive *ret = calloc(1, sizeof(*ret)); ret->type = TYPE_TYPE_PRIMITIVE; ret->src = strdup(src); @@ -100,7 +102,16 @@ size_t type_size(Type *t) { } else if(t->type == TYPE_TYPE_ARRAY) { return type_size(t->array.of) * t->array.length; } else if(t->type == TYPE_TYPE_RECORD) { - return t->record.size; + size_t max = 0; + + for(size_t f = 0; f < t->record.fieldCount; f++) { + size_t end = t->record.fieldOffsets[f] + type_size(t->record.fieldTypes[f]); + if(max < end) { + max = end; + } + } + + return max; } abort(); @@ -123,7 +134,19 @@ int type_equal(Type *O, Type *T) { } else if(O->type == TYPE_TYPE_POINTER) { return type_equal(O->pointer.of, T->pointer.of); } else if(O->type == TYPE_TYPE_ARRAY) { - return type_equal(O->array.of, T->array.of) && O->array.length == T->array.length; + if(!type_equal(O->array.of, T->array.of)) { + return 0; + } + + if(O->array.lengthIsGeneric != T->array.lengthIsGeneric) { + return 0; + } + + if(O->array.lengthIsGeneric) { + return O->array.lengthGenericParamIdx == T->array.lengthGenericParamIdx && !strcmp(O->array.lengthGenericParamName, T->array.lengthGenericParamName); + } else { + return O->array.length == T->array.length; + } } else if(O->type == TYPE_TYPE_FUNCTION) { if(!type_equal(O->function.ret, T->function.ret)) { return 0; @@ -151,7 +174,7 @@ int type_equal(Type *O, Type *T) { /* TODO: cache */ Type *type_pointer_wrap(Type *t) { - TypePointer *ret = malloc(sizeof(*ret)); + TypePointer *ret = calloc(1, sizeof(*ret)); ret->type = TYPE_TYPE_POINTER; ret->of = t; return (Type*) ret; @@ -182,3 +205,180 @@ int type_is_castable(Type *from, Type *to) { return 0; } + +bool type_is_generic(Type *t) { + if(t->type == TYPE_TYPE_GENERIC) { + return true; + } else if(t->type == TYPE_TYPE_FUNCTION) { + if(type_is_generic(t->function.ret)) { + return true; + } + + for(int i = 0; i < t->function.argCount; i++) { + if(type_is_generic(t->function.args[i])) { + return true; + } + } + } else if(t->type == TYPE_TYPE_RECORD) { + for(int i = 0; i < t->record.fieldCount; i++) { + if(type_is_generic(t->record.fieldTypes[i])) { + return true; + } + } + } else if(t->type == TYPE_TYPE_POINTER) { + return type_is_generic(t->pointer.of); + } else if(t->type == TYPE_TYPE_ARRAY) { + return type_is_generic(t->array.of) || t->array.lengthIsGeneric; + } + + return false; +} + +static void *parametrization_get_by_index(Parametrization *list, size_t idx) { + for(size_t i = 0; list && i < idx; i++) { + list = list->next; + } + return list ? list->param : NULL; +} + +static void parametrization_set_by_index(Parametrization **list, size_t idx, void *param) { + if(*list == NULL) { + *list = calloc(1, sizeof(Parametrization)); + } + + for(size_t i = 1; i <= idx; i++) { + if((*list)->next == NULL) { + (*list)->next = calloc(1, sizeof(Parametrization)); + } + + list = &(*list)->next; + } + + (*list)->param = param; +} + +Type *type_parametrize(Type *t, Parametrizations *parametrizations, Parametrizations *renames) { + if(t->type == TYPE_TYPE_RECORD) { + t = type_shallow_copy(t); + + for(size_t f = 0; f < t->record.fieldCount; f++) { + t->record.fieldTypes[f] = type_parametrize(t->record.fieldTypes[f], parametrizations, renames); + } + + if(!type_is_generic(t)) { + // Now that everything is concrete we may set the field offsets + + size_t nextOffset = 0; + + for(size_t f = 0; f < t->record.fieldCount; f++) { + t->record.fieldOffsets[f] = nextOffset; + + nextOffset += type_size(t->record.fieldTypes[f]); + } + } + } else if(t->type == TYPE_TYPE_FUNCTION) { + t = type_shallow_copy(t); + + t->function.ret = type_parametrize(t->function.ret, parametrizations, renames); + + for(size_t i = 0; i < t->function.argCount; i++) { + t->function.args[i] = type_parametrize(t->function.args[i], parametrizations, renames); + } + } else if(t->type == TYPE_TYPE_GENERIC) { + Type *newt = parametrization_get_by_index(parametrizations->typeParams, t->generic.paramIdx); + + if(renames) { + parametrization_set_by_index(&renames->typeParams, t->generic.paramIdx, t); + } + + if(newt) { + return newt; + } + } else if(t->type == TYPE_TYPE_POINTER) { + t = type_shallow_copy(t); + + t->pointer.of = type_parametrize(t->pointer.of, parametrizations, renames); + } else if(t->type == TYPE_TYPE_ARRAY) { + t = type_shallow_copy(t); + + t->array.of = type_parametrize(t->array.of, parametrizations, renames); + + if(t->array.lengthIsGeneric) { + AST *n = parametrization_get_by_index(parametrizations->intParams, t->array.lengthGenericParamIdx); + + if(n) { + while(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR && n->exprVar.thing->data.cexpr.concrete) { + n = n->exprVar.thing->data.cexpr.concrete; + } + + if(n->nodeKind == AST_EXPR_PRIMITIVE) { + t->array.length = n->exprPrim.val; + t->array.lengthIsGeneric = false; + } else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR) { + t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx; + t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName; + t->array.lengthIsGeneric = true; + } else { + stahp_node(n, "Invalid parametrization expression."); + } + } + + parametrization_set_by_index(&renames->intParams, t->array.lengthGenericParamIdx, t->array.lengthGenericParamName); + } + } + + return t; +} + +Type *type_shallow_copy(Type *t) { + if(t->type == TYPE_TYPE_PRIMITIVE) { + Type *n = calloc(1, sizeof(TypePrimitive)); + memcpy(n, t, sizeof(TypePrimitive)); + return n; + } else if(t->type == TYPE_TYPE_POINTER) { + Type *n = calloc(1, sizeof(TypePointer)); + memcpy(n, t, sizeof(TypePointer)); + return n; + } else if(t->type == TYPE_TYPE_ARRAY) { + Type *n = calloc(1, sizeof(TypeArray)); + memcpy(n, t, sizeof(TypeArray)); + return n; + } else if(t->type == TYPE_TYPE_GENERIC) { + Type *n = calloc(1, sizeof(TypeGeneric)); + memcpy(n, t, sizeof(TypeGeneric)); + return n; + } else if(t->type == TYPE_TYPE_FUNCTION) { + Type *n = calloc(1, sizeof(TypeFunction)); + n->type = TYPE_TYPE_FUNCTION; + + n->function.ret = t->function.ret; + n->function.argCount = t->function.argCount; + + n->function.argNames = calloc(n->function.argCount, sizeof(*n->function.argNames)); + memcpy(n->function.argNames, t->function.argNames, n->function.argCount * sizeof(*n->function.argNames)); + + n->function.args = calloc(n->function.argCount, sizeof(*n->function.args)); + memcpy(n->function.args, t->function.args, n->function.argCount * sizeof(*n->function.args)); + + return n; + } else if(t->type == TYPE_TYPE_RECORD) { + Type *n = calloc(1, sizeof(TypeRecord)); + n->type = TYPE_TYPE_RECORD; + + n->record.name = strdup(t->record.name); + + n->record.fieldCount = t->record.fieldCount; + + n->record.fieldNames = calloc(n->record.fieldCount, sizeof(*n->record.fieldNames)); + memcpy(n->record.fieldNames, t->record.fieldNames, n->record.fieldCount * sizeof(*n->record.fieldNames)); + + n->record.fieldTypes = calloc(n->record.fieldCount, sizeof(*n->record.fieldTypes)); + memcpy(n->record.fieldTypes, t->record.fieldTypes, n->record.fieldCount * sizeof(*n->record.fieldTypes)); + + n->record.fieldOffsets = calloc(n->record.fieldCount, sizeof(*n->record.fieldOffsets)); + memcpy(n->record.fieldOffsets, t->record.fieldOffsets, n->record.fieldCount * sizeof(*n->record.fieldOffsets)); + + return n; + } + abort(); +} diff --git a/src/types.h b/src/types.h index f3dd4e0..106579a 100644 --- a/src/types.h +++ b/src/types.h @@ -3,9 +3,10 @@ #include #include +#include typedef enum { - TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_ERROR + TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_GENERIC, TYPE_TYPE_ERROR } TypeType; union Type; @@ -48,7 +49,12 @@ typedef struct TypeArray { TypeType type; union Type *of; - size_t length; /* 0 means unknown */ + + intmax_t length; + + bool lengthIsGeneric; + char *lengthGenericParamName; + size_t lengthGenericParamIdx; } TypeArray; typedef struct TypeRecord { @@ -56,14 +62,19 @@ typedef struct TypeRecord { char *name; - size_t size; - union Type **fieldTypes; size_t *fieldOffsets; char **fieldNames; size_t fieldCount; } TypeRecord; +typedef struct TypeGeneric { + TypeType type; + + char *paramName; + size_t paramIdx; +} TypeGeneric; + typedef union Type { TypeType type; @@ -72,6 +83,7 @@ typedef union Type { TypeFunction function; TypeArray array; TypeRecord record; + TypeGeneric generic; } Type; extern Type TYPE_ERROR; @@ -90,4 +102,21 @@ int type_is_number(Type *t); char *type_to_string(Type*); +typedef struct Parametrization { + void *param; + + struct Parametrization *next; +} Parametrization; + +typedef struct { + Parametrization *typeParams; + Parametrization *intParams; +} Parametrizations; + +Type *type_parametrize(Type *target, Parametrizations *parametrizations, Parametrizations *renames); + +Type *type_shallow_copy(Type *t); + +bool type_is_generic(Type *t); + #endif diff --git a/src/utils.h b/src/utils.h index 7b41d05..2e8724e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -2,6 +2,9 @@ #define NCTREF_UTILS_H #include +#include +#include +#include inline static size_t djb2(const char *str) { size_t hash = 5381; @@ -14,4 +17,25 @@ inline static size_t djb2(const char *str) { return hash; } +inline static bool unstupid_strtol(const char *str, char **endptr, int base, long *result) { + errno = 0; + + char *endptr2 = NULL; + *result = strtol(str, &endptr2, base); + + if(endptr2 == str) { + return false; + } + + if(errno == ERANGE) { + return false; + } + + if(endptr) { + *endptr = endptr2; + } + + return true; +} + #endif diff --git a/src/vartable.c b/src/vartable.c index 9eb4e13..3445002 100644 --- a/src/vartable.c +++ b/src/vartable.c @@ -31,7 +31,7 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) { } VarTable *vartable_new(VarTable *parent) { - VarTable *ret = malloc(sizeof(*ret)); + VarTable *ret = calloc(1, sizeof(*ret)); ret->parent = parent; ret->count = 0; ret->names = NULL; @@ -70,7 +70,7 @@ VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e) return e; } -void vartable_new_reachingdefs_for_all_vars(VarTable *this) { +/*void vartable_new_reachingdefs_for_all_vars(VarTable *this) { for(size_t i = 0; i < this->count; i++) { if(this->data[i]->kind == VARTABLEENTRY_VAR) { this->data[i]->data.var.reachingDefs = reachingdefs_push(this->data[i]->data.var.reachingDefs); @@ -92,11 +92,33 @@ void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) { if(this->parent) { vartable_coalesce_reachingdefs_for_all_vars(this->parent); } +}*/ + +VarTable *vartable_merge(VarTable *child) { + VarTable *parent = child->parent; + + parent->names = realloc(parent->names, sizeof(*parent->names) * (parent->count + child->count)); + parent->data = realloc(parent->data, sizeof(*parent->data) * (parent->count + child->count)); + + for(size_t i = 0; i < child->count; i++) { + child->data[i]->owner = parent; + + parent->names[parent->count] = child->names[i]; + parent->data[parent->count] = child->data[i]; + + parent->count++; + } + + free(child->names); + free(child->data); + free(child); + + return parent; } void vte_precolor(VarTableEntry *vte, int color) { - assert(vte->kind == VARTABLEENTRY_VAR); - assert(!vte->data.var.precolored); + assert(vte->kind == VARTABLEENTRY_VAR && "vte must be var"); + assert(!vte->data.var.precolored && "already precolored"); vte->data.var.precolored = true; vte->data.var.color = color; diff --git a/src/vartable.h b/src/vartable.h index ce32363..79a02bf 100644 --- a/src/vartable.h +++ b/src/vartable.h @@ -4,8 +4,11 @@ #include"types.h" #include +struct Token; +union AST; + typedef enum { - VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE + VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE, VARTABLEENTRY_CEXPR } VarTableEntryKind; union AST; @@ -41,6 +44,12 @@ typedef struct VarTableEntry { char isLocal; char isExternal; const char *name; + + struct { + struct Token *rangeTokens; + size_t startTokI; + size_t endTokI; + } genfunc; } symbol; struct { // For debugging @@ -67,6 +76,15 @@ typedef struct VarTableEntry { struct { Type *ptr; } type; + struct { + // cexpr is used for expression parametization as opposed to type parametrization + // I don't like the idea of having a special VarTableEntry kind for these, but all other places were worse + const char *paramName; + size_t paramIdx; + + // If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL + union AST *concrete; + } cexpr; }; } data; } VarTableEntry; @@ -84,8 +102,10 @@ VarTableEntry *vartable_get(VarTable*, const char*); VarTableEntry *vartable_find(VarTable*, const char*); VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*); -void vartable_new_reachingdefs_for_all_vars(VarTable*); -void vartable_coalesce_reachingdefs_for_all_vars(VarTable*); +VarTable *vartable_merge(VarTable *child); + +//void vartable_new_reachingdefs_for_all_vars(VarTable*); +//void vartable_coalesce_reachingdefs_for_all_vars(VarTable*); void vte_precolor(VarTableEntry *vte, int color); diff --git a/src/x86.h b/src/x86.h index 3086f51..b44b5ed 100644 --- a/src/x86.h +++ b/src/x86.h @@ -35,8 +35,13 @@ static inline int is_xop(AST *e) { if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) { return XOP_MEM; - } else if(c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) { - if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { + } else if( + (c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) || + (c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR)) { + + if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) { + return XOP_MEM; + } else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { return XOP_MEM; } else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val; diff --git a/tests/ops.nct b/tests/ops.nct index 713aced..02f215b 100644 --- a/tests/ops.nct +++ b/tests/ops.nct @@ -1,8 +1,9 @@ u16 a = 12; u16 b = a & 6; u16 c = b ^ a | 3; -u16 d = 11 * c; +u16 o = 5; +u16 d = o * 2; -if(a) { +if(a == 0) { u16 e = b + c + d; -} \ No newline at end of file +}