xo-umbrella2/xo-tokenizer2/src/tokenizer2/TkInputState.cpp

152 lines
4.2 KiB
C++

/** @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<input_error, span_type>
{
// 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 */