Echo Writes Code

text.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "crucible/parsing/text.hpp"

#include <sstream>

namespace crucible::parsing::text {
  TextState::TextState(std::u8string_view const &input) :
    my_input(input) {
  }

  TextState::TextState(std::u8string_view const &input, std::size_t const code_unit_offset) :
    my_input(input),
    my_code_unit_offset(code_unit_offset) {
  }

  auto TextState::is_finished() const -> bool {
    return my_code_unit_offset >= my_input.size();
  }

  auto TextState::get_remaining_code_units_in_input() const -> std::u8string_view {
    return my_input.substr(my_code_unit_offset);
  }

  auto TextState::advance_by_code_units(std::size_t const code_unit_count) const -> TextState {
    return TextState { my_input, my_code_unit_offset + code_unit_count };
  }

  auto TextState::format_location() const -> std::string {
    std::ostringstream buffer;

    buffer
      << "{ \"source_type\" : \"text\", \"code_unit\" : "
      << my_code_unit_offset
      << " }";

    return buffer.str();
  }

  CharacterSequence::CharacterSequence(std::u8string_view const &character_sequence) :
    my_character_sequence(character_sequence) {
  }

  auto CharacterSequence::operator()(StateType const &state) const -> ResultType {
    auto const &remaining_code_units = state.get_remaining_code_units_in_input();

    if (remaining_code_units.size() < my_character_sequence.size()) {
      return result::reject(state, TextError { CharacterSequenceMismatch {} });
    }

    auto const sequence_begin = my_character_sequence.begin();
    auto const sequence_end = my_character_sequence.end();
    auto const input_begin = remaining_code_units.begin();
    bool const is_equal = std::equal(sequence_begin, sequence_end, input_begin);

    if (is_equal) {
      auto const next_state = state.advance_by_code_units(my_character_sequence.size());
      return result::accept(next_state, core::none::None {});
    } else {
      return result::reject(state, TextError { CharacterSequenceMismatch {} });
    }
  }
}