expose ListParser via public API

master
Daniel Kolesa 2016-08-15 18:48:06 +01:00
parent a638e460c5
commit 661aef0c0f
3 changed files with 168 additions and 166 deletions

139
cs_gen.cc
View File

@ -24,7 +24,7 @@ static char const *parsestring(char const *p) {
return p;
}
ostd::ConstCharRange cs_parse_str(ostd::ConstCharRange str) {
static ostd::ConstCharRange cs_parse_str(ostd::ConstCharRange str) {
for (; !str.empty(); str.pop_front())
switch (str.front()) {
case '\r':
@ -59,7 +59,7 @@ static inline char *cutstring(char const *&p) {
return buf;
}
char const *parseword(char const *p) {
static char const *parseword(char const *p) {
constexpr int maxbrak = 100;
static char brakstack[maxbrak];
int brakdepth = 0;
@ -99,6 +99,141 @@ static inline char *cutword(char const *&p) {
return p != word ? cs_dup_ostr(ostd::ConstCharRange(word, p - word)) : nullptr;
}
namespace util {
void ListParser::skip() {
for (;;) {
while (!input.empty()) {
char c = input.front();
if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
input.pop_front();
else
break;
}
if ((input.size() < 2) || (input[0] != '/') || (input[1] != '/'))
break;
input = ostd::find(input, '\n');
}
}
bool ListParser::parse() {
skip();
if (input.empty())
return false;
switch (input.front()) {
case '"':
quote = input;
input.pop_front();
item = input;
input = cs_parse_str(input);
item = ostd::slice_until(item, input);
if (!input.empty() && (input.front() == '"'))
input.pop_front();
quote = ostd::slice_until(quote, input);
break;
case '(':
case '[': {
quote = input;
input.pop_front();
item = input;
char btype = quote.front();
int brak = 1;
for (;;) {
input = ostd::find_one_of(input,
ostd::ConstCharRange("\"/;()[]"));
if (input.empty())
return true;
char c = input.front();
input.pop_front();
switch (c) {
case '"':
input = cs_parse_str(input);
if (!input.empty() && (input.front() == '"'))
input.pop_front();
break;
case '/':
if (!input.empty() && (input.front() == '/'))
input = ostd::find(input, '\n');
break;
case '(':
case '[':
brak += (c == btype);
break;
case ')':
if ((btype == '(') && (--brak <= 0))
goto endblock;
break;
case ']':
if ((btype == '[') && (--brak <= 0))
goto endblock;
break;
}
}
endblock:
item = ostd::slice_until(item, input);
item.pop_back();
quote = ostd::slice_until(quote, input);
break;
}
case ')':
case ']':
return false;
default: {
char const *e = parseword(input.data());
item = input;
input.pop_front_n(e - input.data());
item = ostd::slice_until(item, input);
quote = item;
break;
}
}
skip();
if (!input.empty() && (input.front() == ';'))
input.pop_front();
return true;
}
ostd::String ListParser::element() {
ostd::String s;
s.reserve(item.size());
if (!quote.empty() && (quote.front() == '"')) {
auto writer = s.iter_cap();
util::unescape_string(writer, item);
writer.put('\0');
} else {
memcpy(s.data(), item.data(), item.size());
s[item.size()] = '\0';
}
s.advance(item.size());
return s;
}
ostd::Size list_length(ostd::ConstCharRange s) {
ListParser p(s);
ostd::Size ret = 0;
while (p.parse()) ++ret;
return ret;
}
ostd::Maybe<ostd::String> list_index(ostd::ConstCharRange s,
ostd::Size idx) {
ListParser p(s);
for (ostd::Size i = 0; i < idx; ++i)
if (!p.parse()) return ostd::nothing;
if (!p.parse())
return ostd::nothing;
return ostd::move(p.element());
}
ostd::Vector<ostd::String> list_explode(ostd::ConstCharRange s,
ostd::Size limit) {
ostd::Vector<ostd::String> ret;
ListParser p(s);
while ((ret.size() < limit) && p.parse())
ret.push(ostd::move(p.element()));
return ret;
}
} /* namespace util */
static inline int cs_ret_code(int type, int def = 0) {
return (type >= VAL_ANY) ? ((type == VAL_CSTR) ? RET_STR : def)
: (type << CODE_RET);

View File

@ -571,6 +571,20 @@ namespace util {
return ret;
}
struct ListParser {
ostd::ConstCharRange input;
ostd::ConstCharRange quote = ostd::ConstCharRange();
ostd::ConstCharRange item = ostd::ConstCharRange();
ListParser() = delete;
ListParser(ostd::ConstCharRange src): input(src) {}
void skip();
bool parse();
ostd::String element();
};
ostd::Size list_length(ostd::ConstCharRange s);
ostd::Maybe<ostd::String> list_index(
ostd::ConstCharRange s, ostd::Size idx

View File

@ -4,153 +4,6 @@
namespace cscript {
char *cs_dup_ostr(ostd::ConstCharRange s);
ostd::ConstCharRange cs_parse_str(ostd::ConstCharRange str);
char const *parseword(char const *p);
struct ListParser {
ostd::ConstCharRange input;
ostd::ConstCharRange quote = ostd::ConstCharRange();
ostd::ConstCharRange item = ostd::ConstCharRange();
ListParser() = delete;
ListParser(ostd::ConstCharRange src): input(src) {}
void skip() {
for (;;) {
while (!input.empty()) {
char c = input.front();
if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
input.pop_front();
else
break;
}
if ((input.size() < 2) || (input[0] != '/') || (input[1] != '/'))
break;
input = ostd::find(input, '\n');
}
}
bool parse() {
skip();
if (input.empty())
return false;
switch (input.front()) {
case '"':
quote = input;
input.pop_front();
item = input;
input = cs_parse_str(input);
item = ostd::slice_until(item, input);
if (!input.empty() && (input.front() == '"'))
input.pop_front();
quote = ostd::slice_until(quote, input);
break;
case '(':
case '[': {
quote = input;
input.pop_front();
item = input;
char btype = quote.front();
int brak = 1;
for (;;) {
input = ostd::find_one_of(input,
ostd::ConstCharRange("\"/;()[]"));
if (input.empty())
return true;
char c = input.front();
input.pop_front();
switch (c) {
case '"':
input = cs_parse_str(input);
if (!input.empty() && (input.front() == '"'))
input.pop_front();
break;
case '/':
if (!input.empty() && (input.front() == '/'))
input = ostd::find(input, '\n');
break;
case '(':
case '[':
brak += (c == btype);
break;
case ')':
if ((btype == '(') && (--brak <= 0))
goto endblock;
break;
case ']':
if ((btype == '[') && (--brak <= 0))
goto endblock;
break;
}
}
endblock:
item = ostd::slice_until(item, input);
item.pop_back();
quote = ostd::slice_until(quote, input);
break;
}
case ')':
case ']':
return false;
default: {
char const *e = parseword(input.data());
item = input;
input.pop_front_n(e - input.data());
item = ostd::slice_until(item, input);
quote = item;
break;
}
}
skip();
if (!input.empty() && (input.front() == ';'))
input.pop_front();
return true;
}
ostd::String element() {
ostd::String s;
s.reserve(item.size());
if (!quote.empty() && (quote.front() == '"')) {
auto writer = s.iter_cap();
util::unescape_string(writer, item);
writer.put('\0');
} else {
memcpy(s.data(), item.data(), item.size());
s[item.size()] = '\0';
}
s.advance(item.size());
return s;
}
};
namespace util {
ostd::Size list_length(ostd::ConstCharRange s) {
ListParser p(s);
ostd::Size ret = 0;
while (p.parse()) ++ret;
return ret;
}
ostd::Maybe<ostd::String> list_index(ostd::ConstCharRange s,
ostd::Size idx) {
ListParser p(s);
for (ostd::Size i = 0; i < idx; ++i)
if (!p.parse()) return ostd::nothing;
if (!p.parse())
return ostd::nothing;
return ostd::move(p.element());
}
ostd::Vector<ostd::String> list_explode(ostd::ConstCharRange s,
ostd::Size limit) {
ostd::Vector<ostd::String> ret;
ListParser p(s);
while ((ret.size() < limit) && p.parse())
ret.push(ostd::move(p.element()));
return ret;
}
}
static inline void cs_set_iter(Ident &id, char *val, IdentStack &stack) {
if (id.stack == &stack) {
@ -178,7 +31,7 @@ static void cs_loop_list_conc(
IdentStack stack;
ostd::Vector<char> r;
int n = 0;
for (ListParser p(list); p.parse(); ++n) {
for (util::ListParser p(list); p.parse(); ++n) {
char *val = p.element().disown();
cs_set_iter(*id, val, stack);
if (n && space)
@ -198,7 +51,7 @@ static void cs_loop_list_conc(
int cs_list_includes(ostd::ConstCharRange list, ostd::ConstCharRange needle) {
int offset = 0;
for (ListParser p(list); p.parse();) {
for (util::ListParser p(list); p.parse();) {
if (p.item == needle)
return offset;
++offset;
@ -217,7 +70,7 @@ void cs_init_lib_list(CsState &cs) {
if (args.empty())
return;
ostd::String str = ostd::move(args[0].get_str());
ListParser p(str);
util::ListParser p(str);
p.item = str;
for (ostd::Size i = 1; i < args.size(); ++i) {
p.input = str;
@ -241,7 +94,7 @@ void cs_init_lib_list(CsState &cs) {
CsInt offset = ostd::max(skip, 0),
len = (numargs >= 3) ? ostd::max(count, 0) : -1;
ListParser p(args[0].get_strr());
util::ListParser p(args[0].get_strr());
for (CsInt i = 0; i < offset; ++i)
if (!p.parse()) break;
if (len < 0) {
@ -268,7 +121,7 @@ void cs_init_lib_list(CsState &cs) {
}
IdentStack stack;
int n = -1;
for (ListParser p(args[1].get_strr()); p.parse();) {
for (util::ListParser p(args[1].get_strr()); p.parse();) {
++n;
cs_set_iter(*id, cs_dup_ostr(p.item), stack);
if (cs.run_bool(body)) {
@ -289,7 +142,7 @@ found:
return;
IdentStack stack;
int n = -1;
for (ListParser p(args[1].get_strr()); p.parse();) {
for (util::ListParser p(args[1].get_strr()); p.parse();) {
++n;
cs_set_iter(*id, cs_dup_ostr(p.item), stack);
if (cs.run_bool(body)) {
@ -312,7 +165,7 @@ found:
cs.add_command(name, "s" fmt "i", [&cs](TvalRange args, TaggedValue &res) { \
CsInt n = 0, skip = args[2].get_int(); \
auto val = args[1].gmeth(); \
for (ListParser p(args[0].get_strr()); p.parse(); ++n) { \
for (util::ListParser p(args[0].get_strr()); p.parse(); ++n) { \
if (cmp) { \
res.set_int(n); \
return; \
@ -336,7 +189,7 @@ found:
#define CS_CMD_LIST_ASSOC(name, fmt, gmeth, cmp) \
cs.add_command(name, "s" fmt, [&cs](TvalRange args, TaggedValue &res) { \
auto val = args[1].gmeth(); \
for (ListParser p(args[0].get_strr()); p.parse();) { \
for (util::ListParser p(args[0].get_strr()); p.parse();) { \
if (cmp) { \
if (p.parse()) { \
auto elem = p.element(); \
@ -364,7 +217,7 @@ found:
return;
IdentStack stack;
int n = 0;
for (ListParser p(args[1].get_strr()); p.parse(); ++n) {
for (util::ListParser p(args[1].get_strr()); p.parse(); ++n) {
cs_set_iter(*id, p.element().disown(), stack);
cs.run_int(body);
}
@ -379,7 +232,7 @@ found:
return;
IdentStack stack, stack2;
int n = 0;
for (ListParser p(args[2].get_strr()); p.parse(); n += 2) {
for (util::ListParser p(args[2].get_strr()); p.parse(); n += 2) {
cs_set_iter(*id, p.element().disown(), stack);
cs_set_iter(*id2, p.parse() ? p.element().disown()
: cs_dup_ostr(""), stack2);
@ -400,7 +253,7 @@ found:
return;
IdentStack stack, stack2, stack3;
int n = 0;
for (ListParser p(args[3].get_strr()); p.parse(); n += 3) {
for (util::ListParser p(args[3].get_strr()); p.parse(); n += 3) {
cs_set_iter(*id, p.element().disown(), stack);
cs_set_iter(*id2, p.parse() ? p.element().disown()
: cs_dup_ostr(""), stack2);
@ -437,7 +290,7 @@ found:
IdentStack stack;
ostd::Vector<char> r;
int n = 0;
for (ListParser p(args[1].get_strr()); p.parse(); ++n) {
for (util::ListParser p(args[1].get_strr()); p.parse(); ++n) {
char *val = cs_dup_ostr(p.item);
cs_set_iter(*id, val, stack);
if (cs.run_bool(body)) {
@ -459,7 +312,7 @@ found:
return;
IdentStack stack;
int n = 0, r = 0;
for (ListParser p(args[1].get_strr()); p.parse(); ++n) {
for (util::ListParser p(args[1].get_strr()); p.parse(); ++n) {
char *val = cs_dup_ostr(p.item);
cs_set_iter(*id, val, stack);
if (cs.run_bool(body))
@ -476,7 +329,7 @@ found:
ostd::ConstCharRange conj = args[1].get_strr();
ostd::Size len = util::list_length(s);
ostd::Size n = 0;
for (ListParser p(s); p.parse(); ++n) {
for (util::ListParser p(s); p.parse(); ++n) {
if (!p.quote.empty() && (p.quote.front() == '"')) {
buf.reserve(buf.size() + p.item.size());
auto writer = ostd::CharRange(&buf[buf.size()],
@ -514,7 +367,7 @@ found:
ostd::ConstCharRange elems = args[1].get_strr(); \
ostd::Vector<char> buf; \
init; \
for (ListParser p(iter); p.parse();) { \
for (util::ListParser p(iter); p.parse();) { \
if (cs_list_includes(filter, p.item) dir 0) { \
if (!buf.empty()) \
buf.push(' '); \
@ -539,7 +392,7 @@ found:
ostd::ConstCharRange s = args[0].get_strr();
ostd::ConstCharRange vals = args[1].get_strr();
char const *list = s.data();
ListParser p(s);
util::ListParser p(s);
for (CsInt i = 0; i < offset; ++i)
if (!p.parse())
break;
@ -613,7 +466,7 @@ static void cs_list_sort(
ostd::Size total = 0;
char *cstr = cs_dup_ostr(list);
for (ListParser p(list); p.parse();) {
for (util::ListParser p(list); p.parse();) {
cstr[&p.item[p.item.size()] - list.data()] = '\0';
ListSortItem item = { &cstr[p.item.data() - list.data()], p.quote };
items.push(item);