nctref/src/ast/dump.c
2025-10-10 17:15:52 +03:00

340 lines
8.0 KiB
C

#include"dump.h"
#include"ast.h"
#include"types.h"
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include"utils.h"
char *type_to_string(Type *t) {
if(t->type == TYPE_TYPE_PRIMITIVE) {
char ret[16] = {};
int i = 0;
ret[i++] = t->primitive.isFloat ? 'f' : (t->primitive.isUnsigned ? 'u' : 'i');
snprintf(ret + i, sizeof(ret) - i, "%i", t->primitive.width);
return strdup(ret);
} else if(t->type == TYPE_TYPE_POINTER) {
char *c = type_to_string(t->pointer.of);
char *r = malp("%s*", c);
free(c);
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("%li", t->array.length);
}
char *r = malp("%s[%s]", of, len);
free(of);
free(len);
return r;
}
return strdup("@unimp");
}
static char *ast_dumpe(AST *tlc, AST *e) {
if(!e) {
return malp("(null)");
}
if(e->nodeKind == AST_EXPR_PRIMITIVE) {
return malp("%i", e->exprPrim.val);
} else if(e->nodeKind == AST_EXPR_VAR) {
ScopeItem *vte = e->exprVar.thing;
if(vte->kind == SCOPEITEM_VAR) {
return strdup(vte->data.var.name);
} else if(vte->kind == SCOPEITEM_SYMBOL) {
return strdup(vte->data.symbol.name);
} else if(vte->kind == SCOPEITEM_CEXPR) {
return ast_dumpe(tlc, vte->data.cexpr.concrete);
} else abort();
} else if(e->nodeKind == AST_EXPR_UNARY_OP) {
const char *op = NULL;
switch(e->exprUnOp.operator) {
case UNOP_REF:
op = "&";
break;
case UNOP_DEREF:
op = "*";
break;
case UNOP_BITWISE_NOT:
op = "~";
break;
case UNOP_NEGATE:
op = "-";
break;
case UNOP_NOT:
op = "!";
break;
default:
abort();
}
char *c = ast_dumpe(tlc, e->exprUnOp.operand);
char *r = malp("%s%s", op, c);
free(c);
return r;
} else if(e->nodeKind == AST_EXPR_BINARY_OP) {
char *a = ast_dumpe(tlc, e->exprBinOp.operands[0]);
char *b = ast_dumpe(tlc, e->exprBinOp.operands[1]);
const char *op;
switch(e->exprBinOp.operator) {
case BINOP_ADD:
op = "+";
break;
case BINOP_SUB:
op = "-";
break;
case BINOP_MUL:
op = "*";
break;
case BINOP_DIV:
op = "/";
break;
case BINOP_BITWISE_AND:
op = "&";
break;
case BINOP_BITWISE_OR:
op = "|";
break;
case BINOP_BITWISE_XOR:
op = "^";
break;
case BINOP_EQUAL:
op = "==";
break;
case BINOP_NEQUAL:
op = "!=";
break;
case BINOP_LESS:
op = "<";
break;
case BINOP_GREATER:
op = ">";
break;
case BINOP_LEQUAL:
op = "<=";
break;
case BINOP_GEQUAL:
op = ">=";
break;
case BINOP_MULHI:
op = "*^";
break;
case BINOP_LOGICAL_AND:
op = "&&";
break;
case BINOP_LOGICAL_OR:
op = "||";
break;
default:
abort();
}
char *r = malp("(%s %s %s)", a, op, b);
free(a);
free(b);
return r;
} else if(e->nodeKind == AST_EXPR_STACK_POINTER) {
return malp("@stack");
} 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);
free(rettype);
}
for(int i = 0; i < e->expression.type->function.argCount; i++) {
char *argtype = type_to_string(e->expression.type->function.args[i]);
char *out2 = malp(i == e->expression.type->function.argCount - 1 ? "%s%s" : "%s%s, ", out, argtype);
free(out);
free(argtype);
out = out2;
}
{
char *choonk = ast_dumpc(tlc, e->exprFunc.chunk);
char *out2 = malp("%s) {\n%s}", out, choonk);
free(out);
free(choonk);
out = out2;
}
return out;
} else if(e->nodeKind == AST_EXPR_CALL) {
char *w = ast_dumpe(tlc, e->exprCall.what);
char *out = malp("%s(", w);
free(w);
size_t argCount = e->exprCall.what->expression.type->pointer.of->function.argCount;
for(size_t i = 0; i < argCount; i++) {
char *a = ast_dumpe(tlc, e->exprCall.args[i]);
char *out2 = malp(i == argCount - 1 ? "%s%s)" : "%s%s, ", out, a);
free(a);
free(out);
out = out2;
}
return out;
} else if(e->nodeKind == AST_EXPR_EXT_SALLOC) {
char *w = type_to_string(e->exprExtSalloc.size);
char *out = malp("@salloc(%s)", w);
free(w);
return out;
} else if(e->nodeKind == AST_EXPR_CAST) {
char *a = ast_dumpe(tlc, e->exprCast.what);
char *b = type_to_string(e->exprCast.to);
char *out = malp("(%s as %s)", a, b);
free(a);
free(b);
return out;
} else if(e->nodeKind == AST_EXPR_DOT) {
char *a = ast_dumpe(tlc, e->exprDot.a);
char *out = malp(e->nodeKind == AST_EXPR_BINARY_OP ? "(%s).%s" : "%s.%s", a, e->exprDot.b);
free(a);
return out;
}
return malp("@unimp:%s", AST_KIND_STR[e->nodeKind]);
}
static char *ast_dumps(AST *tlc, AST *s) {
if(s->nodeKind == AST_STMT_ASSIGN) {
if(s->stmtAssign.to) {
char *a = ast_dumpe(tlc, s->stmtAssign.what);
char *b = ast_dumpe(tlc, s->stmtAssign.to);
char *r = malp("%s = %s;", a, b);
free(a);
free(b);
return r;
} else {
char *a = ast_dumpe(tlc, s->stmtAssign.what);
char *r = malp("%s = ; /* fake def */", a);
free(a);
return r;
}
} else if(s->nodeKind == AST_STMT_JUMP) {
char *a = ast_dumpe(tlc, s->stmtJump.condition);
char *r = malp("jump %s if %s;", s->stmtJump.label, a);
free(a);
return r;
} else if(s->nodeKind == AST_STMT_LABEL) {
return malp("@label %s;", s->stmtLabel.name);
} else if(s->nodeKind == AST_STMT_LOOP) {
char *inner = ast_dumpc(tlc, s->stmtLoop.body);
char *c = malp("loop {\n%s}", inner);
free(inner);
return c;
} else if(s->nodeKind == AST_STMT_IF) {
char *cond = ast_dumpe(tlc, s->stmtIf.expression);
char *inner = ast_dumpc(tlc, s->stmtIf.then);
char *elss = s->stmtIf.elss ? ast_dumpc(tlc, s->stmtIf.elss) : NULL;
char *c;
if(elss) {
c = malp("if(%s) {\n%s} else {\n%s}", cond, inner, elss);
free(elss);
} else {
c = malp("if(%s) {\n%s}", cond, inner);
}
free(cond);
free(inner);
return c;
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) {
const char *name;
if(s->stmtExpr.expr->exprVar.thing->kind == SCOPEITEM_VAR) {
name = s->stmtExpr.expr->exprVar.thing->data.var.name;
} else {
name = s->stmtExpr.expr->exprVar.thing->data.symbol.name;
}
return malp("%s; /* loop guard */", name);
} else if(s->nodeKind == AST_STMT_EXPR) {
return ast_dumpe(tlc, s->stmtExpr.expr);
} else if(s->nodeKind == AST_STMT_DECL) {
ScopeItem *si = s->stmtDecl.thing;
const char *name = si->kind == SCOPEITEM_VAR ? si->data.var.name : si->data.symbol.name;
char *a = type_to_string(si->type);
char *c;
if(s->stmtDecl.expression) {
char *b = ast_dumpe(tlc, s->stmtDecl.expression);
c = malp("%s %s = %s;", a, name, b);
free(b);
} else {
c = malp("%s %s;", a, name);
}
free(a);
return c;
} else if(s->nodeKind == AST_STMT_RETURN) {
if(s->stmtReturn.val) {
char *e = ast_dumpe(tlc, s->stmtReturn.val);
char *c = malp("return %s;", e);
free(e);
return c;
} else {
return malp("return;");
}
}
return malp("@unimp:%s;", AST_KIND_STR[s->nodeKind]);
}
static char *stmt_live_range_dbgs(AST *tlc, AST *stmt) {
char *ret = malp("");
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
ScopeItem *si = tlc->chunk.vars[v];
if(si->data.var.liveRangeStart == stmt) {
char *ret2 = malp("%s (%s start)", ret, si->data.var.name);
free(ret);
ret = ret2;
}
if(si->data.var.liveRangeEnd == stmt) {
char *ret2 = malp("%s (%s end)", ret, si->data.var.name);
free(ret);
ret = ret2;
}
}
return ret;
}
char *ast_dumpc(AST *tlc, AST *chu) {
AST *stmt = chu->chunk.statementFirst;
char *ret = malp("");
while(stmt) {
char *new = ast_dumps(tlc, stmt);
char *users = stmt_live_range_dbgs(tlc, stmt);
char *ret2 = malp("%s%s%s\n", ret, new, users);
free(ret);
free(new);
free(users);
ret = ret2;
stmt = stmt->statement.next;
}
return ret;
}
char *ast_dump(AST *tlc) {
return ast_dumpc(tlc, tlc);
}