Mercurial > hg > orthanc
diff Core/Lua/LuaFunctionCall.cpp @ 997:1b1d51e9f1a2 lua-scripting
return Json from Lua
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 03 Jul 2014 18:12:50 +0200 |
parents | cf52f3bcb2b3 |
children | 160dfe770618 |
line wrap: on
line diff
--- a/Core/Lua/LuaFunctionCall.cpp Thu Jul 03 16:27:16 2014 +0200 +++ b/Core/Lua/LuaFunctionCall.cpp Thu Jul 03 18:12:50 2014 +0200 @@ -34,7 +34,9 @@ #include "LuaFunctionCall.h" #include <cassert> - +#include <stdio.h> +#include <boost/lexical_cast.hpp> +#include <glog/logging.h> namespace Orthanc { @@ -80,7 +82,7 @@ lua_pushnumber(context_.lua_, value); } - void LuaFunctionCall::PushJSON(const Json::Value& value) + void LuaFunctionCall::PushJson(const Json::Value& value) { CheckAlreadyExecuted(); @@ -119,7 +121,7 @@ lua_pushnumber(context_.lua_, i + 1); // Push the value of the cell - PushJSON(value[i]); + PushJson(value[i]); // Stores the pair in the table lua_rawset(context_.lua_, -3); @@ -138,7 +140,7 @@ lua_pushstring(context_.lua_, it->c_str()); // Push the value of the cell - PushJSON(value[*it]); + PushJson(value[*it]); // Stores the pair in the table lua_rawset(context_.lua_, -3); @@ -150,7 +152,7 @@ } } - void LuaFunctionCall::Execute(int numOutputs) + void LuaFunctionCall::ExecuteInternal(int numOutputs) { CheckAlreadyExecuted(); @@ -177,13 +179,8 @@ bool LuaFunctionCall::ExecutePredicate() { - Execute(1); - - if (lua_gettop(context_.lua_) == 0) - { - throw LuaException("No output was provided by the function"); - } - + ExecuteInternal(1); + if (!lua_isboolean(context_.lua_, 1)) { throw LuaException("The function is not a predicate (only true/false outputs allowed)"); @@ -191,4 +188,95 @@ return lua_toboolean(context_.lua_, 1) != 0; } + + + static void PopJson(Json::Value& result, + lua_State* lua, + int top) + { + if (lua_istable(lua, top)) + { + Json::Value tmp = Json::objectValue; + bool isArray = true; + size_t size = 0; + + // http://stackoverflow.com/a/6142700/881731 + + // Push another reference to the table on top of the stack (so we know + // where it is, and this function can work for negative, positive and + // pseudo indices + lua_pushvalue(lua, top); + // stack now contains: -1 => table + lua_pushnil(lua); + // stack now contains: -1 => nil; -2 => table + while (lua_next(lua, -2)) + { + // stack now contains: -1 => value; -2 => key; -3 => table + // copy the key so that lua_tostring does not modify the original + lua_pushvalue(lua, -2); + // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table + std::string key(lua_tostring(lua, -1)); + Json::Value v; + PopJson(v, lua, -2); + + tmp[key] = v; + + size += 1; + try + { + if (boost::lexical_cast<size_t>(key) != size) + { + isArray = false; + } + } + catch (boost::bad_lexical_cast&) + { + isArray = false; + } + + // pop value + copy of key, leaving original key + lua_pop(lua, 2); + // stack now contains: -1 => key; -2 => table + } + // stack now contains: -1 => table (when lua_next returns 0 it pops the key + // but does not push anything.) + // Pop table + lua_pop(lua, 1); + + // Stack is now the same as it was on entry to this function + + if (isArray) + { + result = Json::arrayValue; + for (size_t i = 0; i < size; i++) + { + result.append(tmp[boost::lexical_cast<std::string>(i + 1)]); + } + } + else + { + result = tmp; + } + } + else if (lua_isnumber(lua, top)) + { + result = static_cast<float>(lua_tonumber(lua, top)); + } + else if (lua_isstring(lua, top)) + { + result = std::string(lua_tostring(lua, top)); + } + else + { + LOG(WARNING) << "Unsupported Lua type when returning Json"; + result = Json::nullValue; + } + } + + + void LuaFunctionCall::ExecuteToJson(Json::Value& result) + { + ExecuteInternal(1); + PopJson(result, context_.lua_, lua_gettop(context_.lua_)); + } }