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::string_view const &input) :
    my_input { input } {
  }

  TextState::TextState(std::string_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::string_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::string_view 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 errors::make_reject(state, errors::UnexpectedEndOfInput {});
    }

    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 errors::make_accept(next_state, core::none::None {});
    } else {
      return errors::make_reject(state, errors::UnexpectedInput {});
    }
  }
}