larpcc/ast_str.c
2026-09-29 04:22:57 +02:00

284 lines
7.0 KiB
C

#include "ast.h"
#include "collection.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static void push(AstStringifier* s, const char* str)
{
for (; *str; ++str) {
arena_array_push(s->arena,
(void**)&s->string,
&s->string_cap,
&s->string_size,
(void*)str,
sizeof(*str));
}
char ch = '\0';
arena_array_push(s->arena,
(void**)&s->string,
&s->string_cap,
&s->string_size,
(void*)&ch,
sizeof(ch));
s->string_size -= 1;
}
#define pushf(S, ...) \
do { \
size_t len = snprintf(nullptr, 0, __VA_ARGS__); \
char* buf = calloc(len + 1, 1); \
snprintf(buf, len + 1, __VA_ARGS__); \
push(S, buf); \
free(buf); \
} while (false)
static void indent(AstStringifier* s)
{
for (int i = 0; i < s->depth; ++i) {
push(s, " ");
}
}
void ast_stringifier_init(AstStringifier* s, Arena* arena)
{
*s = (AstStringifier) {
ARRAY_FIELD_INIT(string),
.arena = arena,
.depth = 0,
};
}
void ast_stmt_block_to_string(AstStringifier* s, const AstStmtBlock* node)
{
pushf(s, "StmtBlock %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "stmts: [");
if (node->stmts_size) {
s->depth += 1;
push(s, "\n");
for (size_t i = 0; i < node->stmts_size; ++i) {
indent(s);
ast_stmt_to_string(s, node->stmts[i]);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
}
push(s, "],");
s->depth -= 1;
indent(s);
push(s, "}");
}
void ast_stmt_to_string(AstStringifier* s, const AstStmt* node)
{
switch (node->ty) {
case AstStmt_Decl: {
pushf(s, "Stmt::Decl %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "decl: ");
ast_decl_to_string(s, node->decl);
push(s, ",\n");
s->depth -= 1;
indent(s);
push(s, "}");
break;
}
case AstStmt_Expr: {
pushf(s, "Stmt::Expr %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "expr: ");
ast_expr_to_string(s, node->expr);
push(s, ",\n");
s->depth -= 1;
indent(s);
push(s, "}");
break;
}
}
}
static void spec_to_string(AstStringifier* s, AstSpec spec)
{
struct {
AstSpec specifier;
const char* ident;
} spec_idents[] = {
{ AstSpec_Int, "int" },
{ AstSpec_Char, "char" },
{ AstSpec_Unsigned, "unsigned" },
{ AstSpec_Static, "static" },
{ AstSpec_Const, "const" },
{ AstSpec_Inline, "inline" },
{ AstSpec_Typedef, "typedef" },
{ AstSpec_Enum, "enum" },
{ AstSpec_Struct, "struct" },
{ AstSpec_Union, "union" },
};
bool first = true;
for (size_t i = 0; i < sizeof(spec_idents) / sizeof(spec_idents[0]); ++i) {
if (spec & spec_idents[i].specifier) {
if (!first)
push(s, " ");
first = false;
push(s, spec_idents[i].ident);
}
}
}
void ast_decl_to_string(AstStringifier* s, const AstDecl* node)
{
pushf(s, "Decl %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "spec: [");
spec_to_string(s, node->spec);
push(s, "],\n");
if (node->spec & AstSpec_DefTy) {
assert(node->type_ident);
indent(s);
pushf(s, "type_ident: \"%s\",\n", node->type_ident);
}
indent(s);
push(s, "declars: [");
if (node->declars_size) {
push(s, "\n");
s->depth += 1;
for (size_t i = 0; i < node->declars_size; ++i) {
indent(s);
ast_declar_to_string(s, node->declars[i]);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "],\n");
} else {
push(s, "],\n");
}
if (node->function_body) {
indent(s);
push(s, "function_body: ");
ast_stmt_block_to_string(s, node->function_body);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "}");
}
void ast_declar_to_string(AstStringifier* s, const AstDeclar* node)
{
switch (node->ty) {
case AstDeclar_Ident: {
pushf(s, "Declar::Ident %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
pushf(s, "ident: \"%s\",\n", node->ident);
break;
}
case AstDeclar_Pointer: {
pushf(
s, "Declar::Pointer %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "declar: ");
ast_declar_to_string(s, node->pointer.declar);
push(s, ",\n");
indent(s);
push(s, "spec: [");
spec_to_string(s, node->pointer.spec);
push(s, "],\n");
break;
}
case AstDeclar_Array: {
pushf(s, "Declar::Array %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "declar: ");
ast_declar_to_string(s, node->array.declar);
push(s, ",\n");
indent(s);
push(s, "expr: ");
ast_expr_to_string(s, node->array.expr);
push(s, ",\n");
break;
}
case AstDeclar_Function: {
pushf(
s, "Declar::Function %d:%d {\n", node->loc.line, node->loc.col);
s->depth += 1;
indent(s);
push(s, "declar: ");
ast_declar_to_string(s, node->array.declar);
push(s, ",\n");
indent(s);
push(s, "params: [");
if (node->function.params_size) {
push(s, "\n");
s->depth += 1;
for (size_t i = 0; i < node->function.params_size; ++i) {
indent(s);
ast_decl_to_string(s, node->function.params[i]);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "],\n");
} else {
push(s, "],\n");
}
break;
}
}
if (node->init_expr) {
indent(s);
push(s, "decl: ");
ast_expr_to_string(s, node->init_expr);
push(s, ",\n");
}
s->depth -= 1;
indent(s);
push(s, "}");
}
void ast_expr_to_string(AstStringifier* s, const AstExpr* node)
{
push(s, "<expr>");
}