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 --- Makefile | 2 +- boot/catboot.h | 2 +- boot/visit.c | 1185 ----------------------------------------------------- boot/visit/tree.c | 1185 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1187 insertions(+), 1187 deletions(-) delete mode 100644 boot/visit.c create mode 100644 boot/visit/tree.c diff --git a/Makefile b/Makefile index 046c3c1..b8948ac 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ LDFLAGS ?= -ltcc .DEFAULT_GOAL := all -BOOTSTRAP_SOURCES = boot/catboot.c boot/catboot.h boot/common.c boot/lex.c boot/tree.c boot/visit.c boot/parse.c boot/transpile.c boot/build.c +BOOTSTRAP_SOURCES = boot/catboot.c boot/catboot.h boot/common.c boot/lex.c boot/tree.c boot/visit/tree.c boot/parse.c boot/transpile.c boot/build.c BOOTSTRAP_TEST_SOURCES = boot/tests/test.c SOURCES = src/catskill.csk diff --git a/boot/catboot.h b/boot/catboot.h index f7d3e2d..00764f0 100644 --- a/boot/catboot.h +++ b/boot/catboot.h @@ -17,6 +17,6 @@ #include "lex.c" #include "tree.c" #include "parse.c" -#include "visit.c" +#include "visit/tree.c" #include "transpile.c" #include "build.c" diff --git a/boot/visit.c b/boot/visit.c deleted file mode 100644 index 83de09a..0000000 --- a/boot/visit.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * 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 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