123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #include "eval.h"
- #include "json.h"
- #include <util/string/cast.h>
- #include <util/system/guard.h>
- #include <util/stream/mem.h>
- #include <util/string/builder.h>
- TLuaEval::TLuaEval()
- : FunctionNameCounter_(0)
- {
- LuaState_.BootStrap();
- }
- void TLuaEval::SetVariable(TZtStringBuf name, const NJson::TJsonValue& value) {
- TGuard<TMutex> guard(LuaMutex_);
- NLua::PushJsonValue(&LuaState_, value);
- LuaState_.set_global(name.c_str());
- }
- void TLuaEval::RunExpressionLocked(const TGuard<TMutex>&, const TExpression& expr) {
- LuaState_.push_global(expr.Name.c_str());
- LuaState_.call(0, 1);
- }
- TString TLuaEval::EvalCompiled(const TExpression& expr) {
- TGuard<TMutex> guard(LuaMutex_);
- RunExpressionLocked(guard, expr);
- return LuaState_.pop_value();
- }
- void TLuaEval::EvalCompiledRaw(const TExpression& expr) {
- TGuard<TMutex> guard(LuaMutex_);
- RunExpressionLocked(guard, expr);
- }
- bool TLuaEval::EvalCompiledCondition(const TExpression& expr) {
- TGuard<TMutex> guard(LuaMutex_);
- RunExpressionLocked(guard, expr);
- return LuaState_.pop_bool_strict();
- }
- TString TLuaEval::EvalRaw(TStringBuf code) {
- TMemoryInput bodyIn(code.data(), code.size());
- LuaState_.Load(&bodyIn, "main");
- LuaState_.call(0, 1);
- return LuaState_.pop_value();
- }
- void TLuaEval::ParseChunk(TStringBuf code) {
- TMemoryInput in(code.data(), code.size());
- LuaState_.Load(&in, "chunk_" + GenerateName());
- LuaState_.call(0, 0);
- }
- TString TLuaEval::EvalExpression(TStringBuf expression) {
- const auto expr = Compile(expression);
- try {
- return EvalCompiled(expr);
- } catch (const yexception& e) {
- throw yexception(e) << '\n' << expression;
- }
- }
- TLuaEval::TExpression TLuaEval::Compile(TStringBuf expression) {
- TGuard<TMutex> guard(LuaMutex_);
- TString name = GenerateName();
- TString body = "function ";
- body += name;
- body += "()\n\treturn (";
- body += expression;
- body += ")\nend\n";
- try {
- TMemoryInput bodyIn(body.c_str(), body.size());
- LuaState_.Load(&bodyIn, "chunk_" + name);
- LuaState_.call(0, 0);
- } catch (const yexception& e) {
- ythrow yexception(e) << "\n"
- << body;
- }
- return {name};
- }
- TLuaEval::TExpression TLuaEval::CompileFunction(TStringBuf expression) {
- TString name = GenerateName();
- TStringBuilder body;
- body << "function " << name << "()" << Endl
- << expression << Endl
- << "end";
- return CompileRaw(TStringBuf(body.data(), body.size()), name);
- }
- TLuaEval::TExpression TLuaEval::CompileRaw(TStringBuf body, const TString& name) {
- TGuard<TMutex> guard(LuaMutex_);
- try {
- TMemoryInput bodyIn(body.data(), body.size());
- LuaState_.Load(&bodyIn, "chunk_" + name);
- LuaState_.call(0, 0);
- } catch (const yexception& e) {
- ythrow yexception(e) << "\n" << body;
- }
- return { name };
- }
- TString TLuaEval::DumpStack() {
- TString result;
- {
- TStringOutput so(result);
- LuaState_.DumpStack(&so);
- }
- return result;
- }
- TString TLuaEval::GenerateName() {
- TGuard<TMutex> guard(LuaMutex_);
- return "dummy_" + ToString(FunctionNameCounter_++);
- }
- template <class T>
- static inline T FindEnd(T b, T e) {
- size_t cnt = 0;
- while (b < e) {
- switch (*b) {
- case '{':
- ++cnt;
- break;
- case '}':
- if (cnt == 0) {
- return b;
- }
- --cnt;
- break;
- }
- ++b;
- }
- return b;
- }
- TString TLuaEval::PreprocessOne(TStringBuf line) {
- const size_t pos = line.find("${");
- if (pos == TStringBuf::npos) {
- return EvalExpression(line);
- }
- const char* rpos = FindEnd(line.data() + pos + 2, line.end());
- if (rpos == line.end()) {
- ythrow yexception() << TStringBuf("can not parse ") << line;
- }
- const TStringBuf before = line.SubStr(0, pos);
- const TStringBuf after = TStringBuf(rpos + 1, line.end());
- const TStringBuf code = TStringBuf(line.data() + pos + 2, rpos);
- TString res;
- if (code.find("${") == TStringBuf::npos) {
- res = EvalExpression(code);
- } else {
- res = EvalExpression(Preprocess(code));
- }
- return ToString(before) + res + ToString(after);
- }
- bool TLuaEval::CheckEmptyStack() {
- for (int i = 1; i <= LuaState_.on_stack(); ++i) {
- if (!LuaState_.is_nil(-1 * i)) {
- return false;
- }
- }
- return true;
- }
- TString TLuaEval::Preprocess(TStringBuf line) {
- TString res = ToString(line);
- while (res.find("${") != TString::npos) {
- res = PreprocessOne(res);
- }
- return res;
- }
|