Update the layout tool, to support multi-line strings
This commit is contained in:
parent
425985cfe4
commit
8d8f2e236a
2 changed files with 290 additions and 234 deletions
|
|
@ -52,6 +52,52 @@ static Metadata metadata_from_comment(absl::string_view comment)
|
|||
return md;
|
||||
}
|
||||
|
||||
///
|
||||
static std::string cstrQuote(absl::string_view text)
|
||||
{
|
||||
std::string cstr;
|
||||
cstr.reserve(2 * text.size() + 2);
|
||||
|
||||
cstr.push_back('"');
|
||||
|
||||
for (char c : text) {
|
||||
switch (c) {
|
||||
case '\a' :
|
||||
cstr.append("\\a");
|
||||
break;
|
||||
case '\b' :
|
||||
cstr.append("\\b");
|
||||
break;
|
||||
case '\t' :
|
||||
cstr.append("\\t");
|
||||
break;
|
||||
case '\n' :
|
||||
cstr.append("\\n");
|
||||
break;
|
||||
case '\v' :
|
||||
cstr.append("\\v");
|
||||
break;
|
||||
case '\f' :
|
||||
cstr.append("\\f");
|
||||
break;
|
||||
case '\r' :
|
||||
cstr.append("\\r");
|
||||
break;
|
||||
case '"':
|
||||
case '\\':
|
||||
cstr.push_back('\\');
|
||||
cstr.push_back(c);
|
||||
break;
|
||||
default:
|
||||
cstr.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cstr.push_back('"');
|
||||
return cstr;
|
||||
}
|
||||
|
||||
///
|
||||
static void codegen_item(int& idCounter, int parentId, int parentX, int parentY, const LayoutItem& item, absl::string_view oldTheme)
|
||||
{
|
||||
|
|
@ -95,7 +141,7 @@ static void codegen_item(int& idCounter, int parentId, int parentX, int parentY,
|
|||
else if (item.align & 8)
|
||||
align = "kRightText";
|
||||
|
||||
std::cout << "auto"/*item.classname*/ << "* const view__" << id << " = create" << item.classname << "(CRect(" << relX << ", " << relY << ", " << (relX + item.w) << ", " << (relY + item.h) << "), " << tag << ", \"" << label << "\", " << align << ", " << item.labelsize << ");\n";
|
||||
std::cout << "auto"/*item.classname*/ << "* const view__" << id << " = create" << item.classname << "(CRect(" << relX << ", " << relY << ", " << (relX + item.w) << ", " << (relY + item.h) << "), " << tag << ", " << cstrQuote(label) << ", " << align << ", " << item.labelsize << ");\n";
|
||||
|
||||
if (!item.id.empty())
|
||||
std::cout << item.id << " = view__" << id << ";\n";
|
||||
|
|
|
|||
|
|
@ -11,214 +11,6 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef std::vector<std::string> TokenList;
|
||||
static bool read_file_tokens(const char *filename, TokenList &tokens);
|
||||
static Layout read_tokens_layout(TokenList::iterator &tok_it, TokenList::iterator tok_end);
|
||||
|
||||
Layout read_file_layout(const char *filename)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
if (!read_file_tokens(filename, tokens))
|
||||
throw std::runtime_error("Cannot read fluid design file.");
|
||||
|
||||
TokenList::iterator tok_it = tokens.begin();
|
||||
TokenList::iterator tok_end = tokens.end();
|
||||
return read_tokens_layout(tok_it, tok_end);
|
||||
}
|
||||
|
||||
static std::string consume_next_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
if (tok_it == tok_end)
|
||||
throw file_format_error("Premature end of tokens");
|
||||
return *tok_it++;
|
||||
}
|
||||
|
||||
static bool try_consume_next_token(const char *text, TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
if (tok_it == tok_end)
|
||||
return false;
|
||||
|
||||
if (*tok_it != text)
|
||||
return false;
|
||||
|
||||
++tok_it;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ensure_next_token(const char *text, TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
std::string tok = consume_next_token(tok_it, tok_end);
|
||||
if (tok != text)
|
||||
throw file_format_error("Unexpected token: " + tok);
|
||||
}
|
||||
|
||||
static std::string consume_enclosed_string(TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
ensure_next_token("{", tok_it, tok_end);
|
||||
unsigned depth = 1;
|
||||
|
||||
std::string text;
|
||||
for (;;) {
|
||||
std::string part = consume_next_token(tok_it, tok_end);
|
||||
if (part == "}") {
|
||||
if (--depth == 0)
|
||||
return text;
|
||||
}
|
||||
else if (part == "{")
|
||||
++depth;
|
||||
if (!text.empty())
|
||||
text.push_back(' ');
|
||||
text.append(part);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static std::string consume_any_string(TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
if (tok_it != tok_end && *tok_it == "{")
|
||||
return consume_enclosed_string(tok_it, tok_end);
|
||||
else
|
||||
return consume_next_token(tok_it, tok_end);
|
||||
}
|
||||
|
||||
static int consume_int_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
std::string text = consume_next_token(tok_it, tok_end);
|
||||
return std::stoi(text);
|
||||
}
|
||||
|
||||
static int consume_real_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
std::string text = consume_next_token(tok_it, tok_end);
|
||||
return std::stod(text);
|
||||
}
|
||||
|
||||
static void consume_layout_item_properties(LayoutItem &item, TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
ensure_next_token("{", tok_it, tok_end);
|
||||
for (bool have = true; have;) {
|
||||
if (try_consume_next_token("open", tok_it, tok_end))
|
||||
; // skip
|
||||
else if (try_consume_next_token("selected", tok_it, tok_end))
|
||||
; // skip
|
||||
else if (try_consume_next_token("label", tok_it, tok_end))
|
||||
item.label = consume_any_string(tok_it, tok_end);
|
||||
else if (try_consume_next_token("xywh", tok_it, tok_end)) {
|
||||
ensure_next_token("{", tok_it, tok_end);
|
||||
item.x = consume_int_token(tok_it, tok_end);
|
||||
item.y = consume_int_token(tok_it, tok_end);
|
||||
item.w = consume_int_token(tok_it, tok_end);
|
||||
item.h = consume_int_token(tok_it, tok_end);
|
||||
ensure_next_token("}", tok_it, tok_end);
|
||||
}
|
||||
else if (try_consume_next_token("box", tok_it, tok_end))
|
||||
item.box = consume_next_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("down_box", tok_it, tok_end))
|
||||
item.down_box = consume_next_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("labelfont", tok_it, tok_end))
|
||||
item.labelfont = consume_int_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("labelsize", tok_it, tok_end))
|
||||
item.labelsize = consume_int_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("labeltype", tok_it, tok_end))
|
||||
item.labeltype = consume_any_string(tok_it, tok_end);
|
||||
else if (try_consume_next_token("textsize", tok_it, tok_end))
|
||||
item.textsize = consume_int_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("align", tok_it, tok_end))
|
||||
item.align = consume_int_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("type", tok_it, tok_end))
|
||||
item.type = consume_any_string(tok_it, tok_end);
|
||||
else if (try_consume_next_token("callback", tok_it, tok_end))
|
||||
item.callback = consume_any_string(tok_it, tok_end);
|
||||
else if (try_consume_next_token("class", tok_it, tok_end))
|
||||
item.classname = consume_any_string(tok_it, tok_end);
|
||||
else if (try_consume_next_token("value", tok_it, tok_end))
|
||||
item.value = consume_real_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("minimum", tok_it, tok_end))
|
||||
item.minimum = consume_real_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("maximum", tok_it, tok_end))
|
||||
item.maximum = consume_real_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("step", tok_it, tok_end))
|
||||
item.step = consume_real_token(tok_it, tok_end);
|
||||
else if (try_consume_next_token("image", tok_it, tok_end))
|
||||
item.image.filepath = consume_any_string(tok_it, tok_end);
|
||||
else if (try_consume_next_token("hide", tok_it, tok_end))
|
||||
item.hidden = true;
|
||||
else if (try_consume_next_token("visible", tok_it, tok_end))
|
||||
/* skip */;
|
||||
else if (try_consume_next_token("comment", tok_it, tok_end))
|
||||
item.comment = consume_any_string(tok_it, tok_end);
|
||||
else
|
||||
have = false;
|
||||
}
|
||||
ensure_next_token("}", tok_it, tok_end);
|
||||
}
|
||||
|
||||
static LayoutItem consume_layout_item(const std::string &classname, TokenList::iterator &tok_it, TokenList::iterator tok_end, bool anonymous = false)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.classname = classname;
|
||||
if (!anonymous)
|
||||
item.id = consume_any_string(tok_it, tok_end);
|
||||
consume_layout_item_properties(item, tok_it, tok_end);
|
||||
if (tok_it != tok_end && *tok_it == "{") {
|
||||
consume_next_token(tok_it, tok_end);
|
||||
for (std::string text; (text = consume_next_token(tok_it, tok_end)) != "}";) {
|
||||
if (text == "decl") {
|
||||
consume_any_string(tok_it, tok_end);
|
||||
consume_any_string(tok_it, tok_end);
|
||||
}
|
||||
else if (text == "Function") {
|
||||
consume_any_string(tok_it, tok_end);
|
||||
consume_any_string(tok_it, tok_end);
|
||||
consume_any_string(tok_it, tok_end);
|
||||
}
|
||||
else
|
||||
item.items.push_back(consume_layout_item(text, tok_it, tok_end));
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static Layout read_tokens_layout(TokenList::iterator &tok_it, TokenList::iterator tok_end)
|
||||
{
|
||||
Layout layout;
|
||||
|
||||
std::string version_name;
|
||||
std::string header_name;
|
||||
std::string code_name;
|
||||
|
||||
while (tok_it != tok_end) {
|
||||
std::string key = consume_next_token(tok_it, tok_end);
|
||||
|
||||
if (key == "version")
|
||||
version_name = consume_next_token(tok_it, tok_end);
|
||||
else if (key == "header_name") {
|
||||
ensure_next_token("{", tok_it, tok_end);
|
||||
header_name = consume_next_token(tok_it, tok_end);
|
||||
ensure_next_token("}", tok_it, tok_end);
|
||||
}
|
||||
else if (key == "code_name") {
|
||||
ensure_next_token("{", tok_it, tok_end);
|
||||
code_name = consume_next_token(tok_it, tok_end);
|
||||
ensure_next_token("}", tok_it, tok_end);
|
||||
}
|
||||
else if (key == "decl") {
|
||||
consume_any_string(tok_it, tok_end);
|
||||
consume_any_string(tok_it, tok_end);
|
||||
}
|
||||
else if (key == "widget_class") {
|
||||
key = consume_next_token(tok_it, tok_end);
|
||||
layout.items.push_back(consume_layout_item(key, tok_it, tok_end, true));
|
||||
layout.items.back().id = key;
|
||||
}
|
||||
else
|
||||
layout.items.push_back(consume_layout_item(key, tok_it, tok_end));
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
///
|
||||
class tokenizer {
|
||||
public:
|
||||
|
|
@ -227,7 +19,21 @@ public:
|
|||
absl::string_view dropped_delims,
|
||||
absl::string_view kept_delims);
|
||||
|
||||
absl::string_view next();
|
||||
absl::string_view next(bool consume);
|
||||
std::string string_until(char closing, bool consume);
|
||||
bool at_end() const;
|
||||
|
||||
private:
|
||||
bool is_dropped(char c) const {
|
||||
return dropped_delims_.find(c) != dropped_delims_.npos;
|
||||
}
|
||||
bool is_kept(char c) const {
|
||||
return kept_delims_.find(c) != kept_delims_.npos;
|
||||
}
|
||||
bool is_delim(char c) const {
|
||||
return dropped_delims_.find(c) != dropped_delims_.npos ||
|
||||
kept_delims_.find(c) != kept_delims_.npos;
|
||||
}
|
||||
|
||||
private:
|
||||
absl::string_view text_;
|
||||
|
|
@ -243,19 +49,8 @@ tokenizer::tokenizer(
|
|||
{
|
||||
}
|
||||
|
||||
absl::string_view tokenizer::next()
|
||||
absl::string_view tokenizer::next(bool consume)
|
||||
{
|
||||
auto is_dropped = [this](char c) -> bool {
|
||||
return dropped_delims_.find(c) != dropped_delims_.npos;
|
||||
};
|
||||
auto is_kept = [this](char c) -> bool {
|
||||
return kept_delims_.find(c) != kept_delims_.npos;
|
||||
};
|
||||
auto is_delim = [this](char c) -> bool {
|
||||
return dropped_delims_.find(c) != dropped_delims_.npos ||
|
||||
kept_delims_.find(c) != kept_delims_.npos;
|
||||
};
|
||||
|
||||
absl::string_view text = text_;
|
||||
|
||||
while (!text.empty() && is_dropped(text[0]))
|
||||
|
|
@ -266,7 +61,7 @@ absl::string_view tokenizer::next()
|
|||
|
||||
size_t pos;
|
||||
{
|
||||
auto it = std::find_if(text.begin(), text.end(), is_delim);
|
||||
auto it = std::find_if(text.begin(), text.end(), [this](char c) -> bool { return is_delim(c); });
|
||||
if (it == text.end())
|
||||
pos = text.size();
|
||||
else {
|
||||
|
|
@ -276,17 +71,240 @@ absl::string_view tokenizer::next()
|
|||
}
|
||||
|
||||
absl::string_view token = text.substr(0, pos);
|
||||
text_ = text.substr(pos);
|
||||
if (consume)
|
||||
text_ = text.substr(pos);
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string tokenizer::string_until(char closing, bool consume)
|
||||
{
|
||||
absl::string_view text = text_;
|
||||
std::string result;
|
||||
|
||||
result.reserve(256);
|
||||
|
||||
for (char c; !text.empty() &&
|
||||
((c = text[0]), text.remove_prefix(1), c != closing); ) {
|
||||
if (c != '\\')
|
||||
result.push_back(c);
|
||||
else {
|
||||
if (!text.empty()) {
|
||||
c = text[0];
|
||||
text.remove_prefix(1);
|
||||
result.push_back(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (consume)
|
||||
text_ = text;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool tokenizer::at_end() const
|
||||
{
|
||||
absl::string_view text = text_;
|
||||
|
||||
while (!text.empty() && is_dropped(text[0]))
|
||||
text.remove_prefix(1);
|
||||
|
||||
return text.empty();
|
||||
}
|
||||
|
||||
///
|
||||
static bool read_file_tokens(const char *filename, TokenList &tokens)
|
||||
typedef std::vector<std::string> TokenList;
|
||||
static bool read_file_lines(const char *filename, std::string &text);
|
||||
static Layout read_tokens_layout(tokenizer &tkzr);
|
||||
|
||||
Layout read_file_layout(const char *filename)
|
||||
{
|
||||
std::string text;
|
||||
if (!read_file_lines(filename, text))
|
||||
throw std::runtime_error("Cannot read fluid design file.");
|
||||
|
||||
tokenizer tok(text, " \t\r\n", "{}");
|
||||
return read_tokens_layout(tok);
|
||||
}
|
||||
|
||||
static std::string consume_next_token(tokenizer &tkzr)
|
||||
{
|
||||
if (tkzr.at_end())
|
||||
throw file_format_error("Premature end of tokens");
|
||||
return std::string(tkzr.next(true));
|
||||
}
|
||||
|
||||
static bool try_consume_next_token(const char *text, tokenizer &tkzr)
|
||||
{
|
||||
if (tkzr.at_end())
|
||||
return false;
|
||||
|
||||
if (tkzr.next(false) != text)
|
||||
return false;
|
||||
|
||||
tkzr.next(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ensure_next_token(const char *text, tokenizer &tkzr)
|
||||
{
|
||||
std::string tok = consume_next_token(tkzr);
|
||||
if (tok != text)
|
||||
throw file_format_error("Unexpected token: " + tok);
|
||||
}
|
||||
|
||||
static std::string consume_any_string(tokenizer &tkzr)
|
||||
{
|
||||
if (!tkzr.at_end() && tkzr.next(false) == "{") {
|
||||
tkzr.next(true);
|
||||
return tkzr.string_until('}', true);
|
||||
}
|
||||
else
|
||||
return consume_next_token(tkzr);
|
||||
}
|
||||
|
||||
static int consume_int_token(tokenizer &tkzr)
|
||||
{
|
||||
std::string text = consume_next_token(tkzr);
|
||||
return std::stoi(text);
|
||||
}
|
||||
|
||||
static int consume_real_token(tokenizer &tkzr)
|
||||
{
|
||||
std::string text = consume_next_token(tkzr);
|
||||
return std::stod(text);
|
||||
}
|
||||
|
||||
static void consume_layout_item_properties(LayoutItem &item, tokenizer &tkzr)
|
||||
{
|
||||
ensure_next_token("{", tkzr);
|
||||
for (bool have = true; have;) {
|
||||
if (try_consume_next_token("open", tkzr))
|
||||
; // skip
|
||||
else if (try_consume_next_token("selected", tkzr))
|
||||
; // skip
|
||||
else if (try_consume_next_token("label", tkzr))
|
||||
item.label = consume_any_string(tkzr);
|
||||
else if (try_consume_next_token("xywh", tkzr)) {
|
||||
ensure_next_token("{", tkzr);
|
||||
item.x = consume_int_token(tkzr);
|
||||
item.y = consume_int_token(tkzr);
|
||||
item.w = consume_int_token(tkzr);
|
||||
item.h = consume_int_token(tkzr);
|
||||
ensure_next_token("}", tkzr);
|
||||
}
|
||||
else if (try_consume_next_token("box", tkzr))
|
||||
item.box = consume_next_token(tkzr);
|
||||
else if (try_consume_next_token("down_box", tkzr))
|
||||
item.down_box = consume_next_token(tkzr);
|
||||
else if (try_consume_next_token("labelfont", tkzr))
|
||||
item.labelfont = consume_int_token(tkzr);
|
||||
else if (try_consume_next_token("labelsize", tkzr))
|
||||
item.labelsize = consume_int_token(tkzr);
|
||||
else if (try_consume_next_token("labeltype", tkzr))
|
||||
item.labeltype = consume_any_string(tkzr);
|
||||
else if (try_consume_next_token("textsize", tkzr))
|
||||
item.textsize = consume_int_token(tkzr);
|
||||
else if (try_consume_next_token("align", tkzr))
|
||||
item.align = consume_int_token(tkzr);
|
||||
else if (try_consume_next_token("type", tkzr))
|
||||
item.type = consume_any_string(tkzr);
|
||||
else if (try_consume_next_token("callback", tkzr))
|
||||
item.callback = consume_any_string(tkzr);
|
||||
else if (try_consume_next_token("class", tkzr))
|
||||
item.classname = consume_any_string(tkzr);
|
||||
else if (try_consume_next_token("value", tkzr))
|
||||
item.value = consume_real_token(tkzr);
|
||||
else if (try_consume_next_token("minimum", tkzr))
|
||||
item.minimum = consume_real_token(tkzr);
|
||||
else if (try_consume_next_token("maximum", tkzr))
|
||||
item.maximum = consume_real_token(tkzr);
|
||||
else if (try_consume_next_token("step", tkzr))
|
||||
item.step = consume_real_token(tkzr);
|
||||
else if (try_consume_next_token("image", tkzr))
|
||||
item.image.filepath = consume_any_string(tkzr);
|
||||
else if (try_consume_next_token("hide", tkzr))
|
||||
item.hidden = true;
|
||||
else if (try_consume_next_token("visible", tkzr))
|
||||
/* skip */;
|
||||
else if (try_consume_next_token("comment", tkzr))
|
||||
item.comment = consume_any_string(tkzr);
|
||||
else
|
||||
have = false;
|
||||
}
|
||||
ensure_next_token("}", tkzr);
|
||||
}
|
||||
|
||||
static LayoutItem consume_layout_item(const std::string &classname, tokenizer &tkzr, bool anonymous = false)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.classname = classname;
|
||||
if (!anonymous)
|
||||
item.id = consume_any_string(tkzr);
|
||||
consume_layout_item_properties(item, tkzr);
|
||||
if (!tkzr.at_end() && tkzr.next(false) == "{") {
|
||||
consume_next_token(tkzr);
|
||||
for (std::string text; (text = consume_next_token(tkzr)) != "}";) {
|
||||
if (text == "decl") {
|
||||
consume_any_string(tkzr);
|
||||
consume_any_string(tkzr);
|
||||
}
|
||||
else if (text == "Function") {
|
||||
consume_any_string(tkzr);
|
||||
consume_any_string(tkzr);
|
||||
consume_any_string(tkzr);
|
||||
}
|
||||
else
|
||||
item.items.push_back(consume_layout_item(text, tkzr));
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static Layout read_tokens_layout(tokenizer &tkzr)
|
||||
{
|
||||
Layout layout;
|
||||
|
||||
std::string version_name;
|
||||
std::string header_name;
|
||||
std::string code_name;
|
||||
|
||||
while (!tkzr.at_end()) {
|
||||
std::string key = consume_next_token(tkzr);
|
||||
|
||||
if (key == "version")
|
||||
version_name = consume_next_token(tkzr);
|
||||
else if (key == "header_name") {
|
||||
ensure_next_token("{", tkzr);
|
||||
header_name = consume_next_token(tkzr);
|
||||
ensure_next_token("}", tkzr);
|
||||
}
|
||||
else if (key == "code_name") {
|
||||
ensure_next_token("{", tkzr);
|
||||
code_name = consume_next_token(tkzr);
|
||||
ensure_next_token("}", tkzr);
|
||||
}
|
||||
else if (key == "decl") {
|
||||
consume_any_string(tkzr);
|
||||
consume_any_string(tkzr);
|
||||
}
|
||||
else if (key == "widget_class") {
|
||||
key = consume_next_token(tkzr);
|
||||
layout.items.push_back(consume_layout_item(key, tkzr, true));
|
||||
layout.items.back().id = key;
|
||||
}
|
||||
else
|
||||
layout.items.push_back(consume_layout_item(key, tkzr));
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
///
|
||||
static bool read_file_lines(const char *filename, std::string &text)
|
||||
{
|
||||
std::ifstream stream(filename);
|
||||
std::string line;
|
||||
|
||||
std::string text;
|
||||
while (std::getline(stream, line)) {
|
||||
if (!line.empty() && line[0] != '#') {
|
||||
text.append(line);
|
||||
|
|
@ -294,13 +312,5 @@ static bool read_file_tokens(const char *filename, TokenList &tokens)
|
|||
}
|
||||
}
|
||||
|
||||
if (stream.bad())
|
||||
return false;
|
||||
|
||||
tokenizer tok(text, " \t\r\n", "{}");
|
||||
absl::string_view token;
|
||||
while (!(token = tok.next()).empty())
|
||||
tokens.emplace_back(token);
|
||||
|
||||
return !stream.bad();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue