/** @file TkInputState.cpp * * @author Roland Conybeare, Jun 2025 **/ #include "TkInputState.hpp" namespace xo { namespace scm { using CharT = char; bool TkInputState::is_newline(CharT ch) { return (ch == '\n'); } bool TkInputState::is_whitespace(CharT ch) { switch(ch) { case ' ': return true; case '\t': return true; case '\n': return true; case '\r': return true; } return false; } TkInputState TkInputState::rewind(std::size_t n) const { return TkInputState(this->current_line_, (n <= current_pos_) ? current_pos_ - n : 0, 0 /*whitespace*/); } void TkInputState::advance(size_t z) { scope log(XO_DEBUG(debug_flag_)); this->current_pos_ += z; log && log(xtag("z", z), xtag("current_pos", current_pos_)); } void TkInputState::advance_until(const CharT * pos) { scope log(XO_DEBUG(debug_flag_)); assert(current_line_.lo() <= pos && pos <= current_line_.hi()); this->current_pos_ = pos - current_line_.lo(); log && log(xtag("current_pos", current_pos_)); } auto TkInputState::consume_current_line() -> span_type { span_type retval = current_line_; this->discard_current_line(); return retval; } void TkInputState::discard_current_line() { this->current_line_ = span_type::make_null(); this->current_pos_ = 0; this->whitespace_ = 0; } auto TkInputState::capture_current_line(const span_type & input, bool eof_flag) -> std::pair { // see also discard_current_line() // note: must capture entirety of first line, // for example including leading whitespace. // See discussion in tokenizer scan() method scope log(XO_DEBUG(debug_flag_), xtag("input", input)); /* look ahead to {end of line, end of input}, whichever comes first */ const CharT * sol = input.lo(); const CharT * eol = sol; if (sol == current_line_.lo()) { log && log("short-circuit - current line already stashed"); /* nothing to do here */ return std::make_pair(input_error::ok, current_line_); } while ((eol < input.hi()) && (*eol != '\n')) ++eol; if (*eol == '\n') { /* include \n at end-of-line */ ++eol; } else { if (!eof_flag) { /* caller expected to provide complete line of input. complain and ignore */ return std::make_pair(input_error::incomplete, input.prefix(0ul)); } } this->current_line_ = span_type(sol, eol); this->current_pos_ = 0; this->whitespace_ = 0; log && log(xtag("current_line", print::printspan(current_line_)), xtag("current_pos", current_pos_)); return std::make_pair(input_error::ok, span_type(sol, eol)); } const CharT * TkInputState::skip_leading_whitespace() { scope log(XO_DEBUG(debug_flag_)); const CharT * ix = current_line_.lo() + current_pos_; this->whitespace_ = 0; /* skip whitespace + remember beginning of most recent line */ while (is_whitespace(*ix) && (ix != current_line_.hi())) { ++ix; ++(this->whitespace_); } this->tk_start_ = ix - current_line_.lo(); this->current_pos_ = ix - current_line_.lo(); return ix; } } /*namespace scm*/ } /*namespace xo*/ /* end TkInputState.cpp */