mu: support json output directly

Allow for dumping json directly from the Sexp structures, so we don't
need any external libs (i.e. json-glib) anymore.
This commit is contained in:
Dirk-Jan C. Binnema
2020-10-26 18:39:56 +02:00
parent f2e87ea2d4
commit d2aa1f91b0
10 changed files with 93 additions and 66 deletions

View File

@ -33,7 +33,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
if (!call.is_call()) {
throw Mu::Error{Error::Code::Command,
"expected call-sexpr but got %s",
call.to_string().c_str()};
call.to_sexp_string().c_str()};
}
const auto& params{call.list()};
@ -41,7 +41,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
if (cmd_it == cmap.end())
throw Mu::Error{Error::Code::Command,
"unknown command in call %s",
call.to_string().c_str()};
call.to_sexp_string().c_str()};
const auto& cinfo{cmd_it->second};
@ -67,7 +67,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
if (arginfo.required)
throw Mu::Error{Error::Code::Command,
"missing required parameter %s in call %s",
argname.c_str(), call.to_string().c_str()};
argname.c_str(), call.to_sexp_string().c_str()};
continue; // not required
}
@ -78,7 +78,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
"parameter %s expects type %s, but got %s in call %s",
argname.c_str(), to_string(arginfo.type).c_str(),
to_string(param_it->type()).c_str(),
call.to_string().c_str()};
call.to_sexp_string().c_str()};
}
// all passed parameters must be known
@ -87,7 +87,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
[&](auto&& arg) {return params.at(i).value() == arg.first;}))
throw Mu::Error{Error::Code::Command,
"unknown parameter %s in call %s",
params.at(i).value().c_str(), call.to_string().c_str()};
params.at(i).value().c_str(), call.to_sexp_string().c_str()};
}
if (cinfo.handler)

View File

@ -179,7 +179,7 @@ Sexp::make_parse (const std::string& expr)
std::string
Sexp::to_string () const
Sexp::to_sexp_string () const
{
std::stringstream sstrm;
@ -188,7 +188,7 @@ Sexp::to_string () const
sstrm << '(';
bool first{true};
for (auto&& child : list()) {
sstrm << (first ? "" : " ") << child.to_string();
sstrm << (first ? "" : " ") << child.to_sexp_string();
first = false;
}
sstrm << ')';
@ -206,3 +206,55 @@ Sexp::to_string () const
return sstrm.str();
}
std::string
Sexp::to_json_string () const
{
std::stringstream sstrm;
switch (type()) {
case Type::List: {
// property-lists become JSON objects
if (is_prop_list()) {
sstrm << "{";
auto it{list().begin()};
bool first{true};
while (it != list().end()) {
sstrm << (first?"":",") << quote(it->value()) << ":";
++it;
sstrm << it->to_json_string();
++it;
first = false;
}
sstrm << "}";
} else { // other lists become arrays.
sstrm << '[';
bool first{true};
for (auto&& child : list()) {
sstrm << (first ? "" : ", ") << child.to_json_string();
first = false;
}
sstrm << ']';
}
break;
}
case Type::String:
sstrm << quote(value());
break;
case Type::Symbol:
if (is_nil())
sstrm << "false";
else if (is_t())
sstrm << "true";
else
sstrm << quote(value());
break;
case Type::Number:
case Type::Empty:
default:
sstrm << value();
}
return sstrm.str();
}

View File

@ -104,11 +104,19 @@ struct Sexp {
}
/**
* Convert a Sexp::Node to its string representation
* Convert a Sexp::Node to its S-expression string representation
*
* @return the string representation
*/
std::string to_string() const;
std::string to_sexp_string() const;
/**
* Convert a Sexp::Node to its JSON string representation
*
* @return the string representation
*/
std::string to_json_string() const;
/**
* Return the type of this Node.
@ -341,7 +349,7 @@ operator<<(std::ostream& os, Sexp::Type id)
static inline std::ostream&
operator<<(std::ostream& os, const Sexp& sexp)
{
os << sexp.to_string();
os << sexp.to_sexp_string();
return os;
}

View File

@ -63,17 +63,17 @@ test_list()
const auto nstr{Sexp::make_string("foo")};
g_assert_true(nstr.value() == "foo");
g_assert_true(nstr.type() == Sexp::Type::String);
assert_equal(nstr.to_string(), "\"foo\"");
assert_equal(nstr.to_sexp_string(), "\"foo\"");
const auto nnum{Sexp::make_number(123)};
g_assert_true(nnum.value() == "123");
g_assert_true(nnum.type() == Sexp::Type::Number);
assert_equal(nnum.to_string(), "123");
assert_equal(nnum.to_sexp_string(), "123");
const auto nsym{Sexp::make_symbol("blub")};
g_assert_true(nsym.value() == "blub");
g_assert_true(nsym.type() == Sexp::Type::Symbol);
assert_equal(nsym.to_string(), "blub");
assert_equal(nsym.to_sexp_string(), "blub");
Sexp::List list;
list .add(Sexp::make_string("foo"))
@ -85,7 +85,7 @@ test_list()
g_assert_true(nlst.type() == Sexp::Type::List);
g_assert_true(nlst.list().at(1).value() == "123");
assert_equal(nlst.to_string(),"(\"foo\" 123 blub)");
assert_equal(nlst.to_sexp_string(),"(\"foo\" 123 blub)");
}
@ -95,7 +95,7 @@ test_prop_list()
Sexp::List l1;
l1.add_prop(":foo", Sexp::make_string("bar"));
Sexp s2{Sexp::make_list(std::move(l1))};
assert_equal(s2.to_string(), "(:foo \"bar\")");
assert_equal(s2.to_sexp_string(), "(:foo \"bar\")");
Sexp::List l2;
@ -105,7 +105,7 @@ test_prop_list()
Sexp::List l3;
l3.add_prop(":cuux", Sexp::make_list(std::move(l2)));
Sexp s3{Sexp::make_list(std::move(l3))};
assert_equal(s3.to_string(), "(:cuux (:foo \"bar\" :bar 77))");
assert_equal(s3.to_sexp_string(), "(:cuux (:foo \"bar\" :bar 77))");
}
static void
@ -122,7 +122,7 @@ test_props()
":flub", Sexp::make_symbol("fnord"),
":boo", std::move(sexp2));
assert_equal(sexp.to_string(),
assert_equal(sexp.to_sexp_string(),
"(:foo \"b\303\244r\" :cuux 123 :flub fnord :boo (\"foo\" 123 blub))");
}