diff --git a/apps/interpreter/source/main.cpp b/apps/interpreter/source/main.cpp index 70cb251..961dfc3 100644 --- a/apps/interpreter/source/main.cpp +++ b/apps/interpreter/source/main.cpp @@ -109,7 +109,7 @@ int main(int argc, char ** argv) for (std::size_t i = 0; i < filenames.size(); ++i) { std::cout << "Input file " << filenames[i] << " AST dump:\n\n"; - ast::print(std::cout, parsed[i]); + ast::print(std::cout, *parsed[i]); std::cout << "\n"; } std::cout << std::flush; diff --git a/backlog.txt b/backlog.txt index 0d25ed4..e3c7632 100644 --- a/backlog.txt +++ b/backlog.txt @@ -1,3 +1,2 @@ * Mutually recursive functions -* Refactor all tree visitors to prevent infinite recursion (maybe add decicated tree traversal functions & visitors?) -* Type identifier location + move types to ast library / split type values and type ast nodes +* Type identifier location diff --git a/libs/ast/include/pslang/ast/expression_visitor.hpp b/libs/ast/include/pslang/ast/expression_visitor.hpp new file mode 100644 index 0000000..2aebf38 --- /dev/null +++ b/libs/ast/include/pslang/ast/expression_visitor.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include + +namespace pslang::ast +{ + + namespace detail + { + + template + struct const_expression_visitor_helper + { + Visitor & visitor; + + template + void operator()(Expression const & expression) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, expression); + } + else + { + visitor(expression); + } + } + + void operator()(literal const & expression) + { + std::visit(*this, expression); + } + + void operator()(expression const & expression) + { + std::visit(*this, expression); + } + }; + + template + struct expression_visitor_helper + { + Visitor & visitor; + + template + void operator()(Expression & expression) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, expression); + } + else + { + visitor(expression); + } + } + + void operator()(literal & expression) + { + std::visit(*this, expression); + } + + void operator()(expression & expression) + { + std::visit(*this, expression); + } + }; + + } + + template + void apply(Visitor && visitor, expression const & expression) + { + detail::const_expression_visitor_helper helper{visitor}; + helper(expression); + } + + template + void apply(Visitor && visitor, expression & expression) + { + detail::expression_visitor_helper helper{visitor}; + helper(expression); + } + +} diff --git a/libs/ast/include/pslang/ast/print.hpp b/libs/ast/include/pslang/ast/print.hpp index b0f4f23..db01a8f 100644 --- a/libs/ast/include/pslang/ast/print.hpp +++ b/libs/ast/include/pslang/ast/print.hpp @@ -1,6 +1,8 @@ #pragma once -#include +#include +#include +#include #include @@ -13,8 +15,9 @@ namespace pslang::ast std::size_t indent_level = 0; }; - void print(std::ostream & out, expression_ptr const & node, print_options const & options = {}); - void print(std::ostream & out, statement_ptr const & node, print_options const & options = {}); - void print(std::ostream & out, statement_list_ptr const & node, print_options const & options = {}); + void print(std::ostream & out, type const & node); + void print(std::ostream & out, expression const & node, print_options const & options = {}); + void print(std::ostream & out, statement const & node, print_options const & options = {}); + void print(std::ostream & out, statement_list const & node, print_options const & options = {}); } diff --git a/libs/ast/include/pslang/ast/statement_visitor.hpp b/libs/ast/include/pslang/ast/statement_visitor.hpp new file mode 100644 index 0000000..7c26e2d --- /dev/null +++ b/libs/ast/include/pslang/ast/statement_visitor.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include + +namespace pslang::ast +{ + + namespace detail + { + + template + struct const_statement_visitor_helper + { + Visitor & visitor; + + template + void operator()(Statement const & statement) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, statement); + } + else + { + visitor(statement); + } + } + + void operator()(statement const & statement) + { + std::visit(*this, statement); + } + }; + + template + struct statement_visitor_helper + { + Visitor & visitor; + + template + void operator()(Statement & statement) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, statement); + } + else + { + visitor(statement); + } + } + + void operator()(statement & statement) + { + std::visit(*this, statement); + } + }; + + } + + template + void apply(Visitor && visitor, statement const & statement) + { + detail::const_statement_visitor_helper helper{visitor}; + helper(statement); + } + + template + void apply(Visitor && visitor, statement & statement) + { + detail::statement_visitor_helper helper{visitor}; + helper(statement); + } + + template + void apply(Visitor && visitor, statement_list const & statement_list) + { + detail::const_statement_visitor_helper helper{visitor}; + helper(statement_list); + } + + template + void apply(Visitor && visitor, statement_list & statement_list) + { + detail::statement_visitor_helper helper{visitor}; + helper(statement_list); + } + +} diff --git a/libs/ast/include/pslang/ast/type_visitor.hpp b/libs/ast/include/pslang/ast/type_visitor.hpp new file mode 100644 index 0000000..f44ec9d --- /dev/null +++ b/libs/ast/include/pslang/ast/type_visitor.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include + +namespace pslang::ast +{ + + namespace detail + { + + template + struct const_type_visitor_helper + { + Visitor & visitor; + + template + void operator()(Type const & type) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, type); + } + else + { + visitor(type); + } + } + + void operator()(types::primitive_type const & type) + { + std::visit(*this, type); + } + + void operator()(ast::type const & type) + { + std::visit(*this, type); + } + }; + + template + struct type_visitor_helper + { + Visitor & visitor; + + template + void operator()(Type & type) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, type); + } + else + { + visitor(type); + } + } + + void operator()(types::primitive_type & type) + { + std::visit(*this, type); + } + + void operator()(ast::type & type) + { + std::visit(*this, type); + } + }; + + } + + template + void apply(Visitor && visitor, type const & type) + { + detail::const_type_visitor_helper helper{visitor}; + helper(type); + } + + template + void apply(Visitor && visitor, type & type) + { + detail::type_visitor_helper helper{visitor}; + helper(type); + } + +} diff --git a/libs/ast/source/print.cpp b/libs/ast/source/print.cpp index 7d2939a..16790e5 100644 --- a/libs/ast/source/print.cpp +++ b/libs/ast/source/print.cpp @@ -1,4 +1,8 @@ #include +#include +#include +#include +#include #include #include @@ -10,7 +14,7 @@ namespace pslang::ast namespace { - print_options child(print_options options) + print_options as_child(print_options options) { options.indent_level += 1; return options; @@ -22,332 +26,377 @@ namespace pslang::ast out << options.indent_string; } - void print(std::ostream & out, type const & type, print_options const & options); - - void print_impl(std::ostream & out, types::unit_type const &, print_options const &) + struct type_print_visitor { - out << "unit"; - } + std::ostream & out; - void print_impl(std::ostream & out, types::primitive_type const & type, print_options const &) - { - types::print(out, type); - } - - void print_impl(std::ostream & out, array_type const & type, print_options const & options) - { - print(out, *type.element_type, options); - out << "[" << type.size << "]"; - } - - void print_impl(std::ostream & out, function_type const & type, print_options const & options) - { - if (type.arguments.size() == 1) + void operator()(types::unit_type const &) { - print(out, *type.arguments.front(), options); - out << " -> "; - print(out, *type.result, options); - return; + out << "unit"; } - out << '('; - bool first = true; - for (auto const & argument : type.arguments) + template + void operator()(types::primitive_type_base const & type) { - if (!first) out << ", "; - first = false; - print(out, *argument, options); + types::print(out, types::primitive_type{type}); } - out << ") -> "; - print(out, *type.result, options); - } - void print_impl(std::ostream & out, type_identifier const & type, print_options const & options) - { - out << type.name; - } - - void print(std::ostream & out, type const & type, print_options const & options) - { - std::visit([&](auto const & type){ print_impl(out, type, options); }, type); - } - - void print_impl(std::ostream & out, bool_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "bool literal { value = " << (node.value ? "true" : "false") << " }\n"; - } - - void print_impl(std::ostream & out, i8_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "i8 literal { value = " << (std::int32_t)node.value << " }\n"; - } - - void print_impl(std::ostream & out, u8_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "u8 literal { value = " << (std::uint32_t)node.value << " }\n"; - } - - void print_impl(std::ostream & out, i16_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "i16 literal { value = " << node.value << " }\n"; - } - - void print_impl(std::ostream & out, u16_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "u16 literal { value = " << node.value << " }\n"; - } - - void print_impl(std::ostream & out, i32_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "i32 literal { value = " << node.value << " }\n"; - } - - void print_impl(std::ostream & out, u32_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "u32 literal { value = " << node.value << " }\n"; - } - - void print_impl(std::ostream & out, i64_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "i64 literal { value = " << node.value << " }\n"; - } - - void print_impl(std::ostream & out, u64_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "u64 literal { value = " << node.value << " }\n"; - } - - void print_impl(std::ostream & out, f32_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "f32 literal { value = " << std::setprecision(7) << node.value << " }\n"; - } - - void print_impl(std::ostream & out, f64_literal const & node, print_options const & options) - { - put_indent(out, options); - out << "f64 literal { value = " << std::setprecision(15) << node.value << " }\n"; - } - - void print_impl(std::ostream & out, literal const & node, print_options const & options) - { - std::visit([&](auto const & value){ print_impl(out, value, options); }, node); - } - - void print_impl(std::ostream & out, identifier const & node, print_options const & options) - { - put_indent(out, options); - out << "identifier { name = \"" << node.name << "\" }\n"; - } - - void print_impl(std::ostream & out, unary_operation const & node, print_options const & options) - { - put_indent(out, options); - out << node.type << '\n'; - print(out, node.arg1, child(options)); - } - - void print_impl(std::ostream & out, binary_operation const & node, print_options const & options) - { - put_indent(out, options); - out << node.type << '\n'; - print(out, node.arg1, child(options)); - print(out, node.arg2, child(options)); - } - - void print_impl(std::ostream & out, cast_operation const & node, print_options const & options) - { - put_indent(out, options); - out << "cast as "; - print(out, *node.type, options); - out << '\n'; - print(out, node.expression, child(options)); - } - - void print_impl(std::ostream & out, function_call const & node, print_options const & options) - { - put_indent(out, options); - out << "call\n"; - print(out, node.function, child(options)); - for (auto const & argument : node.arguments) - print(out, argument, child(options)); - } - - void print_impl(std::ostream & out, array const & node, print_options const & options) - { - put_indent(out, options); - out << "array\n"; - for (auto const & element : node.elements) - print(out, element, child(options)); - } - - void print_impl(std::ostream & out, array_access const & node, print_options const & options) - { - put_indent(out, options); - out << "array access\n"; - print(out, node.array, child(options)); - print(out, node.index, child(options)); - } - - void print_impl(std::ostream & out, field_access const & node, print_options const & options) - { - put_indent(out, options); - out << "field access { name = \"" << node.field_name << "\" }\n"; - print(out, node.object, child(options)); - } - - void print_impl(std::ostream & out, expression_ptr const & node, print_options const & options) - { - std::visit([&](auto const & value){ print_impl(out, value, options); }, *node); - } - - void print_impl(std::ostream & out, assignment const & node, print_options const & options) - { - put_indent(out, options); - out << "assignment\n"; - print(out, node.lhs, child(options)); - print(out, node.rhs, child(options)); - } - - void print_impl(std::ostream & out, variable_declaration const & node, print_options const & options) - { - put_indent(out, options); - out << "variable declaration { category = " << node.category << ", name = \"" << node.name << "\""; - if (node.type) + template + void operator()(Self & self, array_type const & type) { - out << ", type = "; - print(out, *node.type, options); + self(*type.element_type); + out << "[" << type.size << "]"; } - out << " }\n"; - print(out, node.initializer, child(options)); - } - void print_impl(std::ostream & out, if_block const & node, print_options const & options) - { - put_indent(out, options); - out << "if\n"; - print(out, node.condition, child(options)); - } - - void print_impl(std::ostream & out, else_block const & node, print_options const & options) - { - put_indent(out, options); - out << "else\n"; - } - - void print_impl(std::ostream & out, else_if_block const & node, print_options const & options) - { - put_indent(out, options); - out << "else if\n"; - print(out, node.condition, child(options)); - } - - void print_impl(std::ostream & out, if_chain const & node, print_options const & options) - { - put_indent(out, options); - out << "if chain\n"; - for (auto const & block : node.blocks) + template + void operator()(Self & self, function_type const & type) { - put_indent(out, child(options)); - out << "condition\n"; - if (block.condition) - print(out, block.condition, child(child(options))); - else + if (type.arguments.size() == 1) { - put_indent(out, child(child(options))); - out << "(none)\n"; + self(*type.arguments.front()); + out << " -> "; + self(*type.result); + return; } - put_indent(out, child(options)); - out << "body\n"; - print(out, block.statements, child(child(options))); + out << '('; + bool first = true; + for (auto const & argument : type.arguments) + { + if (!first) out << ", "; + first = false; + self(*argument); + } + out << ") -> "; + self(*type.result); } - } - void print_impl(std::ostream & out, while_block const & node, print_options const & options) - { - put_indent(out, options); - out << "while\n"; - print(out, node.condition, child(options)); - print(out, node.statements, child(options)); - } - - void print_impl(std::ostream & out, function_definition const & node, print_options const & options) - { - put_indent(out, options); - out << "function { name = \"" << node.name << "\", return type = "; - print(out, *node.return_type, options); - out << " }\n"; - for (auto const & arg : node.arguments) + void operator()(type_identifier const & type) { - put_indent(out, child(options)); - out << "argument { name = \"" << arg.name << "\", type = "; - print(out, *arg.type, options); + out << type.name; + } + }; + + struct expression_print_visitor + { + std::ostream & out; + print_options options; + + template + void child(Self & self, Node const & node) + { + ++options.indent_level; + self(node); + --options.indent_level; + } + + void operator()(bool_literal const & node) + { + put_indent(out, options); + out << "bool literal { value = " << (node.value ? "true" : "false") << " }\n"; + } + + void operator()(i8_literal const & node) + { + put_indent(out, options); + out << "i8 literal { value = " << (std::int32_t)node.value << " }\n"; + } + + void operator()(u8_literal const & node) + { + put_indent(out, options); + out << "u8 literal { value = " << (std::uint32_t)node.value << " }\n"; + } + + void operator()(i16_literal const & node) + { + put_indent(out, options); + out << "i16 literal { value = " << node.value << " }\n"; + } + + void operator()(u16_literal const & node) + { + put_indent(out, options); + out << "u16 literal { value = " << node.value << " }\n"; + } + + void operator()(i32_literal const & node) + { + put_indent(out, options); + out << "i32 literal { value = " << node.value << " }\n"; + } + + void operator()(u32_literal const & node) + { + put_indent(out, options); + out << "u32 literal { value = " << node.value << " }\n"; + } + + void operator()(i64_literal const & node) + { + put_indent(out, options); + out << "i64 literal { value = " << node.value << " }\n"; + } + + void operator()(u64_literal const & node) + { + put_indent(out, options); + out << "u64 literal { value = " << node.value << " }\n"; + } + + void operator()(f32_literal const & node) + { + put_indent(out, options); + out << "f32 literal { value = " << std::setprecision(7) << node.value << " }\n"; + } + + void operator()(f64_literal const & node) + { + put_indent(out, options); + out << "f64 literal { value = " << std::setprecision(15) << node.value << " }\n"; + } + + void operator()(identifier const & node) + { + put_indent(out, options); + out << "identifier { name = \"" << node.name << "\" }\n"; + } + + template + void operator()(Self & self, unary_operation const & node) + { + put_indent(out, options); + out << node.type << '\n'; + child(self, *node.arg1); + } + + template + void operator()(Self & self, binary_operation const & node) + { + put_indent(out, options); + out << node.type << '\n'; + child(self, *node.arg1); + child(self, *node.arg2); + } + + template + void operator()(Self & self, cast_operation const & node) + { + put_indent(out, options); + out << "cast as "; + print(out, *node.type); + out << '\n'; + child(self, *node.expression); + } + + template + void operator()(Self & self, function_call const & node) + { + put_indent(out, options); + out << "call\n"; + child(self, *node.function); + for (auto const & argument : node.arguments) + child(self, *argument); + } + + template + void operator()(Self & self, array const & node) + { + put_indent(out, options); + out << "array\n"; + for (auto const & element : node.elements) + child(self, *element); + } + + template + void operator()(Self & self, array_access const & node) + { + put_indent(out, options); + out << "array access\n"; + child(self, *node.array); + child(self, *node.index); + } + + template + void operator()(Self & self, field_access const & node) + { + put_indent(out, options); + out << "field access { name = \"" << node.field_name << "\" }\n"; + child(self, *node.object); + } + }; + + struct statement_print_visitor + { + std::ostream & out; + print_options options; + + template + void child(Self & self, Node const & node) + { + ++options.indent_level; + self(node); + --options.indent_level; + } + + void operator()(expression_ptr const & node) + { + print(out, *node, options); + } + + template + void operator()(Self & self, assignment const & node) + { + put_indent(out, options); + out << "assignment\n"; + child(self, node.lhs); + child(self, node.rhs); + } + + template + void operator()(Self & self, 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(self, node.initializer); + } + + template + void operator()(Self & self, if_block const & node) + { + put_indent(out, options); + out << "if\n"; + child(self, node.condition); + } + + void operator()(else_block const & node) + { + put_indent(out, options); + out << "else\n"; + } + + template + void operator()(Self & self, else_if_block const & node) + { + put_indent(out, options); + out << "else if\n"; + child(self, node.condition); + } + + template + void operator()(Self & self, 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(self, block.condition); + else + { + put_indent(out, as_child(options)); + out << "(none)\n"; + } + + put_indent(out, options); + out << "body\n"; + child(self, *block.statements); + } + --options.indent_level; + } + + template + void operator()(Self & self, while_block const & node) + { + put_indent(out, options); + out << "while\n"; + child(self, node.condition); + child(self, *node.statements); + } + + template + void operator()(Self & self, 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(self, *node.statements); + } + + template + void operator()(Self & self, return_statement const & node) + { + put_indent(out, options); + out << "return\n"; + if (node.value) + child(self, node.value); + } + + void operator()(field_definition const & node) + { + put_indent(out, options); + out << "field { name = \"" << node.name << "\", type = "; + print(out, *node.type); out << " }\n"; } - put_indent(out, child(options)); - out << "body\n"; - print(out, node.statements, child(child(options))); - } - void print_impl(std::ostream & out, return_statement const & node, print_options const & options) - { - put_indent(out, options); - out << "return\n"; - if (node.value) - print(out, node.value, child(options)); - } + template + void operator()(Self & self, struct_definition const & node) + { + put_indent(out, options); + out << "struct { name = \"" << node.name << "\" }\n"; + for (auto const & field : node.fields) + child(self, field); + } - void print_impl(std::ostream & out, field_definition const & node, print_options const & options) - { - put_indent(out, options); - out << "field { name = \"" << node.name << "\", type = "; - print(out, *node.type, options); - out << " }\n"; - } - - void print_impl(std::ostream & out, struct_definition const & node, print_options const & options) - { - put_indent(out, options); - out << "struct { name = \"" << node.name << "\" }\n"; - for (auto const & field : node.fields) - print_impl(out, field, child(options)); - } - - void print_impl(std::ostream & out, statement_ptr const & node, print_options const & options) - { - std::visit([&](auto const & value){ print_impl(out, value, options); }, *node); - } - - void print_impl(std::ostream & out, statement_list_ptr const & node, print_options const & options) - { - for (auto const & statement : node->statements) - print(out, statement, options); - } + template + void operator()(Self & self, statement_list const & node) + { + for (auto const & statement : node.statements) + self(*statement); + } + }; } - void print(std::ostream & out, expression_ptr const & node, print_options const & options) + void print(std::ostream & out, type const & node) { - print_impl(out, node, options); + apply(type_print_visitor{out}, node); } - void print(std::ostream & out, statement_ptr const & node, print_options const & options) + void print(std::ostream & out, expression const & node, print_options const & options) { - print_impl(out, node, options); + apply(expression_print_visitor{out, options}, node); } - void print(std::ostream & out, statement_list_ptr const & node, print_options const & options) + void print(std::ostream & out, statement const & node, print_options const & options) { - print_impl(out, node, options); + apply(statement_print_visitor{out, options}, node); } + + void print(std::ostream & out, statement_list const & node, print_options const & options) + { + apply(statement_print_visitor{out, options}, node); + } + } diff --git a/libs/types/include/pslang/types/type_visitor.hpp b/libs/types/include/pslang/types/type_visitor.hpp new file mode 100644 index 0000000..62b941b --- /dev/null +++ b/libs/types/include/pslang/types/type_visitor.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include + +namespace pslang::types +{ + + namespace detail + { + + template + struct const_visitor_helper + { + Visitor & visitor; + + template + void operator()(Type const & type) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, type); + } + else + { + visitor(type); + } + } + + void operator()(types::primitive_type const & type) + { + std::visit(*this, type); + } + + void operator()(types::type const & type) + { + std::visit(*this, type); + } + }; + + template + struct visitor_helper + { + Visitor & visitor; + + template + void operator()(Type & type) + { + if constexpr (std::is_invocable_v) + { + visitor(*this, type); + } + else + { + visitor(type); + } + } + + void operator()(types::primitive_type & type) + { + std::visit(*this, type); + } + + void operator()(types::type & type) + { + std::visit(*this, type); + } + }; + + } + + template + void apply(Visitor && visitor, type const & type) + { + detail::const_visitor_helper helper{visitor}; + helper(type); + } + + template + void apply(Visitor && visitor, type & type) + { + detail::visitor_helper helper{visitor}; + helper(type); + } + +} diff --git a/libs/types/source/print.cpp b/libs/types/source/print.cpp index b8621a6..40dc718 100644 --- a/libs/types/source/print.cpp +++ b/libs/types/source/print.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace pslang::types { @@ -7,114 +7,111 @@ namespace pslang::types namespace { - void print_impl(std::ostream & out, unit_type const & type) + struct print_visitor { - out << "unit"; - } + std::ostream & out; - void print_impl(std::ostream & out, bool_type const &) - { - out << "bool"; - } - - void print_impl(std::ostream & out, i8_type const &) - { - out << "i8"; - } - - void print_impl(std::ostream & out, u8_type const &) - { - out << "u8"; - } - - void print_impl(std::ostream & out, i16_type const &) - { - out << "i16"; - } - - void print_impl(std::ostream & out, u16_type const &) - { - out << "u16"; - } - - void print_impl(std::ostream & out, i32_type const &) - { - out << "i32"; - } - - void print_impl(std::ostream & out, u32_type const &) - { - out << "u32"; - } - - void print_impl(std::ostream & out, i64_type const &) - { - out << "i64"; - } - - void print_impl(std::ostream & out, u64_type const &) - { - out << "u64"; - } - - void print_impl(std::ostream & out, f32_type const &) - { - out << "f32"; - } - - void print_impl(std::ostream & out, f64_type const &) - { - out << "f64"; - } - - void print_impl(std::ostream & out, primitive_type const & type) - { - std::visit([&](auto const & value){ print_impl(out, value); }, type); - } - - void print_impl(std::ostream & out, array_type const & type) - { - print(out, *type.element_type); - out << "[" << type.size << "]"; - } - - void print_impl(std::ostream & out, function_type const & type) - { - if (type.arguments.size() == 1) + void operator()(unit_type const & type) { - print(out, *type.arguments.front()); - out << " -> "; - print(out, *type.result); - return; + out << "unit"; } - out << '('; - bool first = true; - for (auto const & argument : type.arguments) + void operator()(bool_type const &) { - if (!first) out << ", "; - first = false; - print(out, *argument); + out << "bool"; } - out << ") -> "; - print(out, *type.result); - } - void print_impl(std::ostream & out, named_type const & type) - { - out << type.name; - } + void operator()(i8_type const &) + { + out << "i8"; + } - void print_impl(std::ostream & out, type const & type) - { - std::visit([&](auto const & value){ print_impl(out, value); }, type); - } + void operator()(u8_type const &) + { + out << "u8"; + } + + void operator()(i16_type const &) + { + out << "i16"; + } + + void operator()(u16_type const &) + { + out << "u16"; + } + + void operator()(i32_type const &) + { + out << "i32"; + } + + void operator()(u32_type const &) + { + out << "u32"; + } + + void operator()(i64_type const &) + { + out << "i64"; + } + + void operator()(u64_type const &) + { + out << "u64"; + } + + void operator()(f32_type const &) + { + out << "f32"; + } + + void operator()(f64_type const &) + { + out << "f64"; + } + + template + void operator()(Self & self, array_type const & type) + { + self(*type.element_type); + out << "[" << type.size << "]"; + } + + template + void operator()(Self & self, function_type const & type) + { + if (type.arguments.size() == 1) + { + self(*type.arguments.front()); + out << " -> "; + self(*type.result); + return; + } + + out << '('; + bool first = true; + for (auto const & argument : type.arguments) + { + if (!first) out << ", "; + first = false; + self(*argument); + } + out << ") -> "; + self(*type.result); + } + + void operator()(named_type const & type) + { + out << type.name; + } + }; } void print(std::ostream & out, type const & type) { - print_impl(out, type); + apply(print_visitor{out}, type); } }