eval.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include "eval.h"
  2. #include "json.h"
  3. #include <util/string/cast.h>
  4. #include <util/system/guard.h>
  5. #include <util/stream/mem.h>
  6. #include <util/string/builder.h>
  7. TLuaEval::TLuaEval()
  8. : FunctionNameCounter_(0)
  9. {
  10. LuaState_.BootStrap();
  11. }
  12. void TLuaEval::SetVariable(TZtStringBuf name, const NJson::TJsonValue& value) {
  13. TGuard<TMutex> guard(LuaMutex_);
  14. NLua::PushJsonValue(&LuaState_, value);
  15. LuaState_.set_global(name.c_str());
  16. }
  17. void TLuaEval::RunExpressionLocked(const TGuard<TMutex>&, const TExpression& expr) {
  18. LuaState_.push_global(expr.Name.c_str());
  19. LuaState_.call(0, 1);
  20. }
  21. TString TLuaEval::EvalCompiled(const TExpression& expr) {
  22. TGuard<TMutex> guard(LuaMutex_);
  23. RunExpressionLocked(guard, expr);
  24. return LuaState_.pop_value();
  25. }
  26. void TLuaEval::EvalCompiledRaw(const TExpression& expr) {
  27. TGuard<TMutex> guard(LuaMutex_);
  28. RunExpressionLocked(guard, expr);
  29. }
  30. bool TLuaEval::EvalCompiledCondition(const TExpression& expr) {
  31. TGuard<TMutex> guard(LuaMutex_);
  32. RunExpressionLocked(guard, expr);
  33. return LuaState_.pop_bool_strict();
  34. }
  35. TString TLuaEval::EvalRaw(TStringBuf code) {
  36. TMemoryInput bodyIn(code.data(), code.size());
  37. LuaState_.Load(&bodyIn, "main");
  38. LuaState_.call(0, 1);
  39. return LuaState_.pop_value();
  40. }
  41. void TLuaEval::ParseChunk(TStringBuf code) {
  42. TMemoryInput in(code.data(), code.size());
  43. LuaState_.Load(&in, "chunk_" + GenerateName());
  44. LuaState_.call(0, 0);
  45. }
  46. TString TLuaEval::EvalExpression(TStringBuf expression) {
  47. const auto expr = Compile(expression);
  48. try {
  49. return EvalCompiled(expr);
  50. } catch (const yexception& e) {
  51. throw yexception(e) << '\n' << expression;
  52. }
  53. }
  54. TLuaEval::TExpression TLuaEval::Compile(TStringBuf expression) {
  55. TGuard<TMutex> guard(LuaMutex_);
  56. TString name = GenerateName();
  57. TString body = "function ";
  58. body += name;
  59. body += "()\n\treturn (";
  60. body += expression;
  61. body += ")\nend\n";
  62. try {
  63. TMemoryInput bodyIn(body.c_str(), body.size());
  64. LuaState_.Load(&bodyIn, "chunk_" + name);
  65. LuaState_.call(0, 0);
  66. } catch (const yexception& e) {
  67. ythrow yexception(e) << "\n"
  68. << body;
  69. }
  70. return {name};
  71. }
  72. TLuaEval::TExpression TLuaEval::CompileFunction(TStringBuf expression) {
  73. TString name = GenerateName();
  74. TStringBuilder body;
  75. body << "function " << name << "()" << Endl
  76. << expression << Endl
  77. << "end";
  78. return CompileRaw(TStringBuf(body.data(), body.size()), name);
  79. }
  80. TLuaEval::TExpression TLuaEval::CompileRaw(TStringBuf body, const TString& name) {
  81. TGuard<TMutex> guard(LuaMutex_);
  82. try {
  83. TMemoryInput bodyIn(body.data(), body.size());
  84. LuaState_.Load(&bodyIn, "chunk_" + name);
  85. LuaState_.call(0, 0);
  86. } catch (const yexception& e) {
  87. ythrow yexception(e) << "\n" << body;
  88. }
  89. return { name };
  90. }
  91. TString TLuaEval::DumpStack() {
  92. TString result;
  93. {
  94. TStringOutput so(result);
  95. LuaState_.DumpStack(&so);
  96. }
  97. return result;
  98. }
  99. TString TLuaEval::GenerateName() {
  100. TGuard<TMutex> guard(LuaMutex_);
  101. return "dummy_" + ToString(FunctionNameCounter_++);
  102. }
  103. template <class T>
  104. static inline T FindEnd(T b, T e) {
  105. size_t cnt = 0;
  106. while (b < e) {
  107. switch (*b) {
  108. case '{':
  109. ++cnt;
  110. break;
  111. case '}':
  112. if (cnt == 0) {
  113. return b;
  114. }
  115. --cnt;
  116. break;
  117. }
  118. ++b;
  119. }
  120. return b;
  121. }
  122. TString TLuaEval::PreprocessOne(TStringBuf line) {
  123. const size_t pos = line.find("${");
  124. if (pos == TStringBuf::npos) {
  125. return EvalExpression(line);
  126. }
  127. const char* rpos = FindEnd(line.data() + pos + 2, line.end());
  128. if (rpos == line.end()) {
  129. ythrow yexception() << TStringBuf("can not parse ") << line;
  130. }
  131. const TStringBuf before = line.SubStr(0, pos);
  132. const TStringBuf after = TStringBuf(rpos + 1, line.end());
  133. const TStringBuf code = TStringBuf(line.data() + pos + 2, rpos);
  134. TString res;
  135. if (code.find("${") == TStringBuf::npos) {
  136. res = EvalExpression(code);
  137. } else {
  138. res = EvalExpression(Preprocess(code));
  139. }
  140. return ToString(before) + res + ToString(after);
  141. }
  142. bool TLuaEval::CheckEmptyStack() {
  143. for (int i = 1; i <= LuaState_.on_stack(); ++i) {
  144. if (!LuaState_.is_nil(-1 * i)) {
  145. return false;
  146. }
  147. }
  148. return true;
  149. }
  150. TString TLuaEval::Preprocess(TStringBuf line) {
  151. TString res = ToString(line);
  152. while (res.find("${") != TString::npos) {
  153. res = PreprocessOne(res);
  154. }
  155. return res;
  156. }