/*
* Copyright (C) 2023 Johnny Richard
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "ast_pretty_printer.h"
#include "ast.h"
#include "string_view.h"
#include
#include
#include
const char *operation_kinds[AST_BINOP_N] = {
[AST_BINOP_ADITION] = "+", [AST_BINOP_SUBTRACTION] = "-", [AST_BINOP_MULTIPLICATION] = "*",
[AST_BINOP_DIVISION] = "/", [AST_BINOP_EQUAL] = "==", [AST_BINOP_NOT_EQUAL] = "!=",
[AST_BINOP_AND] = "&&", [AST_BINOP_OR] = "||", [AST_BINOP_GT] = ">",
[AST_BINOP_LT] = "<", [AST_BINOP_LT_EQUAL] = "<=", [AST_BINOP_GT_EQUAL] = ">=",
};
void
ast_pretty_printer_init(ast_pretty_printer_t *printer, FILE *stream);
inline static void
ast_pretty_printer_add_indentation(ast_pretty_printer_t *printer);
inline static void
ast_pretty_printer_rm_indentation(ast_pretty_printer_t *printer);
inline static void
ast_pretty_printer_set_lst_children(ast_pretty_printer_t *printer);
static void
ast_pretty_printer_print_indentation(ast_pretty_printer_t *printer);
static int
ast_pretty_printer_printf(ast_pretty_printer_t *printer, const char *fmt, ...);
void
ast_pretty_printer_init(ast_pretty_printer_t *printer, FILE *stream)
{
assert(printer);
assert(stream);
printer->indentation_fmt = 0ULL;
printer->indentation_lst_children = 0ULL;
printer->indentation_level = 0;
printer->stream = stream;
}
void
ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast)
{
assert(ast);
switch (ast->kind) {
case AST_FUNCTION_PARAMETER:
break;
case AST_NAMESPACE:
ast_pretty_printer_printf(printer, "Namespace\n");
ast_pretty_printer_add_indentation(printer);
{
for (size_t i = 0; i < ast->data.ns.nodes->size; ++i) {
if (i + 1 >= ast->data.ns.nodes->size) {
ast_pretty_printer_set_lst_children(printer);
}
ast_pretty_printer_print_ast(printer, vector_at(ast->data.ns.nodes, i));
}
ast_pretty_printer_rm_indentation(printer);
}
break;
case AST_IF_STMT: {
ast_if_stmt_t if_stmt = ast->data.if_stmt;
ast_pretty_printer_printf(printer, "IfStmt\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_printf(printer, "condition:\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, if_stmt.condition);
ast_pretty_printer_rm_indentation(printer);
}
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_printf(printer, "body:\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, if_stmt.body);
ast_pretty_printer_rm_indentation(printer);
}
ast_pretty_printer_rm_indentation(printer);
}
break;
}
case AST_BINARY_OPERATION: {
ast_binary_operation_t binop = ast->data.binary_operation;
ast_pretty_printer_printf(printer, "BinaryOperation operation='%s'\n", operation_kinds[binop.kind]);
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_printf(printer, "left:\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, binop.left);
ast_pretty_printer_rm_indentation(printer);
}
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_printf(printer, "right:\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, binop.right);
ast_pretty_printer_rm_indentation(printer);
}
ast_pretty_printer_rm_indentation(printer);
}
break;
}
case AST_FUNCTION_DECLARATION: {
string_view_t function_name = ast_node_function_declaration_name(ast);
ast_pretty_printer_printf(printer, "FunctionDecl name='" SVFMT "'\n", SVARG(&function_name));
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_printf(printer, "body:\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, ast->data.function.body);
ast_pretty_printer_rm_indentation(printer);
}
ast_pretty_printer_rm_indentation(printer);
}
break;
}
case AST_FUNCTION_CALL: {
ast_function_call_t var = ast->data.function_call;
ast_pretty_printer_printf(printer, "FunctionCall name='" SVFMT "'\n", SVARG(&var.identifier->name));
break;
}
case AST_BLOCK: {
ast_pretty_printer_printf(printer, "Block\n");
ast_pretty_printer_add_indentation(printer);
{
for (size_t i = 0; i < ast->data.block.body->size; ++i) {
if (i + 1 >= ast->data.block.body->size) {
ast_pretty_printer_set_lst_children(printer);
}
ast_pretty_printer_print_ast(printer, vector_at(ast->data.block.body, i));
}
ast_pretty_printer_rm_indentation(printer);
}
break;
}
case AST_LITERAL: {
ast_literal_t literal = ast->data.literal;
switch (literal.kind) {
case AST_LITERAL_INTEGER: {
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_printf(printer, "Literal type=i32 value='%d'\n", literal.value.integer);
break;
}
case AST_LITERAL_BOOL:
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_printf(
printer, "Literal type=bool value='%s'\n", literal.value.boolean ? "true" : "false");
break;
}
break;
}
case AST_RETURN_STMT: {
ast_return_stmt_t return_stmt = ast->data.return_stmt;
ast_pretty_printer_printf(printer, "ReturnStmt\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, return_stmt.argument);
ast_pretty_printer_rm_indentation(printer);
}
break;
}
case AST_VARIABLE_DECLARATION: {
ast_variable_declaration_t var_decl = ast->data.variable_declaration;
ast_pretty_printer_printf(printer, "VariableDecl name='" SVFMT "'\n", SVARG(&var_decl.identifier.name));
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, var_decl.value);
ast_pretty_printer_rm_indentation(printer);
}
break;
}
case AST_VARIABLE_ASSIGNMENT: {
ast_variable_assignment_t var_assign = ast->data.variable_assignment;
ast_pretty_printer_printf(printer, "VariableAssignment name='" SVFMT "'\n", SVARG(&var_assign.identifier->name));
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_printf(printer, "expression:\n");
ast_pretty_printer_add_indentation(printer);
{
ast_pretty_printer_set_lst_children(printer);
ast_pretty_printer_print_ast(printer, var_assign.expression);
ast_pretty_printer_rm_indentation(printer);
}
ast_pretty_printer_rm_indentation(printer);
}
break;
}
case AST_VARIABLE: {
ast_variable_t var = ast->data.variable;
ast_pretty_printer_printf(printer, "Variable name='" SVFMT "'\n", SVARG(&var.identifier->name));
break;
}
case AST_UNKOWN_NODE: {
fprintf(printer->stream, "AST_UNKOWN_NODE\n");
break;
}
}
}
static int
ast_pretty_printer_printf(ast_pretty_printer_t *printer, const char *fmt, ...)
{
int ret = 0;
va_list args;
va_start(args, fmt);
ast_pretty_printer_print_indentation(printer);
ret = vprintf(fmt, args);
va_end(args);
return ret;
}
inline static void
ast_pretty_printer_add_indentation(ast_pretty_printer_t *printer)
{
printer->indentation_level++;
printer->indentation_fmt |= 1ULL << printer->indentation_level;
}
inline static void
ast_pretty_printer_rm_indentation(ast_pretty_printer_t *printer)
{
printer->indentation_level--;
}
inline static void
ast_pretty_printer_set_lst_children(ast_pretty_printer_t *printer)
{
printer->indentation_lst_children |= 1ULL << printer->indentation_level;
}
static void
ast_pretty_printer_print_indentation(ast_pretty_printer_t *printer)
{
for (size_t i = 0; i <= printer->indentation_level; ++i) {
if ((printer->indentation_fmt >> i) & 1ULL) {
if (i + 1 > printer->indentation_level && (printer->indentation_lst_children & (1ULL << i))) {
printer->indentation_lst_children ^= (1ULL << i);
printer->indentation_fmt ^= (1ULL << i);
fprintf(printer->stream, "└─ ");
} else if (i + 1 > printer->indentation_level) {
fprintf(printer->stream, "├─ ");
} else {
fprintf(printer->stream, "│ ");
}
} else {
fprintf(printer->stream, " ");
}
}
}