alias_local and get_ident() memory safety (always return refs)

master
Daniel Kolesa 2021-04-24 23:33:19 +02:00
parent 960f463259
commit f4b8d077bb
11 changed files with 238 additions and 218 deletions

View File

@ -68,6 +68,12 @@ struct LIBCUBESCRIPT_EXPORT ident {
*/
int get_index() const;
/** @brief Check if the idents are the same. */
bool operator==(ident &other) const;
/** @brief Check if the idents are not the same. */
bool operator!=(ident &other) const;
/** @brief Check if the ident is a cubescript::alias.
*
* Effectively like `get_type() == ident_type::ALIAS`.

View File

@ -36,20 +36,18 @@ namespace cubescript {
* Therefore, what you can do is something like this:
*
* ```
* if (alias_local s{my_thread, &my_thread.new_ident("test")}; s) {
* {
* alias_local s{my_thread, "test"};
* // branch taken when the alias was successfully pushed
* // setting the alias will only be visible within this scope
* s.set(some_value); // a convenient setter
* my_thread.run(...);
* } else {
* // you can handle an error here
* }
* ```
*
* The `else` branch can happen one case; either the given ident is `nullptr`
* (which will never happen here) or it's not a cubescript::alias (which can
* happen if an ident of such name already exists and is not an alias). If
* it fails, obviously no push/pop happens.
* If the provided input is not an alias, a cubescript::error will be thrown.
* Often you don't have to catch it (since this is primarily intended for use
* within commands, the error will propagate outside your command).
*
* Since the goal is to interact tightly with RAII and ensure consistency at
* all times, it is not possible to copy or move this object. That means you
@ -58,7 +56,20 @@ namespace cubescript {
*/
struct LIBCUBESCRIPT_EXPORT alias_local {
/** @brief Construct the local handler */
alias_local(state &cs, ident *a);
alias_local(state &cs, ident &a);
/** @brief Construct the local handler
*
* The ident will be retrieved using state::new_ident().
*/
alias_local(state &cs, std::string_view name);
/** @brief Construct the local handler
*
* The ident will be retrieved from the value. If the contained value
* is not an ident, it will be treated as a name.
*/
alias_local(state &cs, any_value const &val);
/** @brief Destroy the local handler */
~alias_local();
@ -93,9 +104,6 @@ struct LIBCUBESCRIPT_EXPORT alias_local {
*/
bool set(any_value val);
/** @brief Get if there is an alias associated with this handler */
explicit operator bool() const noexcept;
private:
alias *p_alias;
void *p_sp;

View File

@ -220,6 +220,13 @@ struct LIBCUBESCRIPT_EXPORT string_ref {
*/
bool operator==(string_ref const &s) const;
/** @brief Check if the string does not equal another.
*
* This is effectively a `data() != s.data()` address comparison, and
* therefore always has constant time complexity.
*/
bool operator!=(string_ref const &s) const;
private:
string_ref(char const *p);
@ -374,9 +381,9 @@ struct LIBCUBESCRIPT_EXPORT any_value {
/** @brief Get the value as an ident.
*
* If the contained value is not an ident, `nullptr` is returned.
* If the contained value is not an ident, a dummy is returned.
*/
ident *get_ident() const;
ident &get_ident(state &cs) const;
/** @brief Get the value as representable inside the language.
*

View File

@ -170,6 +170,14 @@ LIBCUBESCRIPT_EXPORT int ident::get_index() const {
return p_impl->p_index;
}
LIBCUBESCRIPT_EXPORT bool ident::operator==(ident &other) const {
return this == &other;
}
LIBCUBESCRIPT_EXPORT bool ident::operator!=(ident &other) const {
return this != &other;
}
LIBCUBESCRIPT_EXPORT bool ident::is_alias() const {
return get_type() == ident_type::ALIAS;
}
@ -463,19 +471,28 @@ LIBCUBESCRIPT_EXPORT int command::get_num_args() const {
/* external API for alias stack management */
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident *a) {
if (!a || !a->is_alias()) {
p_alias = nullptr;
return;
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident &a) {
if (!a.is_alias()) {
throw error{cs, "ident '%s' is not an alias", a.get_name().data()};
}
auto &ts = state_p{cs}.ts();
p_alias = static_cast<alias *>(a);
p_alias = static_cast<alias *>(&a);
auto &ast = ts.get_astack(p_alias);
ast.push(ts.idstack.emplace_back());
p_sp = &ast;
ast.flags &= ~IDENT_FLAG_UNKNOWN;
}
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, std::string_view name):
alias_local{cs, cs.new_ident(name)}
{}
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, any_value const &v):
alias_local{cs, (
v.get_type() == value_type::IDENT
) ? v.get_ident(cs) : cs.new_ident(v.get_string(cs))}
{}
LIBCUBESCRIPT_EXPORT alias_local::~alias_local() {
if (p_alias) {
static_cast<alias_stack *>(p_sp)->pop();
@ -490,8 +507,4 @@ LIBCUBESCRIPT_EXPORT bool alias_local::set(any_value val) {
return true;
}
LIBCUBESCRIPT_EXPORT alias_local::operator bool() const noexcept {
return !!p_alias;
}
} /* namespace cubescript */

View File

@ -124,7 +124,7 @@ state::state(alloc_func func, void *data) {
statep->cmd_ivar = &new_command("//ivar_builtin", "$iN", [](
auto &cs, auto args, auto &
) {
auto *iv = args[0].get_ident()->get_ivar();
auto *iv = args[0].get_ident(cs).get_ivar();
if (args[2].get_integer() <= 1) {
std::printf("%s = ", iv->get_name().data());
std::printf(INTEGER_FORMAT, iv->get_value());
@ -137,7 +137,7 @@ state::state(alloc_func func, void *data) {
statep->cmd_fvar = &new_command("//fvar_builtin", "$fN", [](
auto &cs, auto args, auto &
) {
auto *fv = args[0].get_ident()->get_fvar();
auto *fv = args[0].get_ident(cs).get_fvar();
if (args[2].get_integer() <= 1) {
auto val = fv->get_value();
std::printf("%s = ", fv->get_name().data());
@ -155,7 +155,7 @@ state::state(alloc_func func, void *data) {
statep->cmd_svar = &new_command("//svar_builtin", "$sN", [](
auto &cs, auto args, auto &
) {
auto *sv = args[0].get_ident()->get_svar();
auto *sv = args[0].get_ident(cs).get_svar();
if (args[2].get_integer() <= 1) {
auto val = sv->get_value();
if (val.view().find('"') == std::string_view::npos) {

View File

@ -158,4 +158,8 @@ LIBCUBESCRIPT_EXPORT bool string_ref::operator==(string_ref const &s) const {
return p_str == s.p_str;
}
LIBCUBESCRIPT_EXPORT bool string_ref::operator!=(string_ref const &s) const {
return p_str != s.p_str;
}
} /* namespace cubescript */

View File

@ -311,11 +311,11 @@ bcode_ref any_value::get_code() const {
return bcode_p::make_ref(csv_get<bcode *>(&p_stor));
}
ident *any_value::get_ident() const {
ident &any_value::get_ident(state &cs) const {
if (get_type() != value_type::IDENT) {
return nullptr;
return *state_p{cs}.ts().istate->id_dummy;
}
return csv_get<ident *>(&p_stor);
return *csv_get<ident *>(&p_stor);
}
string_ref any_value::get_string(state &cs) const {

View File

@ -9,18 +9,18 @@
namespace cubescript {
static inline void push_alias(thread_state &ts, ident *id, ident_stack &st) {
if (id->is_alias() && !static_cast<alias *>(id)->is_arg()) {
auto *aimp = static_cast<alias_impl *>(id);
static inline void push_alias(thread_state &ts, ident &id, ident_stack &st) {
if (id.is_alias() && !static_cast<alias &>(id).is_arg()) {
auto *aimp = static_cast<alias_impl *>(&id);
auto ast = ts.get_astack(aimp);
ast.push(st);
ast.flags &= ~IDENT_FLAG_UNKNOWN;
}
}
static inline void pop_alias(thread_state &ts, ident *id) {
if (id->is_alias() && !static_cast<alias *>(id)->is_arg()) {
ts.get_astack(static_cast<alias *>(id)).pop();
static inline void pop_alias(thread_state &ts, ident &id) {
if (id.is_alias() && !static_cast<alias &>(id).is_arg()) {
ts.get_astack(static_cast<alias *>(&id)).pop();
}
}
@ -548,13 +548,13 @@ std::uint32_t *vm_exec(
std::size_t idstsz = ts.idstack.size();
for (std::size_t i = 0; i < numlocals; ++i) {
push_alias(
ts, args[offset + i].get_ident(),
ts, args[offset + i].get_ident(cs),
ts.idstack.emplace_back()
);
}
auto cleanup = [&]() {
for (std::size_t i = offset; i < args.size(); ++i) {
pop_alias(ts, args[i].get_ident());
pop_alias(ts, args[i].get_ident(cs));
}
ts.idstack.resize(idstsz);
};
@ -1111,13 +1111,13 @@ noid:
std::size_t idstsz = ts.idstack.size();
for (size_t j = 0; j < size_t(callargs); ++j) {
push_alias(
ts, &args[offset + j].force_ident(cs),
ts, args[offset + j].force_ident(cs),
ts.idstack.emplace_back()
);
}
auto cleanup = [&]() {
for (size_t j = 0; j < size_t(callargs); ++j) {
pop_alias(ts, args[offset + j].get_ident());
pop_alias(ts, args[offset + j].get_ident(cs));
}
ts.idstack.resize(idstsz);
};

View File

@ -15,7 +15,7 @@ static inline void do_loop(
if (n <= 0) {
return;
}
if (alias_local st{cs, &id}; st) {
alias_local st{cs, id};
any_value idv{};
for (integer_type i = 0; i < n; ++i) {
idv.set_integer(offset + i * step);
@ -31,7 +31,6 @@ static inline void do_loop(
}
}
}
}
static inline void do_loop_conc(
state &cs, any_value &res, ident &id, integer_type offset, integer_type n,
@ -40,7 +39,7 @@ static inline void do_loop_conc(
if (n <= 0) {
return;
}
if (alias_local st{cs, &id}; st) {
alias_local st{cs, id};
charbuf s{cs};
any_value idv{};
for (integer_type i = 0; i < n; ++i) {
@ -63,7 +62,6 @@ static inline void do_loop_conc(
end:
res.set_string(s.str(), cs);
}
}
LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
new_cmd_quiet(gcs, "error", "s", [](auto &cs, auto args, auto &) {
@ -71,8 +69,8 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
});
new_cmd_quiet(gcs, "pcall", "err", [](auto &cs, auto args, auto &ret) {
alias *cret = args[1].get_ident()->get_alias();
alias *css = args[2].get_ident()->get_alias();
alias *cret = args[1].get_ident(cs).get_alias();
alias *css = args[2].get_ident(cs).get_alias();
if (!cret || !css) {
ret.set_integer(0);
return;
@ -158,41 +156,40 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
});
new_cmd_quiet(gcs, "pushif", "rte", [](auto &cs, auto args, auto &res) {
if (alias_local st{cs, args[0].get_ident()}; st) {
alias_local st{cs, args[0]};
if (st.get_alias()->is_arg()) {
return;
throw error{cs, "cannot push an argument"};
}
if (args[1].get_bool()) {
st.set(args[1]);
res = cs.run(args[2].get_code());
}
}
});
new_cmd_quiet(gcs, "loop", "rie", [](auto &cs, auto args, auto &) {
do_loop(
cs, *args[0].get_ident(), 0, args[1].get_integer(), 1, bcode_ref{},
args[2].get_code()
cs, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
bcode_ref{}, args[2].get_code()
);
});
new_cmd_quiet(gcs, "loop+", "riie", [](auto &cs, auto args, auto &) {
do_loop(
cs, *args[0].get_ident(), args[1].get_integer(),
cs, args[0].get_ident(cs), args[1].get_integer(),
args[2].get_integer(), 1, bcode_ref{}, args[3].get_code()
);
});
new_cmd_quiet(gcs, "loop*", "riie", [](auto &cs, auto args, auto &) {
do_loop(
cs, *args[0].get_ident(), 0, args[1].get_integer(),
cs, args[0].get_ident(cs), 0, args[1].get_integer(),
args[2].get_integer(), bcode_ref{}, args[3].get_code()
);
});
new_cmd_quiet(gcs, "loop+*", "riiie", [](auto &cs, auto args, auto &) {
do_loop(
cs, *args[0].get_ident(), args[1].get_integer(),
cs, args[0].get_ident(cs), args[1].get_integer(),
args[3].get_integer(), args[2].get_integer(),
bcode_ref{}, args[4].get_code()
);
@ -200,21 +197,21 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
new_cmd_quiet(gcs, "loopwhile", "riee", [](auto &cs, auto args, auto &) {
do_loop(
cs, *args[0].get_ident(), 0, args[1].get_integer(), 1,
cs, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
args[2].get_code(), args[3].get_code()
);
});
new_cmd_quiet(gcs, "loopwhile+", "riiee", [](auto &cs, auto args, auto &) {
do_loop(
cs, *args[0].get_ident(), args[1].get_integer(),
cs, args[0].get_ident(cs), args[1].get_integer(),
args[2].get_integer(), 1, args[3].get_code(), args[4].get_code()
);
});
new_cmd_quiet(gcs, "loopwhile*", "riiee", [](auto &cs, auto args, auto &) {
do_loop(
cs, *args[0].get_ident(), 0, args[2].get_integer(),
cs, args[0].get_ident(cs), 0, args[2].get_integer(),
args[1].get_integer(), args[3].get_code(), args[4].get_code()
);
});
@ -223,7 +220,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
auto &cs, auto args, auto &
) {
do_loop(
cs, *args[0].get_ident(), args[1].get_integer(),
cs, args[0].get_ident(cs), args[1].get_integer(),
args[3].get_integer(), args[2].get_integer(), args[4].get_code(),
args[5].get_code()
);
@ -248,7 +245,7 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), 0, args[1].get_integer(), 1,
cs, res, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
args[2].get_code(), true
);
});
@ -257,7 +254,7 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_integer(),
cs, res, args[0].get_ident(cs), args[1].get_integer(),
args[2].get_integer(), 1, args[3].get_code(), true
);
});
@ -266,7 +263,7 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), 0, args[2].get_integer(),
cs, res, args[0].get_ident(cs), 0, args[2].get_integer(),
args[1].get_integer(), args[3].get_code(), true
);
});
@ -275,7 +272,7 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_integer(),
cs, res, args[0].get_ident(cs), args[1].get_integer(),
args[3].get_integer(), args[2].get_integer(),
args[4].get_code(), true
);
@ -285,7 +282,7 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), 0, args[1].get_integer(), 1,
cs, res, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
args[2].get_code(), false
);
});
@ -294,7 +291,7 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_integer(),
cs, res, args[0].get_ident(cs), args[1].get_integer(),
args[2].get_integer(), 1, args[3].get_code(), false
);
});
@ -303,7 +300,7 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), 0, args[2].get_integer(),
cs, res, args[0].get_ident(cs), 0, args[2].get_integer(),
args[1].get_integer(), args[3].get_code(), false
);
});
@ -312,20 +309,19 @@ end:
auto &cs, auto args, auto &res
) {
do_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_integer(),
cs, res, args[0].get_ident(cs), args[1].get_integer(),
args[3].get_integer(), args[2].get_integer(),
args[4].get_code(), false
);
});
new_cmd_quiet(gcs, "push", "rte", [](auto &cs, auto args, auto &res) {
if (alias_local st{cs, args[0].get_ident()}; st) {
alias_local st{cs, args[0]};
if (st.get_alias()->is_arg()) {
return;
throw error{cs, "cannot push an argument"};
}
st.set(args[1]);
res = cs.run(args[2].get_code());
}
});
new_cmd_quiet(gcs, "resetvar", "s", [](auto &cs, auto args, auto &) {

View File

@ -73,10 +73,10 @@ static inline void list_assoc(
}
static void loop_list_conc(
state &cs, any_value &res, ident *id, std::string_view list,
state &cs, any_value &res, ident &id, std::string_view list,
bcode_ref &&body, bool space
) {
if (alias_local st{cs, id}; st) {
alias_local st{cs, id};
any_value idv{};
charbuf r{cs};
int n = 0;
@ -100,7 +100,6 @@ static void loop_list_conc(
end:
res.set_string(r.str(), cs);
}
}
int list_includes(
state &cs, std::string_view list, std::string_view needle
@ -206,7 +205,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
});
new_cmd_quiet(gcs, "listfind", "rse", [](auto &cs, auto args, auto &res) {
if (alias_local st{cs, args[0].get_ident()}; st) {
alias_local st{cs, args[0]};
any_value idv{};
auto body = args[2].get_code();
int n = -1;
@ -219,12 +218,11 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
return;
}
}
}
res.set_integer(-1);
});
new_cmd_quiet(gcs, "listassoc", "rse", [](auto &cs, auto args, auto &res) {
if (alias_local st{cs, args[0].get_ident()}; st) {
alias_local st{cs, args[0]};
any_value idv{};
auto body = args[2].get_code();
int n = -1;
@ -242,7 +240,6 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
break;
}
}
}
});
new_cmd_quiet(gcs, "listfind=", "i", [](auto &cs, auto args, auto &res) {
@ -290,7 +287,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
});
new_cmd_quiet(gcs, "looplist", "rse", [](auto &cs, auto args, auto &) {
if (alias_local st{cs, args[0].get_ident()}; st) {
alias_local st{cs, args[0]};
any_value idv{};
auto body = args[2].get_code();
int n = 0;
@ -304,15 +301,11 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
break;
}
}
}
});
new_cmd_quiet(gcs, "looplist2", "rrse", [](auto &cs, auto args, auto &) {
alias_local st1{cs, args[0].get_ident()};
alias_local st2{cs, args[1].get_ident()};
if (!st1 || !st2) {
return;
}
alias_local st1{cs, args[0]};
alias_local st2{cs, args[1]};
any_value idv{};
auto body = args[3].get_code();
int n = 0;
@ -335,12 +328,9 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
});
new_cmd_quiet(gcs, "looplist3", "rrrse", [](auto &cs, auto args, auto &) {
alias_local st1{cs, args[0].get_ident()};
alias_local st2{cs, args[1].get_ident()};
alias_local st3{cs, args[2].get_ident()};
if (!st1 || !st2 || !st3) {
return;
}
alias_local st1{cs, args[0]};
alias_local st2{cs, args[1]};
alias_local st3{cs, args[2]};
any_value idv{};
auto body = args[4].get_code();
int n = 0;
@ -372,7 +362,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
auto &cs, auto args, auto &res
) {
loop_list_conc(
cs, res, args[0].get_ident(), args[1].get_string(cs),
cs, res, args[0].get_ident(cs), args[1].get_string(cs),
args[2].get_code(), true
);
});
@ -381,7 +371,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
auto &cs, auto args, auto &res
) {
loop_list_conc(
cs, res, args[0].get_ident(), args[1].get_string(cs),
cs, res, args[0].get_ident(cs), args[1].get_string(cs),
args[2].get_code(), false
);
});
@ -389,7 +379,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
new_cmd_quiet(gcs, "listfilter", "rse", [](
auto &cs, auto args, auto &res
) {
if (alias_local st{cs, args[0].get_ident()}; st) {
alias_local st{cs, args[0]};
any_value idv{};
auto body = args[2].get_code();
charbuf r{cs};
@ -405,11 +395,10 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
}
}
res.set_string(r.str(), cs);
}
});
new_cmd_quiet(gcs, "listcount", "rse", [](auto &cs, auto args, auto &res) {
if (alias_local st{cs, args[0].get_ident()}; st) {
alias_local st{cs, args[0]};
any_value idv{};
auto body = args[2].get_code();
int n = 0, r = 0;
@ -421,7 +410,6 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
}
}
res.set_integer(r);
}
});
new_cmd_quiet(gcs, "prettylist", "ss", [](auto &cs, auto args, auto &res) {
@ -543,16 +531,13 @@ struct ListSortFun {
static void list_sort(
state &cs, any_value &res, std::string_view list,
ident *x, ident *y, bcode_ref &&body, bcode_ref &&unique
ident &x, ident &y, bcode_ref &&body, bcode_ref &&unique
) {
if (x == y) {
return;
}
alias_local xst{cs, x}, yst{cs, y};
if (!xst || !yst) {
return;
}
valbuf<ListSortItem> items{state_p{cs}.ts().istate};
size_t total = 0;
@ -627,16 +612,16 @@ static void init_lib_list_sort(state &gcs) {
auto &cs, auto args, auto &res
) {
list_sort(
cs, res, args[0].get_string(cs), args[1].get_ident(),
args[2].get_ident(), args[3].get_code(), args[4].get_code()
cs, res, args[0].get_string(cs), args[1].get_ident(cs),
args[2].get_ident(cs), args[3].get_code(), args[4].get_code()
);
});
new_cmd_quiet(gcs, "uniquelist", "srre", [](
auto &cs, auto args, auto &res
) {
list_sort(
cs, res, args[0].get_string(cs), args[1].get_ident(),
args[2].get_ident(), bcode_ref{}, args[3].get_code()
cs, res, args[0].get_string(cs), args[1].get_ident(cs),
args[2].get_ident(cs), bcode_ref{}, args[3].get_code()
);
});
}

View File

@ -325,7 +325,7 @@ int main(int argc, char **argv) {
* to be set, but you may also not be using standard i/o and so on
*/
gcs.new_command("//ivar", "$iiiN", [](auto &css, auto args, auto &) {
auto *iv = args[0].get_ident()->get_ivar();
auto *iv = args[0].get_ident(css).get_ivar();
auto nargs = args[4].get_integer();
if (nargs <= 1) {
auto val = iv->get_value();
@ -355,9 +355,10 @@ int main(int argc, char **argv) {
}
});
gcs.new_command("//var_changed", "$", [](auto &, auto args, auto &) {
gcs.new_command("//var_changed", "$", [](auto &css, auto args, auto &) {
std::printf(
"changed var trigger: %s\n", args[0].get_ident()->get_name().data()
"changed var trigger: %s\n",
args[0].get_ident(css).get_name().data()
);
});