replace list_parser with a simpler api

master
Daniel Kolesa 2021-03-18 23:53:16 +01:00
parent 704f9217f7
commit 9d0494a9da
6 changed files with 224 additions and 277 deletions

View File

@ -75,6 +75,7 @@ struct OSTD_EXPORT cs_strref {
cs_strref() = delete;
cs_strref(cs_shared_state &cs, ostd::string_range str);
cs_strref(cs_state &cs, ostd::string_range str);
cs_strref(cs_strref const &ref);
@ -379,6 +380,7 @@ static inline void *cs_default_alloc(void *, void *p, size_t, size_t ns) {
struct OSTD_EXPORT cs_state {
friend struct cs_error;
friend struct cs_strman;
friend struct cs_strref;
friend struct cs_value;
friend struct cs_gen_state;
@ -649,6 +651,19 @@ private:
bool p_pushed;
};
struct cs_list_parse_state {
cs_list_parse_state(ostd::string_range s = ostd::string_range{}): input{s} {}
ostd::string_range input{};
ostd::string_range item{};
ostd::string_range quoted_item{};
};
OSTD_EXPORT bool list_parse(cs_list_parse_state &ps, cs_state &cs);
OSTD_EXPORT std::size_t list_count(cs_list_parse_state &ps, cs_state &cs);
OSTD_EXPORT cs_strref list_get_item(cs_list_parse_state &ps, cs_state &cs);
OSTD_EXPORT void list_find_item(cs_list_parse_state &ps);
namespace util {
template<typename R>
inline R &&escape_string(R &&writer, ostd::string_range str) {
@ -743,90 +758,6 @@ namespace util {
cs_state &cs, ostd::string_range str
);
struct list_range;
struct OSTD_EXPORT list_parser {
list_parser() = delete;
list_parser(cs_state &cs, ostd::string_range src):
p_state(cs), p_input(src)
{}
void skip();
bool parse();
size_t count();
template<typename R>
R &&get_item(R &&writer) const {
if (!p_quote.empty() && (*p_quote == '"')) {
return unescape_string(std::forward<R>(writer), p_item);
} else {
ostd::range_put_all(writer, p_item);
return std::forward<R>(writer);
}
}
cs_string get_item() const {
return std::move(get_item(ostd::appender<cs_string>()).get());
}
ostd::string_range &get_raw_item(bool quoted = false) {
return quoted ? p_quote : p_item;
}
ostd::string_range const &get_raw_item(bool quoted = false) const {
return quoted ? p_quote : p_item;
}
ostd::string_range &get_input() {
return p_input;
}
list_range iter() noexcept;
private:
ostd::string_range p_quote = ostd::string_range();
ostd::string_range p_item = ostd::string_range();
cs_state &p_state;
ostd::string_range p_input;
};
struct list_range: ostd::input_range<list_range> {
using range_category = ostd::forward_range_tag;
using value_type = ostd::string_range;
using reference = ostd::string_range;
using size_type = std::size_t;
list_range() = delete;
list_range(list_parser &p) noexcept: p_parser(&p) {
pop_front();
}
bool empty() const noexcept {
return !bool(p_item);
}
void pop_front() noexcept {
if (p_parser->parse()) {
p_item = p_parser->get_item();
} else {
p_item.reset();
}
}
ostd::string_range front() const noexcept {
return *p_item;
}
private:
list_parser *p_parser;
std::optional<cs_string> p_item{};
};
inline list_range list_parser::iter() noexcept {
return list_range{*this};
}
template<typename R>
inline void format_int(R &&writer, cs_int val) {
try {

View File

@ -17,14 +17,10 @@ ostd::string_range cs_gen_state::get_str() {
return ret.slice(1, ret.size() - 1);
}
cs_string cs_gen_state::get_str_dup(bool unescape) {
cs_string cs_gen_state::get_str_dup() {
auto str = get_str();
auto app = ostd::appender<cs_string>();
if (unescape) {
util::unescape_string(app, str);
} else {
app.get() = str;
}
util::unescape_string(app, str);
return std::move(app.get());
}

View File

@ -357,107 +357,120 @@ end:
}
return str;
}
void list_parser::skip() {
for (;;) {
while (!p_input.empty()) {
char c = *p_input;
if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) {
++p_input;
} else {
break;
}
}
if ((p_input.size() < 2) || (p_input[0] != '/') || (p_input[1] != '/')) {
break;
}
p_input = ostd::find(p_input, '\n');
}
}
bool list_parser::parse() {
skip();
if (p_input.empty()) {
return false;
}
switch (*p_input) {
case '"':
p_quote = p_input;
p_input = parse_string(p_state, p_input);
p_quote = p_quote.slice(0, &p_input[0] - &p_quote[0]);
p_item = p_quote.slice(1, p_quote.size() - 1);
break;
case '(':
case '[': {
p_quote = p_input;
++p_input;
p_item = p_input;
char btype = *p_quote;
int brak = 1;
for (;;) {
p_input = ostd::find_one_of(
p_input, ostd::string_range("\"/;()[]")
);
if (p_input.empty()) {
return true;
}
char c = *p_input;
++p_input;
switch (c) {
case '"':
p_input = parse_string(p_state, p_input);
break;
case '/':
if (!p_input.empty() && (*p_input == '/')) {
p_input = ostd::find(p_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:
p_item = p_item.slice(0, &p_input[0] - &p_item[0]);
p_item.pop_back();
p_quote = p_quote.slice(0, &p_input[0] - &p_quote[0]);
break;
}
case ')':
case ']':
return false;
default: {
ostd::string_range e = parse_word(p_state, p_input);
p_quote = p_item = p_input.slice(0, &e[0] - &p_input[0]);
p_input = e;
break;
}
}
skip();
if (!p_input.empty() && (*p_input == ';')) {
++p_input;
}
return true;
}
size_t list_parser::count() {
size_t ret = 0;
while (parse()) {
++ret;
}
return ret;
}
} /* namespace util */
OSTD_EXPORT bool list_parse(cs_list_parse_state &ps, cs_state &cs) {
list_find_item(ps);
if (ps.input.empty()) {
return false;
}
switch (*ps.input) {
case '"':
ps.quoted_item = ps.input;
ps.input = util::parse_string(cs, ps.input);
ps.quoted_item = ps.quoted_item.slice(
0, &ps.input[0] - &ps.quoted_item[0]
);
ps.item = ps.quoted_item.slice(1, ps.quoted_item.size() - 1);
break;
case '(':
case '[': {
ps.quoted_item = ps.input;
++ps.input;
ps.item = ps.input;
char btype = *ps.quoted_item;
int brak = 1;
for (;;) {
ps.input = ostd::find_one_of(
ps.input, ostd::string_range("\"/;()[]")
);
if (ps.input.empty()) {
return true;
}
char c = *ps.input;
++ps.input;
switch (c) {
case '"':
ps.input = util::parse_string(cs, ps.input);
break;
case '/':
if (!ps.input.empty() && (*ps.input == '/')) {
ps.input = ostd::find(ps.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:
ps.item = ps.item.slice(0, &ps.input[0] - &ps.item[0]);
ps.item.pop_back();
ps.quoted_item = ps.quoted_item.slice(
0, &ps.input[0] - &ps.quoted_item[0]
);
break;
}
case ')':
case ']':
return false;
default: {
ostd::string_range e = util::parse_word(cs, ps.input);
ps.quoted_item = ps.item = ps.input.slice(0, &e[0] - &ps.input[0]);
ps.input = e;
break;
}
}
list_find_item(ps);
if (!ps.input.empty() && (*ps.input == ';')) {
++ps.input;
}
return true;
}
OSTD_EXPORT std::size_t list_count(cs_list_parse_state &ps, cs_state &cs) {
size_t ret = 0;
while (list_parse(ps, cs)) {
++ret;
}
return ret;
}
OSTD_EXPORT cs_strref list_get_item(cs_list_parse_state &ps, cs_state &cs) {
if (!ps.quoted_item.empty() && (*ps.quoted_item == '"')) {
auto app = ostd::appender<cs_string>();
util::unescape_string(app, ps.item);
return cs_strref{cs, app.get()};
}
return cs_strref{cs, ps.item};
}
OSTD_EXPORT void list_find_item(cs_list_parse_state &ps) {
for (;;) {
while (!ps.input.empty()) {
char c = *ps.input;
if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) {
++ps.input;
} else {
break;
}
}
if ((ps.input.size() < 2) || (ps.input[0] != '/') || (ps.input[1] != '/')) {
break;
}
ps.input = ostd::find(ps.input, '\n');
}
}
} /* namespace cscript */

View File

@ -13,6 +13,12 @@ cs_strref::cs_strref(cs_shared_state &cs, ostd::string_range str):
p_str = cs.strman->add(str);
}
cs_strref::cs_strref(cs_state &cs, ostd::string_range str):
p_state{cs.p_state}
{
p_str = p_state->strman->add(str);
}
cs_strref::cs_strref(cs_strref const &ref): p_state{ref.p_state}, p_str{ref.p_str}
{
p_state->strman->ref(p_str);

View File

@ -195,7 +195,7 @@ struct cs_gen_state {
}
ostd::string_range get_str();
cs_string get_str_dup(bool unescape = true);
cs_string get_str_dup();
ostd::string_range get_word();

View File

@ -35,13 +35,13 @@ static inline void cs_list_find(
) {
cs_int n = 0, skip = args[2].get_int();
T val = cs_arg_val<T>::get(args[1]);
for (util::list_parser p(cs, args[0].get_str()); p.parse(); ++n) {
for (cs_list_parse_state p{args[0].get_str()}; list_parse(p, cs); ++n) {
if (cmp(p, val)) {
res.set_int(n);
return;
}
for (int i = 0; i < skip; ++i) {
if (!p.parse()) {
if (!list_parse(p, cs)) {
goto notfound;
}
++n;
@ -56,14 +56,14 @@ static inline void cs_list_assoc(
cs_state &cs, cs_value_r args, cs_value &res, F cmp
) {
T val = cs_arg_val<T>::get(args[1]);
for (util::list_parser p(cs, args[0].get_str()); p.parse();) {
for (cs_list_parse_state p{args[0].get_str()}; list_parse(p, cs);) {
if (cmp(p, val)) {
if (p.parse()) {
res.set_str(p.get_item());
if (list_parse(p, cs)) {
res.set_str(list_get_item(p, cs));
}
return;
}
if (!p.parse()) {
if (!list_parse(p, cs)) {
break;
}
}
@ -79,8 +79,8 @@ static void cs_loop_list_conc(
}
cs_string r;
int n = 0;
for (util::list_parser p(cs, list); p.parse(); ++n) {
idv.set_str(p.get_item());
for (cs_list_parse_state p{list}; list_parse(p, cs); ++n) {
idv.set_str(list_get_item(p, cs));
idv.push();
if (n && space) {
r += ' ';
@ -104,8 +104,8 @@ int cs_list_includes(
cs_state &cs, ostd::string_range list, ostd::string_range needle
) {
int offset = 0;
for (util::list_parser p(cs, list); p.parse();) {
if (p.get_raw_item() == needle) {
for (cs_list_parse_state p{list}; list_parse(p, cs);) {
if (p.item == needle) {
return offset;
}
++offset;
@ -126,12 +126,12 @@ static inline void cs_list_merge(
if (Swap) {
std::swap(list, elems);
}
for (util::list_parser p(cs, list); p.parse();) {
if (cmp(cs_list_includes(cs, elems, p.get_raw_item()), 0)) {
for (cs_list_parse_state p{list}; list_parse(p, cs);) {
if (cmp(cs_list_includes(cs, elems, p.item), 0)) {
if (!buf.empty()) {
buf += ' ';
}
buf += p.get_raw_item(true);
buf += p.quoted_item;
}
}
res.set_str(buf);
@ -141,7 +141,8 @@ static void cs_init_lib_list_sort(cs_state &cs);
void cs_init_lib_list(cs_state &gcs) {
gcs.new_command("listlen", "s", [](auto &cs, auto args, auto &res) {
res.set_int(cs_int(util::list_parser(cs, args[0].get_str()).count()));
cs_list_parse_state p{args[0].get_str()};
res.set_int(cs_int(list_count(p, cs)));
});
gcs.new_command("at", "si1V", [](auto &cs, auto args, auto &res) {
@ -149,51 +150,51 @@ void cs_init_lib_list(cs_state &gcs) {
return;
}
cs_strref str = args[0].get_str();
util::list_parser p(cs, str);
p.get_raw_item() = str;
cs_list_parse_state p{str};
p.item = str;
for (size_t i = 1; i < args.size(); ++i) {
p.get_input() = str;
p.input = str;
cs_int pos = args[i].get_int();
for (; pos > 0; --pos) {
if (!p.parse()) {
if (!list_parse(p, cs)) {
break;
}
}
if (pos > 0 || !p.parse()) {
p.get_raw_item() = p.get_raw_item(true) = ostd::string_range();
if (pos > 0 || !list_parse(p, cs)) {
p.item = p.quoted_item = ostd::string_range();
}
}
res.set_str(p.get_item());
res.set_str(list_get_item(p, cs));
});
gcs.new_command("sublist", "siiN", [](auto &cs, auto args, auto &res) {
cs_int skip = args[1].get_int(),
cs_int skip = args[1].get_int(),
count = args[2].get_int(),
numargs = args[3].get_int();
cs_int offset = std::max(skip, cs_int(0)),
len = (numargs >= 3) ? std::max(count, cs_int(0)) : -1;
util::list_parser p(cs, args[0].get_str());
cs_list_parse_state p{args[0].get_str()};
for (cs_int i = 0; i < offset; ++i) {
if (!p.parse()) break;
if (!list_parse(p, cs)) break;
}
if (len < 0) {
if (offset > 0) {
p.skip();
list_find_item(p);
}
res.set_str(cs_string{p.get_input()});
res.set_str(cs_string{p.input});
return;
}
char const *list = p.get_input().data();
p.get_raw_item(true) = ostd::string_range();
if (len > 0 && p.parse()) {
while (--len > 0 && p.parse());
char const *list = p.input.data();
p.quoted_item = ostd::string_range();
if (len > 0 && list_parse(p, cs)) {
while (--len > 0 && list_parse(p, cs));
}
ostd::string_range quote = p.get_raw_item(true);
ostd::string_range quote = p.quoted_item;
char const *qend = !quote.empty() ? &quote[quote.size()] : list;
res.set_str(cs_string{list, size_t(qend - list)});
res.set_str(ostd::string_range{list, qend});
});
gcs.new_command("listfind", "rse", [](auto &cs, auto args, auto &res) {
@ -204,9 +205,9 @@ void cs_init_lib_list(cs_state &gcs) {
}
auto body = args[2].get_code();
int n = -1;
for (util::list_parser p(cs, args[1].get_str()); p.parse();) {
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs);) {
++n;
idv.set_str(cs_string{p.get_raw_item()});
idv.set_str(cs_string{p.item});
idv.push();
if (cs.run_bool(body)) {
res.set_int(cs_int(n));
@ -223,17 +224,17 @@ void cs_init_lib_list(cs_state &gcs) {
}
auto body = args[2].get_code();
int n = -1;
for (util::list_parser p(cs, args[1].get_str()); p.parse();) {
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs);) {
++n;
idv.set_str(cs_string{p.get_raw_item()});
idv.set_str(cs_string{p.item});
idv.push();
if (cs.run_bool(body)) {
if (p.parse()) {
res.set_str(p.get_item());
if (list_parse(p, cs)) {
res.set_str(list_get_item(p, cs));
}
break;
}
if (!p.parse()) {
if (!list_parse(p, cs)) {
break;
}
}
@ -241,44 +242,44 @@ void cs_init_lib_list(cs_state &gcs) {
gcs.new_command("listfind=", "i", [](auto &cs, auto args, auto &res) {
cs_list_find<cs_int>(
cs, args, res, [](const util::list_parser &p, cs_int val) {
return cs_parse_int(p.get_raw_item()) == val;
cs, args, res, [](cs_list_parse_state const &p, cs_int val) {
return cs_parse_int(p.item) == val;
}
);
});
gcs.new_command("listfind=f", "f", [](auto &cs, auto args, auto &res) {
cs_list_find<cs_float>(
cs, args, res, [](const util::list_parser &p, cs_float val) {
return cs_parse_float(p.get_raw_item()) == val;
cs, args, res, [](cs_list_parse_state const &p, cs_float val) {
return cs_parse_float(p.item) == val;
}
);
});
gcs.new_command("listfind=s", "s", [](auto &cs, auto args, auto &res) {
cs_list_find<ostd::string_range>(
cs, args, res, [](const util::list_parser &p, ostd::string_range val) {
return p.get_raw_item() == val;
cs, args, res, [](cs_list_parse_state const &p, ostd::string_range val) {
return p.item == val;
}
);
});
gcs.new_command("listassoc=", "i", [](auto &cs, auto args, auto &res) {
cs_list_assoc<cs_int>(
cs, args, res, [](const util::list_parser &p, cs_int val) {
return cs_parse_int(p.get_raw_item()) == val;
cs, args, res, [](cs_list_parse_state const &p, cs_int val) {
return cs_parse_int(p.item) == val;
}
);
});
gcs.new_command("listassoc=f", "f", [](auto &cs, auto args, auto &res) {
cs_list_assoc<cs_float>(
cs, args, res, [](const util::list_parser &p, cs_float val) {
return cs_parse_float(p.get_raw_item()) == val;
cs, args, res, [](cs_list_parse_state const &p, cs_float val) {
return cs_parse_float(p.item) == val;
}
);
});
gcs.new_command("listassoc=s", "s", [](auto &cs, auto args, auto &res) {
cs_list_assoc<ostd::string_range>(
cs, args, res, [](const util::list_parser &p, ostd::string_range val) {
return p.get_raw_item() == val;
cs, args, res, [](cs_list_parse_state const &p, ostd::string_range val) {
return p.item == val;
}
);
});
@ -290,8 +291,8 @@ void cs_init_lib_list(cs_state &gcs) {
}
auto body = args[2].get_code();
int n = 0;
for (util::list_parser p(cs, args[1].get_str()); p.parse(); ++n) {
idv.set_str(p.get_item());
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs); ++n) {
idv.set_str(list_get_item(p, cs));
idv.push();
switch (cs.run_loop(body)) {
case cs_loop_state::BREAK:
@ -312,10 +313,10 @@ end:
}
auto body = args[3].get_code();
int n = 0;
for (util::list_parser p(cs, args[2].get_str()); p.parse(); n += 2) {
idv1.set_str(p.get_item());
if (p.parse()) {
idv2.set_str(p.get_item());
for (cs_list_parse_state p{args[2].get_str()}; list_parse(p, cs); n += 2) {
idv1.set_str(list_get_item(p, cs));
if (list_parse(p, cs)) {
idv2.set_str(list_get_item(p, cs));
} else {
idv2.set_str("");
}
@ -341,15 +342,15 @@ end:
}
auto body = args[4].get_code();
int n = 0;
for (util::list_parser p(cs, args[3].get_str()); p.parse(); n += 3) {
idv1.set_str(p.get_item());
if (p.parse()) {
idv2.set_str(p.get_item());
for (cs_list_parse_state p{args[3].get_str()}; list_parse(p, cs); n += 3) {
idv1.set_str(list_get_item(p, cs));
if (list_parse(p, cs)) {
idv2.set_str(list_get_item(p, cs));
} else {
idv2.set_str("");
}
if (p.parse()) {
idv3.set_str(p.get_item());
if (list_parse(p, cs)) {
idv3.set_str(list_get_item(p, cs));
} else {
idv3.set_str("");
}
@ -391,14 +392,14 @@ end:
auto body = args[2].get_code();
cs_string r;
int n = 0;
for (util::list_parser p(cs, args[1].get_str()); p.parse(); ++n) {
idv.set_str(cs_string{p.get_raw_item()});
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs); ++n) {
idv.set_str(p.item);
idv.push();
if (cs.run_bool(body)) {
if (r.size()) {
r += ' ';
}
r += p.get_raw_item(true);
r += p.quoted_item;
}
}
res.set_str(r);
@ -411,8 +412,8 @@ end:
}
auto body = args[2].get_code();
int n = 0, r = 0;
for (util::list_parser p(cs, args[1].get_str()); p.parse(); ++n) {
idv.set_str(cs_string{p.get_raw_item()});
for (cs_list_parse_state p{args[1].get_str()}; list_parse(p, cs); ++n) {
idv.set_str(p.item);
idv.push();
if (cs.run_bool(body)) {
r++;
@ -425,14 +426,14 @@ end:
auto buf = ostd::appender<cs_string>();
ostd::string_range s = args[0].get_str();
ostd::string_range conj = args[1].get_str();
size_t len = util::list_parser(cs, s).count();
cs_list_parse_state p{s};
size_t len = list_count(p, cs);
size_t n = 0;
for (util::list_parser p(cs, s); p.parse(); ++n) {
if (!p.get_raw_item(true).empty() &&
(p.get_raw_item(true).front() == '"')) {
util::unescape_string(buf, p.get_raw_item());
for (p.input = s; list_parse(p, cs); ++n) {
if (!p.quoted_item.empty() && (p.quoted_item.front() == '"')) {
util::unescape_string(buf, p.item);
} else {
ostd::range_put_all(buf, p.get_raw_item());
ostd::range_put_all(buf, p.item);
}
if ((n + 1) < len) {
if ((len > 2) || conj.empty()) {
@ -470,13 +471,13 @@ end:
ostd::string_range s = args[0].get_str();
ostd::string_range vals = args[1].get_str();
char const *list = s.data();
util::list_parser p(cs, s);
cs_list_parse_state p{s};
for (cs_int i = 0; i < offset; ++i) {
if (!p.parse()) {
if (!list_parse(p, cs)) {
break;
}
}
ostd::string_range quote = p.get_raw_item(true);
ostd::string_range quote = p.quoted_item;
char const *qend = !quote.empty() ? &quote[quote.size()] : list;
cs_string buf;
if (qend > list) {
@ -489,13 +490,13 @@ end:
buf += vals;
}
for (cs_int i = 0; i < len; ++i) {
if (!p.parse()) {
if (!list_parse(p, cs)) {
break;
}
}
p.skip();
if (!p.get_input().empty()) {
switch (p.get_input().front()) {
list_find_item(p);
if (!p.input.empty()) {
switch (p.input.front()) {
case ')':
case ']':
break;
@ -503,7 +504,7 @@ end:
if (!buf.empty()) {
buf += ' ';
}
buf += p.get_input();
buf += p.input;
break;
}
}
@ -545,14 +546,14 @@ static void cs_list_sort(
cs_vector<ListSortItem> items;
size_t total = 0;
for (util::list_parser p(cs, list); p.parse();) {
ListSortItem item = { p.get_raw_item(), p.get_raw_item(true) };
for (cs_list_parse_state p{list}; list_parse(p, cs);) {
ListSortItem item = { p.item, p.quoted_item };
items.push_back(item);
total += item.quote.size();
}
if (items.empty()) {
res.set_str(cs_string{list});
res.set_str(list);
return;
}