aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/tests/parse/basic.cskt2
-rw-r--r--boot/visit.c317
2 files changed, 178 insertions, 141 deletions
diff --git a/boot/tests/parse/basic.cskt b/boot/tests/parse/basic.cskt
index fcc6af0..a59aff6 100644
--- a/boot/tests/parse/basic.cskt
+++ b/boot/tests/parse/basic.cskt
@@ -9,6 +9,6 @@ main = fun () int {
>>>
-(expr (binary = (expr (name main)) (expr (function (returns (type name int)) (block
+(expr (binary = (expr (name main)) (expr (function (returns (type name int)) (block
(return (expr (binary + (expr 1) (expr 2))))
))))) \ No newline at end of file
diff --git a/boot/visit.c b/boot/visit.c
index 500fb5a..3cc3e55 100644
--- a/boot/visit.c
+++ b/boot/visit.c
@@ -501,28 +501,59 @@ struct Tree_Printer
{
uint indentation_level;
FILE* output;
+ bool did_print_last_visit;
};
+#define TREE_PRINTER_PREAMBLE \
+ DATA_FOR_VISIT(struct Tree_Printer, printer); \
+ tree_printer_reset_print_state(printer);
+
+void
+tree_printer_out(struct Tree_Printer* printer, const ascii* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(printer->output, format, args);
+ va_end(args);
+
+ printer->did_print_last_visit = true;
+}
+
+#define PRINT(...) tree_printer_out(printer, __VA_ARGS__)
+#define PRINT_WHITESPACE_IF_NEEDED(s) \
+ do { \
+ if (printer->did_print_last_visit) { PRINT(s); } \
+ tree_printer_reset_print_state(printer); \
+ } while (0)
+
+void
+tree_printer_reset_print_state(struct Tree_Printer* printer)
+{
+ printer->did_print_last_visit = false;
+}
+
void
tree_printer_indent(struct Tree_Printer* printer)
{
- for (uint i = 0; i < printer->indentation_level; ++i) fprintf(printer->output, "\t");
+ for (uint i = 0; i < printer->indentation_level; ++i) PRINT("\t");
}
void
printer_visit_tree(struct Visit* visit, struct Tree* tree)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
+
FOR_EACH (struct Statement*, statement, tree->top_level_statements) {
VISIT(visit_statement, statement);
- fprintf(printer->output, "\n");
+ PRINT("\n");
}
}
void
printer_visit_statement(struct Visit* visit, struct Statement* statement)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
+
tree_printer_indent(printer);
walk_statement(visit, statement);
}
@@ -530,67 +561,67 @@ printer_visit_statement(struct Visit* visit, struct Statement* statement)
void
printer_visit_statement_declaration(struct Visit* visit, struct Statement* stmt)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
if (stmt->value.declaration.kind == STATEMENT_DECLARATION_VARIABLE)
- fprintf(printer->output, "(variable ");
+ PRINT("(variable ");
else if (stmt->value.declaration.kind == STATEMENT_DECLARATION_CONSTANT)
- fprintf(printer->output, "(constant ");
+ PRINT("(constant ");
VISIT(visit_bare_declaration_node, &stmt->value.declaration.inner);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_statement_conditional(struct Visit* visit, struct Statement* stmt)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(conditional");
+ PRINT("(conditional");
for (uint i = 0; i < stmt->value.conditional.condition_count; ++i) {
const struct Statement_Conditional_Branch* branch = &stmt->value.conditional.conditions[i];
- fprintf(printer->output, " ");
+ PRINT(" ");
if (branch->when) {
- fprintf(printer->output, "(when ");
+ PRINT("(when ");
VISIT(visit_expression, branch->when);
- fprintf(printer->output, ") ");
+ PRINT(") ");
} else {
- fprintf(printer->output, "(always) ");
+ PRINT("(always) ");
}
VISIT(visit_block_node, (struct Block_Node*)&branch->then);
}
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_statement_loop(struct Visit* visit, struct Statement* stmt)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(loop ");
+ PRINT("(loop ");
switch (stmt->value.loop.style) {
case STATEMENT_LOOP_STYLE_C:
- fprintf(printer->output, "c-style ");
+ PRINT("c-style ");
VISIT(visit_bare_declaration_node, &stmt->value.loop.declaration);
- fprintf(printer->output, " (condition ");
+ PRINT(" (condition ");
VISIT(visit_expression, stmt->value.loop.condition);
- fprintf(printer->output, ") (iteration ");
+ PRINT(") (iteration ");
VISIT(visit_expression, stmt->value.loop.iteration);
- fprintf(printer->output, ") ");
+ PRINT(") ");
break;
case STATEMENT_LOOP_STYLE_FOR_EACH:
- fprintf(printer->output, "for-each ");
+ PRINT("for-each ");
VISIT(visit_bare_declaration_node, &stmt->value.loop.declaration);
- fprintf(printer->output, " ");
+ PRINT(" ");
break;
case STATEMENT_LOOP_STYLE_WHILE:
- fprintf(printer->output, "while (condition ");
+ PRINT("while (condition ");
VISIT(visit_expression, stmt->value.loop.condition);
- fprintf(printer->output, ") ");
+ PRINT(") ");
break;
case STATEMENT_LOOP_STYLE_ENDLESS:
- fprintf(printer->output, "endless ");
+ PRINT("endless ");
break;
default:
fprintf(stderr, "unexpected loop style in `printer_visit_statement_loop`");
@@ -598,258 +629,256 @@ printer_visit_statement_loop(struct Visit* visit, struct Statement* stmt)
}
VISIT(visit_block_node, &stmt->value.loop.body);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_statement_return(struct Visit* visit, struct Statement* stmt)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(return");
+ PRINT("(return");
if (stmt->value.return_value.value) {
- fprintf(printer->output, " ");
+ PRINT(" ");
VISIT(visit_expression, stmt->value.return_value.value);
}
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_statement_break(struct Visit* visit, struct Statement* stmt)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(break)");
+ PRINT("(break)");
}
void
printer_visit_statement_continue(struct Visit* visit, struct Statement* stmt)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(continue)");
+ PRINT("(continue)");
}
void
printer_visit_statement_defer(struct Visit* visit, struct Statement* stmt)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(defer ");
+ PRINT("(defer ");
if (stmt->value.defer.expression) {
VISIT(visit_expression, stmt->value.defer.expression);
} else {
VISIT(visit_block_node, &stmt->value.defer.block);
}
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression(struct Visit* visit, struct Expression* expression)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
- fprintf(printer->output, "(expr ");
+ TREE_PRINTER_PREAMBLE
+ PRINT("(expr ");
walk_expression(visit, expression);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression_integer_literal(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "%ld", expr->value.integer_literal.value);
+ PRINT("%ld", expr->value.integer_literal.value);
}
void
printer_visit_expression_float_literal(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "%lf", expr->value.float_literal.value);
+ PRINT("%lf", expr->value.float_literal.value);
}
void
printer_visit_expression_string_literal(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "\"%s\"", expr->value.string_literal.value.data);
+ PRINT("\"%s\"", expr->value.string_literal.value.data);
}
void
printer_visit_expression_boolean_literal(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "%s", expr->value.bool_literal.value ? "true" : "false");
+ PRINT("%s", expr->value.bool_literal.value ? "true" : "false");
}
void
printer_visit_expression_name(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(name %s)", expr->value.name.name.data);
+ PRINT("(name %s)", expr->value.name.name.data);
}
void
printer_visit_expression_unary_operation(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(unary %s ",
- unary_operation_to_string(expr->value.unary_operator.operation));
+ PRINT("(unary %s ", unary_operation_to_string(expr->value.unary_operator.operation));
VISIT(visit_expression, expr->value.unary_operator.operand);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression_binary_operation(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(binary %s ",
- binary_operation_to_string(expr->value.binary_operator.operation));
+ PRINT("(binary %s ", binary_operation_to_string(expr->value.binary_operator.operation));
VISIT(visit_expression, expr->value.binary_operator.left_operand);
- fprintf(printer->output, " ");
+ PRINT(" ");
VISIT(visit_expression, expr->value.binary_operator.right_operand);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression_group(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(group ");
+ PRINT("(group ");
VISIT(visit_expression, expr->value.group.inner_expression);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression_call_or_construct(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
struct Expression_Call_Or_Construct* coc = &expr->value.call_or_construct;
- fprintf(printer->output, "(call/construct ");
+ PRINT("(call/construct ");
VISIT(visit_expression, coc->subject);
uint i = 0;
FOR_EACH (struct Expression*, argument, coc->arguments) {
struct String name = string_array_at(&coc->argument_names, i++);
if (name.data && name.data[0] != '\0') {
- fprintf(printer->output, " (named arg '%s' ", name.data);
+ PRINT(" (named arg '%s' ", name.data);
} else {
- fprintf(printer->output, " (arg ");
+ PRINT(" (arg ");
}
VISIT(visit_expression, argument);
- fprintf(printer->output, ")");
+ PRINT(")");
}
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression_subscript(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(subscript ");
+ PRINT("(subscript ");
VISIT(visit_expression, expr->value.subscript.subject);
- fprintf(printer->output, " ");
+ PRINT(" ");
VISIT(visit_expression, expr->value.subscript.index);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression_member(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(member of ");
+ PRINT("(member of ");
VISIT(visit_expression, expr->value.member.subject);
- fprintf(printer->output, " named %s)", expr->value.member.name.data);
+ PRINT(" named %s)", expr->value.member.name.data);
}
void
printer_visit_expression_increment_decrement(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
const struct Expression_Increment_Decrement* inc_dec = &expr->value.increment_decrement;
const ascii* prefix_or_postfix = inc_dec->prefix ? "prefix" : "postfix";
- fprintf(printer->output, "(increment/decrement %s %s ",
- increment_decrement_operation_to_string(inc_dec->operation), prefix_or_postfix);
+ PRINT("(increment/decrement %s %s ",
+ increment_decrement_operation_to_string(inc_dec->operation), prefix_or_postfix);
VISIT(visit_expression, inc_dec->subject);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_expression_function(struct Visit* visit, struct Expression* expr)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
struct Expression_Function* fun = &expr->value.function;
- fprintf(printer->output, "(function ");
+ PRINT("(function ");
VISIT(visit_function_header_node, &fun->header);
- fprintf(printer->output, " ");
+ PRINT_WHITESPACE_IF_NEEDED(" ");
VISIT(visit_block_node, (struct Block_Node*)&fun->body);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_type_node(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
- fprintf(printer->output, "(type ");
+ TREE_PRINTER_PREAMBLE
+ PRINT("(type ");
walk_type_node(visit, node);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_type_node_name(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "name %s", node->value.name.name.data);
+ PRINT("name %s", node->value.name.name.data);
}
void
printer_visit_type_node_array(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "array of ");
+ PRINT("array of ");
VISIT(visit_type_node, node->value.array.element_type);
}
void
printer_visit_type_node_reference(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "reference to ");
+ PRINT("reference to ");
VISIT(visit_type_node, node->value.reference.referenced_type);
}
void
printer_visit_type_node_maybe(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "maybe ");
+ PRINT("maybe ");
VISIT(visit_type_node, node->value.maybe.inner_type);
}
void
printer_visit_type_node_tuple(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "tuple");
+ PRINT("tuple");
FOR_EACH (struct Type_Node*, current, node->value.tuple.head) {
- fprintf(printer->output, " ");
+ PRINT(" ");
VISIT(visit_type_node, current);
}
}
@@ -857,31 +886,31 @@ printer_visit_type_node_tuple(struct Visit* visit, struct Type_Node* node)
void
printer_visit_type_node_map(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "map ");
+ PRINT("map ");
VISIT(visit_type_node, node->value.map.key_type);
- fprintf(printer->output, " = ");
+ PRINT(" = ");
VISIT(visit_type_node, node->value.map.value_type);
}
void
printer_visit_type_node_function(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "function ");
+ PRINT("function ");
VISIT(visit_function_header_node, &node->value.function.header);
}
void
printer_visit_type_node_structure(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "structure");
+ PRINT("structure");
FOR_EACH (struct Type_Node*, current, node->value.structure.fields) {
- fprintf(printer->output, " (field %s) ", current->value_name.data);
+ PRINT(" (field %s) ", current->value_name.data);
VISIT(visit_type_node, current);
}
}
@@ -889,16 +918,16 @@ printer_visit_type_node_structure(struct Visit* visit, struct Type_Node* node)
void
printer_visit_type_node_variant(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "variant");
+ PRINT("variant");
FOR_EACH (struct Type_Node*, current, node->value.variant.variants) {
if (current->type == TYPE_NODE_NONE) {
- fprintf(printer->output, " (variant %s)", current->value_name.data);
+ PRINT(" (variant %s)", current->value_name.data);
} else {
- fprintf(printer->output, " (variant %s of ", current->value_name.data);
+ PRINT(" (variant %s of ", current->value_name.data);
VISIT(visit_type_node, current);
- fprintf(printer->output, ")");
+ PRINT(")");
}
}
}
@@ -906,104 +935,106 @@ printer_visit_type_node_variant(struct Visit* visit, struct Type_Node* node)
void
printer_visit_type_node_class(struct Visit* visit, struct Type_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "class");
+ PRINT("class");
FOR_EACH (struct Type_Node*, current, node->value.class.methods) {
- fprintf(printer->output, " (method %s ", current->value_name.data);
+ PRINT(" (method %s ", current->value_name.data);
VISIT(visit_function_header_node, &current->value.function.header);
- fprintf(printer->output, ")");
+ PRINT(")");
}
}
void
printer_visit_block_node(struct Visit* visit, struct Block_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(block \n");
+ PRINT("(block\n");
printer->indentation_level++;
FOR_EACH (struct Statement*, statement, node->statements) {
VISIT(visit_statement, statement);
- fprintf(printer->output, "\n");
+ PRINT("\n");
}
printer->indentation_level--;
tree_printer_indent(printer);
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_bare_declaration_node(struct Visit* visit, struct Bare_Declaration_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
- fprintf(printer->output, "(declaration ");
- STRING_ARRAY_FOR_EACH (i, name, node->names) { fprintf(printer->output, "%s ", name.data); }
+ PRINT("(declaration ");
+ STRING_ARRAY_FOR_EACH (i, name, node->names) { PRINT("%s ", name.data); }
if (node->type && node->type->type != TYPE_NODE_NONE) {
VISIT(visit_type_node, node->type);
- fprintf(printer->output, " ");
+ PRINT(" ");
}
if (node->initializer) {
- fprintf(printer->output, "(initializer ");
+ PRINT("(initializer ");
VISIT(visit_expression, node->initializer);
- fprintf(printer->output, ")");
+ PRINT(")");
}
- fprintf(printer->output, ")");
+ PRINT(")");
}
void
printer_visit_function_header(struct Visit* visit, struct Function_Header_Node* header)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
FOR_EACH (struct Type_Node*, current, header->parameters_type_and_name) {
- if (current != header->parameters_type_and_name) fprintf(printer->output, " ");
+ if (current != header->parameters_type_and_name) PRINT(" ");
if (current->value_name.data && current->value_name.data[0] != '\0')
- fprintf(printer->output, "(param %s) ", current->value_name.data);
+ PRINT("(param %s) ", current->value_name.data);
else
- fprintf(printer->output, "(param) ");
+ PRINT("(param) ");
VISIT(visit_type_node, current);
}
+ PRINT_WHITESPACE_IF_NEEDED(" ");
+
if (header->return_type) {
- fprintf(printer->output, " (returns ");
+ PRINT("(returns ");
VISIT(visit_type_node, header->return_type);
- fprintf(printer->output, ")");
+ PRINT(")");
}
}
void
printer_visit_pragma_node(struct Visit* visit, struct Pragma_Node* node)
{
- DATA_FOR_VISIT(struct Tree_Printer, printer);
+ TREE_PRINTER_PREAMBLE
const ascii* pragma_name = pragma_type_to_string(node->type);
- fprintf(printer->output, "(pragma %s", pragma_name);
+ PRINT("(pragma %s", pragma_name);
for (uint ai = 0; ai < node->argument_count; ++ai) {
struct Pragma_Argument* arg = &node->arguments[ai];
switch (arg->type) {
case PRAGMA_ARGUMENT_NUMBER:
- fprintf(printer->output, " (number %ld)", arg->value.number);
+ PRINT(" (number %ld)", arg->value.number);
break;
case PRAGMA_ARGUMENT_DECIMAL:
- fprintf(printer->output, " (decimal %lf)", arg->value.decimal);
+ PRINT(" (decimal %lf)", arg->value.decimal);
break;
case PRAGMA_ARGUMENT_NAME_OR_STRING:
- fprintf(printer->output, " (name/string '%s')", arg->value.name_or_string.data);
+ PRINT(" (name/string '%s')", arg->value.name_or_string.data);
break;
default:
failure("unexpected pragma argument type in `printer_visit_pragma_node`");
}
}
- fprintf(printer->output, ")");
+ PRINT(")");
if (node->next) {
- fprintf(printer->output, " ");
+ PRINT(" ");
VISIT(visit_pragma_node, node->next);
}
}
@@ -1056,8 +1087,14 @@ struct Visit_Table printer_visit_functions = {
void
tree_printer(struct Tree* tree)
{
- struct Tree_Printer printer = { .indentation_level = 0, .output = stdout };
+ struct Tree_Printer printer = {
+ .indentation_level = 0, .output = stdout, .did_print_last_visit = false
+ };
struct Visit visit = { .table = &printer_visit_functions, .user_data = &printer };
walk(&visit, tree);
}
+
+#undef PRINT
+#undef PRINT_WHITESPACE_IF_NEEDED
+#undef TREE_PRINTER_PREAMBLE