blob: 1a074f2b3e105a4bff3607c0715b9ef6df6d92c7 [file] [log] [blame]
/*
* Copyright (c) 2021, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LuaEngine.h"
#include <utility>
extern "C" {
#include "lauxlib.h"
#include "lualib.h"
}
namespace android {
namespace automotive {
namespace telemetry {
namespace script_executor {
LuaEngine::LuaEngine() {
// Instantiate Lua environment
mLuaState = luaL_newstate();
luaL_openlibs(mLuaState);
}
LuaEngine::~LuaEngine() {
lua_close(mLuaState);
}
lua_State* LuaEngine::GetLuaState() {
return mLuaState;
}
void LuaEngine::ResetListener(ScriptExecutorListener* listener) {
mListener.reset(listener);
}
int LuaEngine::LoadScript(const char* scriptBody) {
// As the first step in Lua script execution we want to load
// the body of the script into Lua stack and have it processed by Lua
// to catch any errors.
// More on luaL_dostring: https://www.lua.org/manual/5.3/manual.html#lual_dostring
// If error, pushes the error object into the stack.
const auto status = luaL_dostring(mLuaState, scriptBody);
if (status) {
// Removes error object from the stack.
// Lua stack must be properly maintained due to its limited size,
// ~20 elements and its critical function because all interaction with
// Lua happens via the stack.
// Starting read about Lua stack: https://www.lua.org/pil/24.2.html
// TODO(b/192284232): add test case to trigger this.
lua_pop(mLuaState, 1);
}
return status;
}
bool LuaEngine::PushFunction(const char* functionName) {
// Interaction between native code and Lua happens via Lua stack.
// In such model, a caller first pushes the name of the function
// that needs to be called, followed by the function's input
// arguments, one input value pushed at a time.
// More info: https://www.lua.org/pil/24.2.html
lua_getglobal(mLuaState, functionName);
const auto status = lua_isfunction(mLuaState, /*idx= */ -1);
// TODO(b/192284785): add test case for wrong function name in Lua.
if (status == 0) lua_pop(mLuaState, 1);
return status;
}
int LuaEngine::Run() {
// Performs blocking call of the provided Lua function. Assumes all
// input arguments are in the Lua stack as well in proper order.
// On how to call Lua functions: https://www.lua.org/pil/25.2.html
// Doc on lua_pcall: https://www.lua.org/manual/5.3/manual.html#lua_pcall
// TODO(b/189241508): Once we implement publishedData parsing, nargs should
// change from 1 to 2.
// TODO(b/192284612): add test case for failed call.
return lua_pcall(mLuaState, /* nargs= */ 1, /* nresults= */ 0, /*errfunc= */ 0);
}
} // namespace script_executor
} // namespace telemetry
} // namespace automotive
} // namespace android