shushus

Спринт 16. Разработка лексического анализатора языка Mython.

Jun 22nd, 2023 (edited)
384
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 38.06 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. lexer.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5.  
  6. #include <sstream>
  7. #include <stdexcept>
  8. #include <string>
  9. #include <variant>
  10. #include <vector>
  11. #include <map>
  12.  
  13. namespace parse {
  14. namespace token_type {
  15.    
  16. struct Number {int value;};
  17. struct Id {std::string value;};
  18. struct Char {char value;};
  19. struct String {std::string value;};
  20.  
  21. struct Class {};
  22. struct Return {};
  23. struct If {};
  24. struct Else {};
  25. struct Def {};
  26. struct Newline {};
  27. struct Print {};
  28. struct Indent {};
  29. struct Dedent {};
  30. struct Eof {};
  31. struct And {};
  32. struct Or {};
  33. struct Not {};
  34. struct Eq {};
  35. struct NotEq {};
  36. struct LessOrEq {};
  37. struct GreaterOrEq {};
  38. struct None {};
  39. struct True {};
  40. struct False {};
  41.  
  42. }//end namespace token_type
  43.  
  44. using TokenBase = std::variant<token_type::Number,
  45.                                token_type::Id,
  46.                                token_type::Char,
  47.                                token_type::String,
  48.                                token_type::Class,
  49.                                token_type::Return,     
  50.                                token_type::If,
  51.                                token_type::Else,
  52.                                token_type::Def,
  53.                                token_type::Newline,
  54.                                token_type::Print,
  55.                                token_type::Indent,
  56.                                token_type::Dedent,
  57.                                token_type::And,
  58.                                token_type::Or,
  59.                                token_type::Not,
  60.                                token_type::Eq,
  61.                                token_type::NotEq,      
  62.                                token_type::LessOrEq,
  63.                                token_type::GreaterOrEq,
  64.                                token_type::None,   
  65.                                token_type::True,
  66.                                token_type::False,
  67.                                token_type::Eof>;
  68.  
  69. struct Token : TokenBase {
  70.     using TokenBase::TokenBase;
  71.  
  72.     template <typename T>
  73.     [[nodiscard]] bool Is() const {return std::holds_alternative<T>(*this);}
  74.  
  75.     template <typename T>
  76.     [[nodiscard]] const T& As() const {return std::get<T>(*this);}
  77.  
  78.     template <typename T>
  79.     [[nodiscard]] const T* TryAs() const {return std::get_if<T>(this);}
  80. };
  81.  
  82. bool operator==(const Token& lhs, const Token& rhs);
  83. bool operator!=(const Token& lhs, const Token& rhs);
  84.  
  85. std::ostream& operator<<(std::ostream& os, const Token& rhs);
  86.  
  87. class LexerError : public std::runtime_error {
  88.     public:
  89.         using std::runtime_error::runtime_error;
  90. };
  91.  
  92. class Lexer {
  93.    
  94.     public:
  95.  
  96.         explicit Lexer(std::istream& input);
  97.  
  98.         [[nodiscard]] const Token& CurrentToken() const;
  99.         Token NextToken();
  100.  
  101.         template <typename T>
  102.         const T& Expect() const {
  103.        
  104.             using namespace std::literals;
  105.        
  106.             if (CurrentToken().Is<T>()) {
  107.                 return CurrentToken().As<T>();
  108.            
  109.             } else {
  110.                 throw LexerError("expectation error");
  111.             }        
  112.         }
  113.  
  114.         template <typename T, typename U>
  115.         void Expect(const U& value) const {
  116.        
  117.             using namespace std::literals;
  118.        
  119.             try {
  120.            
  121.                 if (CurrentToken().As<T>().value != value) {
  122.                     throw LexerError("expectation error");
  123.                 } else {
  124.                     return;
  125.                 }
  126.            
  127.             } catch (std::bad_variant_access&) {
  128.                 throw LexerError("expectation error");
  129.             }
  130.         }
  131.  
  132.         template <typename T>
  133.         const T& ExpectNext() {
  134.             NextToken();
  135.             return Expect<T>();
  136.         }
  137.  
  138.         template <typename T, typename U>
  139.         void ExpectNext(const U& value) {
  140.             NextToken();
  141.             Expect<T>(value);
  142.         }
  143.  
  144.     private:
  145.  
  146.         std::map<std::string, Token> keywords_ {
  147.             {"class", token_type::Class{}},
  148.             {"return", token_type::Return{}},
  149.             {"if", token_type::If{}},
  150.             {"else", token_type::Else{}},
  151.             {"def", token_type::Def{}},
  152.             {"print", token_type::Print{}},
  153.             {"or", token_type::Or{}},
  154.             {"None", token_type::None{}},
  155.             {"and", token_type::And{}},
  156.             {"not", token_type::Not{}},
  157.             {"True", token_type::True{}},
  158.             {"False", token_type::False{}}
  159.         };
  160.    
  161.         int spaces_ = 0;
  162.    
  163.         std::vector<Token> tokens_;
  164.         std::vector<Token>::const_iterator current_token_;
  165.    
  166.         void parse_number(std::istream& input);
  167.         void parse_char(std::istream& input);
  168.         void parse_string(std::istream& input);
  169.         void parse_operator(std::istream& input);
  170.         void parse_id(std::istream& input);
  171.         void parse_newline(std::istream& input);
  172.         void parse_indent(std::istream& input);
  173.  
  174.         void pass_spaces(std::istream& input);
  175.         void pass_comment(std::istream& input);
  176.    
  177.         std::vector<Token>::const_iterator parse_tokens(std::istream& input);
  178. };
  179.  
  180. }//end namespace parse
  181. -----------------------------------------------------------------------
  182. lexer.cpp
  183. -----------------------------------------------------------------------
  184. #include "lexer.h"
  185.  
  186. #include <algorithm>
  187. #include <charconv>
  188. #include <unordered_map>
  189.  
  190. using namespace std;
  191.  
  192. namespace parse {
  193.  
  194. bool operator==(const Token& lhs, const Token& rhs) {
  195.     using namespace token_type;
  196.  
  197.     if (lhs.index() != rhs.index()) {return false;}
  198.     if (lhs.Is<Char>()) {return lhs.As<Char>().value == rhs.As<Char>().value;}
  199.     if (lhs.Is<Number>()) {return lhs.As<Number>().value == rhs.As<Number>().value;}
  200.     if (lhs.Is<String>()) {return lhs.As<String>().value == rhs.As<String>().value;}
  201.     if (lhs.Is<Id>()) {return lhs.As<Id>().value == rhs.As<Id>().value;}
  202.     return true;
  203. }
  204.  
  205. bool operator!=(const Token& lhs, const Token& rhs) {return !(lhs == rhs);}
  206.  
  207. std::ostream& operator<<(std::ostream& os, const Token& rhs) {
  208.     using namespace token_type;
  209.  
  210. #define VALUED_OUTPUT(type) \
  211.     if (auto p = rhs.TryAs<type>()) return os << #type << '{' << p->value << '}';
  212.  
  213.     VALUED_OUTPUT(Number);
  214.     VALUED_OUTPUT(Id);
  215.     VALUED_OUTPUT(String);
  216.     VALUED_OUTPUT(Char);
  217.  
  218. #undef VALUED_OUTPUT
  219.  
  220. #define UNVALUED_OUTPUT(type) \
  221.     if (rhs.Is<type>()) return os << #type;
  222.  
  223.     UNVALUED_OUTPUT(Class);
  224.     UNVALUED_OUTPUT(Return);
  225.     UNVALUED_OUTPUT(If);
  226.     UNVALUED_OUTPUT(Else);
  227.     UNVALUED_OUTPUT(Def);
  228.     UNVALUED_OUTPUT(Newline);
  229.     UNVALUED_OUTPUT(Print);
  230.     UNVALUED_OUTPUT(Indent);
  231.     UNVALUED_OUTPUT(Dedent);
  232.     UNVALUED_OUTPUT(And);
  233.     UNVALUED_OUTPUT(Or);
  234.     UNVALUED_OUTPUT(Not);
  235.     UNVALUED_OUTPUT(Eq);
  236.     UNVALUED_OUTPUT(NotEq);
  237.     UNVALUED_OUTPUT(LessOrEq);
  238.     UNVALUED_OUTPUT(GreaterOrEq);
  239.     UNVALUED_OUTPUT(None);
  240.     UNVALUED_OUTPUT(True);
  241.     UNVALUED_OUTPUT(False);
  242.     UNVALUED_OUTPUT(Eof);
  243.  
  244. #undef UNVALUED_OUTPUT
  245.  
  246.     return os << "Unknown token :("sv;
  247. }
  248.  
  249. Lexer::Lexer(std::istream& input) : current_token_(parse_tokens(input)) {}
  250.  
  251. const Token& Lexer::CurrentToken() const {return *current_token_;}
  252.  
  253. Token Lexer::NextToken() {
  254.    
  255.     if ((current_token_ + 1) == tokens_.end()) {
  256.         return token_type::Eof{};
  257.        
  258.     } else {
  259.         return *++current_token_;
  260.     }  
  261. }
  262.  
  263. void Lexer::parse_number(std::istream& input) {
  264.  
  265.     char curr;
  266.     curr = input.peek();
  267.  
  268.     if (std::isdigit(curr)) {
  269.  
  270.         string parsed;
  271.  
  272.         while (input.get(curr)) {
  273.  
  274.             if (std::isdigit(curr)) {
  275.                 parsed.push_back(curr);
  276.  
  277.             } else {
  278.                 input.putback(curr);
  279.                 break;
  280.             }
  281.         }
  282.  
  283.         tokens_.emplace_back(token_type::Number{std::stoi(parsed)});
  284.     }
  285. }
  286.    
  287. void Lexer::parse_char(std::istream& input) {
  288.    
  289.     char curr;
  290.     curr = input.peek();
  291.    
  292.     if (std::ispunct(curr)) {
  293.        
  294.         if (curr == '#') {
  295.             pass_comment(input);
  296.             return;
  297.         }
  298.        
  299.         input.get(curr);        
  300.         tokens_.emplace_back(token_type::Char{curr});
  301.     }
  302. }
  303.    
  304. void Lexer::parse_string(std::istream& input) {
  305.      
  306.     char quote;
  307.     input.get(quote);
  308.      
  309.     if (quote == '\'' || quote == '\"') {
  310.        
  311.         auto it = std::istreambuf_iterator<char>(input);
  312.         auto end = std::istreambuf_iterator<char>();
  313.        
  314.         std::string str;
  315.        
  316.         while (it != end) {
  317.            
  318.             const char curr = *it;
  319.             if (curr == quote) {
  320.                 ++it;
  321.                 break;
  322.                
  323.             } else if (curr == '\\') {
  324.                 ++it;
  325.                
  326.                 if (it == end) {
  327.                     throw std::logic_error("unable to parse. string");
  328.                 }
  329.                
  330.                 const char escaped = *(it);            
  331.                 switch (escaped) {
  332.                        
  333.                     case 'n':
  334.                         str.push_back('\n');
  335.                         break;
  336.                        
  337.                     case 't':
  338.                         str.push_back('\t');
  339.                         break;
  340.                        
  341.                     case 'r':
  342.                         str.push_back('\r');
  343.                         break;
  344.                        
  345.                     case '"':
  346.                         str.push_back('"');
  347.                         break;
  348.                        
  349.                     case '\'':
  350.                         str.push_back('\'');
  351.                         break;
  352.                    
  353.                     case '\\':
  354.                         str.push_back('\\');
  355.                         break;
  356.                    
  357.                     default:
  358.                         throw std::invalid_argument("invalid escape char");
  359.                 }
  360.                
  361.             } else if (curr == '\n' || curr == '\r') {
  362.                 throw std::logic_error("invalid eof"s);
  363.                
  364.             } else {
  365.                 str.push_back(curr);
  366.             }
  367.            
  368.             ++it;
  369.         }
  370.        
  371.         tokens_.emplace_back(token_type::String{str});
  372.        
  373.     } else {
  374.         input.putback(quote);
  375.     }
  376. }
  377.    
  378. void Lexer::parse_operator(std::istream& input) {
  379.    
  380.     char curr;
  381.     input.get(curr);
  382.    
  383.     char next = input.peek();
  384.    
  385.     if (curr == '=' && next == '=') {
  386.         input.get();
  387.         tokens_.emplace_back(token_type::Eq{});
  388.        
  389.     } else if (curr == '!' && next == '=') {
  390.         input.get();
  391.         tokens_.emplace_back(token_type::NotEq{});
  392.        
  393.     } else if (curr == '<' && next == '=') {
  394.         input.get();
  395.         tokens_.emplace_back(token_type::LessOrEq{});  
  396.        
  397.     } else if (curr == '>' && next == '=') {
  398.         input.get();
  399.         tokens_.emplace_back(token_type::GreaterOrEq{});
  400.  
  401.     } else {
  402.         input.putback(curr);
  403.     }
  404. }
  405.    
  406. void Lexer::parse_id(std::istream& input) {
  407.    
  408.     char curr;
  409.     curr = input.peek();
  410.    
  411.     if (std::isalpha(curr) || curr == '_') {
  412.        
  413.         std::string parsed;
  414.        
  415.         while (input.get(curr)) {
  416.            
  417.             if (std::isalnum(curr) || curr == '_') {
  418.                 parsed.push_back(curr);
  419.                
  420.             } else {
  421.                 input.putback(curr);
  422.                 break;
  423.             }
  424.         }
  425.        
  426.         if (keywords_.find(parsed) != keywords_.end()) {
  427.             tokens_.push_back(keywords_.at(parsed));
  428.            
  429.         } else {
  430.             tokens_.emplace_back(token_type::Id{parsed});
  431.         }
  432.     }
  433. }
  434.    
  435. void Lexer::parse_newline(std::istream& input) {
  436.  
  437.     char curr;
  438.     input.get(curr);
  439.  
  440.     if (curr == '\n') {
  441.  
  442.         if (!tokens_.empty() && tokens_.back() != token_type::Newline{}) {
  443.             tokens_.emplace_back(token_type::Newline{});
  444.         }
  445.  
  446.         parse_indent(input);
  447.  
  448.     } else {
  449.         input.putback(curr);
  450.     }
  451. }
  452.    
  453. void Lexer::parse_indent(std::istream& input) {
  454.  
  455.     int spaces = 0;
  456.     char curr;
  457.    
  458.     while (input.get(curr) && curr == ' ') {
  459.         ++spaces;
  460.     }
  461.    
  462.     if (input.rdstate() != std::ios_base::eofbit) {
  463.         input.putback(curr);
  464.     }
  465.    
  466.     char next = input.peek();
  467.    
  468.     if (next == '\n' || next == '#') {
  469.         return;
  470.     }
  471.    
  472.     int indents = (spaces - spaces_) / 2;
  473.     spaces_ = spaces;
  474.    
  475.     Token indent;
  476.    
  477.     if (indents > 0) {
  478.         indent = token_type::Indent{};
  479.        
  480.     } else if (indents < 0) {
  481.         indent = token_type::Dedent{};
  482.     }
  483.    
  484.     for (int i = 0; i < std::abs(indents); ++i) {
  485.         tokens_.emplace_back(indent);
  486.     }
  487. }
  488.    
  489. void Lexer::pass_spaces(std::istream& input) {
  490.    
  491.     while (input.peek() == ' ') {
  492.         input.get();
  493.     }
  494. }
  495.  
  496. void Lexer::pass_comment(std::istream& input) {
  497.    
  498.     char curr;
  499.     input.get(curr);
  500.    
  501.     if (curr == '#') {
  502.        
  503.         string comment;
  504.         getline(input, comment, '\n');
  505.        
  506.         if (input.rdstate() != std::ios_base::eofbit) {
  507.             input.putback('\n');
  508.         }
  509.        
  510.     } else {
  511.         input.putback(curr);
  512.     }
  513. }
  514.    
  515. std::vector<Token>::const_iterator Lexer::parse_tokens(std::istream& input) {
  516.    
  517.     char curr;
  518.    
  519.     while (input.get(curr)) {
  520.        
  521.         input.putback(curr);
  522.  
  523.         parse_newline(input);
  524.         parse_string(input);
  525.         parse_id(input);
  526.         parse_operator(input);
  527.         parse_char(input);
  528.         parse_number(input);
  529.  
  530.         pass_spaces(input);
  531.     }
  532.    
  533.     if (!tokens_.empty() && tokens_.back() != token_type::Newline{} && tokens_.back() != token_type::Dedent{}) {
  534.         tokens_.emplace_back(token_type::Newline{});
  535.     }
  536.    
  537.     tokens_.emplace_back(token_type::Eof{});
  538.     return tokens_.begin();
  539. }
  540.    
  541. }//end namespace parse
  542. -----------------------------------------------------------------------
  543. main.cpp
  544. -----------------------------------------------------------------------
  545. #include "lexer.h"
  546. #include "test_runner_p.h"
  547.  
  548. #include <iostream>
  549.  
  550. namespace parse {
  551. void RunOpenLexerTests(TestRunner& tr);
  552. }
  553.  
  554. int main() {
  555.     try {
  556.         TestRunner tr;
  557.         parse::RunOpenLexerTests(tr);
  558.         parse::Lexer lexer(std::cin);
  559.         parse::Token t;
  560.         while ((t = lexer.CurrentToken()) != parse::token_type::Eof{}) {
  561.             std::cout << t << std::endl;
  562.             lexer.NextToken();
  563.         }
  564.     } catch (const std::exception& e) {
  565.         std::cerr << e.what();
  566.         return 1;
  567.     }
  568. }
  569. -----------------------------------------------------------------------
  570. lexer_test_open.cpp
  571. -----------------------------------------------------------------------
  572. #include "lexer.h"
  573. #include "test_runner_p.h"
  574.  
  575. #include <sstream>
  576. #include <string>
  577.  
  578. using namespace std;
  579.  
  580. namespace parse {
  581.  
  582. namespace {
  583. void TestSimpleAssignment() {
  584.     istringstream input("x = 42\n"s);
  585.     Lexer lexer(input);
  586.  
  587.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Id{"x"s}));
  588.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  589.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{42}));
  590.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  591.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  592.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  593.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  594. }
  595.  
  596. void TestKeywords() {
  597.     istringstream input("class return if else def print or None and not True False"s);
  598.     Lexer lexer(input);
  599.  
  600.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Class{}));
  601.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Return{}));
  602.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::If{}));
  603.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Else{}));
  604.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Def{}));
  605.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Print{}));
  606.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Or{}));
  607.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::None{}));
  608.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::And{}));
  609.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Not{}));
  610.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::True{}));
  611.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::False{}));
  612. }
  613.  
  614. void TestNumbers() {
  615.     istringstream input("42 15 -53"s);
  616.     Lexer lexer(input);
  617.  
  618.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Number{42}));
  619.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{15}));
  620.  
  621.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'-'}));
  622.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{53}));
  623. }
  624.  
  625. void TestIds() {
  626.     istringstream input("x    _42 big_number   Return Class  dEf"s);
  627.     Lexer lexer(input);
  628.  
  629.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Id{"x"s}));
  630.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"_42"s}));
  631.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"big_number"s}));
  632.     ASSERT_EQUAL(lexer.NextToken(),
  633.                  Token(token_type::Id{"Return"s}));  // keywords are case-sensitive
  634.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"Class"s}));
  635.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"dEf"s}));
  636. }
  637.  
  638. void TestStrings() {
  639.     istringstream input(
  640.         R"('word' "two words" 'long string with a double quote " inside' "another long string with single quote ' inside")"s);
  641.     Lexer lexer(input);
  642.  
  643.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::String{"word"s}));
  644.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::String{"two words"s}));
  645.     ASSERT_EQUAL(lexer.NextToken(),
  646.                  Token(token_type::String{"long string with a double quote \" inside"s}));
  647.     ASSERT_EQUAL(lexer.NextToken(),
  648.                  Token(token_type::String{"another long string with single quote ' inside"s}));
  649. }
  650.  
  651. void TestOperations() {
  652.     istringstream input("+-*/= > < != == <> <= >="s);
  653.     Lexer lexer(input);
  654.  
  655.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Char{'+'}));
  656.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'-'}));
  657.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'*'}));
  658.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'/'}));
  659.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  660.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'>'}));
  661.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'<'}));
  662.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::NotEq{}));
  663.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eq{}));
  664.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'<'}));
  665.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'>'}));
  666.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::LessOrEq{}));
  667.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::GreaterOrEq{}));
  668. }
  669.  
  670. void TestIndentsAndNewlines() {
  671.     istringstream input(R"(
  672. no_indent
  673.  indent_one
  674.    indent_two
  675.      indent_three
  676.      indent_three
  677.      indent_three
  678.    indent_two
  679.  indent_one
  680.    indent_two
  681. no_indent
  682. )"s);
  683.  
  684.     Lexer lexer(input);
  685.  
  686.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Id{"no_indent"s}));
  687.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  688.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  689.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_one"s}));
  690.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  691.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  692.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_two"s}));
  693.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  694.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  695.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_three"s}));
  696.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  697.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_three"s}));
  698.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  699.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_three"s}));
  700.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  701.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  702.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_two"s}));
  703.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  704.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  705.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_one"s}));
  706.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  707.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  708.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"indent_two"s}));
  709.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  710.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  711.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  712.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"no_indent"s}));
  713.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  714.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  715. }
  716.  
  717. void TestEmptyLinesAreIgnored() {
  718.     istringstream input(R"(
  719. x = 1
  720.  y = 2
  721.  
  722.  z = 3
  723.  
  724.  
  725. )"s);
  726.     Lexer lexer(input);
  727.  
  728.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Id{"x"s}));
  729.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  730.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{1}));
  731.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  732.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  733.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"y"s}));
  734.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  735.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{2}));
  736.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  737.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"z"s}));
  738.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  739.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{3}));
  740.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  741.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  742.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  743. }
  744.  
  745. void TestMythonProgram() {
  746.     istringstream input(R"(
  747. x = 4
  748. y = "hello"
  749.  
  750. class Point:
  751.  def __init__(self, x, y):
  752.    self.x = x
  753.    self.y = y
  754.  
  755.  def __str__(self):
  756.    return str(x) + ' ' + str(y)
  757.  
  758. p = Point(1, 2)
  759. print str(p)
  760. )"s);
  761.     Lexer lexer(input);
  762.  
  763.     ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Id{"x"s}));
  764.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  765.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{4}));
  766.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  767.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"y"s}));
  768.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  769.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::String{"hello"s}));
  770.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  771.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Class{}));
  772.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"Point"s}));
  773.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{':'}));
  774.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  775.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  776.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Def{}));
  777.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"__init__"s}));
  778.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'('}));
  779.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"self"s}));
  780.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{','}));
  781.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"x"s}));
  782.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{','}));
  783.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"y"s}));
  784.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{')'}));
  785.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{':'}));
  786.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  787.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  788.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"self"s}));
  789.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'.'}));
  790.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"x"s}));
  791.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  792.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"x"s}));
  793.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  794.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"self"s}));
  795.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'.'}));
  796.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"y"s}));
  797.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  798.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"y"s}));
  799.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  800.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  801.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Def{}));
  802.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"__str__"s}));
  803.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'('}));
  804.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"self"s}));
  805.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{')'}));
  806.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{':'}));
  807.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  808.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Indent{}));
  809.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Return{}));
  810.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"str"s}));
  811.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'('}));
  812.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"x"s}));
  813.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{')'}));
  814.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'+'}));
  815.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::String{" "s}));
  816.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'+'}));
  817.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"str"s}));
  818.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'('}));
  819.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"y"s}));
  820.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{')'}));
  821.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  822.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  823.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Dedent{}));
  824.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"p"s}));
  825.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'='}));
  826.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"Point"s}));
  827.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'('}));
  828.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{1}));
  829.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{','}));
  830.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Number{2}));
  831.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{')'}));
  832.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  833.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Print{}));
  834.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"str"s}));
  835.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{'('}));
  836.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"p"s}));
  837.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Char{')'}));
  838.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  839.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  840.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  841.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  842.     ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  843. }
  844.  
  845. void TestExpect() {
  846.     istringstream is("bugaga"s);
  847.     Lexer lex(is);
  848.  
  849.     ASSERT_DOESNT_THROW(lex.Expect<token_type::Id>());
  850.     ASSERT_EQUAL(lex.Expect<token_type::Id>().value, "bugaga"s);
  851.     ASSERT_DOESNT_THROW(lex.Expect<token_type::Id>("bugaga"s));
  852.     ASSERT_THROWS(lex.Expect<token_type::Id>("widget"s), LexerError);
  853.     ASSERT_THROWS(lex.Expect<token_type::Return>(), LexerError);
  854. }
  855.  
  856. void TestExpectNext() {
  857.     istringstream is("+ bugaga + def 52"s);
  858.     Lexer lex(is);
  859.  
  860.     ASSERT_EQUAL(lex.CurrentToken(), Token(token_type::Char{'+'}));
  861.     ASSERT_DOESNT_THROW(lex.ExpectNext<token_type::Id>());
  862.     ASSERT_DOESNT_THROW(lex.ExpectNext<token_type::Char>('+'));
  863.     ASSERT_THROWS(lex.ExpectNext<token_type::Newline>(), LexerError);
  864.     ASSERT_THROWS(lex.ExpectNext<token_type::Number>(57), LexerError);
  865. }
  866.  
  867. void TestAlwaysEmitsNewlineAtTheEndOfNonemptyLine() {
  868.     {
  869.         istringstream is("a b"s);
  870.         Lexer lexer(is);
  871.  
  872.         ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Id{"a"s}));
  873.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"b"s}));
  874.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  875.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  876.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  877.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  878.     }
  879.     {
  880.         istringstream is("+"s);
  881.         Lexer lexer(is);
  882.  
  883.         ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Char{'+'}));
  884.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  885.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  886.     }
  887. }
  888. void TestCommentsAreIgnored() {
  889.     {
  890.         istringstream is(R"(# comment
  891. )"s);
  892.         Lexer lexer(is);
  893.  
  894.         ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Eof{}));
  895.     }
  896.     {
  897.         istringstream is(R"(# comment
  898.  
  899. )"s);
  900.         Lexer lexer(is);
  901.         ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Eof{}));
  902.     }
  903.     {
  904.         istringstream is(R"(# comment
  905. x #another comment
  906. abc#
  907. '#'
  908. "#123"
  909. #)"s);
  910.  
  911.         Lexer lexer(is);
  912.         ASSERT_EQUAL(lexer.CurrentToken(), Token(token_type::Id{"x"s}));
  913.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  914.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Id{"abc"s}));
  915.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  916.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::String{"#"s}));
  917.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  918.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::String{"#123"s}));
  919.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Newline{}));
  920.         ASSERT_EQUAL(lexer.NextToken(), Token(token_type::Eof{}));
  921.     }
  922. }
  923.    
  924. }//end namespace
  925.  
  926. void RunOpenLexerTests(TestRunner& tr) {
  927.     RUN_TEST(tr, parse::TestSimpleAssignment);
  928.     RUN_TEST(tr, parse::TestKeywords);
  929.     RUN_TEST(tr, parse::TestNumbers);
  930.     RUN_TEST(tr, parse::TestIds);
  931.     RUN_TEST(tr, parse::TestStrings);
  932.     RUN_TEST(tr, parse::TestOperations);
  933.     RUN_TEST(tr, parse::TestIndentsAndNewlines);
  934.     RUN_TEST(tr, parse::TestEmptyLinesAreIgnored);
  935.     RUN_TEST(tr, parse::TestExpect);
  936.     RUN_TEST(tr, parse::TestExpectNext);
  937.     RUN_TEST(tr, parse::TestMythonProgram);
  938.     RUN_TEST(tr, parse::TestAlwaysEmitsNewlineAtTheEndOfNonemptyLine);
  939.     RUN_TEST(tr, parse::TestCommentsAreIgnored);
  940. }
  941.  
  942. }//end namespace parse
  943. -----------------------------------------------------------------------
  944. test_runner_p.h
  945. -----------------------------------------------------------------------
  946. #pragma once
  947.  
  948. #include <iostream>
  949. #include <map>
  950. #include <set>
  951. #include <sstream>
  952. #include <stdexcept>
  953. #include <string>
  954. #include <unordered_map>
  955. #include <vector>
  956.  
  957. namespace TestRunnerPrivate {
  958. template <class Map>
  959. std::ostream& PrintMap(std::ostream& os, const Map& m) {
  960.     os << "{";
  961.     bool first = true;
  962.     for (const auto& kv : m) {
  963.         if (!first) {
  964.             os << ", ";
  965.         }
  966.         first = false;
  967.         os << kv.first << ": " << kv.second;
  968.     }
  969.     return os << "}";
  970. }
  971. }//end namespace TestRunnerPrivate
  972.  
  973. template <class T>
  974. std::ostream& operator<<(std::ostream& os, const std::vector<T>& s) {
  975.     os << "{";
  976.     bool first = true;
  977.     for (const auto& x : s) {
  978.         if (!first) {
  979.             os << ", ";
  980.         }
  981.         first = false;
  982.         os << x;
  983.     }
  984.     return os << "}";
  985. }
  986.  
  987. template <class T>
  988. std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
  989.     os << "{";
  990.     bool first = true;
  991.     for (const auto& x : s) {
  992.         if (!first) {
  993.             os << ", ";
  994.         }
  995.         first = false;
  996.         os << x;
  997.     }
  998.     return os << "}";
  999. }
  1000.  
  1001. template <class K, class V>
  1002. std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {
  1003.     return TestRunnerPrivate::PrintMap(os, m);
  1004. }
  1005.  
  1006. template <class K, class V>
  1007. std::ostream& operator<<(std::ostream& os, const std::unordered_map<K, V>& m) {
  1008.     return TestRunnerPrivate::PrintMap(os, m);
  1009. }
  1010.  
  1011. template <class T, class U>
  1012. void AssertEqual(const T& t, const U& u, const std::string& hint = {}) {
  1013.     if (!(t == u)) {
  1014.         std::ostringstream os;
  1015.         os << "Assertion failed: " << t << " != " << u;
  1016.         if (!hint.empty()) {
  1017.             os << " hint: " << hint;
  1018.         }
  1019.         throw std::runtime_error(os.str());
  1020.     }
  1021. }
  1022.  
  1023. inline void Assert(bool b, const std::string& hint) {
  1024.     AssertEqual(b, true, hint);
  1025. }
  1026.  
  1027. class TestRunner {
  1028. public:
  1029.     template <class TestFunc>
  1030.     void RunTest(TestFunc func, const std::string& test_name) {
  1031.         try {
  1032.             func();
  1033.             std::cerr << test_name << " OK" << std::endl;
  1034.         } catch (std::exception& e) {
  1035.             ++fail_count;
  1036.             std::cerr << test_name << " fail: " << e.what() << std::endl;
  1037.         } catch (...) {
  1038.             ++fail_count;
  1039.             std::cerr << "Unknown exception caught" << std::endl;
  1040.         }
  1041.     }
  1042.  
  1043.     ~TestRunner() {
  1044.         std::cerr.flush();
  1045.         if (fail_count > 0) {
  1046.             std::cerr << fail_count << " unit tests failed. Terminate" << std::endl;
  1047.             exit(1);
  1048.         }
  1049.     }
  1050.  
  1051. private:
  1052.     int fail_count = 0;
  1053. };
  1054.  
  1055. #ifndef FILE_NAME
  1056. #define FILE_NAME __FILE__
  1057. #endif
  1058.  
  1059. #define ASSERT_EQUAL(x, y)                                                                       \
  1060.     {                                                                                            \
  1061.         std::ostringstream __assert_equal_private_os;                                            \
  1062.         __assert_equal_private_os << #x << " != " << #y << ", " << FILE_NAME << ":" << __LINE__; \
  1063.         AssertEqual(x, y, __assert_equal_private_os.str());                                      \
  1064.     }
  1065.  
  1066. #define ASSERT(x)                                                                   \
  1067.     {                                                                               \
  1068.         std::ostringstream __assert_private_os;                                     \
  1069.         __assert_private_os << #x << " is false, " << FILE_NAME << ":" << __LINE__; \
  1070.         Assert(static_cast<bool>(x), __assert_private_os.str());                    \
  1071.     }
  1072.  
  1073. #define RUN_TEST(tr, func) tr.RunTest(func, #func)
  1074.  
  1075. #define ASSERT_THROWS(expr, expected_exception)                                                   \
  1076.     {                                                                                             \
  1077.         bool __assert_private_flag = true;                                                        \
  1078.         try {                                                                                     \
  1079.             expr;                                                                                 \
  1080.             __assert_private_flag = false;                                                        \
  1081.         } catch (expected_exception&) {                                                           \
  1082.         } catch (...) {                                                                           \
  1083.             std::ostringstream __assert_private_os;                                               \
  1084.             __assert_private_os << "Expression " #expr                                            \
  1085.                                    " threw an unexpected exception"                               \
  1086.                                    " " FILE_NAME ":"                                              \
  1087.                                 << __LINE__;                                                      \
  1088.             Assert(false, __assert_private_os.str());                                             \
  1089.         }                                                                                         \
  1090.         if (!__assert_private_flag) {                                                             \
  1091.             std::ostringstream __assert_private_os;                                               \
  1092.             __assert_private_os << "Expression " #expr                                            \
  1093.                                    " is expected to throw " #expected_exception " " FILE_NAME ":" \
  1094.                                 << __LINE__;                                                      \
  1095.             Assert(false, __assert_private_os.str());                                             \
  1096.         }                                                                                         \
  1097.     }
  1098.  
  1099. #define ASSERT_DOESNT_THROW(expr)                               \
  1100.     try {                                                       \
  1101.         expr;                                                   \
  1102.     } catch (...) {                                             \
  1103.         std::ostringstream __assert_private_os;                 \
  1104.         __assert_private_os << "Expression " #expr              \
  1105.                                " threw an unexpected exception" \
  1106.                                " " FILE_NAME ":"                \
  1107.                             << __LINE__;                        \
  1108.         Assert(false, __assert_private_os.str());               \
  1109.     }
  1110.  
  1111. #define EOF_GUARD
Advertisement
Add Comment
Please, Sign In to add comment