diff --git a/lib/utils/mu-command-parser.cc b/lib/utils/mu-command-parser.cc index 596be055..bca538ed 100644 --- a/lib/utils/mu-command-parser.cc +++ b/lib/utils/mu-command-parser.cc @@ -60,7 +60,7 @@ Command::invoke(const Command::CommandMap& cmap, const Node& call) const auto param_it = [&]() { for (size_t i = 1; i < params.size(); i += 2) if (params.at(i).type() == Type::Symbol && - params.at(i).value() == ':' + argname) + params.at(i).value() == argname) return params.begin() + i + 1; return params.end(); @@ -86,7 +86,7 @@ Command::invoke(const Command::CommandMap& cmap, const Node& call) // 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.at(i).value() == ":" + arg.first;})) + [&](auto&& arg) {return params.at(i).value() == arg.first;})) throw command_error("unknown parameter '" + params.at(i).value() + "'"); } @@ -97,10 +97,19 @@ Command::invoke(const Command::CommandMap& cmap, const Node& call) static auto find_param_node (const Parameters& params, const std::string& argname) { + if (params.empty()) + throw Error(Error::Code::InvalidArgument, + "params must not be empty"); + + if (argname.empty() || argname.at(0) != ':') + throw Error(Error::Code::InvalidArgument, + "property key must start with ':' but got '%s')", + argname.c_str()); + for (size_t i = 1; i < params.size(); i += 2) { if (i + 1 != params.size() && params.at(i).type() == Type::Symbol && - params.at(i).value() == ':' + argname) + params.at(i).value() == argname) return params.begin() + i + 1; } @@ -123,7 +132,8 @@ Command::get_string_or (const Parameters& params, const std::string& argname, if (it == params.end() || is_nil(*it)) return alt; else if (it->type() != Type::String) - throw Error(Error::Code::InvalidArgument, "expected but got %s (value: '%s')", + throw Error(Error::Code::InvalidArgument, + "expected but got %s (value: '%s')", to_string(it->type()).c_str(), it->value().c_str()); @@ -138,7 +148,8 @@ Command::get_symbol_or (const Parameters& params, const std::string& argname, if (it == params.end() || is_nil(*it)) return alt; else if (it->type() != Type::Symbol) - throw Error(Error::Code::InvalidArgument, "expected but got %s (value: '%s')", + throw Error(Error::Code::InvalidArgument, + "expected but got %s (value: '%s')", to_string(it->type()).c_str(), it->value().c_str()); @@ -154,7 +165,8 @@ Command::get_int_or (const Parameters& params, const std::string& argname, if (it == params.end() || is_nil(*it)) return alt; else if (it->type() != Type::Number) - throw Error(Error::Code::InvalidArgument, "expected but got %s", + throw Error(Error::Code::InvalidArgument, + "expected but got %s", to_string(it->type()).c_str()); else return ::atoi(it->value().c_str()); @@ -168,7 +180,8 @@ Command::get_bool_or (const Parameters& params, const std::string& argname, if (it == params.end()) return alt; else if (it->type() != Type::Symbol) - throw Error(Error::Code::InvalidArgument, "expected but got %s", + throw Error(Error::Code::InvalidArgument, + "expected but got %s", to_string(it->type()).c_str()); else return it->value() != Nil; @@ -181,7 +194,8 @@ Command::get_string_vec (const Parameters& params, const std::string& argname) if (it == params.end() || is_nil(*it)) return {}; else if (it->type() != Type::List) - throw Error(Error::Code::InvalidArgument, "expected but got %s", + throw Error(Error::Code::InvalidArgument, + "expected but got %s", to_string(it->type()).c_str()); std::vector vec; diff --git a/lib/utils/mu-command-parser.hh b/lib/utils/mu-command-parser.hh index 9ad8110d..f76b1852 100644 --- a/lib/utils/mu-command-parser.hh +++ b/lib/utils/mu-command-parser.hh @@ -134,7 +134,7 @@ static inline std::ostream& operator<<(std::ostream& os, const Command::CommandInfo& info) { for (auto&& arg: info.args) - os << " " << arg.first << ": " << arg.second << '\n' + os << " " << arg.first << " " << arg.second << '\n' << " " << arg.second.docstring << "\n"; return os; diff --git a/lib/utils/test-command-parser.cc b/lib/utils/test-command-parser.cc index 00da3163..bd5a7e7d 100644 --- a/lib/utils/test-command-parser.cc +++ b/lib/utils/test-command-parser.cc @@ -35,12 +35,12 @@ test_param_getters() std::cout << node << "\n"; - g_assert_cmpint(Command::get_int_or(node.elements(), "bar"), ==, 123); - assert_equal(Command::get_string_or(node.elements(), "bra", "bla"), "bla"); - assert_equal(Command::get_string_or(node.elements(), "cuux"), "456"); + g_assert_cmpint(Command::get_int_or(node.elements(), ":bar"), ==, 123); + assert_equal(Command::get_string_or(node.elements(), ":bra", "bla"), "bla"); + assert_equal(Command::get_string_or(node.elements(), ":cuux"), "456"); - g_assert_true(Command::get_bool_or(node.elements(),"boo") == false); - g_assert_true(Command::get_bool_or(node.elements(),"bah") == true); + g_assert_true(Command::get_bool_or(node.elements(),":boo") == false); + g_assert_true(Command::get_bool_or(node.elements(),":bah") == true); } @@ -67,15 +67,14 @@ test_command() CommandMap cmap; - cmap.emplace("my-command", CommandInfo{ - ArgMap{ {"param1", ArgInfo{Sexp::Node::Type::String, true, "some string" }}, - {"param2", ArgInfo{Sexp::Node::Type::Number, false, "some integer"}}}, + ArgMap{ {":param1", ArgInfo{Sexp::Node::Type::String, true, "some string" }}, + {":param2", ArgInfo{Sexp::Node::Type::Number, false, "some integer"}}}, "My command,", {}}); - //std::cout << cmap << "\n"; + std::cout << "****** " << cmap << "\n"; g_assert_true(call(cmap, "(my-command :param1 \"hello\")")); g_assert_true(call(cmap, "(my-command :param1 \"hello\" :param2 123)")); @@ -93,8 +92,8 @@ test_command2() cmap.emplace("bla", CommandInfo{ ArgMap{ - {"foo", ArgInfo{Sexp::Node::Type::Number, false, "foo"}}, - {"bar", ArgInfo{Sexp::Node::Type::String, false, "bar"}}, + {":foo", ArgInfo{Sexp::Node::Type::Number, false, "foo"}}, + {":bar", ArgInfo{Sexp::Node::Type::String, false, "bar"}}, },"yeah", [&](const auto& params){}}); @@ -115,8 +114,8 @@ test_command_fail() cmap.emplace("my-command", CommandInfo{ - ArgMap{ {"param1", ArgInfo{Sexp::Node::Type::String, true, "some string" }}, - {"param2", ArgInfo{Sexp::Node::Type::Number, false, "some integer"}}}, + ArgMap{ {":param1", ArgInfo{Sexp::Node::Type::String, true, "some string" }}, + {":param2", ArgInfo{Sexp::Node::Type::Number, false, "some integer"}}}, "My command,", {}});