diff --git a/include/basic_printers.hpp b/include/basic_printers.hpp index 55975fd..34321e4 100644 --- a/include/basic_printers.hpp +++ b/include/basic_printers.hpp @@ -7,40 +7,109 @@ namespace printers { class Printer { public: - Printer(std::ostream &output, size_t tab_width, + Printer(std::ostream &output, size_t tab_width, size_t width_limit, bool print_words_instead_of_symbols) - : output_(output), tab_width_(tab_width), + : output_(output), tab_width_(tab_width), width_limit_(width_limit), print_words_instead_of_symbols_(print_words_instead_of_symbols), - current_column_(0) {} + current_position_(0), current_indentation_level_(0) {} - template void print(const T &value) { output_ << value; } - - void new_line() { - print('\n'); - print_spaces(current_column_ * tab_width_); + void print_converted(const std::string &value) { + for (auto &ch : value) { + output_ << to_printable_symbol(ch); + current_position_ += to_printable_symbol(ch).size(); + } } - void indent() { ++current_column_; } + // value shouldn't contain '\n', '\t', etc. + void print(const std::string &value) { + output_ << value; + current_position_ += value.size(); + } - void deindent() { --current_column_; } + void column_down() { + size_t current_position = current_position_; + end_line(); + print_spaces(current_position); + } + + void new_indent_line() { + end_line(); + print_spaces(current_indentation_level_ * tab_width_); + } + + void new_line(size_t indentation) { + end_line(); + print_spaces(indentation); + } + + void indent() { ++current_indentation_level_; } + + void deindent() { --current_indentation_level_; } void tab() { print_spaces(tab_width_); } void space() { print_spaces(1); } - bool print_words_instead_of_symbols() { + size_t current_position() const { return current_position_; } + + size_t width_limit() const { return width_limit_; } + + size_t width_left() const { + return std::max(static_cast(width_limit_) - + static_cast(current_position_), + static_cast(0)); + } + + bool print_words_instead_of_symbols() const { return print_words_instead_of_symbols_; } + size_t get_current_position() { return current_position_; } + private: + void end_line() { + output_ << "\n"; + current_position_ = 0; + } void print_spaces(size_t n) { print(std::string(n, ' ')); } + static std::string to_printable_symbol(char ch) { + switch (ch) { + case '\a': + return "\\a"; + case '\b': + return "\\b"; + case '\e': + return "\\e"; + case '\f': + return "\\f"; + case '\n': + return "\\n"; + case '\r': + return "\\r"; + case '\t': + return "\\t"; + case '\v': + return "\\v"; + case '\'': + return "\\\'"; + case '\"': + return "\\\""; + // case ' ': + // return "\\s"; + default: + return std::string(1, ch); + } + } + private: std::ostream &output_; - size_t tab_width_ = 2; + size_t tab_width_ = 0; + size_t width_limit_ = 0; bool print_words_instead_of_symbols_ = false; - size_t current_column_ = 0; + size_t current_position_ = 0; + size_t current_indentation_level_ = 0; }; void print_literal(const nodes::Literal &literal, Printer &printer); diff --git a/include/expression_nodes.hpp b/include/expression_nodes.hpp index 41e379a..bb49b6f 100644 --- a/include/expression_nodes.hpp +++ b/include/expression_nodes.hpp @@ -528,6 +528,20 @@ public: return std::nullopt; } + std::variant * + get_any() { + return &expression_; + } + + const std::variant * + get_any() const { + return &expression_; + } + bool is_scoped() const { return is_scoped_; } private: diff --git a/include/expression_printers.hpp b/include/expression_printers.hpp index 543fea8..293a01d 100644 --- a/include/expression_printers.hpp +++ b/include/expression_printers.hpp @@ -9,6 +9,8 @@ void print_expression(const nodes::Expression &expression, // --- flow control +void print_case(const nodes::Match::Case &expression, Printer &printer); + void print_match(const nodes::Match &expression, printers::Printer &printer); void print_condition(const nodes::Condition &expression, diff --git a/include/type_nodes.hpp b/include/type_nodes.hpp index e341c8a..a45d1f0 100644 --- a/include/type_nodes.hpp +++ b/include/type_nodes.hpp @@ -58,9 +58,9 @@ public: is_on_heap_(is_on_heap), is_optional_(is_optional), is_result_(is_result) {} - std::string *get_name() { return name_.get(); } + Identifier *get_name() { return &name_; } - const std::string *get_name() const { return name_.get(); } + const Identifier *get_name() const { return &name_; } size_t get_parametrs_size() const { return parameters_.size(); } diff --git a/src/basic_builders.cpp b/src/basic_builders.cpp index 592a5f1..f354525 100644 --- a/src/basic_builders.cpp +++ b/src/basic_builders.cpp @@ -26,6 +26,10 @@ std::optional to_escape_symbol(char ch) { return '\t'; case 'v': return '\v'; + case '\'': + return '\''; + case '\"': + return '\"'; case 's': return ' '; default: diff --git a/src/basic_printers.cpp b/src/basic_printers.cpp index ea2d82f..dfca297 100644 --- a/src/basic_printers.cpp +++ b/src/basic_printers.cpp @@ -2,56 +2,29 @@ #include "error_handling.hpp" +#include + namespace printers { -namespace utils { -std::string to_printable_symbol(char ch) { - switch (ch) { - case '\a': - return "\\a"; - case '\b': - return "\\b"; - case '\e': - return "\\e"; - case '\f': - return "\\f"; - case '\n': - return "\\n"; - case '\r': - return "\\r"; - case '\t': - return "\\t"; - case '\v': - return "\\v"; - // case ' ': - // return "\\s"; - default: - return std::string(1, ch); - } -} - -} // namespace utils - void print_literal(const nodes::Literal &literal, Printer &printer) { switch (literal.get_any()->index()) { case 0: // double // print in parseable form ?? - printer.print(literal.get().value()); + printer.print(std::to_string(*literal.get().value())); return; case 1: // long long - printer.print(literal.get().value()); + printer.print(std::to_string(*literal.get().value())); return; case 2: // std::string - printer.print("\"\""); - // more efficient approach ?? - for (auto &ch : *literal.get().value()) { - printer.print(utils::to_printable_symbol(ch)); - } - printer.print("\"\""); + printer.print("\""); + printer.print_converted( + *literal.get() + .value()); // special symbols are converted inside + printer.print("\""); return; case 3: // char printer.print("\'\'"); - printer.print(utils::to_printable_symbol(*literal.get().value())); + printer.print_converted(std::string(1, *literal.get().value())); printer.print("\'\'"); return; case 4: // bool @@ -72,11 +45,11 @@ void print_literal(const nodes::Literal &literal, Printer &printer) { } void print_identifier(const nodes::Identifier &identifier, Printer &printer) { - printer.print(identifier.get()); + printer.print(*identifier.get()); } void print_annotation(const std::string &annotation, Printer &printer) { - printer.print('@'); + printer.print("@"); printer.print(annotation); } diff --git a/src/expression_builders.cpp b/src/expression_builders.cpp index b237b79..883b826 100644 --- a/src/expression_builders.cpp +++ b/src/expression_builders.cpp @@ -16,94 +16,109 @@ build_expression(parser::ParseTree::Node parser_node, nodes::TypeStorage &type_storage) { tokens::Type type = tokens::string_to_type(parser_node.get_type()); + auto maybe_parenthesis = parser_node.next_sibling(); + bool is_scoped = + (!maybe_parenthesis.is_null() && maybe_parenthesis.get_value() == "("); + switch (type) { // --- flow control case tokens::Type::MATCH: return expression_storage.add_expression(nodes::Expression( - build_match(parser_node, expression_storage, type_storage))); + build_match(parser_node, expression_storage, type_storage), is_scoped)); case tokens::Type::CONDITION: return expression_storage.add_expression(nodes::Expression( - build_condition(parser_node, expression_storage, type_storage))); + build_condition(parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::LOOP: return expression_storage.add_expression(nodes::Expression( - build_loop(parser_node, expression_storage, type_storage))); + build_loop(parser_node, expression_storage, type_storage), is_scoped)); // --- operators case tokens::Type::COMMA_EXPRESSION: return expression_storage.add_expression(nodes::Expression( - build_comma_expression(parser_node, expression_storage, type_storage))); + build_comma_expression(parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::OPERATOR_EXPRESSION: return expression_storage.add_expression( nodes::Expression(build_operator_expression( - parser_node, expression_storage, type_storage))); + parser_node, expression_storage, type_storage), + is_scoped)); // --- containers case tokens::Type::BLOCK: return expression_storage.add_expression(nodes::Expression( - build_block(parser_node, expression_storage, type_storage))); + build_block(parser_node, expression_storage, type_storage), is_scoped)); case tokens::Type::ARRAY: return expression_storage.add_expression(nodes::Expression( - build_array(parser_node, expression_storage, type_storage))); + build_array(parser_node, expression_storage, type_storage), is_scoped)); // --- modifiers case tokens::Type::RETURN: return expression_storage.add_expression(nodes::Expression( - build_return(parser_node, expression_storage, type_storage))); + build_return(parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::NAME_DEFINITION: return expression_storage.add_expression( - nodes::Expression(build_name_definition(parser_node))); + nodes::Expression(build_name_definition(parser_node), is_scoped)); case tokens::Type::ARRAY_ACCESS: return expression_storage.add_expression(nodes::Expression( - build_array_access(parser_node, expression_storage, type_storage))); + build_array_access(parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::TUPLE_ACCESS: return expression_storage.add_expression(nodes::Expression( - build_tuple_access(parser_node, expression_storage, type_storage))); + build_tuple_access(parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::LOOP_CONTROL: return expression_storage.add_expression( - nodes::Expression(build_loop_control(parser_node))); + nodes::Expression(build_loop_control(parser_node), is_scoped)); case tokens::Type::REFERENCE_EXPRESSION: return expression_storage.add_expression( nodes::Expression(build_reference_expression( - parser_node, expression_storage, type_storage))); + parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::SUFFIX_EXPRESSION: - return expression_storage.add_expression( - nodes::Expression(build_suffix_expression( - parser_node, expression_storage, type_storage))); + return expression_storage.add_expression(nodes::Expression( + build_suffix_expression(parser_node, expression_storage, type_storage), + is_scoped)); // --- other case tokens::Type::NAME_EXPRESSION: return expression_storage.add_expression(nodes::Expression( - build_name_expression(parser_node, expression_storage, type_storage))); + build_name_expression(parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::ARGUMENT_NAME_IDENTIFIER: case tokens::Type::SIMPLE_NAME_IDENTIFIER: case tokens::Type::PLACEHOLDER: return expression_storage.add_expression( - nodes::Expression(nodes::NameExpression( - build_node(parser_node), build_identifier(parser_node)))); + nodes::Expression(nodes::NameExpression(build_node(parser_node), + build_identifier(parser_node)), + is_scoped)); case tokens::Type::CONSTRUCTOR: return expression_storage.add_expression(nodes::Expression( - build_constructor(parser_node, expression_storage, type_storage))); + build_constructor(parser_node, expression_storage, type_storage), + is_scoped)); case tokens::Type::LAMBDA: return expression_storage.add_expression(nodes::Expression( - build_lambda(parser_node, expression_storage, type_storage))); + build_lambda(parser_node, expression_storage, type_storage), + is_scoped)); // --- literals case tokens::Type::FLOAT_NUMBER_LITERAL: return expression_storage.add_expression( - nodes::Expression(build_float_number_literal(parser_node))); + nodes::Expression(build_float_number_literal(parser_node), is_scoped)); case tokens::Type::NUMBER_LITERAL: return expression_storage.add_expression( - nodes::Expression(build_number_literal(parser_node))); + nodes::Expression(build_number_literal(parser_node), is_scoped)); case tokens::Type::STRING_LITERAL: return expression_storage.add_expression( - nodes::Expression(build_string_literal(parser_node))); + nodes::Expression(build_string_literal(parser_node), is_scoped)); case tokens::Type::CHAR_LITERAL: return expression_storage.add_expression( - nodes::Expression(build_char_literal(parser_node))); + nodes::Expression(build_char_literal(parser_node), is_scoped)); case tokens::Type::BOOL_LITERAL: return expression_storage.add_expression( - nodes::Expression(build_bool_literal(parser_node))); + nodes::Expression(build_bool_literal(parser_node), is_scoped)); case tokens::Type::UNIT_LITERAL: return expression_storage.add_expression( - nodes::Expression(build_unit_literal(parser_node))); + nodes::Expression(build_unit_literal(parser_node), is_scoped)); case tokens::Type::NULL_LITERAL: return expression_storage.add_expression( - nodes::Expression(build_null_literal(parser_node))); + nodes::Expression(build_null_literal(parser_node), is_scoped)); default: error_handling::handle_parsing_error("Unexprected expression node type", parser_node); @@ -370,7 +385,7 @@ nodes::Access build_tuple_access(parser::ParseTree::Node parser_node, build_expression(parser_node.nth_named_child(0), expression_storage, type_storage), expression_storage.add_expression(nodes::Expression( - build_number_literal(parser_node.nth_named_child(1))))); + build_number_literal(parser_node.nth_named_child(1)), false))); } // 'break' | 'continue' diff --git a/src/expression_printers.cpp b/src/expression_printers.cpp index 3b20201..08ed8ed 100644 --- a/src/expression_printers.cpp +++ b/src/expression_printers.cpp @@ -7,23 +7,194 @@ namespace printers { void print_expression(const nodes::Expression &expression, - printers::Printer &printer) {} // IN PROGRESS + printers::Printer &printer) { + if (expression.is_scoped()) { + printer.print("("); + } + + switch (expression.get_any()->index()) { + // --- flow control + case 0: // Match + print_match(*expression.get().value(), printer); + break; + case 1: // Condition + print_condition(*expression.get().value(), printer); + break; + case 2: // Loop + print_loop(*expression.get().value(), printer); + break; + // --- containers + case 3: // Container + print_container(*expression.get().value(), printer); + break; + // --- modifiers + case 4: // Return + print_return(*expression.get().value(), printer); + break; + case 5: // NameDefinition + print_name_definition(*expression.get().value(), + printer); + break; + case 6: // Access + print_access(*expression.get().value(), printer); + break; + case 7: // LoopControl + print_loop_control(*expression.get().value(), printer); + break; + case 8: // ModifierExpression + print_modifier_expression( + *expression.get().value(), printer); + break; + // --- other + case 9: // NameExpression + print_name_expression(*expression.get().value(), + printer); + break; + case 10: // Constructor + print_constructor(*expression.get().value(), printer); + break; + case 11: // Lambda + print_lambda(*expression.get().value(), printer); + break; + // --- literal + case 12: // Literal + print_literal(*expression.get().value(), printer); + break; + } + + if (expression.is_scoped()) { + printer.print(")"); + } +} // --- flow control +void print_case(const nodes::Match::Case &expression, Printer &printer) { + + switch (expression.case_type()) { + case nodes::Match::Case::PATTERN_VALUE: + printer.print(":="); + break; + case nodes::Match::Case::VALUE_PATTERN: + printer.print("=:"); + break; + } + + printer.space(); + + print_expression(*expression.get_value(), printer); + + if (expression.get_condition().has_value()) { + + printer.print(printer.print_words_instead_of_symbols() ? " if " : " ?? "); + print_expression(*expression.get_condition().value(), printer); + } + + if (expression.get_expression().has_value()) { + printer.print(printer.print_words_instead_of_symbols() ? " do " : " => "); + print_expression(*expression.get_expression().value(), printer); + } +} // IN PROGRESS + void print_match(const nodes::Match &expression, printers::Printer &printer) { + print_expression(*expression.get_value(), printer); + + printer.space(); + + size_t indentation = printer.get_current_position(); + + for (size_t i = 0; i < expression.cases_size(); ++i) { + print_case(*expression.get_case(i), printer); + + if (i + 1 < expression.cases_size()) { + printer.new_line(indentation); + } + } + } // IN PROGRESS void print_condition(const nodes::Condition &expression, - printers::Printer &printer) {} // IN PROGRESS + printers::Printer &printer) { + + for (size_t i = 0; i < expression.cases_size(); ++i) { + if (i == 0) { + printer.print(printer.print_words_instead_of_symbols() ? "if " : "?? "); + } else { + printer.print(printer.print_words_instead_of_symbols() ? "elif " : "!! "); + } + + print_expression(*expression.get_case(i).first, printer); + + printer.print(printer.print_words_instead_of_symbols() ? "do " : "=> "); + + print_expression(*expression.get_case(i).second, printer); + } + + if (expression.get_else_case().has_value()) { + printer.print(printer.print_words_instead_of_symbols() ? "else " : "!!=> "); + print_expression(*expression.get_else_case().value(), printer); + } +} void print_loop(const nodes::Loop &expression, printers::Printer &printer) { + printer.print(printer.print_words_instead_of_symbols() ? "for " : "@"); + + switch (expression.get_type()) { + case nodes::Loop::LOOP: + printer.space(); + break; + case nodes::Loop::WHILE: + printer.space(); + print_expression(*expression.get_condition().value(), printer); + printer.space(); + break; + case nodes::Loop::FOR: + printer.space(); + print_expression(*expression.get_variable().value(), printer); + printer.print(" : "); + print_expression(*expression.get_interval().value(), printer); + printer.space(); + break; + } + + printer.print(printer.print_words_instead_of_symbols() ? "do " : "=> "); + + print_expression(*expression.get_expression(), printer); + printer.print(";"); } // IN PROGRESS // --- containers void print_container(const nodes::Container &expression, - printers::Printer &printer) {} // IN PROGRESS + printers::Printer &printer) { + bool is_array = expression.get_type() == nodes::Container::ARRAY; + + if (is_array) { + printer.print("[["); + } else { + printer.print("{"); + printer.indent(); + printer.new_indent_line(); + } + + for (size_t i = 0; i < expression.expressions_size(); ++i) { + print_expression(*expression.get_expression(i), printer); + if (is_array) { + printer.space(); + } else { + printer.print(";"); + printer.new_indent_line(); + } + } + + if (is_array) { + printer.print("]]"); + } else { + printer.deindent(); + printer.print("}"); + printer.new_indent_line(); + } +} // IN PROGRESS // --- modifiers @@ -78,10 +249,10 @@ void print_access(const nodes::Access &expression, printers::Printer &printer) { switch (expression.get_type()) { case nodes::Access::ARRAY: - printer.print('['); + printer.print("["); break; case nodes::Access::TUPLE: - printer.print('.'); + printer.print("."); break; default: break; @@ -91,7 +262,7 @@ void print_access(const nodes::Access &expression, printers::Printer &printer) { switch (expression.get_type()) { case nodes::Access::ARRAY: - printer.print(']'); + printer.print("]"); break; case nodes::Access::TUPLE: break; @@ -151,10 +322,10 @@ void print_modifier_expression(const nodes::ModifierExpression &expression, switch (expression.get_modifier()) { case nodes::Modifier::OR_FALSE: - printer.print('?'); + printer.print("?"); break; case nodes::Modifier::OR_RETURN: - printer.print('!'); + printer.print("!"); break; default: break; @@ -168,13 +339,13 @@ void print_name_expression(const nodes::NameExpression &expression, if (expression.is_operator_call() || expression.is_point_call()) { print_expression(*expression.get_argument_value(0), printer); if (expression.is_point_call()) { - printer.print('.'); + printer.print("."); } else { printer.space(); } } else if (expression.get_prefix().has_value()) { print_type(*expression.get_prefix().value(), printer); - printer.print('.'); + printer.print("."); } print_identifier(*expression.get_name(), printer); @@ -216,7 +387,7 @@ void print_lambda(const nodes::Lambda &expression, printers::Printer &printer) { printer.space(); } - printer.print(printer.print_words_instead_of_symbols() ? "do " : "-> "); + printer.print(printer.print_words_instead_of_symbols() ? "do " : "=> "); print_expression(*expression.get_expression(), printer); diff --git a/src/type_printers.cpp b/src/type_printers.cpp index 8a9b213..75c3034 100644 --- a/src/type_printers.cpp +++ b/src/type_printers.cpp @@ -6,25 +6,25 @@ namespace printers { void print_type(const nodes::Type &type, printers::Printer &printer) { if (type.is_on_heap()) { - printer.print('^'); + printer.print("^"); } - printer.print(type.get_name()); + print_identifier(*type.get_name(), printer); if (type.is_optional()) { - printer.print('?'); + printer.print("?"); } if (type.is_result()) { - printer.print('!'); + printer.print("!"); } - printer.print('['); + printer.print("["); for (size_t i = 0; i < type.get_parametrs_size(); ++i) { print_type(*type.get_parameter(i), printer); printer.space(); } - printer.print(']'); + printer.print("]"); } void print_tuple_type(const nodes::TupleType &type, @@ -53,7 +53,7 @@ void print_variant_type(const nodes::VariantType &type, print_tuple_type(*type.get(i), printer); if (i + 1 < type.size()) { - printer.new_line(); + printer.new_indent_line(); } } } // IN PROGRESS