lib/utils: build s-expression programmatically building

Allow for programmatically buildings sexps, rather that using raw
strings.
This commit is contained in:
Dirk-Jan C. Binnema
2020-06-01 19:01:03 +03:00
parent b672f6bc1d
commit 3afdc08d50
11 changed files with 507 additions and 270 deletions

View File

@ -27,24 +27,25 @@ using namespace Mu;
using namespace Command;
using namespace Sexp;
using Type = Node::Type;
static Mu::Error
command_error(const std::string& msg)
{
return Mu::Error(Error::Code::Command, msg);
}
void
Command::invoke(const Command::CommandMap& cmap, const Node& call)
{
if (call.type != Type::List || call.children.empty() ||
call.children[0].type != Type::Symbol)
if (call.type() != Type::List || call.elements().empty() ||
call.elements().at(0).type() != Type::Symbol)
throw command_error("call must be a list starting with a symbol");
const auto& params{call.children};
const auto cmd_it = cmap.find(params[0].value);
const auto& params{call.elements()};
const auto cmd_it = cmap.find(params.at(0).value());
if (cmd_it == cmap.end())
throw command_error("unknown command '" + params[0].value + "'");
throw command_error("unknown command '" + params.at(0).value() + "'");
const auto& cinfo{cmd_it->second};
@ -58,8 +59,8 @@ Command::invoke(const Command::CommandMap& cmap, const Node& call)
// so, we're looking for the odd-numbered parameters.
const auto param_it = [&]() {
for (size_t i = 1; i < params.size(); i += 2)
if (params[i].type == Type::Symbol &&
params[i].value == ':' + argname)
if (params.at(i).type() == Type::Symbol &&
params.at(i).value() == ':' + argname)
return params.begin() + i + 1;
return params.end();
@ -75,31 +76,31 @@ Command::invoke(const Command::CommandMap& cmap, const Node& call)
// the types must match, but the 'nil' symbol is acceptable as
// "no value"
if (param_it->type != arginfo.type &&
!(param_it->type == Type::Symbol && param_it->value == "nil"))
if (param_it->type() != arginfo.type &&
!(param_it->type() == Type::Symbol && param_it->value() == "nil"))
throw command_error("parameter '" + argname + "' expects type " +
to_string(arginfo.type) +
" but got " + to_string(param_it->type));
" but got " + to_string(param_it->type()));
}
// all passed parameters must be known
for (size_t i = 1; i < params.size(); i += 2) {
if (std::none_of(cinfo.args.begin(), cinfo.args.end(),
[&](auto&& arg) {return params[i].value == ":" + arg.first;}))
throw command_error("unknown parameter '" + params[i].value + "'");
[&](auto&& arg) {return params.at(i).value() == ":" + arg.first;}))
throw command_error("unknown parameter '" + params.at(i).value() + "'");
}
if (cinfo.handler)
cinfo.handler(params);
}
static Parameters::const_iterator
static auto
find_param_node (const Parameters& params, const std::string& argname)
{
for (size_t i = 1; i < params.size(); i += 2) {
if (i + 1 != params.size() &&
params[i].type == Type::Symbol &&
params[i].value == ':' + argname)
params.at(i).type() == Type::Symbol &&
params.at(i).value() == ':' + argname)
return params.begin() + i + 1;
}
@ -111,7 +112,7 @@ constexpr auto Nil = "nil";
static bool
is_nil(const Node& node)
{
return node.type == Type::Symbol && node.value == Nil;
return node.type() == Type::Symbol && node.value() == Nil;
}
const std::string&
@ -121,12 +122,12 @@ Command::get_string_or (const Parameters& params, const std::string& argname,
const auto it = find_param_node (params, argname);
if (it == params.end() || is_nil(*it))
return alt;
else if (it->type != Type::String)
else if (it->type() != Type::String)
throw Error(Error::Code::InvalidArgument, "expected <string> but got %s (value: '%s')",
to_string(it->type).c_str(),
it->value.c_str());
to_string(it->type()).c_str(),
it->value().c_str());
return it->value;
return it->value();
}
const std::string&
@ -136,12 +137,12 @@ Command::get_symbol_or (const Parameters& params, const std::string& argname,
const auto it = find_param_node (params, argname);
if (it == params.end() || is_nil(*it))
return alt;
else if (it->type != Type::Symbol)
else if (it->type() != Type::Symbol)
throw Error(Error::Code::InvalidArgument, "expected <symbol> but got %s (value: '%s')",
to_string(it->type).c_str(),
it->value.c_str());
to_string(it->type()).c_str(),
it->value().c_str());
return it->value;
return it->value();
}
@ -152,11 +153,11 @@ Command::get_int_or (const Parameters& params, const std::string& argname,
const auto it = find_param_node (params, argname);
if (it == params.end() || is_nil(*it))
return alt;
else if (it->type != Type::Integer)
else if (it->type() != Type::Number)
throw Error(Error::Code::InvalidArgument, "expected <integer> but got %s",
to_string(it->type).c_str());
to_string(it->type()).c_str());
else
return ::atoi(it->value.c_str());
return ::atoi(it->value().c_str());
}
bool
@ -166,11 +167,11 @@ Command::get_bool_or (const Parameters& params, const std::string& argname,
const auto it = find_param_node (params, argname);
if (it == params.end())
return alt;
else if (it->type != Type::Symbol)
else if (it->type() != Type::Symbol)
throw Error(Error::Code::InvalidArgument, "expected <symbol> but got %s",
to_string(it->type).c_str());
to_string(it->type()).c_str());
else
return it->value != Nil;
return it->value() != Nil;
}
std::vector<std::string>
@ -179,17 +180,17 @@ Command::get_string_vec (const Parameters& params, const std::string& argname)
const auto it = find_param_node (params, argname);
if (it == params.end() || is_nil(*it))
return {};
else if (it->type != Type::List)
else if (it->type() != Type::List)
throw Error(Error::Code::InvalidArgument, "expected <list> but got %s",
to_string(it->type).c_str());
to_string(it->type()).c_str());
std::vector<std::string> vec;
for (const auto& n: it->children) {
if (n.type != Type::String)
for (const auto& n: it->elements()) {
if (n.type() != Type::String)
throw Error(Error::Code::InvalidArgument,
"expected string element but got %s",
to_string(n.type).c_str());
vec.emplace_back (n.value);
to_string(n.type()).c_str());
vec.emplace_back (n.value());
}
return vec;