#include "bed.h" #include "internal/parser/parser.h" namespace bed::internal::parser { void Parser::locator(AddressPromise &addr) { addr.base = AddressPromise::None{}; switch (peek()) { case '.': token(io::Token::AddressSymbol); advance(); end_token(); addr.base = AddressPromise::Current{}; break; case '$': token(io::Token::AddressSymbol); advance(); end_token(); addr.base = AddressPromise::Last{}; break; case '%': token(io::Token::AddressSymbol); advance(); end_token(); addr.base = AddressPromise::LastRange{}; break; case '[': token(io::Token::AddressSymbol); advance(); end_token(); addr.base = AddressPromise::Block{Direction::Backward}; break; case ']': token(io::Token::AddressSymbol); advance(); end_token(); addr.base = AddressPromise::Block{Direction::Forward}; break; case '^': token(io::Token::AddressSymbol); advance(); end_token(); addr.base = AddressPromise::Diagnostic{Direction::Backward}; break; case '~': token(io::Token::AddressSymbol); advance(); end_token(); addr.base = AddressPromise::Diagnostic{Direction::Forward}; break; case '\'': token(io::Token::Mark); advance(); if (('a' <= peek() && peek() <= 'z') || ('A' <= peek() && peek() <= 'Z')) addr.base = AddressPromise::Mark{peek()}; else throw ed_error("Valid mark needed after \'"); advance(); end_token(); break; case '{': { token(io::Token::AddressSymbol); advance(); end_token(); uint16_t j = 0; std::string func; std::string arg; token(io::Token::RubyFunction); while (peek(j) != '}') { if (peek(j) == '\0') throw ed_error("Scripted address not terminated"); if (peek(j) == '\\') ++j; if (peek(j) == ':') { func = peek_str(j); advance(j + 1); end_token(); token(io::Token::RubyArg); j = 0; continue; } ++j; } if (func.size()) arg = peek_str(j); else func = peek_str(j); addr.base = AddressPromise::Scripted{std::move(func), std::move(arg)}; advance(j); end_token(); token(io::Token::AddressSymbol); advance(); end_token(); } break; case '/': { token(io::Token::Regexp); advance(); uint64_t j = 0; while (true) { if (peek(j) == '\0') break; if (peek(j) == '/') break; else if (peek(j) == '\\') j += 2; else if (peek(j) == '[') while (peek(j) != '\0' && cmd[i] != ']') j++; else j++; } addr.base = AddressPromise::Regex( Direction::Forward, std::string(peek_str(j)) ); advance(j + 1); end_token(); } break; case '?': { token(io::Token::Regexp); advance(); uint16_t j = 0; while (true) { if (peek(j) == '\0') break; if (peek(j) == '?') break; else if (peek(j) == '\\') j += 2; else if (peek(j) == '[') while (peek(j) != '\0' && cmd[i] != ']') j++; else j++; } addr.base = AddressPromise::Regex( Direction::Backward, std::string(peek_str(j)) ); advance(j + 1); end_token(); } break; case '<': { token(io::Token::Label); advance(); uint16_t j = 0; while (peek(j) != '>' && peek(j) != '<' && peek(j) != '\0') j++; switch (peek(j)) { case '\0': case '>': addr.base = AddressPromise::SymbolDefinition{ std::string(peek_str(j)) }; break; case '<': addr.base = AddressPromise::SymbolReference{ Direction::Backward, std::string(peek_str(j)) }; break; } advance(j + 1); end_token(); } break; case '>': { token(io::Token::Label); advance(); uint16_t j = 0; while (peek(j) != '>' && peek(j) != '\0') j++; switch (peek(j)) { case '\0': throw ed_error("Unterminated symbol reference addressing."); case '>': addr.base = AddressPromise::SymbolReference{ Direction::Forward, std::string(peek_str(j)) }; break; } advance(j + 1); end_token(); } break; case '+': { token(io::Token::AddressSymbol); advance(); end_token(); token(io::Token::Number); addr.base = AddressPromise::Current{}; uint16_t j = 0; uint64_t num = 0; while ('0' <= peek(j) && peek(j) <= '9') { num = num * 10 + (peek(j) - '0'); j++; } if (j == 0) num = 1; addr.offset += num; advance(j); end_token(); } break; case '-': { token(io::Token::AddressSymbol); advance(); end_token(); token(io::Token::Number); addr.base = AddressPromise::Current{}; uint16_t j = 0; uint64_t num = 0; while ('0' <= peek(j) && peek(j) <= '9') { num = num * 10 + (peek(j) - '0'); j++; } if (j == 0) num = 1; addr.offset -= num; advance(j); end_token(); } break; default: if ('0' <= peek() && peek() <= '9') { token(io::Token::Number); uint64_t num = 0; while ('0' <= peek() && peek() <= '9') { num = num * 10 + (peek() - '0'); advance(); } addr.base = AddressPromise::Number{num}; end_token(); } } } int64_t Parser::offset() { int64_t offset = 0; while (peek() == '+' || peek() == '-' || ('0' <= peek() && peek() <= '9')) { bool positive = peek() != '-'; token(io::Token::AddressSymbol); if (peek() == '+' || peek() == '-') advance(); end_token(); token(io::Token::Number); uint16_t j = 0; int64_t num = 0; while ('0' <= peek(j) && peek(j) <= '9') num = num * 10 + (peek(j++) - '0'); if (j == 0) num = 1; advance(j); end_token(); offset += positive ? num : -num; skip_ws(); } skip_ws(); return offset; } void Parser::address(AddressPromise &addr) { if (peek() == ':') { token(io::Token::BufferName); advance(); uint16_t j = 0; while (peek(j) != ':' && peek(j) != '\0') j++; addr.bufname = peek_str(j); advance(j); if (peek() == ':') advance(); end_token(); } skip_ws(); if (peek() == '\0') return; locator(addr); skip_ws(); addr.offset += offset(); } void Parser::addresses(std::vector &addresses) { skip_ws(); addresses.push_back({}); auto *addr = &addresses.back(); address(*addr); while (peek() == ',' || peek() == ';') { addr->jumping = peek() == ';'; token(io::Token::AddressSeperator); advance(); skip_ws(); addresses.push_back({}); addr = &addresses.back(); address(*addr); } if (addresses.size() == 1 && addr->offset == 0 && !addr->bufname.has_value() && std::holds_alternative(addr->base)) addresses.pop_back(); } } // namespace bed::internal::parser