From 1512abed55dd3f779eb774eb03f605397a4a45fe Mon Sep 17 00:00:00 2001 From: Mel Date: Sun, 3 May 2026 01:30:28 +0200 Subject: Move tree visit definitions in visit.c to visit/tree.c for future consistency Signed-off-by: Mel --- boot/visit/tree.c | 1185 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1185 insertions(+) create mode 100644 boot/visit/tree.c (limited to 'boot/visit') diff --git a/boot/visit/tree.c b/boot/visit/tree.c new file mode 100644 index 0000000..001cd36 --- /dev/null +++ b/boot/visit/tree.c @@ -0,0 +1,1185 @@ +/* + * visit system for the catskill syntax tree, + * implementing a default traversal mechanism, + * allowing for selective operations on it. + * includes a simple tree printer as the primary example of usage. + * + * Copyright (c) 2025, Mel G. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +#pragma once + +#include "../catboot.h" + +struct Tree_Visit +{ + struct Tree_Visit_Table* table; + void* user_data; +}; + +struct Tree_Visit_Table +{ + void (*visit_tree)(struct Tree_Visit* visitor, struct Tree* tree); + + void (*visit_statement)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + void (*visit_statement_declaration)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + void (*visit_statement_conditional)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + void (*visit_statement_loop)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + void (*visit_statement_return)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + void (*visit_statement_break)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + void (*visit_statement_continue)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + void (*visit_statement_defer)(struct Tree_Visit* visitor, struct Tree_Statement* stmt); + + void (*visit_expression)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_integer_literal)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_float_literal)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_string_literal)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_boolean_literal)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_name)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_unary_operation)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_binary_operation)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_group)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_call)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_construct)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_subscript)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_member)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_increment_decrement)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_try)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_must)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + void (*visit_expression_function)(struct Tree_Visit* visitor, struct Tree_Expression* expr); + + void (*visit_type_node)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_name)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_array)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_reference)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_maybe)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_tuple)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_map)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_function)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_structure)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_variant)(struct Tree_Visit* visitor, struct Tree_Type* node); + void (*visit_type_node_class)(struct Tree_Visit* visitor, struct Tree_Type* node); + + void (*visit_block_node)(struct Tree_Visit* visitor, struct Tree_Block* node); + void (*visit_bare_declaration_node)(struct Tree_Visit* visitor, struct Tree_Bare_Declaration* node); + void (*visit_function_header_node)(struct Tree_Visit* visitor, struct Tree_Function_Header* header); + void (*visit_argument_group_node)(struct Tree_Visit* visitor, struct Tree_Argument_Group* node); + void (*visit_pragma_node)(struct Tree_Visit* visitor, struct Tree_Pragma* node); +}; + +#define VISIT(visit_function, node) visit->table->visit_function(visit, node); + +#define VISIT_MAYBE(visit_function, node) \ + if (node) visit->table->visit_function(visit, node) + +#define DATA_FOR_VISIT(type, name) \ + type* name = (type*)visit->user_data; \ + if (!name) { failure("visit user data is NULL for " #name); } + +// tree_walk functions are the default traversal mechanism + +// define a tree_walk function which goes nowhere. +#define TREE_WALK_LEAF_FUNCTION(name, type) \ + void name(struct Tree_Visit* visit, type node) {} + +// top-level tree_walk function for beginning the visit flow. +void +tree_walk(struct Tree_Visit* visit, struct Tree* tree) +{ + VISIT(visit_tree, tree); +} + +void +tree_walk_tree(struct Tree_Visit* visit, struct Tree* tree) +{ + FOR_EACH (struct Tree_Statement*, statement, tree->top_level_statements) { + VISIT(visit_statement, statement); + } +} + +void +tree_walk_statement(struct Tree_Visit* visit, struct Tree_Statement* statement) +{ + switch (statement->kind) { + case TREE_STATEMENT_EXPRESSION: + VISIT(visit_expression, statement->value.expression.inner); + break; + case TREE_STATEMENT_DECLARATION: + VISIT(visit_statement_declaration, statement); + break; + case TREE_STATEMENT_BLOCK: + VISIT(visit_block_node, &statement->value.block.inner); + break; + case TREE_STATEMENT_CONDITIONAL: + VISIT(visit_statement_conditional, statement); + break; + case TREE_STATEMENT_LOOP: + VISIT(visit_statement_loop, statement); + break; + case TREE_STATEMENT_RETURN: + VISIT(visit_statement_return, statement); + break; + case TREE_STATEMENT_BREAK: + VISIT(visit_statement_break, statement); + break; + case TREE_STATEMENT_CONTINUE: + VISIT(visit_statement_continue, statement); + break; + case TREE_STATEMENT_DEFER: + VISIT(visit_statement_defer, statement); + break; + case TREE_STATEMENT_PRAGMA: + VISIT(visit_pragma_node, statement->value.pragma.inner); + break; + default: + failure("unexpected statement kind in `tree_walk_statement`"); + } +} + +void +tree_walk_statement_declaration(struct Tree_Visit* visit, struct Tree_Statement* statement) +{ + VISIT(visit_bare_declaration_node, &statement->value.declaration.inner); +} + +void +tree_walk_statement_conditional(struct Tree_Visit* visit, struct Tree_Statement* statement) +{ + struct Tree_Statement_Value_Conditional* conditional = &statement->value.conditional; + for (uint i = 0; i < conditional->condition_count; ++i) { + VISIT_MAYBE(visit_expression, conditional->conditions[i].when); + VISIT(visit_block_node, &conditional->conditions[i].then); + } +} + +void +tree_walk_statement_loop(struct Tree_Visit* visit, struct Tree_Statement* statement) +{ + struct Tree_Statement_Value_Loop* loop = &statement->value.loop; + VISIT_MAYBE(visit_expression, loop->condition); + VISIT_MAYBE(visit_expression, loop->iteration); + VISIT(visit_block_node, &loop->body); +} + +void +tree_walk_statement_return(struct Tree_Visit* visit, struct Tree_Statement* statement) +{ + VISIT_MAYBE(visit_expression, statement->value.return_value.value); +} + +// although.. maybe with `break` we could make a loop become an expression, +// this returning the break value as the value of the loop? +// something to think about. +TREE_WALK_LEAF_FUNCTION(tree_walk_statement_break, struct Tree_Statement*); + +TREE_WALK_LEAF_FUNCTION(tree_walk_statement_continue, struct Tree_Statement*); + +void +tree_walk_statement_defer(struct Tree_Visit* visit, struct Tree_Statement* statement) +{ + VISIT_MAYBE(visit_expression, statement->value.defer.expression); + VISIT(visit_block_node, &statement->value.defer.block); +} + +void +tree_walk_expression(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + switch (expression->kind) { + case TREE_EXPRESSION_INTEGER_LITERAL: + VISIT(visit_expression_integer_literal, expression); + break; + case TREE_EXPRESSION_FLOAT_LITERAL: + VISIT(visit_expression_float_literal, expression); + break; + case TREE_EXPRESSION_STRING_LITERAL: + VISIT(visit_expression_string_literal, expression); + break; + case TREE_EXPRESSION_BOOLEAN_LITERAL: + VISIT(visit_expression_boolean_literal, expression); + break; + case TREE_EXPRESSION_NAME: + VISIT(visit_expression_name, expression); + break; + case TREE_EXPRESSION_UNARY_OPERATION: + VISIT(visit_expression_unary_operation, expression); + break; + case TREE_EXPRESSION_BINARY_OPERATION: + VISIT(visit_expression_binary_operation, expression); + break; + case TREE_EXPRESSION_GROUP: + VISIT(visit_expression_group, expression); + break; + case TREE_EXPRESSION_CALL: + VISIT(visit_expression_call, expression); + break; + case TREE_EXPRESSION_CONSTRUCT: + VISIT(visit_expression_construct, expression); + break; + case TREE_EXPRESSION_SUBSCRIPT: + VISIT(visit_expression_subscript, expression); + break; + case TREE_EXPRESSION_MEMBER: + VISIT(visit_expression_member, expression); + break; + case TREE_EXPRESSION_INCREMENT_DECREMENT: + VISIT(visit_expression_increment_decrement, expression); + break; + case TREE_EXPRESSION_TRY: + VISIT(visit_expression_try, expression); + break; + case TREE_EXPRESSION_MUST: + VISIT(visit_expression_must, expression); + break; + case TREE_EXPRESSION_FUNCTION: + VISIT(visit_expression_function, expression); + break; + case TREE_EXPRESSION_TYPE: + VISIT(visit_type_node, expression->value.type.type); + break; + default: + failure("unexpected expression kind in `tree_walk_expression`"); + } +} + +TREE_WALK_LEAF_FUNCTION(tree_walk_expression_integer_literal, struct Tree_Expression*); + +TREE_WALK_LEAF_FUNCTION(tree_walk_expression_float_literal, struct Tree_Expression*); + +TREE_WALK_LEAF_FUNCTION(tree_walk_expression_string_literal, struct Tree_Expression*); + +TREE_WALK_LEAF_FUNCTION(tree_walk_expression_boolean_literal, struct Tree_Expression*); + +TREE_WALK_LEAF_FUNCTION(tree_walk_expression_name, struct Tree_Expression*); + +void +tree_walk_expression_unary_operation(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + VISIT(visit_expression, expression->value.unary_operator.operand); +} + +void +tree_walk_expression_binary_operation(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + VISIT(visit_expression, expression->value.binary_operator.left_operand); + VISIT(visit_expression, expression->value.binary_operator.right_operand); +} + +void +tree_walk_expression_group(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + VISIT(visit_expression, expression->value.group.inner_expression); +} + +void +tree_walk_expression_call(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + struct Tree_Expression_Call* call = &expression->value.call; + VISIT(visit_expression, call->subject); + VISIT(visit_argument_group_node, &call->argument_group); +} + +void +tree_walk_expression_construct(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + struct Tree_Expression_Construct* construct = &expression->value.construct; + VISIT(visit_expression, construct->subject); + VISIT(visit_argument_group_node, &construct->argument_group); +} + +void +tree_walk_expression_subscript(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + VISIT(visit_expression, expression->value.subscript.subject); + VISIT(visit_expression, expression->value.subscript.index); +} + +void +tree_walk_expression_member(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + VISIT(visit_expression, expression->value.member.subject); +} + +void +tree_walk_expression_increment_decrement(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + VISIT(visit_expression, expression->value.increment_decrement.subject); +} + +TREE_WALK_LEAF_FUNCTION(tree_walk_expression_try, struct Tree_Expression*); + +TREE_WALK_LEAF_FUNCTION(tree_walk_expression_must, struct Tree_Expression*); + +void +tree_walk_expression_function(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + VISIT(visit_function_header_node, &expression->value.function.header); + VISIT(visit_block_node, &expression->value.function.body); +} + +void +tree_walk_type(struct Tree_Visit* visit, struct Tree_Type* node) +{ + switch (node->type) { + case TREE_TYPE_NONE: + break; + case TREE_TYPE_NAME: + VISIT(visit_type_node_name, node); + break; + case TREE_TYPE_ARRAY: + VISIT(visit_type_node_array, node); + break; + case TREE_TYPE_REFERENCE: + VISIT(visit_type_node_reference, node); + break; + case TREE_TYPE_MAYBE: + VISIT(visit_type_node_maybe, node); + break; + case TREE_TYPE_TUPLE: + VISIT(visit_type_node_tuple, node); + break; + case TREE_TYPE_MAP: + VISIT(visit_type_node_map, node); + break; + case TREE_TYPE_FUNCTION: + VISIT(visit_type_node_function, node); + break; + case TREE_TYPE_STRUCTURE: + VISIT(visit_type_node_structure, node); + break; + case TREE_TYPE_VARIANT: + VISIT(visit_type_node_variant, node); + break; + case TREE_TYPE_CLASS: + VISIT(visit_type_node_class, node); + break; + default: + failure("unexpected type node kind in `tree_walk_type`"); + } +} + +TREE_WALK_LEAF_FUNCTION(tree_walk_type_name, struct Tree_Type*); + +void +tree_walk_type_array(struct Tree_Visit* visit, struct Tree_Type* node) +{ + VISIT(visit_type_node, node->value.array.element_type); +} + +void +tree_walk_type_reference(struct Tree_Visit* visit, struct Tree_Type* node) +{ + VISIT(visit_type_node, node->value.reference.referenced_type); +} + +void +tree_walk_type_maybe(struct Tree_Visit* visit, struct Tree_Type* node) +{ + VISIT(visit_type_node, node->value.maybe.inner_type); +} + +void +tree_walk_type_tuple(struct Tree_Visit* visit, struct Tree_Type* node) +{ + FOR_EACH (struct Tree_Type*, current, node->value.tuple.head) { + VISIT(visit_type_node, current); + } +} + +void +tree_walk_type_map(struct Tree_Visit* visit, struct Tree_Type* node) +{ + VISIT(visit_type_node, node->value.map.key_type); + VISIT(visit_type_node, node->value.map.value_type); +} + +void +tree_walk_type_function(struct Tree_Visit* visit, struct Tree_Type* node) +{ + VISIT(visit_function_header_node, &node->value.function.header); +} + +void +tree_walk_type_structure(struct Tree_Visit* visit, struct Tree_Type* node) +{ + FOR_EACH (struct Tree_Type*, field, node->value.structure.fields) { + VISIT(visit_type_node, field); + } +} + +void +tree_walk_type_variant(struct Tree_Visit* visit, struct Tree_Type* node) +{ + FOR_EACH (struct Tree_Type*, method, node->value.variant.variants) { + VISIT(visit_type_node, method); + } +} + +void +tree_walk_type_class(struct Tree_Visit* visit, struct Tree_Type* node) +{ + FOR_EACH (struct Tree_Type*, method, node->value.class.methods) { + VISIT(visit_type_node, method); + } +} + +void +tree_walk_block(struct Tree_Visit* visit, struct Tree_Block* node) +{ + FOR_EACH (struct Tree_Statement*, statement, node->statements) { VISIT(visit_statement, statement); } +} + +void +tree_walk_bare_declaration(struct Tree_Visit* visit, struct Tree_Bare_Declaration* node) +{ + VISIT_MAYBE(visit_type_node, node->type); + VISIT(visit_expression, node->initializer); +} + +void +tree_walk_function_header(struct Tree_Visit* visit, struct Tree_Function_Header* header) +{ + FOR_EACH (struct Tree_Type*, param_type, header->parameters_type_and_name) { + VISIT(visit_type_node, param_type); + } + VISIT_MAYBE(visit_type_node, header->return_type); +} + +void +tree_walk_argument_group(struct Tree_Visit* visit, struct Tree_Argument_Group* node) +{ + FOR_EACH (struct Tree_Expression*, argument, node->arguments) { VISIT(visit_expression, argument); } +} + +void +tree_walk_pragma(struct Tree_Visit* visit, struct Tree_Pragma* node) +{ + // visit each pragma node in the linked list. + VISIT_MAYBE(visit_pragma_node, node->next); +} + +struct Tree_Visit_Table tree_walk_functions = { + .visit_tree = tree_walk_tree, + + .visit_statement = tree_walk_statement, + .visit_statement_declaration = tree_walk_statement_declaration, + .visit_statement_conditional = tree_walk_statement_conditional, + .visit_statement_loop = tree_walk_statement_loop, + .visit_statement_return = tree_walk_statement_return, + .visit_statement_break = tree_walk_statement_break, + .visit_statement_continue = tree_walk_statement_continue, + .visit_statement_defer = tree_walk_statement_defer, + + .visit_expression = tree_walk_expression, + .visit_expression_integer_literal = tree_walk_expression_integer_literal, + .visit_expression_float_literal = tree_walk_expression_float_literal, + .visit_expression_string_literal = tree_walk_expression_string_literal, + .visit_expression_boolean_literal = tree_walk_expression_boolean_literal, + .visit_expression_name = tree_walk_expression_name, + .visit_expression_unary_operation = tree_walk_expression_unary_operation, + .visit_expression_binary_operation = tree_walk_expression_binary_operation, + .visit_expression_group = tree_walk_expression_group, + .visit_expression_call = tree_walk_expression_call, + .visit_expression_construct = tree_walk_expression_construct, + .visit_expression_subscript = tree_walk_expression_subscript, + .visit_expression_member = tree_walk_expression_member, + .visit_expression_increment_decrement = tree_walk_expression_increment_decrement, + .visit_expression_function = tree_walk_expression_function, + + .visit_type_node = tree_walk_type, + .visit_type_node_name = tree_walk_type_name, + .visit_type_node_array = tree_walk_type_array, + .visit_type_node_reference = tree_walk_type_reference, + .visit_type_node_maybe = tree_walk_type_maybe, + .visit_type_node_tuple = tree_walk_type_tuple, + .visit_type_node_map = tree_walk_type_map, + .visit_type_node_function = tree_walk_type_function, + .visit_type_node_structure = tree_walk_type_structure, + .visit_type_node_variant = tree_walk_type_variant, + .visit_type_node_class = tree_walk_type_class, + + .visit_block_node = tree_walk_block, + .visit_bare_declaration_node = tree_walk_bare_declaration, + .visit_function_header_node = tree_walk_function_header, + .visit_argument_group_node = tree_walk_argument_group, + .visit_pragma_node = tree_walk_pragma, +}; + +// fills in the visit table with default tree_walk functions +void +tree_visit_table_fill_defaults(struct Tree_Visit_Table* table) +{ + // not portable, nor safe, but sometimes you need to have a bit of fun! :3 + + // assumptions: + // - sizeof(struct Tree_Visit_Table) is a multiple of the size of a function pointer, + // with no padding between function pointers. + // - the size of a function pointer is the same across all platforms we care about. + // - casting struct Tree_Visit_Table to a function pointer array is undefined, but safe. + const uint function_count = sizeof(struct Tree_Visit_Table) / sizeof(void (*)()); + typedef void (*Function_Ptr)(); + + for (uint fi = 0; fi < function_count; ++fi) { + Function_Ptr* function_slot = &((Function_Ptr*)table)[fi]; + Function_Ptr* tree_walk = &((Function_Ptr*)&tree_walk_functions)[fi]; + if (!*function_slot) *function_slot = *tree_walk; + } +} + +// the most rudimentary usage of the visit system is a simple tree printer. +// prints the tree in a simple, human-readable format that resembles Lisp syntax, +// to a file or stdout (by default). +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) PRINT("\t"); +} + +void +tree_printer_visit_tree(struct Tree_Visit* visit, struct Tree* tree) +{ + TREE_PRINTER_PREAMBLE + + FOR_EACH (struct Tree_Statement*, statement, tree->top_level_statements) { + VISIT(visit_statement, statement); + PRINT("\n"); + } +} + +void +tree_printer_visit_statement(struct Tree_Visit* visit, struct Tree_Statement* statement) +{ + TREE_PRINTER_PREAMBLE + + tree_printer_indent(printer); + tree_walk_statement(visit, statement); +} + +void +tree_printer_visit_statement_declaration(struct Tree_Visit* visit, struct Tree_Statement* stmt) +{ + TREE_PRINTER_PREAMBLE + + if (stmt->value.declaration.kind == TREE_STATEMENT_DECLARATION_VARIABLE) + PRINT("(variable "); + else if (stmt->value.declaration.kind == TREE_STATEMENT_DECLARATION_CONSTANT) + PRINT("(constant "); + + VISIT(visit_bare_declaration_node, &stmt->value.declaration.inner); + PRINT(")"); +} + +void +tree_printer_visit_statement_conditional(struct Tree_Visit* visit, struct Tree_Statement* stmt) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(conditional"); + for (uint i = 0; i < stmt->value.conditional.condition_count; ++i) { + const struct Tree_Statement_Conditional_Branch* branch = &stmt->value.conditional.conditions[i]; + PRINT(" "); + if (branch->when) { + PRINT("(when "); + VISIT(visit_expression, branch->when); + PRINT(") "); + } else { + PRINT("(always) "); + } + VISIT(visit_block_node, (struct Tree_Block*)&branch->then); + } + PRINT(")"); +} + +void +tree_printer_visit_statement_loop(struct Tree_Visit* visit, struct Tree_Statement* stmt) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(loop "); + + switch (stmt->value.loop.style) { + case TREE_STATEMENT_LOOP_STYLE_C: + PRINT("c-style "); + VISIT(visit_bare_declaration_node, &stmt->value.loop.declaration); + PRINT(" (condition "); + VISIT(visit_expression, stmt->value.loop.condition); + PRINT(") (iteration "); + VISIT(visit_expression, stmt->value.loop.iteration); + PRINT(") "); + break; + case TREE_STATEMENT_LOOP_STYLE_FOR_EACH: + PRINT("for-each "); + VISIT(visit_bare_declaration_node, &stmt->value.loop.declaration); + PRINT(" "); + break; + case TREE_STATEMENT_LOOP_STYLE_WHILE: + PRINT("while (condition "); + VISIT(visit_expression, stmt->value.loop.condition); + PRINT(") "); + break; + case TREE_STATEMENT_LOOP_STYLE_ENDLESS: + PRINT("endless "); + break; + default: + fprintf(stderr, "unexpected loop style in `tree_printer_visit_statement_loop`"); + break; + } + + VISIT(visit_block_node, &stmt->value.loop.body); + PRINT(")"); +} + +void +tree_printer_visit_statement_return(struct Tree_Visit* visit, struct Tree_Statement* stmt) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(return"); + if (stmt->value.return_value.value) { + PRINT(" "); + VISIT(visit_expression, stmt->value.return_value.value); + } + PRINT(")"); +} + +void +tree_printer_visit_statement_break(struct Tree_Visit* visit, struct Tree_Statement* stmt) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(break)"); +} + +void +tree_printer_visit_statement_continue(struct Tree_Visit* visit, struct Tree_Statement* stmt) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(continue)"); +} + +void +tree_printer_visit_statement_defer(struct Tree_Visit* visit, struct Tree_Statement* stmt) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(defer "); + if (stmt->value.defer.expression) { + VISIT(visit_expression, stmt->value.defer.expression); + } else { + VISIT(visit_block_node, &stmt->value.defer.block); + } + PRINT(")"); +} + +void +tree_printer_visit_expression(struct Tree_Visit* visit, struct Tree_Expression* expression) +{ + TREE_PRINTER_PREAMBLE + PRINT("(expr "); + tree_walk_expression(visit, expression); + PRINT(")"); +} + +void +tree_printer_visit_expression_integer_literal(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("%ld", expr->value.integer_literal.value); +} + +void +tree_printer_visit_expression_float_literal(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("%lf", expr->value.float_literal.value); +} + +void +tree_printer_visit_expression_string_literal(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("\"%s\"", expr->value.string_literal.value.data); +} + +void +tree_printer_visit_expression_boolean_literal(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("%s", expr->value.bool_literal.value ? "true" : "false"); +} + +void +tree_printer_visit_expression_name(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(name %s)", expr->value.name.name.data); +} + +void +tree_printer_visit_expression_unary_operation(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(unary %s ", unary_operation_to_string(expr->value.unary_operator.operation)); + VISIT(visit_expression, expr->value.unary_operator.operand); + PRINT(")"); +} + +void +tree_printer_visit_expression_binary_operation(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(binary %s ", binary_operation_to_string(expr->value.binary_operator.operation)); + VISIT(visit_expression, expr->value.binary_operator.left_operand); + PRINT(" "); + VISIT(visit_expression, expr->value.binary_operator.right_operand); + PRINT(")"); +} + +void +tree_printer_visit_expression_group(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(group "); + VISIT(visit_expression, expr->value.group.inner_expression); + PRINT(")"); +} + +void +tree_printer_visit_expression_call(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + struct Tree_Expression_Call* call = &expr->value.call; + PRINT("(call "); + VISIT(visit_expression, call->subject); + VISIT(visit_argument_group_node, &call->argument_group); + + PRINT(")"); +} + +void +tree_printer_visit_expression_construct(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + struct Tree_Expression_Construct* construct = &expr->value.construct; + PRINT("(construct "); + VISIT(visit_expression, construct->subject); + VISIT(visit_argument_group_node, &construct->argument_group); + + PRINT(")"); +} + +void +tree_printer_visit_expression_subscript(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(subscript "); + VISIT(visit_expression, expr->value.subscript.subject); + PRINT(" "); + VISIT(visit_expression, expr->value.subscript.index); + PRINT(")"); +} + +void +tree_printer_visit_expression_member(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(member of "); + VISIT(visit_expression, expr->value.member.subject); + PRINT(" named %s)", expr->value.member.name.data); +} + +void +tree_printer_visit_expression_increment_decrement(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + const struct Tree_Expression_Increment_Decrement* inc_dec = &expr->value.increment_decrement; + const ascii* prefix_or_postfix = inc_dec->prefix ? "prefix" : "postfix"; + PRINT("(increment/decrement %s %s ", + increment_decrement_operation_to_string(inc_dec->operation), prefix_or_postfix); + VISIT(visit_expression, inc_dec->subject); + PRINT(")"); +} + +void +tree_printer_visit_expression_try(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(try "); + VISIT(visit_expression, expr->value.try.expression); + PRINT(")"); +} + +void +tree_printer_visit_expression_must(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(must "); + VISIT(visit_expression, expr->value.must.expression); + PRINT(")"); +} + +void +tree_printer_visit_expression_function(struct Tree_Visit* visit, struct Tree_Expression* expr) +{ + TREE_PRINTER_PREAMBLE + + struct Tree_Expression_Function* fun = &expr->value.function; + PRINT("(function "); + VISIT(visit_function_header_node, &fun->header); + PRINT_WHITESPACE_IF_NEEDED(" "); + VISIT(visit_block_node, (struct Tree_Block*)&fun->body); + PRINT(")"); +} + +void +tree_printer_visit_type(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + PRINT("(type "); + if (node->variadic) PRINT("variadic "); + tree_walk_type(visit, node); + PRINT(")"); +} + +void +tree_printer_visit_type_name(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("name %s", node->value.name.name.data); +} + +void +tree_printer_visit_type_array(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("array of "); + VISIT(visit_type_node, node->value.array.element_type); +} + +void +tree_printer_visit_type_reference(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("reference to "); + VISIT(visit_type_node, node->value.reference.referenced_type); +} + +void +tree_printer_visit_type_maybe(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("maybe "); + VISIT(visit_type_node, node->value.maybe.inner_type); +} + +void +tree_printer_visit_type_tuple(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("tuple"); + FOR_EACH (struct Tree_Type*, current, node->value.tuple.head) { + PRINT(" "); + VISIT(visit_type_node, current); + } +} + +void +tree_printer_visit_type_map(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("map "); + VISIT(visit_type_node, node->value.map.key_type); + PRINT(" = "); + VISIT(visit_type_node, node->value.map.value_type); +} + +void +tree_printer_visit_type_function(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("function "); + VISIT(visit_function_header_node, &node->value.function.header); +} + +void +tree_printer_visit_type_structure(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("structure"); + FOR_EACH (struct Tree_Type*, current, node->value.structure.fields) { + PRINT(" (field %s) ", current->value_name.data); + VISIT(visit_type_node, current); + } +} + +void +tree_printer_visit_type_variant(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("variant"); + FOR_EACH (struct Tree_Type*, current, node->value.variant.variants) { + if (current->type == TREE_TYPE_NONE) { + PRINT(" (variant %s)", current->value_name.data); + } else { + PRINT(" (variant %s of ", current->value_name.data); + VISIT(visit_type_node, current); + PRINT(")"); + } + } +} + +void +tree_printer_visit_type_class(struct Tree_Visit* visit, struct Tree_Type* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("class"); + FOR_EACH (struct Tree_Type*, current, node->value.class.methods) { + PRINT(" (method %s ", current->value_name.data); + VISIT(visit_function_header_node, ¤t->value.function.header); + PRINT(")"); + } +} + +void +tree_printer_visit_block(struct Tree_Visit* visit, struct Tree_Block* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(block"); + if (node->statements) { + PRINT("\n"); + printer->indentation_level++; + FOR_EACH (struct Tree_Statement*, statement, node->statements) { + VISIT(visit_statement, statement); + PRINT("\n"); + } + printer->indentation_level--; + tree_printer_indent(printer); + } + PRINT(")"); +} + +void +tree_printer_visit_bare_declaration(struct Tree_Visit* visit, struct Tree_Bare_Declaration* node) +{ + TREE_PRINTER_PREAMBLE + + PRINT("(declaration "); + FOR_EACH_ARRAY(struct String, name, &node->names, { + PRINT("%s ", name.data); + }) + + if (node->type && node->type->type != TREE_TYPE_NONE) { + VISIT(visit_type_node, node->type); + PRINT(" "); + } + + if (node->initializer) { + PRINT("(initializer "); + VISIT(visit_expression, node->initializer); + PRINT(")"); + } + PRINT(")"); +} + +void +printer_visit_function_header(struct Tree_Visit* visit, struct Tree_Function_Header* header) +{ + TREE_PRINTER_PREAMBLE + + FOR_EACH (struct Tree_Type*, current, header->parameters_type_and_name) { + // if (current != header->parameters_type_and_name) PRINT(" "); + PRINT_WHITESPACE_IF_NEEDED(" "); + + if (current->value_name.data && current->value_name.data[0] != '\0') + PRINT("(param %s) ", current->value_name.data); + else + PRINT("(param) "); + + VISIT(visit_type_node, current); + } + + PRINT_WHITESPACE_IF_NEEDED(" "); + + if (header->return_type) { + PRINT("(returns "); + VISIT(visit_type_node, header->return_type); + PRINT(")"); + } +} + +void +tree_printer_visit_pragma(struct Tree_Visit* visit, struct Tree_Pragma* node) +{ + TREE_PRINTER_PREAMBLE + + const ascii* pragma_name = tree_pragma_type_to_string(node->type); + + PRINT("(pragma %s", pragma_name); + for (uint ai = 0; ai < node->argument_count; ++ai) { + struct Tree_Pragma_Argument* arg = &node->arguments[ai]; + switch (arg->type) { + case TREE_PRAGMA_ARGUMENT_NUMBER: + PRINT(" (number %ld)", arg->value.number); + break; + case TREE_PRAGMA_ARGUMENT_DECIMAL: + PRINT(" (decimal %lf)", arg->value.decimal); + break; + case TREE_PRAGMA_ARGUMENT_NAME_OR_STRING: + PRINT(" (name/string '%s')", arg->value.name_or_string.data); + break; + default: + failure("unexpected pragma argument type in `tree_printer_visit_pragma`"); + } + } + PRINT(")"); + + if (node->next) { + PRINT(" "); + VISIT(visit_pragma_node, node->next); + } +} + +void +tree_printer_visit_argument_group(struct Tree_Visit* visit, struct Tree_Argument_Group* node) +{ + TREE_PRINTER_PREAMBLE + + uint i = 0; + FOR_EACH (struct Tree_Expression*, argument, node->arguments) { + struct String name = *array_at(struct String, &node->argument_names, i++); + if (name.data && name.data[0] != '\0') { + PRINT(" (named arg '%s' ", name.data); + } else { + PRINT(" (arg "); + } + VISIT(visit_expression, argument); + PRINT(")"); + } +} + +struct Tree_Visit_Table tree_printer_visit_functions = { + .visit_tree = tree_printer_visit_tree, + + .visit_statement = tree_printer_visit_statement, + .visit_statement_declaration = tree_printer_visit_statement_declaration, + .visit_statement_conditional = tree_printer_visit_statement_conditional, + .visit_statement_loop = tree_printer_visit_statement_loop, + .visit_statement_return = tree_printer_visit_statement_return, + .visit_statement_break = tree_printer_visit_statement_break, + .visit_statement_continue = tree_printer_visit_statement_continue, + .visit_statement_defer = tree_printer_visit_statement_defer, + + .visit_expression = tree_printer_visit_expression, + .visit_expression_integer_literal = tree_printer_visit_expression_integer_literal, + .visit_expression_float_literal = tree_printer_visit_expression_float_literal, + .visit_expression_string_literal = tree_printer_visit_expression_string_literal, + .visit_expression_boolean_literal = tree_printer_visit_expression_boolean_literal, + .visit_expression_name = tree_printer_visit_expression_name, + .visit_expression_unary_operation = tree_printer_visit_expression_unary_operation, + .visit_expression_binary_operation = tree_printer_visit_expression_binary_operation, + .visit_expression_group = tree_printer_visit_expression_group, + .visit_expression_call = tree_printer_visit_expression_call, + .visit_expression_construct = tree_printer_visit_expression_construct, + .visit_expression_subscript = tree_printer_visit_expression_subscript, + .visit_expression_member = tree_printer_visit_expression_member, + .visit_expression_increment_decrement = tree_printer_visit_expression_increment_decrement, + .visit_expression_try = tree_printer_visit_expression_try, + .visit_expression_must = tree_printer_visit_expression_must, + .visit_expression_function = tree_printer_visit_expression_function, + + .visit_type_node = tree_printer_visit_type, + .visit_type_node_name = tree_printer_visit_type_name, + .visit_type_node_array = tree_printer_visit_type_array, + .visit_type_node_reference = tree_printer_visit_type_reference, + .visit_type_node_maybe = tree_printer_visit_type_maybe, + .visit_type_node_tuple = tree_printer_visit_type_tuple, + .visit_type_node_map = tree_printer_visit_type_map, + .visit_type_node_function = tree_printer_visit_type_function, + .visit_type_node_structure = tree_printer_visit_type_structure, + .visit_type_node_variant = tree_printer_visit_type_variant, + .visit_type_node_class = tree_printer_visit_type_class, + + .visit_block_node = tree_printer_visit_block, + .visit_bare_declaration_node = tree_printer_visit_bare_declaration, + .visit_function_header_node = printer_visit_function_header, + .visit_argument_group_node = tree_printer_visit_argument_group, + .visit_pragma_node = tree_printer_visit_pragma, +}; + +void +tree_printer(struct Tree* tree) +{ + struct Tree_Printer printer = { + .indentation_level = 0, .output = stdout, .did_print_last_visit = false + }; + struct Tree_Visit visit = { .table = &tree_printer_visit_functions, .user_data = &printer }; + + tree_walk(&visit, tree); +} + +#undef PRINT +#undef PRINT_WHITESPACE_IF_NEEDED +#undef TREE_PRINTER_PREAMBLE -- cgit 1.4.1