static const char* node_str[] = { [NODE_BUILTIN] = "BUILTIN", [NODE_NUMBER] = "NUMBER", [NODE_BOOL] = "BOOL", [NODE_STRING] = "STRING", [NODE_SYMBOL] = "SYMBOL", [NODE_TYPE] = "TYPE", [NODE_DEF] = "DEF", [NODE_SET] = "SET", [NODE_FUN] = "FUN", [NODE_BLOCK] = "BLOCK", [NODE_IF] = "IF", [NODE_FUNCALL] = "FUNCALL", }; void viz_node(Node *node) { if (node == NULL) { return; } printf("%zu [width=2.5,shape=Mrecord,label=\"", node->id); printf(" %s -- [%4ld:%-4ld] ", node_str[node->type], node->line, node->col); if (node->expr_type != NULL) { printf("| T: "); sv_write(&node->expr_type->name); } switch (node->type) { case NODE_NUMBER: { printf("| Value: "); if (node->number.negative) { printf("-"); } if (node->number.fractional != 0) { printf("%zu.%zu", node->number.integral, node->number.fractional); } else { printf("%zu", node->number.integral); } printf("\"];\n"); } break; case NODE_SYMBOL: case NODE_TYPE: case NODE_STRING: { printf(" | Value: "); sv_write(&node->string); printf("\"];\n"); } break; case NODE_BOOL: { printf(" | Value: "); if (node->boolean) { printf("true"); } else { printf("false"); } printf("\"];\n"); } break; case NODE_BUILTIN: { printf(" | Name: %s", token_str[node->builtin.type]); printf(" | Args: "); printf("\"];\n"); size_t n_args = array_size(node->builtin.args); for (size_t i = 0; i < n_args; ++i) { viz_node(node->builtin.args[i]); printf("%zu:args:e->%zu:top:w;\n", node->id, node->builtin.args[i]->id); } } break; case NODE_DEF: { printf(" | Name: "); sv_write(&node->def.symbol->string); printf(" | Type: "); sv_write(&node->def.type->string); printf(" | Expr: "); printf("\"];\n"); viz_node(node->def.value); printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); } break; case NODE_SET: { printf(" | Name: "); sv_write(&node->set.symbol->string); printf(" | Expr: "); printf("\"];\n"); viz_node(node->set.value); printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); } break; case NODE_BLOCK: { printf(" | Exprs: "); printf("\"];\n"); size_t n_expr = array_size(node->block.expr); for (size_t i = 0; i < n_expr; ++i) { viz_node(node->block.expr[i]); printf("%zu:expr:e->%zu:top:w;\n", node->id, node->block.expr[i]->id); } } break; case NODE_IF: { printf(" | Cond: "); printf(" | ExprTrue:"); if (node->ifexpr.expr_false != NULL) { printf(" | ExprFalse: "); } printf("\"];\n"); viz_node(node->ifexpr.cond); printf("%zu:cond:e->%zu:top:w;\n", node->id, node->ifexpr.cond->id); viz_node(node->ifexpr.expr_true); printf("%zu:t:e->%zu:top:w;\n", node->id, node->ifexpr.expr_true->id); if (node->ifexpr.expr_false != NULL) { viz_node(node->ifexpr.expr_false); printf("%zu:f:e->%zu:top:w;\n", node->id, node->ifexpr.expr_false->id); } } break; case NODE_FUN: { printf(" | Name: "); sv_write(&node->fun.name->string); printf(" | Type: "); printf("("); size_t n_params = array_size(node->fun.param_names); for (size_t i = 0; i < n_params; ++i) { printf(":"); sv_write(&node->fun.param_types[i]->string); if (i < n_params - 1) { printf(" "); } } printf("):"); sv_write(&node->fun.return_type->string); if (n_params > 0) { printf(" | Parameters: ("); for (size_t i = 0; i < n_params; ++i) { sv_write(&node->fun.param_names[i]->string); if (i < n_params - 1) { printf(" "); } } printf(")"); } printf(" | Body: "); printf("\"];\n"); viz_node(node->fun.body); printf("%zu:bod:e->%zu:top:w;\n", node->id, node->fun.body->id); } break; case NODE_FUNCALL: { printf(" | Name: "); sv_write(&node->funcall.name->string); printf(" | Args: "); printf("\"];\n"); size_t n_args = array_size(node->funcall.args); for (size_t i = 0; i < n_args; ++i) { viz_node(node->funcall.args[i]); printf("%zu:args:e->%zu:top:w;\n", node->id, node->funcall.args[i]->id); } } break; } } void viz_ast(Root *roots) { if (roots == NULL) { return; } printf("digraph ast {\n"); printf("rankdir=LR;\n"); printf("ranksep=\"0.95 equally\";\n"); printf("nodesep=\"0.5 equally\";\n"); printf("overlap=scale;\n"); for (size_t i = 0; i < array_size(roots); ++i) { printf("subgraph %zu {\n", i); Node *root = roots[array_size(roots) - 1 - i]; viz_node(root); printf("}\n"); } printf("}\n"); } void viz_symtables(Scope **scopes) { printf("digraph symtables {\n"); printf("rankdir=RL;\n"); printf("ranksep=\"0.95 equally\";\n"); printf("nodesep=\"0.5 equally\";\n"); printf("overlap=scale;\n"); for (size_t i = 0; i < array_size(scopes); ++i) { Scope *scope = scopes[i]; if (array_size(scope->symbols->pairs) == 0) { continue; } printf("%zu [shape=none,label=<", scope->id); printf("\n"); printf(""); for (size_t j = 0; j < array_cap(scope->symbols->pairs); ++j) { HashTablePair pair = scope->symbols->pairs[j]; if (pair.key == NULL) { continue; } Symbol *sym = pair.value; printf(""); printf(""); switch (sym->type) { case SYMBOL_PAR: { printf(""); printf(""); } break; case SYMBOL_VAR: { printf(""); printf(""); } break; case SYMBOL_FUN: { printf(""); printf(""); } break; } printf("\n"); } printf("
NAMEKINDTYPE
"); print_node(sym->name); printf("par"); print_node(sym->var.type); printf("var"); print_node(sym->var.type); printf("fun"); printf("("); size_t n_params = array_size(sym->fun.param_types); for (size_t k = 0; k < n_params; ++k) { print_node(sym->fun.param_types[k]); if (k < n_params - 1) { printf(" "); } } printf(")"); printf(":"); print_node(sym->fun.return_type); printf("
\n"); printf(">];\n"); if (scope->parent != NULL) { printf("%zu -> %zu\n", scope->id, scope->parent->id); } } printf("}\n"); }