#include #include #include #include #include #include #include #include namespace pslang::ast { namespace { print_options as_child(print_options options) { options.indent_level += 1; return options; } void put_indent(std::ostream & out, print_options const & options) { for (std::size_t i = 0; i < options.indent_level; ++i) out << options.indent_string; } struct raw_type_print_visitor : types::const_visitor { std::ostream & out; using const_visitor::apply; void apply(types::unit_type const & type) { out << "unit"; } void apply(types::bool_type const &) { out << "bool"; } void apply(types::i8_type const &) { out << "i8"; } void apply(types::u8_type const &) { out << "u8"; } void apply(types::i16_type const &) { out << "i16"; } void apply(types::u16_type const &) { out << "u16"; } void apply(types::i32_type const &) { out << "i32"; } void apply(types::u32_type const &) { out << "u32"; } void apply(types::i64_type const &) { out << "i64"; } void apply(types::u64_type const &) { out << "u64"; } void apply(types::f16_type const &) { out << "f16"; } void apply(types::f32_type const &) { out << "f32"; } void apply(types::f64_type const &) { out << "f64"; } void apply(types::array_type const & type) { apply(*type.element_type); out << "[" << type.size << "]"; } void apply(types::function_type const & type) { if (type.arguments.size() == 1 && !is_function_type(*type.arguments[0])) { apply(*type.arguments.front()); out << " -> "; apply(*type.result); return; } out << '('; bool first = true; for (auto const & argument : type.arguments) { if (!first) out << ", "; first = false; apply(*argument); } out << ") -> "; apply(*type.result); } void apply(types::struct_type const & type) { out << type.node->name; } void apply(types::pointer_type const & type) { apply(*type.referenced_type); if (type.is_mutable) out << " mut"; out << "*"; } }; struct type_print_visitor : const_type_visitor { std::ostream & out; using const_type_visitor::apply; void apply(types::unit_type const &) { out << "unit"; } template void apply(types::primitive_type_base const & type) { print(out, types::type{types::primitive_type{type}}); } void apply(array_type const & type) { apply(*type.element_type); out << "[" << type.size << "]"; } void apply(function_type const & type) { if (type.arguments.size() == 1 && !std::get_if(type.arguments[0].get())) { apply(*type.arguments.front()); out << " -> "; apply(*type.result); return; } out << '('; bool first = true; for (auto const & argument : type.arguments) { if (!first) out << ", "; first = false; apply(*argument); } out << ") -> "; apply(*type.result); } void apply(pointer_type const & type) { apply(*type.referenced_type); if (type.is_mutable) out << " mut"; out << "*"; } void apply(type_identifier const & type) { out << type.name; } }; struct expression_print_visitor : const_expression_visitor { std::ostream & out; print_options options; using const_expression_visitor::apply; template void child(Node const & node) { ++options.indent_level; apply(node); --options.indent_level; } void apply(bool_literal const & node) { put_indent(out, options); out << "bool literal { value = " << (node.value ? "true" : "false") << " }\n"; } void apply(i8_literal const & node) { put_indent(out, options); out << "i8 literal { value = " << (std::int32_t)node.value << " }\n"; } void apply(u8_literal const & node) { put_indent(out, options); out << "u8 literal { value = " << (std::uint32_t)node.value << " }\n"; } void apply(i16_literal const & node) { put_indent(out, options); out << "i16 literal { value = " << node.value << " }\n"; } void apply(u16_literal const & node) { put_indent(out, options); out << "u16 literal { value = " << node.value << " }\n"; } void apply(i32_literal const & node) { put_indent(out, options); out << "i32 literal { value = " << node.value << " }\n"; } void apply(u32_literal const & node) { put_indent(out, options); out << "u32 literal { value = " << node.value << " }\n"; } void apply(i64_literal const & node) { put_indent(out, options); out << "i64 literal { value = " << node.value << " }\n"; } void apply(u64_literal const & node) { put_indent(out, options); out << "u64 literal { value = " << node.value << " }\n"; } void apply(f16_literal const & node) { put_indent(out, options); out << "f32 literal { value = " << std::setprecision(3) << node.value.repr << " }\n"; } void apply(f32_literal const & node) { put_indent(out, options); out << "f32 literal { value = " << std::setprecision(7) << node.value << " }\n"; } void apply(f64_literal const & node) { put_indent(out, options); out << "f64 literal { value = " << std::setprecision(15) << node.value << " }\n"; } void apply(identifier const & node) { put_indent(out, options); out << "identifier { name = \"" << node.name << "\" }\n"; } void apply(unary_operation const & node) { put_indent(out, options); out << node.type << '\n'; child(*node.arg1); } void apply(binary_operation const & node) { put_indent(out, options); out << node.type << '\n'; child(*node.arg1); child(*node.arg2); } void apply(cast_operation const & node) { put_indent(out, options); out << "cast as "; print(out, *node.type); out << '\n'; child(*node.expression); } void apply(function_call const & node) { put_indent(out, options); if (node.function) { out << "call\n"; child(*node.function); } if (node.type) { out << "constructor { type = "; print(out, *node.type); out << " }\n"; } for (auto const & argument : node.arguments) child(*argument); } void apply(array const & node) { put_indent(out, options); out << "array\n"; for (auto const & element : node.elements) child(*element); } void apply(array_access const & node) { put_indent(out, options); out << "array access\n"; child(*node.array); child(*node.index); } void apply(field_access const & node) { put_indent(out, options); out << "field access { name = \"" << node.field_name << "\" }\n"; child(*node.object); } void apply(if_expression const & node) { put_indent(out, options); out << "if\n"; child(*node.condition); child(*node.if_true); child(*node.if_false); } void apply(sizeof_operator const & node) { put_indent(out, options); if (node.expression) { out << "sizeof\n"; child(*node.expression); } else { out << "sizeof "; print(out, *node.type); out << "\n"; } } void apply(alignof_operator const & node) { put_indent(out, options); if (node.expression) { out << "alignof\n"; child(*node.expression); } else { out << "sizeof "; print(out, *node.type); out << "\n"; } } }; struct statement_print_visitor : const_statement_visitor { std::ostream & out; print_options options; using const_statement_visitor::apply; template void child(Node const & node) { ++options.indent_level; apply(node); --options.indent_level; } void apply(expression_ptr const & node) { print(out, *node, options); } void apply(assignment const & node) { put_indent(out, options); out << "assignment\n"; child(node.lhs); child(node.rhs); } void apply(variable_declaration const & node) { put_indent(out, options); out << "variable declaration { category = " << node.category << ", name = \"" << node.name << "\""; if (node.type) { out << ", type = "; print(out, *node.type); } out << " }\n"; child(node.initializer); } void apply(if_chain const & node) { put_indent(out, options); out << "if chain\n"; ++options.indent_level; for (auto const & block : node.blocks) { put_indent(out, options); out << "condition\n"; if (block.condition) child(block.condition); else { put_indent(out, as_child(options)); out << "(none)\n"; } put_indent(out, options); out << "body\n"; child(*block.statements); } --options.indent_level; } void apply(while_block const & node) { put_indent(out, options); out << "while\n"; child(node.condition); child(*node.statements); } void apply(break_statement const & node) { put_indent(out, options); out << "break\n"; } void apply(continue_statement const & node) { put_indent(out, options); out << "continue\n"; } void apply(function_definition const & node) { put_indent(out, options); out << "function { name = \"" << node.name << "\", return type = "; print(out, *node.return_type); out << " }\n"; ++options.indent_level; for (auto const & arg : node.arguments) { put_indent(out, options); out << "argument { name = \"" << arg.name << "\", type = "; print(out, *arg.type); out << " }\n"; } put_indent(out, options); out << "body\n"; child(*node.statements); --options.indent_level; } void apply(foreign_function_declaration const & node) { put_indent(out, options); out << "foreign function { name = \"" << node.name << "\", return type = "; print(out, *node.return_type); out << " }\n"; ++options.indent_level; for (auto const & arg : node.arguments) { put_indent(out, options); out << "argument { name = \"" << arg.name << "\", type = "; print(out, *arg.type); out << " }\n"; } --options.indent_level; } void apply(return_statement const & node) { put_indent(out, options); out << "return\n"; if (node.value) child(node.value); } void apply(struct_definition const & node) { put_indent(out, options); out << "struct { name = \"" << node.name << "\", size = " << node.layout.size << ", align = " << node.layout.alignment << " }\n"; for (auto const & field : node.fields) { put_indent(out, as_child(options)); out << "field { name = \"" << field.name << "\", type = "; print(out, *field.type); out << ", offset = " << field.layout.offset << " }\n"; } } }; } void print(std::ostream & out, types::type const & type) { raw_type_print_visitor{{}, out}.apply(type); } void print(std::ostream & out, type const & node) { type_print_visitor{{}, out}.apply(node); } void print(std::ostream & out, expression const & node, print_options const & options) { expression_print_visitor{{}, out, options}.apply(node); } void print(std::ostream & out, statement const & node, print_options const & options) { statement_print_visitor{{}, out, options}.apply(node); } void print(std::ostream & out, statement_list const & node, print_options const & options) { statement_print_visitor{{}, out, options}.apply(node); } }