diff options
| author | Mel <mel@rnrd.eu> | 2025-06-30 02:49:42 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2025-06-30 02:49:42 +0200 |
| commit | b16cf0fc98940554ef0febfe443ef690618d5083 (patch) | |
| tree | 15cd49710d66988bf0acbb1ce92f64e3ea01d473 /boot/visit.c | |
| parent | 3d983097329607cc89b63425e97527c5ec0390c8 (diff) | |
| download | catskill-b16cf0fc98940554ef0febfe443ef690618d5083.tar.zst catskill-b16cf0fc98940554ef0febfe443ef690618d5083.zip | |
Implement Visitor system for syntax tree, with re-written tree printer as first usage
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/visit.c')
| -rw-r--r-- | boot/visit.c | 1033 |
1 files changed, 1033 insertions, 0 deletions
diff --git a/boot/visit.c b/boot/visit.c new file mode 100644 index 0000000..396f8b8 --- /dev/null +++ b/boot/visit.c @@ -0,0 +1,1033 @@ +/* + * 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. + */ + +struct Visit +{ + struct Visit_Table* table; + void* user_data; +}; + +struct Visit_Table +{ + void (*visit_tree)(struct Visit* visitor, struct Tree* tree); + + void (*visit_statement)(struct Visit* visitor, struct Statement* stmt); + void (*visit_statement_declaration)(struct Visit* visitor, struct Statement* stmt); + void (*visit_statement_conditional)(struct Visit* visitor, struct Statement* stmt); + void (*visit_statement_loop)(struct Visit* visitor, struct Statement* stmt); + void (*visit_statement_return)(struct Visit* visitor, struct Statement* stmt); + void (*visit_statement_break)(struct Visit* visitor, struct Statement* stmt); + void (*visit_statement_continue)(struct Visit* visitor, struct Statement* stmt); + void (*visit_statement_defer)(struct Visit* visitor, struct Statement* stmt); + + void (*visit_expression)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_integer_literal)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_float_literal)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_string_literal)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_boolean_literal)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_name)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_unary_operation)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_binary_operation)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_group)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_call_or_construct)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_subscript)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_member)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_increment_decrement)(struct Visit* visitor, struct Expression* expr); + void (*visit_expression_function)(struct Visit* visitor, struct Expression* expr); + + void (*visit_type_node)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_name)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_array)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_reference)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_maybe)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_tuple)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_map)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_function)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_structure)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_variant)(struct Visit* visitor, struct Type_Node* node); + void (*visit_type_node_class)(struct Visit* visitor, struct Type_Node* node); + + void (*visit_block_node)(struct Visit* visitor, struct Block_Node* node); + void (*visit_bare_declaration_node)(struct Visit* visitor, struct Bare_Declaration_Node* node); + void (*visit_function_header_node)(struct Visit* visitor, struct Function_Header_Node* header); +}; + +#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); } + +// walk functions are the default traversal mechanism + +// define a walk function which goes nowhere. +#define WALK_LEAF_FUNCTION(name, type) \ + void name(struct Visit* visit, type node) {} + +// top-level walk function for beginning the visit flow. +void +walk(struct Visit* visit, struct Tree* tree) +{ + VISIT(visit_tree, tree); +} + +void +walk_tree(struct Visit* visit, struct Tree* tree) +{ + FOR_EACH(struct Statement*, statement, tree->top_level_statements) + { + VISIT(visit_statement, statement); + } +} + +void +walk_statement(struct Visit* visit, struct Statement* statement) +{ + switch (statement->kind) { + case STATEMENT_EXPRESSION: + VISIT(visit_expression, statement->value.expression.inner); + break; + case STATEMENT_DECLARATION: + VISIT(visit_statement_declaration, statement); + break; + case STATEMENT_BLOCK: + VISIT(visit_block_node, &statement->value.block.inner); + break; + case STATEMENT_CONDITIONAL: + VISIT(visit_statement_conditional, statement); + break; + case STATEMENT_LOOP: + VISIT(visit_statement_loop, statement); + break; + case STATEMENT_RETURN: + VISIT(visit_statement_return, statement); + break; + case STATEMENT_BREAK: + VISIT(visit_statement_break, statement); + break; + case STATEMENT_CONTINUE: + VISIT(visit_statement_continue, statement); + break; + case STATEMENT_DEFER: + VISIT(visit_statement_defer, statement); + break; + default: + failure("unexpected statement kind in `walk_statement`"); + } +} + +void +walk_statement_declaration(struct Visit* visit, struct Statement* statement) +{ + VISIT(visit_bare_declaration_node, &statement->value.declaration.inner); +} + +void +walk_statement_conditional(struct Visit* visit, struct Statement* statement) +{ + struct 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 +walk_statement_loop(struct Visit* visit, struct Statement* statement) +{ + struct 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 +walk_statement_return(struct Visit* visit, struct 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. +WALK_LEAF_FUNCTION(walk_statement_break, struct Statement*); + +WALK_LEAF_FUNCTION(walk_statement_continue, struct Statement*); + +void +walk_statement_defer(struct Visit* visit, struct Statement* statement) +{ + VISIT_MAYBE(visit_expression, statement->value.defer.expression); + VISIT(visit_block_node, &statement->value.defer.block); +} + +void +walk_expression(struct Visit* visit, struct Expression* expression) +{ + switch (expression->kind) { + case EXPRESSION_INTEGER_LITERAL: + VISIT(visit_expression_integer_literal, expression); + break; + case EXPRESSION_FLOAT_LITERAL: + VISIT(visit_expression_float_literal, expression); + break; + case EXPRESSION_STRING_LITERAL: + VISIT(visit_expression_string_literal, expression); + break; + case EXPRESSION_BOOLEAN_LITERAL: + VISIT(visit_expression_boolean_literal, expression); + break; + case EXPRESSION_NAME: + VISIT(visit_expression_name, expression); + break; + case EXPRESSION_UNARY_OPERATION: + VISIT(visit_expression_unary_operation, expression); + break; + case EXPRESSION_BINARY_OPERATION: + VISIT(visit_expression_binary_operation, expression); + break; + case EXPRESSION_GROUP: + VISIT(visit_expression_group, expression); + break; + case EXPRESSION_CALL_OR_CONSTRUCT: + VISIT(visit_expression_call_or_construct, expression); + break; + case EXPRESSION_SUBSCRIPT: + VISIT(visit_expression_subscript, expression); + break; + case EXPRESSION_MEMBER: + VISIT(visit_expression_member, expression); + break; + case EXPRESSION_INCREMENT_DECREMENT: + VISIT(visit_expression_increment_decrement, expression); + break; + case EXPRESSION_FUNCTION: + VISIT(visit_expression_function, expression); + break; + case EXPRESSION_TYPE: + VISIT(visit_type_node, expression->value.type.type); + break; + default: + failure("unexpected expression kind in `walk_expression`"); + } +} + +WALK_LEAF_FUNCTION(walk_expression_integer_literal, struct Expression*); + +WALK_LEAF_FUNCTION(walk_expression_float_literal, struct Expression*); + +WALK_LEAF_FUNCTION(walk_expression_string_literal, struct Expression*); + +WALK_LEAF_FUNCTION(walk_expression_boolean_literal, struct Expression*); + +WALK_LEAF_FUNCTION(walk_expression_name, struct Expression*); + +void +walk_expression_unary_operation(struct Visit* visit, struct Expression* expression) +{ + VISIT(visit_expression, expression->value.unary_operator.operand); +} + +void +walk_expression_binary_operation(struct Visit* visit, struct Expression* expression) +{ + VISIT(visit_expression, expression->value.binary_operator.left_operand); + VISIT(visit_expression, expression->value.binary_operator.right_operand); +} + +void +walk_expression_group(struct Visit* visit, struct Expression* expression) +{ + VISIT(visit_expression, expression->value.group.inner_expression); +} + +void +walk_expression_call_or_construct(struct Visit* visit, struct Expression* expression) +{ + struct Expression_Call_Or_Construct* coc = &expression->value.call_or_construct; + VISIT(visit_expression, coc->subject); + FOR_EACH(struct Expression*, argument, coc->arguments) + { + VISIT(visit_expression, argument); + } +} + +void +walk_expression_subscript(struct Visit* visit, struct Expression* expression) +{ + VISIT(visit_expression, expression->value.subscript.subject); + VISIT(visit_expression, expression->value.subscript.index); +} + +void +walk_expression_member(struct Visit* visit, struct Expression* expression) +{ + VISIT(visit_expression, expression->value.member.subject); +} + +void +walk_expression_increment_decrement(struct Visit* visit, struct Expression* expression) +{ + VISIT(visit_expression, expression->value.increment_decrement.subject); +} + +void +walk_expression_function(struct Visit* visit, struct Expression* expression) +{ + VISIT(visit_function_header_node, &expression->value.function.header); + VISIT(visit_block_node, &expression->value.function.body); +} + +void +walk_type_node(struct Visit* visit, struct Type_Node* node) +{ + switch (node->type) { + case TYPE_NODE_NONE: + break; + case TYPE_NODE_NAME: + VISIT(visit_type_node_name, node); + break; + case TYPE_NODE_ARRAY: + VISIT(visit_type_node_array, node); + break; + case TYPE_NODE_REFERENCE: + VISIT(visit_type_node_reference, node); + break; + case TYPE_NODE_MAYBE: + VISIT(visit_type_node_maybe, node); + break; + case TYPE_NODE_TUPLE: + VISIT(visit_type_node_tuple, node); + break; + case TYPE_NODE_MAP: + VISIT(visit_type_node_map, node); + break; + case TYPE_NODE_FUNCTION: + VISIT(visit_type_node_function, node); + break; + case TYPE_NODE_STRUCTURE: + VISIT(visit_type_node_structure, node); + break; + case TYPE_NODE_VARIANT: + VISIT(visit_type_node_variant, node); + break; + case TYPE_NODE_CLASS: + VISIT(visit_type_node_class, node); + break; + default: + failure("unexpected type node kind in `walk_type_node`"); + } +} + +WALK_LEAF_FUNCTION(walk_type_node_name, struct Type_Node*); + +void +walk_type_node_array(struct Visit* visit, struct Type_Node* node) +{ + VISIT(visit_type_node, node->value.array.element_type); +} + +void +walk_type_node_reference(struct Visit* visit, struct Type_Node* node) +{ + VISIT(visit_type_node, node->value.reference.referenced_type); +} + +void +walk_type_node_maybe(struct Visit* visit, struct Type_Node* node) +{ + VISIT(visit_type_node, node->value.maybe.inner_type); +} + +void +walk_type_node_tuple(struct Visit* visit, struct Type_Node* node) +{ + FOR_EACH(struct Type_Node*, current, node->value.tuple.head) + { + VISIT(visit_type_node, current); + } +} + +void +walk_type_node_map(struct Visit* visit, struct Type_Node* node) +{ + VISIT(visit_type_node, node->value.map.key_type); + VISIT(visit_type_node, node->value.map.value_type); +} + +void +walk_type_node_function(struct Visit* visit, struct Type_Node* node) +{ + VISIT(visit_function_header_node, &node->value.function.header); +} + +void +walk_type_node_structure(struct Visit* visit, struct Type_Node* node) +{ + FOR_EACH(struct Type_Node*, field, node->value.structure.fields) + { + VISIT(visit_type_node, field); + } +} + +void +walk_type_node_variant(struct Visit* visit, struct Type_Node* node) +{ + FOR_EACH(struct Type_Node*, method, node->value.variant.variants) + { + VISIT(visit_type_node, method); + } +} + +void +walk_type_node_class(struct Visit* visit, struct Type_Node* node) +{ + FOR_EACH(struct Type_Node*, method, node->value.class.methods) + { + VISIT(visit_type_node, method); + } +} + +void +walk_block_node(struct Visit* visit, struct Block_Node* node) +{ + FOR_EACH(struct Statement*, statement, node->statements) + { + VISIT(visit_statement, statement); + } +} + +void +walk_bare_declaration_node(struct Visit* visit, struct Bare_Declaration_Node* node) +{ + VISIT_MAYBE(visit_type_node, node->type); + VISIT(visit_expression, node->initializer); +} + +void +walk_function_header_node(struct Visit* visit, struct Function_Header_Node* header) +{ + FOR_EACH(struct Type_Node*, param_type, header->parameters_type_and_name) + { + VISIT(visit_type_node, param_type); + } + VISIT_MAYBE(visit_type_node, header->return_type); +} + +struct Visit_Table walk_functions = { + .visit_tree = walk_tree, + + .visit_statement = walk_statement, + .visit_statement_declaration = walk_statement_declaration, + .visit_statement_conditional = walk_statement_conditional, + .visit_statement_loop = walk_statement_loop, + .visit_statement_return = walk_statement_return, + .visit_statement_break = walk_statement_break, + .visit_statement_continue = walk_statement_continue, + .visit_statement_defer = walk_statement_defer, + + .visit_expression = walk_expression, + .visit_expression_integer_literal = walk_expression_integer_literal, + .visit_expression_float_literal = walk_expression_float_literal, + .visit_expression_string_literal = walk_expression_string_literal, + .visit_expression_boolean_literal = walk_expression_boolean_literal, + .visit_expression_name = walk_expression_name, + .visit_expression_unary_operation = walk_expression_unary_operation, + .visit_expression_binary_operation = walk_expression_binary_operation, + .visit_expression_group = walk_expression_group, + .visit_expression_call_or_construct = walk_expression_call_or_construct, + .visit_expression_subscript = walk_expression_subscript, + .visit_expression_member = walk_expression_member, + .visit_expression_increment_decrement = walk_expression_increment_decrement, + .visit_expression_function = walk_expression_function, + + .visit_type_node = walk_type_node, + .visit_type_node_name = walk_type_node_name, + .visit_type_node_array = walk_type_node_array, + .visit_type_node_reference = walk_type_node_reference, + .visit_type_node_maybe = walk_type_node_maybe, + .visit_type_node_tuple = walk_type_node_tuple, + .visit_type_node_map = walk_type_node_map, + .visit_type_node_function = walk_type_node_function, + .visit_type_node_structure = walk_type_node_structure, + .visit_type_node_variant = walk_type_node_variant, + .visit_type_node_class = walk_type_node_class, + + .visit_block_node = walk_block_node, + .visit_bare_declaration_node = walk_bare_declaration_node, + .visit_function_header_node = walk_function_header_node, +}; + +// fills in the visit table with default walk functions +void +visit_table_fill_defaults(struct Visit_Table* table) +{ + // not portable, nor safe, but sometimes you need to have a bit of fun! :3 + + // assumptions: + // - sizeof(struct 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 Visit_Table to a function pointer array is undefined, but safe. + const uint function_count = sizeof(struct 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* walk = &((Function_Ptr*)&walk_functions)[fi]; + if (!*function_slot) *function_slot = *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; +}; + +void +tree_printer_indent(struct Tree_Printer* printer) +{ + for (uint i = 0; i < printer->indentation_level; ++i) fprintf(printer->output, "\t"); +} + +void +printer_visit_tree(struct Visit* visit, struct Tree* tree) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + FOR_EACH(struct Statement*, statement, tree->top_level_statements) + { + VISIT(visit_statement, statement); + fprintf(printer->output, "\n"); + } +} + +void +printer_visit_statement(struct Visit* visit, struct Statement* statement) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + tree_printer_indent(printer); + walk_statement(visit, statement); +} + +void +printer_visit_statement_declaration(struct Visit* visit, struct Statement* stmt) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + if (stmt->value.declaration.kind == STATEMENT_DECLARATION_VARIABLE) + fprintf(printer->output, "(variable "); + else if (stmt->value.declaration.kind == STATEMENT_DECLARATION_CONSTANT) + fprintf(printer->output, "(constant "); + + VISIT(visit_bare_declaration_node, &stmt->value.declaration.inner); + fprintf(printer->output, ")"); +} + +void +printer_visit_statement_conditional(struct Visit* visit, struct Statement* stmt) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(conditional"); + for (uint i = 0; i < stmt->value.conditional.condition_count; ++i) { + const struct Statement_Conditional_Branch* branch = &stmt->value.conditional.conditions[i]; + fprintf(printer->output, " "); + if (branch->when) { + fprintf(printer->output, "(when "); + VISIT(visit_expression, branch->when); + fprintf(printer->output, ") "); + } else { + fprintf(printer->output, "(always) "); + } + VISIT(visit_block_node, (struct Block_Node*)&branch->then); + } + fprintf(printer->output, ")"); +} + +void +printer_visit_statement_loop(struct Visit* visit, struct Statement* stmt) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(loop "); + + switch (stmt->value.loop.style) { + case STATEMENT_LOOP_STYLE_C: + fprintf(printer->output, "c-style "); + VISIT(visit_bare_declaration_node, &stmt->value.loop.declaration); + fprintf(printer->output, " (condition "); + VISIT(visit_expression, stmt->value.loop.condition); + fprintf(printer->output, ") (iteration "); + VISIT(visit_expression, stmt->value.loop.iteration); + fprintf(printer->output, ") "); + break; + case STATEMENT_LOOP_STYLE_FOR_EACH: + fprintf(printer->output, "for-each "); + VISIT(visit_bare_declaration_node, &stmt->value.loop.declaration); + fprintf(printer->output, " "); + break; + case STATEMENT_LOOP_STYLE_WHILE: + fprintf(printer->output, "while (condition "); + VISIT(visit_expression, stmt->value.loop.condition); + fprintf(printer->output, ") "); + break; + case STATEMENT_LOOP_STYLE_ENDLESS: + fprintf(printer->output, "endless "); + break; + default: + fprintf(stderr, "unexpected loop style in `printer_visit_statement_loop`"); + break; + } + + VISIT(visit_block_node, &stmt->value.loop.body); + fprintf(printer->output, ")"); +} + +void +printer_visit_statement_return(struct Visit* visit, struct Statement* stmt) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(return"); + if (stmt->value.return_value.value) { + fprintf(printer->output, " "); + VISIT(visit_expression, stmt->value.return_value.value); + } + fprintf(printer->output, ")"); +} + +void +printer_visit_statement_break(struct Visit* visit, struct Statement* stmt) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(break)"); +} + +void +printer_visit_statement_continue(struct Visit* visit, struct Statement* stmt) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(continue)"); +} + +void +printer_visit_statement_defer(struct Visit* visit, struct Statement* stmt) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(defer "); + if (stmt->value.defer.expression) { + VISIT(visit_expression, stmt->value.defer.expression); + } else { + VISIT(visit_block_node, &stmt->value.defer.block); + } + fprintf(printer->output, ")"); +} + +void +printer_visit_expression(struct Visit* visit, struct Expression* expression) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + fprintf(printer->output, "(expr "); + walk_expression(visit, expression); + fprintf(printer->output, ")"); +} + +void +printer_visit_expression_integer_literal(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "%ld", expr->value.integer_literal.value); +} + +void +printer_visit_expression_float_literal(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "%lf", expr->value.float_literal.value); +} + +void +printer_visit_expression_string_literal(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "\"%s\"", expr->value.string_literal.value.data); +} + +void +printer_visit_expression_boolean_literal(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "%s", expr->value.bool_literal.value ? "true" : "false"); +} + +void +printer_visit_expression_name(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(name %s)", expr->value.name.name.data); +} + +void +printer_visit_expression_unary_operation(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(unary %s ", + unary_operation_to_string(expr->value.unary_operator.operation)); + VISIT(visit_expression, expr->value.unary_operator.operand); + fprintf(printer->output, ")"); +} + +void +printer_visit_expression_binary_operation(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(binary %s ", + binary_operation_to_string(expr->value.binary_operator.operation)); + VISIT(visit_expression, expr->value.binary_operator.left_operand); + fprintf(printer->output, " "); + VISIT(visit_expression, expr->value.binary_operator.right_operand); + fprintf(printer->output, ")"); +} + +void +printer_visit_expression_group(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(group "); + VISIT(visit_expression, expr->value.group.inner_expression); + fprintf(printer->output, ")"); +} + +void +printer_visit_expression_call_or_construct(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + struct Expression_Call_Or_Construct* coc = &expr->value.call_or_construct; + fprintf(printer->output, "(call/construct "); + VISIT(visit_expression, coc->subject); + + uint i = 0; + FOR_EACH(struct Expression*, argument, coc->arguments) + { + struct String name = string_array_at(&coc->argument_names, i++); + if (name.data && name.data[0] != '\0') { + fprintf(printer->output, " (named arg '%s' ", name.data); + } else { + fprintf(printer->output, " (arg "); + } + VISIT(visit_expression, argument); + fprintf(printer->output, ")"); + } + fprintf(printer->output, ")"); +} + +void +printer_visit_expression_subscript(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(subscript "); + VISIT(visit_expression, expr->value.subscript.subject); + fprintf(printer->output, " "); + VISIT(visit_expression, expr->value.subscript.index); + fprintf(printer->output, ")"); +} + +void +printer_visit_expression_member(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(member of "); + VISIT(visit_expression, expr->value.member.subject); + fprintf(printer->output, " named %s)", expr->value.member.name.data); +} + +void +printer_visit_expression_increment_decrement(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + const struct Expression_Increment_Decrement* inc_dec = &expr->value.increment_decrement; + const ascii* prefix_or_postfix = inc_dec->prefix ? "prefix" : "postfix"; + fprintf(printer->output, "(increment/decrement %s %s ", + increment_decrement_operation_to_string(inc_dec->operation), prefix_or_postfix); + VISIT(visit_expression, inc_dec->subject); + fprintf(printer->output, ")"); +} + +void +printer_visit_expression_function(struct Visit* visit, struct Expression* expr) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + struct Expression_Function* fun = &expr->value.function; + fprintf(printer->output, "(function "); + VISIT(visit_function_header_node, &fun->header); + fprintf(printer->output, " "); + VISIT(visit_block_node, (struct Block_Node*)&fun->body); + fprintf(printer->output, ")"); +} + +void +printer_visit_type_node(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + fprintf(printer->output, "(type "); + walk_type_node(visit, node); + fprintf(printer->output, ")"); +} + +void +printer_visit_type_node_name(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "name %s", node->value.name.name.data); +} + +void +printer_visit_type_node_array(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "array of "); + VISIT(visit_type_node, node->value.array.element_type); +} + +void +printer_visit_type_node_reference(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "reference to "); + VISIT(visit_type_node, node->value.reference.referenced_type); +} + +void +printer_visit_type_node_maybe(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "maybe "); + VISIT(visit_type_node, node->value.maybe.inner_type); +} + +void +printer_visit_type_node_tuple(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "tuple"); + FOR_EACH(struct Type_Node*, current, node->value.tuple.head) + { + fprintf(printer->output, " "); + VISIT(visit_type_node, current); + } +} + +void +printer_visit_type_node_map(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "map "); + VISIT(visit_type_node, node->value.map.key_type); + fprintf(printer->output, " = "); + VISIT(visit_type_node, node->value.map.value_type); +} + +void +printer_visit_type_node_function(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "function "); + VISIT(visit_function_header_node, &node->value.function.header); +} + +void +printer_visit_type_node_structure(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "structure"); + FOR_EACH(struct Type_Node*, current, node->value.structure.fields) + { + fprintf(printer->output, " (field %s) ", current->value_name.data); + VISIT(visit_type_node, current); + } +} + +void +printer_visit_type_node_variant(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "variant"); + FOR_EACH(struct Type_Node*, current, node->value.variant.variants) + { + if (current->type == TYPE_NODE_NONE) { + fprintf(printer->output, " (variant %s)", current->value_name.data); + } else { + fprintf(printer->output, " (variant %s of ", current->value_name.data); + VISIT(visit_type_node, current); + fprintf(printer->output, ")"); + } + } +} + +void +printer_visit_type_node_class(struct Visit* visit, struct Type_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "class"); + FOR_EACH(struct Type_Node*, current, node->value.class.methods) + { + fprintf(printer->output, " (method %s ", current->value_name.data); + VISIT(visit_function_header_node, ¤t->value.function.header); + fprintf(printer->output, ")"); + } +} + +void +printer_visit_block_node(struct Visit* visit, struct Block_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(block \n"); + printer->indentation_level++; + FOR_EACH(struct Statement*, statement, node->statements) + { + VISIT(visit_statement, statement); + fprintf(printer->output, "\n"); + } + printer->indentation_level--; + tree_printer_indent(printer); + fprintf(printer->output, ")"); +} + +void +printer_visit_bare_declaration_node(struct Visit* visit, struct Bare_Declaration_Node* node) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + fprintf(printer->output, "(declaration "); + STRING_ARRAY_FOR_EACH(i, name, node->names) + { + fprintf(printer->output, "%s ", name.data); + } + + if (node->type && node->type->type != TYPE_NODE_NONE) { + VISIT(visit_type_node, node->type); + fprintf(printer->output, " "); + } + + if (node->initializer) { + fprintf(printer->output, "(initializer "); + VISIT(visit_expression, node->initializer); + fprintf(printer->output, ")"); + } + fprintf(printer->output, ")"); +} + +void +printer_visit_function_header(struct Visit* visit, struct Function_Header_Node* header) +{ + DATA_FOR_VISIT(struct Tree_Printer, printer); + + FOR_EACH(struct Type_Node*, current, header->parameters_type_and_name) + { + if (current != header->parameters_type_and_name) fprintf(printer->output, " "); + + if (current->value_name.data && current->value_name.data[0] != '\0') + fprintf(printer->output, "(param %s) ", current->value_name.data); + else + fprintf(printer->output, "(param) "); + + VISIT(visit_type_node, current); + } + + if (header->return_type) { + fprintf(printer->output, " (returns "); + VISIT(visit_type_node, header->return_type); + fprintf(printer->output, ")"); + } +} + +struct Visit_Table printer_visit_functions = { + .visit_tree = printer_visit_tree, + + .visit_statement = printer_visit_statement, + .visit_statement_declaration = printer_visit_statement_declaration, + .visit_statement_conditional = printer_visit_statement_conditional, + .visit_statement_loop = printer_visit_statement_loop, + .visit_statement_return = printer_visit_statement_return, + .visit_statement_break = printer_visit_statement_break, + .visit_statement_continue = printer_visit_statement_continue, + .visit_statement_defer = printer_visit_statement_defer, + + .visit_expression = printer_visit_expression, + .visit_expression_integer_literal = printer_visit_expression_integer_literal, + .visit_expression_float_literal = printer_visit_expression_float_literal, + .visit_expression_string_literal = printer_visit_expression_string_literal, + .visit_expression_boolean_literal = printer_visit_expression_boolean_literal, + .visit_expression_name = printer_visit_expression_name, + .visit_expression_unary_operation = printer_visit_expression_unary_operation, + .visit_expression_binary_operation = printer_visit_expression_binary_operation, + .visit_expression_group = printer_visit_expression_group, + .visit_expression_call_or_construct = printer_visit_expression_call_or_construct, + .visit_expression_subscript = printer_visit_expression_subscript, + .visit_expression_member = printer_visit_expression_member, + .visit_expression_increment_decrement = printer_visit_expression_increment_decrement, + .visit_expression_function = printer_visit_expression_function, + + .visit_type_node = printer_visit_type_node, + .visit_type_node_name = printer_visit_type_node_name, + .visit_type_node_array = printer_visit_type_node_array, + .visit_type_node_reference = printer_visit_type_node_reference, + .visit_type_node_maybe = printer_visit_type_node_maybe, + .visit_type_node_tuple = printer_visit_type_node_tuple, + .visit_type_node_map = printer_visit_type_node_map, + .visit_type_node_function = printer_visit_type_node_function, + .visit_type_node_structure = printer_visit_type_node_structure, + .visit_type_node_variant = printer_visit_type_node_variant, + .visit_type_node_class = printer_visit_type_node_class, + + .visit_block_node = printer_visit_block_node, + .visit_bare_declaration_node = printer_visit_bare_declaration_node, + .visit_function_header_node = printer_visit_function_header, +}; + +void +tree_printer(struct Tree* tree) +{ + struct Tree_Printer printer = { .indentation_level = 0, .output = stdout }; + struct Visit visit = { .table = &printer_visit_functions, .user_data = &printer }; + + walk(&visit, tree); +} |
