* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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 "script_interpreter.h"
#include <algorithm>
#include <fstream>
#include "dump.h"
#include "scope_guard.h"
#include "script_context.h"
#include "script_manager_impl.h"
#include "scanner.h"
#include "script_utils.h"
using namespace std;
using namespace Updater;
namespace Uscript {
static int32_t g_instanceId = 0;
int32_t ScriptInterpreter::ExecuteScript(ScriptManagerImpl *manager, Hpackage::PkgManager::StreamPtr pkgStream)
{
Updater::UPDATER_INIT_RECORD;
if (pkgStream == nullptr) {
USCRIPT_LOGE("Param error");
UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
return USCRIPT_INVALID_PARAM;
}
USCRIPT_LOGI("ExecuteScript %s", pkgStream->GetFileName().c_str());
auto inter = new (std::nothrow) ScriptInterpreter(manager);
if (inter == nullptr) {
USCRIPT_LOGE("Fail to create ScriptInterpreter for script %s", pkgStream->GetFileName().c_str());
UPDATER_LAST_WORD(USCRIPT_ERROR_CREATE_OBJ, pkgStream->GetFileName());
return USCRIPT_ERROR_CREATE_OBJ;
}
ON_SCOPE_EXIT(ReleaseScriptInterpreter) {
if (inter) {
delete inter;
inter = nullptr;
}
};
int32_t ret = inter->LoadScript(pkgStream);
if (ret != USCRIPT_SUCCESS) {
USCRIPT_LOGE("Fail to loadScript script %s", pkgStream->GetFileName().c_str());
UPDATER_LAST_WORD(ret, "Fail to loadScript script" + pkgStream->GetFileName());
return ret;
}
ret = inter->Execute();
USCRIPT_LOGI("ExecuteScript finish ret: %d script: %s ",
ret, pkgStream->GetFileName().c_str());
return ret;
}
ScriptInterpreter::ScriptInterpreter(ScriptManagerImpl *manager) : scriptManager_(manager)
{
instanceId_ = g_instanceId++;
}
ScriptInterpreter::~ScriptInterpreter()
{
delete statements_;
auto iter = functions_.begin();
while (iter != functions_.end()) {
auto entry = iter->second;
if (entry) {
delete entry;
}
iter = functions_.erase(iter);
}
functions_.clear();
contextStack_.clear();
}
int32_t ScriptInterpreter::LoadScript(Hpackage::PkgManager::StreamPtr pkgStream)
{
scanner_ = std::make_unique<Scanner>(this);
parser_ = std::make_unique<Parser>(scanner_.get(), this);
scanner_->set_debug(0);
scanner_->SetPkgStream(pkgStream);
int32_t ret = parser_->parse();
return ret;
}
int32_t ScriptInterpreter::Execute()
{
UScriptContextPtr context = std::make_shared<UScriptInterpretContext>(true);
if (statements_ == nullptr) {
return USCRIPT_INVALID_PARAM;
}
UScriptStatementResult result = statements_->Execute(*this, context);
INTERPRETER_LOGD(*this, context, "statements_ execute result %s ",
UScriptStatementResult::ScriptToString(&result).c_str());
if (result.GetResultType() == UScriptStatementResult::STATEMENT_RESULT_TYPE_ERROR) {
return result.GetError();
}
return USCRIPT_SUCCESS;
}
int32_t ScriptInterpreter::AddFunction(ScriptFunction *function)
{
if (functions_.find(function->GetFunctionName()) != functions_.end()) {
USCRIPT_LOGI("Fail to add function %s, function exist", function->GetFunctionName().c_str());
return USCRIPT_SUCCESS;
}
functions_[function->GetFunctionName()] = function;
return USCRIPT_SUCCESS;
}
ScriptFunction* ScriptInterpreter::FindFunction(const std::string &name)
{
if (functions_.find(name) != functions_.end()) {
return functions_[name];
}
return nullptr;
}
UScriptValuePtr ScriptInterpreter::ExecuteFunction(UScriptContextPtr context, const std::string &name,
ScriptParams *params)
{
ScriptFunction *function = FindFunction(name);
if (function == nullptr) {
USCRIPT_LOGI("Fail to find function %s", name.c_str());
return std::make_shared<ErrorValue>(USCRIPT_NOTEXIST_INSTRUCTION);
} else {
return function->Execute(*this, context, params);
}
}
UScriptValuePtr ScriptInterpreter::FindVariable(UScriptContextPtr local, std::string id)
{
for (auto context = contextStack_.rbegin(); context != contextStack_.rend(); context++) {
UScriptValuePtr variable = (*context)->FindVariable(*this, id);
if (variable != nullptr) {
return variable;
}
if ((*context)->IsTop()) {
break;
}
}
return nullptr;
}
UScriptValuePtr ScriptInterpreter::UpdateVariable(UScriptContextPtr local, std::string id, UScriptValuePtr var)
{
for (auto context = contextStack_.rbegin(); context != contextStack_.rend(); context++) {
UScriptValuePtr variable = (*context)->FindVariable(*this, id);
if (variable != nullptr) {
(*context)->UpdateVariable(*this, id, var);
}
if ((*context)->IsTop()) {
break;
}
}
return nullptr;
}
void ScriptInterpreter::AddStatement(UScriptStatement *statement)
{
if (statements_ == nullptr) {
statements_ = UScriptStatementList::CreateInstance(statement);
} else {
statements_->AddScriptStatement(statement);
}
}
bool ScriptInterpreter::IsNativeFunction(std::string name)
{
return scriptManager_->FindInstruction(name) != nullptr;
}
UScriptValuePtr ScriptInterpreter::ExecuteNativeFunc(UScriptContextPtr context,
const std::string &name, ScriptParams *params)
{
std::shared_ptr<ErrorValue> error = std::make_shared<ErrorValue>(USCRIPT_ERROR_INTERPRET);
std::shared_ptr<ReturnValue> retValue = std::make_shared<ReturnValue>();
INTERPRETER_LOGI(*this, context, "ExecuteNativeFunc::Execute %s ", name.c_str());
UScriptInstruction* instruction = scriptManager_->FindInstruction(name);
if (instruction == nullptr) {
USCRIPT_LOGE("Fail to find instruction %s", name.c_str());
return error;
}
std::shared_ptr<UScriptInstructionContext> funcContext = std::make_shared<UScriptInstructionContext>();
if (funcContext == nullptr) {
USCRIPT_LOGE("Fail to create context %s", name.c_str());
return error;
}
if (params == nullptr) {
int32_t ret = instruction->Execute(*scriptManager_->GetScriptEnv(name), *funcContext.get());
if (ret != USCRIPT_SUCCESS && ret != USCRIPT_UPDATER_MODE_VALUE) {
error->SetValue(ret);
return error;
}
retValue->AddValues(funcContext->GetOutVar());
INTERPRETER_LOGI(*this, context, "ExecuteNativeFunc::Execute %s result: %d", name.c_str(), ret);
return retValue;
}
for (auto id : params->GetParams()) {
UScriptValuePtr result = id->Execute(*this, context);
if (result == nullptr || result->GetValueType() == UScriptValue::VALUE_TYPE_ERROR) {
INTERPRETER_LOGI(*this, context, "ExecuteNativeFunc::Execute %s ", name.c_str());
return error;
}
if (result->GetValueType() != UScriptValue::VALUE_TYPE_LIST) {
funcContext->AddInputParam(result);
} else {
ReturnValue* values = (ReturnValue*)(result.get());
for (auto out : values->GetValues()) {
funcContext->AddInputParam(out);
}
}
}
int32_t ret = instruction->Execute(*scriptManager_->GetScriptEnv(name), *funcContext.get());
INTERPRETER_LOGI(*this, context, "ExecuteNativeFunc::Execute %s result: %d", name.c_str(), ret);
if (ret != USCRIPT_SUCCESS && ret != USCRIPT_UPDATER_MODE_VALUE) {
error->SetValue(ret);
return error;
}
retValue->AddValues(funcContext->GetOutVar());
return retValue;
}
}