diff --git a/lib_list.cc b/lib_list.cc index 5f85d82..623308b 100644 --- a/lib_list.cc +++ b/lib_list.cc @@ -5,6 +5,69 @@ namespace cscript { char *cs_dup_ostr(ostd::ConstCharRange s); +template +struct CsArgVal; + +template<> +struct CsArgVal { + static CsInt get(TaggedValue &tv) { + return tv.get_int(); + } +}; + +template<> +struct CsArgVal { + static CsFloat get(TaggedValue &tv) { + return tv.get_float(); + } +}; + +template<> +struct CsArgVal { + static ostd::ConstCharRange get(TaggedValue &tv) { + return tv.get_strr(); + } +}; + +template +static inline void cs_list_find(TvalRange args, TaggedValue &res, F cmp) { + CsInt n = 0, skip = args[2].get_int(); + T val = CsArgVal::get(args[1]); + for (util::ListParser p(args[0].get_strr()); p.parse(); ++n) { + if (cmp(p, val)) { + res.set_int(n); + return; + } + for (int i = 0; i < skip; ++i) { + if (!p.parse()) { + goto notfound; + } + ++n; + } + } +notfound: + res.set_int(-1); +} + +template +static inline void cs_list_assoc(TvalRange args, TaggedValue &res, F cmp) { + T val = CsArgVal::get(args[1]); + for (util::ListParser p(args[0].get_strr()); p.parse();) { + if (cmp(p, val)) { + if (p.parse()) { + auto elem = p.element(); + auto er = elem.iter(); + elem.disown(); + res.set_mstr(er); + } + return; + } + if (!p.parse()) { + break; + } + } +} + static inline void cs_set_iter(Ident &id, char *val, IdentStack &stack) { if (id.stack == &stack) { if (id.get_valtype() == VAL_STR) { @@ -26,24 +89,27 @@ static void cs_loop_list_conc( CsState &cs, TaggedValue &res, Ident *id, ostd::ConstCharRange list, Bytecode const *body, bool space ) { - if (!id->is_alias()) + if (!id->is_alias()) { return; + } IdentStack stack; ostd::Vector r; int n = 0; for (util::ListParser p(list); p.parse(); ++n) { char *val = p.element().disown(); cs_set_iter(*id, val, stack); - if (n && space) + if (n && space) { r.push(' '); + } TaggedValue v; cs.run_ret(body, v); ostd::String vstr = ostd::move(v.get_str()); r.push_n(vstr.data(), vstr.size()); v.cleanup(); } - if (n) + if (n) { id->pop_arg(); + } r.push('\0'); ostd::Size len = r.size(); res.set_mstr(ostd::CharRange(r.disown(), len - 1)); @@ -52,33 +118,62 @@ static void cs_loop_list_conc( int cs_list_includes(ostd::ConstCharRange list, ostd::ConstCharRange needle) { int offset = 0; for (util::ListParser p(list); p.parse();) { - if (p.item == needle) + if (p.item == needle) { return offset; + } ++offset; } return -1; } +template +static inline void cs_list_merge(TvalRange args, TaggedValue &res, F cmp) { + ostd::ConstCharRange list = args[0].get_strr(); + ostd::ConstCharRange elems = args[1].get_strr(); + ostd::Vector buf; + if (PushList) { + buf.push_n(list.data(), list.size()); + } + if (Swap) { + ostd::swap(list, elems); + } + for (util::ListParser p(list); p.parse();) { + if (cmp(cs_list_includes(elems, p.item), 0)) { + if (!buf.empty()) + buf.push(' '); + buf.push_n(p.quote.data(), p.quote.size()); + } + } + buf.push('\0'); + ostd::Size len = buf.size() - 1; + res.set_mstr(ostd::CharRange(buf.disown(), len)); +} + static void cs_init_lib_list_sort(CsState &cs); void cs_init_lib_list(CsState &cs) { - cs.add_command("listlen", "s", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("listlen", "s", [](TvalRange args, TaggedValue &res) { res.set_int(CsInt(util::list_length(args[0].get_strr()))); }); - cs.add_command("at", "si1V", [&cs](TvalRange args, TaggedValue &res) { - if (args.empty()) + cs.add_command("at", "si1V", [](TvalRange args, TaggedValue &res) { + if (args.empty()) { return; + } ostd::String str = ostd::move(args[0].get_str()); util::ListParser p(str); p.item = str; for (ostd::Size i = 1; i < args.size(); ++i) { p.input = str; CsInt pos = args[i].get_int(); - for (; pos > 0; --pos) - if (!p.parse()) break; - if (pos > 0 || !p.parse()) + for (; pos > 0; --pos) { + if (!p.parse()) { + break; + } + } + if (pos > 0 || !p.parse()) { p.item = p.quote = ostd::ConstCharRange(); + } } auto elem = p.element(); auto er = p.element().iter(); @@ -86,7 +181,7 @@ void cs_init_lib_list(CsState &cs) { res.set_mstr(er); }); - cs.add_command("sublist", "siiN", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("sublist", "siiN", [](TvalRange args, TaggedValue &res) { CsInt skip = args[1].get_int(), count = args[2].get_int(), numargs = args[2].get_int(); @@ -95,19 +190,22 @@ void cs_init_lib_list(CsState &cs) { len = (numargs >= 3) ? ostd::max(count, 0) : -1; util::ListParser p(args[0].get_strr()); - for (CsInt i = 0; i < offset; ++i) + for (CsInt i = 0; i < offset; ++i) { if (!p.parse()) break; + } if (len < 0) { - if (offset > 0) + if (offset > 0) { p.skip(); + } res.set_str(p.input); return; } char const *list = p.input.data(); p.quote = ostd::ConstCharRange(); - if (len > 0 && p.parse()) + if (len > 0 && p.parse()) { while (--len > 0 && p.parse()); + } char const *qend = !p.quote.empty() ? &p.quote[p.quote.size()] : list; res.set_str(ostd::ConstCharRange(list, qend - list)); }); @@ -131,15 +229,17 @@ void cs_init_lib_list(CsState &cs) { } res.set_int(-1); found: - if (n >= 0) + if (n >= 0) { id->pop_arg(); + } }); cs.add_command("listassoc", "rse", [&cs](TvalRange args, TaggedValue &res) { Ident *id = args[0].get_ident(); auto body = args[2].get_code(); - if (!id->is_alias()) + if (!id->is_alias()) { return; + } IdentStack stack; int n = -1; for (util::ListParser p(args[1].get_strr()); p.parse();) { @@ -154,88 +254,89 @@ found: } break; } - if (!p.parse()) + if (!p.parse()) { break; + } } - if (n >= 0) + if (n >= 0) { id->pop_arg(); + } }); -#define CS_CMD_LIST_FIND(name, fmt, gmeth, cmp) \ - 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 (util::ListParser p(args[0].get_strr()); p.parse(); ++n) { \ - if (cmp) { \ - res.set_int(n); \ - return; \ - } \ - for (int i = 0; i < skip; ++i) { \ - if (!p.parse()) \ - goto notfound; \ - ++n; \ - } \ - } \ - notfound: \ - res.set_int(-1); \ + cs.add_command("listfind=", "i", [](TvalRange args, TaggedValue &res) { + cs_list_find( + args, res, [](const util::ListParser &p, CsInt val) { + return cs_parse_int(p.item) == val; + } + ); + }); + cs.add_command("listfind=f", "f", [](TvalRange args, TaggedValue &res) { + cs_list_find( + args, res, [](const util::ListParser &p, CsFloat val) { + return cs_parse_float(p.item) == val; + } + ); + }); + cs.add_command("listfind=s", "s", [](TvalRange args, TaggedValue &res) { + cs_list_find( + args, res, [](const util::ListParser &p, ostd::ConstCharRange val) { + return p.item == val; + } + ); }); - CS_CMD_LIST_FIND("listfind=", "i", get_int, cs_parse_int(p.item) == val); - CS_CMD_LIST_FIND("listfind=f", "f", get_float, cs_parse_float(p.item) == val); - CS_CMD_LIST_FIND("listfind=s", "s", get_strr, p.item == val); - -#undef CS_CMD_LIST_FIND - -#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 (util::ListParser p(args[0].get_strr()); p.parse();) { \ - if (cmp) { \ - if (p.parse()) { \ - auto elem = p.element(); \ - auto er = elem.iter(); \ - elem.disown(); \ - res.set_mstr(er); \ - } \ - return; \ - } \ - if (!p.parse()) \ - break; \ - } \ + cs.add_command("listassoc=", "i", [](TvalRange args, TaggedValue &res) { + cs_list_assoc( + args, res, [](const util::ListParser &p, CsInt val) { + return cs_parse_int(p.item) == val; + } + ); + }); + cs.add_command("listassoc=f", "f", [](TvalRange args, TaggedValue &res) { + cs_list_assoc( + args, res, [](const util::ListParser &p, CsFloat val) { + return cs_parse_float(p.item) == val; + } + ); + }); + cs.add_command("listassoc=s", "s", [](TvalRange args, TaggedValue &res) { + cs_list_assoc( + args, res, [](const util::ListParser &p, ostd::ConstCharRange val) { + return p.item == val; + } + ); }); - - CS_CMD_LIST_ASSOC("listassoc=", "i", get_int, cs_parse_int(p.item) == val); - CS_CMD_LIST_ASSOC("listassoc=f", "f", get_float, cs_parse_float(p.item) == val); - CS_CMD_LIST_ASSOC("listassoc=s", "s", get_strr, p.item == val); - -#undef CS_CMD_LIST_ASSOC cs.add_command("looplist", "rse", [&cs](TvalRange args, TaggedValue &) { Ident *id = args[0].get_ident(); auto body = args[2].get_code(); - if (!id->is_alias()) + if (!id->is_alias()) { return; + } IdentStack stack; int n = 0; for (util::ListParser p(args[1].get_strr()); p.parse(); ++n) { cs_set_iter(*id, p.element().disown(), stack); cs.run_int(body); } - if (n) + if (n) { id->pop_arg(); + } }); cs.add_command("looplist2", "rrse", [&cs](TvalRange args, TaggedValue &) { Ident *id = args[0].get_ident(), *id2 = args[1].get_ident(); auto body = args[3].get_code(); - if (!id->is_alias() || !id2->is_alias()) + if (!id->is_alias() || !id2->is_alias()) { return; + } IdentStack stack, stack2; int n = 0; 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); + cs_set_iter( + *id2, p.parse() ? p.element().disown() : cs_dup_ostr(""), stack2 + ); cs.run_int(body); } if (n) { @@ -249,16 +350,19 @@ found: Ident *id2 = args[1].get_ident(); Ident *id3 = args[2].get_ident(); auto body = args[4].get_code(); - if (!id->is_alias() || !id2->is_alias() || !id3->is_alias()) + if (!id->is_alias() || !id2->is_alias() || !id3->is_alias()) { return; + } IdentStack stack, stack2, stack3; int n = 0; 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); - cs_set_iter(*id3, p.parse() ? p.element().disown() - : cs_dup_ostr(""), stack3); + cs_set_iter( + *id2, p.parse() ? p.element().disown() : cs_dup_ostr(""), stack2 + ); + cs_set_iter( + *id3, p.parse() ? p.element().disown() : cs_dup_ostr(""), stack3 + ); cs.run_int(body); } if (n) { @@ -268,14 +372,18 @@ found: } }); - cs.add_command("looplistconcat", "rse", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("looplistconcat", "rse", [&cs]( + TvalRange args, TaggedValue &res + ) { cs_loop_list_conc( cs, res, args[0].get_ident(), args[1].get_strr(), args[2].get_code(), true ); }); - cs.add_command("looplistconcatword", "rse", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("looplistconcatword", "rse", [&cs]( + TvalRange args, TaggedValue &res + ) { cs_loop_list_conc( cs, res, args[0].get_ident(), args[1].get_strr(), args[2].get_code(), false @@ -285,8 +393,9 @@ found: cs.add_command("listfilter", "rse", [&cs](TvalRange args, TaggedValue &res) { Ident *id = args[0].get_ident(); auto body = args[2].get_code(); - if (!id->is_alias()) + if (!id->is_alias()) { return; + } IdentStack stack; ostd::Vector r; int n = 0; @@ -294,12 +403,15 @@ found: char *val = cs_dup_ostr(p.item); cs_set_iter(*id, val, stack); if (cs.run_bool(body)) { - if (r.size()) r.push(' '); + if (r.size()) { + r.push(' '); + } r.push_n(p.quote.data(), p.quote.size()); } } - if (n) + if (n) { id->pop_arg(); + } r.push('\0'); ostd::Size len = r.size() - 1; res.set_mstr(ostd::CharRange(r.disown(), len)); @@ -308,22 +420,25 @@ found: cs.add_command("listcount", "rse", [&cs](TvalRange args, TaggedValue &res) { Ident *id = args[0].get_ident(); auto body = args[2].get_code(); - if (!id->is_alias()) + if (!id->is_alias()) { return; + } IdentStack stack; int n = 0, r = 0; 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)) + if (cs.run_bool(body)) { r++; + } } - if (n) + if (n) { id->pop_arg(); + } res.set_int(r); }); - cs.add_command("prettylist", "ss", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("prettylist", "ss", [](TvalRange args, TaggedValue &res) { ostd::Vector buf; ostd::ConstCharRange s = args[0].get_strr(); ostd::ConstCharRange conj = args[1].get_strr(); @@ -332,8 +447,9 @@ found: 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()], - buf.capacity() - buf.size()); + auto writer = ostd::CharRange( + &buf[buf.size()], buf.capacity() - buf.size() + ); ostd::Size adv = util::unescape_string(writer, p.item); writer.put('\0'); buf.advance(adv); @@ -341,8 +457,9 @@ found: buf.push_n(p.item.data(), p.item.size()); } if ((n + 1) < len) { - if ((len > 2) || conj.empty()) + if ((len > 2) || conj.empty()) { buf.push(','); + } if ((n + 2 == len) && !conj.empty()) { buf.push(' '); buf.push_n(conj.data(), conj.size()); @@ -355,69 +472,63 @@ found: res.set_mstr(ostd::CharRange(buf.disown(), slen)); }); - cs.add_command("indexof", "ss", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("indexof", "ss", [](TvalRange args, TaggedValue &res) { res.set_int( cs_list_includes(args[0].get_strr(), args[1].get_strr()) ); }); -#define CS_CMD_LIST_MERGE(name, init, iter, filter, dir) \ - cs.add_command(name, "ss", [&cs](TvalRange args, TaggedValue &res) { \ - ostd::ConstCharRange list = args[0].get_strr(); \ - ostd::ConstCharRange elems = args[1].get_strr(); \ - ostd::Vector buf; \ - init; \ - for (util::ListParser p(iter); p.parse();) { \ - if (cs_list_includes(filter, p.item) dir 0) { \ - if (!buf.empty()) \ - buf.push(' '); \ - buf.push_n(p.quote.data(), p.quote.size()); \ - } \ - } \ - buf.push('\0'); \ - ostd::Size len = buf.size() - 1; \ - res.set_mstr(ostd::CharRange(buf.disown(), len)); \ + cs.add_command("listdel", "ss", [](TvalRange args, TaggedValue &res) { + cs_list_merge(args, res, ostd::Less()); + }); + cs.add_command("listintersect", "ss", [](TvalRange args, TaggedValue &res) { + cs_list_merge(args, res, ostd::GreaterEqual()); + }); + cs.add_command("listunion", "ss", [](TvalRange args, TaggedValue &res) { + cs_list_merge(args, res, ostd::Less()); }); - CS_CMD_LIST_MERGE("listdel", {}, list, elems, <); - CS_CMD_LIST_MERGE("listintersect", {}, list, elems, >=); - CS_CMD_LIST_MERGE("listunion", buf.push_n(list.data(), list.size()), elems, - list, <); - -#undef CS_CMD_LIST_MERGE - - cs.add_command("listsplice", "ssii", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("listsplice", "ssii", [](TvalRange args, TaggedValue &res) { CsInt offset = ostd::max(args[2].get_int(), 0); CsInt len = ostd::max(args[3].get_int(), 0); ostd::ConstCharRange s = args[0].get_strr(); ostd::ConstCharRange vals = args[1].get_strr(); char const *list = s.data(); util::ListParser p(s); - for (CsInt i = 0; i < offset; ++i) - if (!p.parse()) + for (CsInt i = 0; i < offset; ++i) { + if (!p.parse()) { break; + } + } char const *qend = !p.quote.empty() ? &p.quote[p.quote.size()] : list; ostd::Vector buf; - if (qend > list) + if (qend > list) { buf.push_n(list, qend - list); + } if (!vals.empty()) { - if (!buf.empty()) + if (!buf.empty()) { buf.push(' '); + } buf.push_n(vals.data(), vals.size()); } - for (CsInt i = 0; i < len; ++i) - if (!p.parse()) + for (CsInt i = 0; i < len; ++i) { + if (!p.parse()) { break; + } + } p.skip(); - if (!p.input.empty()) switch (p.input.front()) { - case ')': - case ']': - break; - default: - if (!buf.empty()) - buf.push(' '); - buf.push_n(p.input.data(), p.input.size()); - break; + if (!p.input.empty()) { + switch (p.input.front()) { + case ')': + case ']': + break; + default: + if (!buf.empty()) { + buf.push(' '); + } + buf.push_n(p.input.data(), p.input.size()); + break; + } } buf.push('\0'); ostd::Size slen = buf.size() - 1; @@ -458,8 +569,9 @@ static void cs_list_sort( CsState &cs, TaggedValue &res, ostd::ConstCharRange list, Ident *x, Ident *y, Bytecode *body, Bytecode *unique ) { - if (x == y || !x->is_alias() || !y->is_alias()) + if (x == y || !x->is_alias() || !y->is_alias()) { return; + } ostd::Vector items; ostd::Size clen = list.size(); @@ -497,9 +609,9 @@ static void cs_list_sort( nuniq = 1; for (ostd::Size i = 1; i < items.size(); i++) { ListSortItem &item = items[i]; - if (f(items[i - 1], item)) + if (f(items[i - 1], item)) { item.quote = nullptr; - else { + } else { totaluniq += item.quote.size(); ++nuniq; } @@ -538,10 +650,12 @@ static void cs_list_sort( ostd::Size offset = 0; for (ostd::Size i = 0; i < items.size(); ++i) { ListSortItem &item = items[i]; - if (item.quote.empty()) + if (item.quote.empty()) { continue; - if (i) + } + if (i) { sorted[offset++] = ' '; + } memcpy(&sorted[offset], item.quote.data(), item.quote.size()); offset += item.quote.size(); } @@ -551,13 +665,17 @@ static void cs_list_sort( } static void cs_init_lib_list_sort(CsState &cs) { - cs.add_command("sortlist", "srree", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("sortlist", "srree", [&cs]( + TvalRange args, TaggedValue &res + ) { cs_list_sort( cs, res, args[0].get_strr(), args[1].get_ident(), args[2].get_ident(), args[3].get_code(), args[4].get_code() ); }); - cs.add_command("uniquelist", "srre", [&cs](TvalRange args, TaggedValue &res) { + cs.add_command("uniquelist", "srre", [&cs]( + TvalRange args, TaggedValue &res + ) { cs_list_sort( cs, res, args[0].get_strr(), args[1].get_ident(), args[2].get_ident(), nullptr, args[3].get_code()