xref: /aosp_15_r20/external/libtextclassifier/native/utils/lua-utils.h (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker  *
4*993b0882SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker  *
8*993b0882SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker  *
10*993b0882SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker  * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker  */
16*993b0882SAndroid Build Coastguard Worker 
17*993b0882SAndroid Build Coastguard Worker #ifndef LIBTEXTCLASSIFIER_UTILS_LUA_UTILS_H_
18*993b0882SAndroid Build Coastguard Worker #define LIBTEXTCLASSIFIER_UTILS_LUA_UTILS_H_
19*993b0882SAndroid Build Coastguard Worker 
20*993b0882SAndroid Build Coastguard Worker #include <vector>
21*993b0882SAndroid Build Coastguard Worker 
22*993b0882SAndroid Build Coastguard Worker #include "actions/types.h"
23*993b0882SAndroid Build Coastguard Worker #include "annotator/types.h"
24*993b0882SAndroid Build Coastguard Worker #include "utils/flatbuffers/mutable.h"
25*993b0882SAndroid Build Coastguard Worker #include "utils/strings/stringpiece.h"
26*993b0882SAndroid Build Coastguard Worker #include "utils/variant.h"
27*993b0882SAndroid Build Coastguard Worker #include "flatbuffers/reflection_generated.h"
28*993b0882SAndroid Build Coastguard Worker 
29*993b0882SAndroid Build Coastguard Worker #ifdef __cplusplus
30*993b0882SAndroid Build Coastguard Worker extern "C" {
31*993b0882SAndroid Build Coastguard Worker #endif
32*993b0882SAndroid Build Coastguard Worker #include "lauxlib.h"
33*993b0882SAndroid Build Coastguard Worker #include "lua.h"
34*993b0882SAndroid Build Coastguard Worker #include "lualib.h"
35*993b0882SAndroid Build Coastguard Worker #ifdef __cplusplus
36*993b0882SAndroid Build Coastguard Worker }
37*993b0882SAndroid Build Coastguard Worker #endif
38*993b0882SAndroid Build Coastguard Worker 
39*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
40*993b0882SAndroid Build Coastguard Worker 
41*993b0882SAndroid Build Coastguard Worker static constexpr const char kLengthKey[] = "__len";
42*993b0882SAndroid Build Coastguard Worker static constexpr const char kPairsKey[] = "__pairs";
43*993b0882SAndroid Build Coastguard Worker static constexpr const char kIndexKey[] = "__index";
44*993b0882SAndroid Build Coastguard Worker static constexpr const char kGcKey[] = "__gc";
45*993b0882SAndroid Build Coastguard Worker static constexpr const char kNextKey[] = "__next";
46*993b0882SAndroid Build Coastguard Worker 
47*993b0882SAndroid Build Coastguard Worker static constexpr const int kIndexStackTop = -1;
48*993b0882SAndroid Build Coastguard Worker 
49*993b0882SAndroid Build Coastguard Worker // Casts to the lua user data type.
50*993b0882SAndroid Build Coastguard Worker template <typename T>
AsUserData(const T * value)51*993b0882SAndroid Build Coastguard Worker void* AsUserData(const T* value) {
52*993b0882SAndroid Build Coastguard Worker   return static_cast<void*>(const_cast<T*>(value));
53*993b0882SAndroid Build Coastguard Worker }
54*993b0882SAndroid Build Coastguard Worker template <typename T>
AsUserData(const T value)55*993b0882SAndroid Build Coastguard Worker void* AsUserData(const T value) {
56*993b0882SAndroid Build Coastguard Worker   return reinterpret_cast<void*>(value);
57*993b0882SAndroid Build Coastguard Worker }
58*993b0882SAndroid Build Coastguard Worker 
59*993b0882SAndroid Build Coastguard Worker // Retrieves up-values.
60*993b0882SAndroid Build Coastguard Worker template <typename T>
FromUpValue(const int index,lua_State * state)61*993b0882SAndroid Build Coastguard Worker T FromUpValue(const int index, lua_State* state) {
62*993b0882SAndroid Build Coastguard Worker   return static_cast<T>(lua_touserdata(state, lua_upvalueindex(index)));
63*993b0882SAndroid Build Coastguard Worker }
64*993b0882SAndroid Build Coastguard Worker 
65*993b0882SAndroid Build Coastguard Worker class LuaEnvironment {
66*993b0882SAndroid Build Coastguard Worker  public:
67*993b0882SAndroid Build Coastguard Worker   virtual ~LuaEnvironment();
68*993b0882SAndroid Build Coastguard Worker   explicit LuaEnvironment();
69*993b0882SAndroid Build Coastguard Worker 
70*993b0882SAndroid Build Coastguard Worker   // Compile a lua snippet into binary bytecode.
71*993b0882SAndroid Build Coastguard Worker   // NOTE: The compiled bytecode might not be compatible across Lua versions
72*993b0882SAndroid Build Coastguard Worker   // and platforms.
73*993b0882SAndroid Build Coastguard Worker   bool Compile(StringPiece snippet, std::string* bytecode) const;
74*993b0882SAndroid Build Coastguard Worker 
75*993b0882SAndroid Build Coastguard Worker   // Loads default libraries.
76*993b0882SAndroid Build Coastguard Worker   void LoadDefaultLibraries();
77*993b0882SAndroid Build Coastguard Worker 
78*993b0882SAndroid Build Coastguard Worker   // Provides a callback to Lua.
79*993b0882SAndroid Build Coastguard Worker   template <typename T>
PushFunction(int (T::* handler)())80*993b0882SAndroid Build Coastguard Worker   void PushFunction(int (T::*handler)()) {
81*993b0882SAndroid Build Coastguard Worker     PushFunction(std::bind(handler, static_cast<T*>(this)));
82*993b0882SAndroid Build Coastguard Worker   }
83*993b0882SAndroid Build Coastguard Worker 
84*993b0882SAndroid Build Coastguard Worker   template <typename F>
PushFunction(const F & func)85*993b0882SAndroid Build Coastguard Worker   void PushFunction(const F& func) const {
86*993b0882SAndroid Build Coastguard Worker     // Copy closure to the lua stack.
87*993b0882SAndroid Build Coastguard Worker     new (lua_newuserdata(state_, sizeof(func))) F(func);
88*993b0882SAndroid Build Coastguard Worker 
89*993b0882SAndroid Build Coastguard Worker     // Register garbage collection callback.
90*993b0882SAndroid Build Coastguard Worker     lua_newtable(state_);
91*993b0882SAndroid Build Coastguard Worker     lua_pushcfunction(state_, &ReleaseFunction<F>);
92*993b0882SAndroid Build Coastguard Worker     lua_setfield(state_, -2, kGcKey);
93*993b0882SAndroid Build Coastguard Worker     lua_setmetatable(state_, -2);
94*993b0882SAndroid Build Coastguard Worker 
95*993b0882SAndroid Build Coastguard Worker     // Push dispatch.
96*993b0882SAndroid Build Coastguard Worker     lua_pushcclosure(state_, &CallFunction<F>, 1);
97*993b0882SAndroid Build Coastguard Worker   }
98*993b0882SAndroid Build Coastguard Worker 
99*993b0882SAndroid Build Coastguard Worker   // Sets up a named table that calls back whenever a member is accessed.
100*993b0882SAndroid Build Coastguard Worker   // This allows to lazily provide required information to the script.
101*993b0882SAndroid Build Coastguard Worker   template <typename T>
PushLazyObject(int (T::* handler)())102*993b0882SAndroid Build Coastguard Worker   void PushLazyObject(int (T::*handler)()) {
103*993b0882SAndroid Build Coastguard Worker     PushLazyObject(std::bind(handler, static_cast<T*>(this)));
104*993b0882SAndroid Build Coastguard Worker   }
105*993b0882SAndroid Build Coastguard Worker 
106*993b0882SAndroid Build Coastguard Worker   template <typename F>
PushLazyObject(const F & func)107*993b0882SAndroid Build Coastguard Worker   void PushLazyObject(const F& func) const {
108*993b0882SAndroid Build Coastguard Worker     lua_newtable(state_);
109*993b0882SAndroid Build Coastguard Worker     lua_newtable(state_);
110*993b0882SAndroid Build Coastguard Worker     PushFunction(func);
111*993b0882SAndroid Build Coastguard Worker     lua_setfield(state_, -2, kIndexKey);
112*993b0882SAndroid Build Coastguard Worker     lua_setmetatable(state_, -2);
113*993b0882SAndroid Build Coastguard Worker   }
114*993b0882SAndroid Build Coastguard Worker 
Push(const int64 value)115*993b0882SAndroid Build Coastguard Worker   void Push(const int64 value) const { lua_pushinteger(state_, value); }
Push(const uint64 value)116*993b0882SAndroid Build Coastguard Worker   void Push(const uint64 value) const { lua_pushinteger(state_, value); }
Push(const int32 value)117*993b0882SAndroid Build Coastguard Worker   void Push(const int32 value) const { lua_pushinteger(state_, value); }
Push(const uint32 value)118*993b0882SAndroid Build Coastguard Worker   void Push(const uint32 value) const { lua_pushinteger(state_, value); }
Push(const int16 value)119*993b0882SAndroid Build Coastguard Worker   void Push(const int16 value) const { lua_pushinteger(state_, value); }
Push(const uint16 value)120*993b0882SAndroid Build Coastguard Worker   void Push(const uint16 value) const { lua_pushinteger(state_, value); }
Push(const int8 value)121*993b0882SAndroid Build Coastguard Worker   void Push(const int8 value) const { lua_pushinteger(state_, value); }
Push(const uint8 value)122*993b0882SAndroid Build Coastguard Worker   void Push(const uint8 value) const { lua_pushinteger(state_, value); }
Push(const float value)123*993b0882SAndroid Build Coastguard Worker   void Push(const float value) const { lua_pushnumber(state_, value); }
Push(const double value)124*993b0882SAndroid Build Coastguard Worker   void Push(const double value) const { lua_pushnumber(state_, value); }
Push(const bool value)125*993b0882SAndroid Build Coastguard Worker   void Push(const bool value) const { lua_pushboolean(state_, value); }
Push(const StringPiece value)126*993b0882SAndroid Build Coastguard Worker   void Push(const StringPiece value) const { PushString(value); }
Push(const flatbuffers::String * value)127*993b0882SAndroid Build Coastguard Worker   void Push(const flatbuffers::String* value) const {
128*993b0882SAndroid Build Coastguard Worker     if (value == nullptr) {
129*993b0882SAndroid Build Coastguard Worker       PushString("");
130*993b0882SAndroid Build Coastguard Worker     } else {
131*993b0882SAndroid Build Coastguard Worker       PushString(StringPiece(value->c_str(), value->size()));
132*993b0882SAndroid Build Coastguard Worker     }
133*993b0882SAndroid Build Coastguard Worker   }
134*993b0882SAndroid Build Coastguard Worker 
135*993b0882SAndroid Build Coastguard Worker   template <typename T>
136*993b0882SAndroid Build Coastguard Worker   T Read(const int index = -1) const;
137*993b0882SAndroid Build Coastguard Worker 
138*993b0882SAndroid Build Coastguard Worker   template <>
139*993b0882SAndroid Build Coastguard Worker   int64 Read<int64>(const int index) const {
140*993b0882SAndroid Build Coastguard Worker     return static_cast<int64>(lua_tointeger(state_, /*idx=*/index));
141*993b0882SAndroid Build Coastguard Worker   }
142*993b0882SAndroid Build Coastguard Worker 
143*993b0882SAndroid Build Coastguard Worker   template <>
144*993b0882SAndroid Build Coastguard Worker   uint64 Read<uint64>(const int index) const {
145*993b0882SAndroid Build Coastguard Worker     return static_cast<uint64>(lua_tointeger(state_, /*idx=*/index));
146*993b0882SAndroid Build Coastguard Worker   }
147*993b0882SAndroid Build Coastguard Worker 
148*993b0882SAndroid Build Coastguard Worker   template <>
149*993b0882SAndroid Build Coastguard Worker   int32 Read<int32>(const int index) const {
150*993b0882SAndroid Build Coastguard Worker     return static_cast<int32>(lua_tointeger(state_, /*idx=*/index));
151*993b0882SAndroid Build Coastguard Worker   }
152*993b0882SAndroid Build Coastguard Worker 
153*993b0882SAndroid Build Coastguard Worker   template <>
154*993b0882SAndroid Build Coastguard Worker   uint32 Read<uint32>(const int index) const {
155*993b0882SAndroid Build Coastguard Worker     return static_cast<uint32>(lua_tointeger(state_, /*idx=*/index));
156*993b0882SAndroid Build Coastguard Worker   }
157*993b0882SAndroid Build Coastguard Worker 
158*993b0882SAndroid Build Coastguard Worker   template <>
159*993b0882SAndroid Build Coastguard Worker   int16 Read<int16>(const int index) const {
160*993b0882SAndroid Build Coastguard Worker     return static_cast<int16>(lua_tointeger(state_, /*idx=*/index));
161*993b0882SAndroid Build Coastguard Worker   }
162*993b0882SAndroid Build Coastguard Worker 
163*993b0882SAndroid Build Coastguard Worker   template <>
164*993b0882SAndroid Build Coastguard Worker   uint16 Read<uint16>(const int index) const {
165*993b0882SAndroid Build Coastguard Worker     return static_cast<uint16>(lua_tointeger(state_, /*idx=*/index));
166*993b0882SAndroid Build Coastguard Worker   }
167*993b0882SAndroid Build Coastguard Worker 
168*993b0882SAndroid Build Coastguard Worker   template <>
169*993b0882SAndroid Build Coastguard Worker   int8 Read<int8>(const int index) const {
170*993b0882SAndroid Build Coastguard Worker     return static_cast<int8>(lua_tointeger(state_, /*idx=*/index));
171*993b0882SAndroid Build Coastguard Worker   }
172*993b0882SAndroid Build Coastguard Worker 
173*993b0882SAndroid Build Coastguard Worker   template <>
174*993b0882SAndroid Build Coastguard Worker   uint8 Read<uint8>(const int index) const {
175*993b0882SAndroid Build Coastguard Worker     return static_cast<uint8>(lua_tointeger(state_, /*idx=*/index));
176*993b0882SAndroid Build Coastguard Worker   }
177*993b0882SAndroid Build Coastguard Worker 
178*993b0882SAndroid Build Coastguard Worker   template <>
179*993b0882SAndroid Build Coastguard Worker   float Read<float>(const int index) const {
180*993b0882SAndroid Build Coastguard Worker     return static_cast<float>(lua_tonumber(state_, /*idx=*/index));
181*993b0882SAndroid Build Coastguard Worker   }
182*993b0882SAndroid Build Coastguard Worker 
183*993b0882SAndroid Build Coastguard Worker   template <>
184*993b0882SAndroid Build Coastguard Worker   double Read<double>(const int index) const {
185*993b0882SAndroid Build Coastguard Worker     return static_cast<double>(lua_tonumber(state_, /*idx=*/index));
186*993b0882SAndroid Build Coastguard Worker   }
187*993b0882SAndroid Build Coastguard Worker 
188*993b0882SAndroid Build Coastguard Worker   template <>
189*993b0882SAndroid Build Coastguard Worker   bool Read<bool>(const int index) const {
190*993b0882SAndroid Build Coastguard Worker     return lua_toboolean(state_, /*idx=*/index);
191*993b0882SAndroid Build Coastguard Worker   }
192*993b0882SAndroid Build Coastguard Worker 
193*993b0882SAndroid Build Coastguard Worker   template <>
194*993b0882SAndroid Build Coastguard Worker   StringPiece Read<StringPiece>(const int index) const {
195*993b0882SAndroid Build Coastguard Worker     return ReadString(index);
196*993b0882SAndroid Build Coastguard Worker   }
197*993b0882SAndroid Build Coastguard Worker 
198*993b0882SAndroid Build Coastguard Worker   template <>
199*993b0882SAndroid Build Coastguard Worker   std::string Read<std::string>(const int index) const {
200*993b0882SAndroid Build Coastguard Worker     return ReadString(index).ToString();
201*993b0882SAndroid Build Coastguard Worker   }
202*993b0882SAndroid Build Coastguard Worker 
203*993b0882SAndroid Build Coastguard Worker   // Reads a string from the stack.
204*993b0882SAndroid Build Coastguard Worker   StringPiece ReadString(int index) const;
205*993b0882SAndroid Build Coastguard Worker 
206*993b0882SAndroid Build Coastguard Worker   // Pushes a string to the stack.
207*993b0882SAndroid Build Coastguard Worker   void PushString(const StringPiece str) const;
208*993b0882SAndroid Build Coastguard Worker 
209*993b0882SAndroid Build Coastguard Worker   // Pushes a flatbuffer to the stack.
PushFlatbuffer(const reflection::Schema * schema,const flatbuffers::Table * table)210*993b0882SAndroid Build Coastguard Worker   void PushFlatbuffer(const reflection::Schema* schema,
211*993b0882SAndroid Build Coastguard Worker                       const flatbuffers::Table* table) const {
212*993b0882SAndroid Build Coastguard Worker     PushFlatbuffer(schema, schema->root_table(), table);
213*993b0882SAndroid Build Coastguard Worker   }
214*993b0882SAndroid Build Coastguard Worker 
215*993b0882SAndroid Build Coastguard Worker   // Reads a flatbuffer from the stack.
216*993b0882SAndroid Build Coastguard Worker   int ReadFlatbuffer(int index, MutableFlatbuffer* buffer) const;
217*993b0882SAndroid Build Coastguard Worker 
218*993b0882SAndroid Build Coastguard Worker   // Pushes an iterator.
219*993b0882SAndroid Build Coastguard Worker   template <typename ItemCallback, typename KeyCallback>
PushIterator(const int length,const ItemCallback & item_callback,const KeyCallback & key_callback)220*993b0882SAndroid Build Coastguard Worker   void PushIterator(const int length, const ItemCallback& item_callback,
221*993b0882SAndroid Build Coastguard Worker                     const KeyCallback& key_callback) const {
222*993b0882SAndroid Build Coastguard Worker     lua_newtable(state_);
223*993b0882SAndroid Build Coastguard Worker     CreateIteratorMetatable(length, item_callback);
224*993b0882SAndroid Build Coastguard Worker     PushFunction([this, length, item_callback, key_callback]() {
225*993b0882SAndroid Build Coastguard Worker       return Iterator::Dispatch(this, length, item_callback, key_callback);
226*993b0882SAndroid Build Coastguard Worker     });
227*993b0882SAndroid Build Coastguard Worker     lua_setfield(state_, -2, kIndexKey);
228*993b0882SAndroid Build Coastguard Worker     lua_setmetatable(state_, -2);
229*993b0882SAndroid Build Coastguard Worker   }
230*993b0882SAndroid Build Coastguard Worker 
231*993b0882SAndroid Build Coastguard Worker   template <typename ItemCallback>
PushIterator(const int length,const ItemCallback & item_callback)232*993b0882SAndroid Build Coastguard Worker   void PushIterator(const int length, const ItemCallback& item_callback) const {
233*993b0882SAndroid Build Coastguard Worker     lua_newtable(state_);
234*993b0882SAndroid Build Coastguard Worker     CreateIteratorMetatable(length, item_callback);
235*993b0882SAndroid Build Coastguard Worker     PushFunction([this, length, item_callback]() {
236*993b0882SAndroid Build Coastguard Worker       return Iterator::Dispatch(this, length, item_callback);
237*993b0882SAndroid Build Coastguard Worker     });
238*993b0882SAndroid Build Coastguard Worker     lua_setfield(state_, -2, kIndexKey);
239*993b0882SAndroid Build Coastguard Worker     lua_setmetatable(state_, -2);
240*993b0882SAndroid Build Coastguard Worker   }
241*993b0882SAndroid Build Coastguard Worker 
242*993b0882SAndroid Build Coastguard Worker   template <typename ItemCallback>
CreateIteratorMetatable(const int length,const ItemCallback & item_callback)243*993b0882SAndroid Build Coastguard Worker   void CreateIteratorMetatable(const int length,
244*993b0882SAndroid Build Coastguard Worker                                const ItemCallback& item_callback) const {
245*993b0882SAndroid Build Coastguard Worker     lua_newtable(state_);
246*993b0882SAndroid Build Coastguard Worker     PushFunction([this, length]() { return Iterator::Length(this, length); });
247*993b0882SAndroid Build Coastguard Worker     lua_setfield(state_, -2, kLengthKey);
248*993b0882SAndroid Build Coastguard Worker     PushFunction([this, length, item_callback]() {
249*993b0882SAndroid Build Coastguard Worker       return Iterator::IterItems(this, length, item_callback);
250*993b0882SAndroid Build Coastguard Worker     });
251*993b0882SAndroid Build Coastguard Worker     lua_setfield(state_, -2, kPairsKey);
252*993b0882SAndroid Build Coastguard Worker     PushFunction([this, length, item_callback]() {
253*993b0882SAndroid Build Coastguard Worker       return Iterator::Next(this, length, item_callback);
254*993b0882SAndroid Build Coastguard Worker     });
255*993b0882SAndroid Build Coastguard Worker     lua_setfield(state_, -2, kNextKey);
256*993b0882SAndroid Build Coastguard Worker   }
257*993b0882SAndroid Build Coastguard Worker 
258*993b0882SAndroid Build Coastguard Worker   template <typename T>
PushVectorIterator(const std::vector<T> * items)259*993b0882SAndroid Build Coastguard Worker   void PushVectorIterator(const std::vector<T>* items) const {
260*993b0882SAndroid Build Coastguard Worker     PushIterator(items ? items->size() : 0, [this, items](const int64 pos) {
261*993b0882SAndroid Build Coastguard Worker       this->Push(items->at(pos));
262*993b0882SAndroid Build Coastguard Worker       return 1;
263*993b0882SAndroid Build Coastguard Worker     });
264*993b0882SAndroid Build Coastguard Worker   }
265*993b0882SAndroid Build Coastguard Worker 
266*993b0882SAndroid Build Coastguard Worker   template <typename T>
PushVector(const std::vector<T> & items)267*993b0882SAndroid Build Coastguard Worker   void PushVector(const std::vector<T>& items) const {
268*993b0882SAndroid Build Coastguard Worker     lua_newtable(state_);
269*993b0882SAndroid Build Coastguard Worker     for (int i = 0; i < items.size(); i++) {
270*993b0882SAndroid Build Coastguard Worker       // Key: index, 1-based.
271*993b0882SAndroid Build Coastguard Worker       Push(i + 1);
272*993b0882SAndroid Build Coastguard Worker 
273*993b0882SAndroid Build Coastguard Worker       // Value.
274*993b0882SAndroid Build Coastguard Worker       Push(items[i]);
275*993b0882SAndroid Build Coastguard Worker       lua_settable(state_, /*idx=*/-3);
276*993b0882SAndroid Build Coastguard Worker     }
277*993b0882SAndroid Build Coastguard Worker   }
278*993b0882SAndroid Build Coastguard Worker 
PushEmptyVector()279*993b0882SAndroid Build Coastguard Worker   void PushEmptyVector() const { lua_newtable(state_); }
280*993b0882SAndroid Build Coastguard Worker 
281*993b0882SAndroid Build Coastguard Worker   template <typename T>
282*993b0882SAndroid Build Coastguard Worker   std::vector<T> ReadVector(const int index = -1) const {
283*993b0882SAndroid Build Coastguard Worker     std::vector<T> result;
284*993b0882SAndroid Build Coastguard Worker     if (lua_type(state_, /*idx=*/index) != LUA_TTABLE) {
285*993b0882SAndroid Build Coastguard Worker       TC3_LOG(ERROR) << "Expected a table, got: "
286*993b0882SAndroid Build Coastguard Worker                      << lua_type(state_, /*idx=*/kIndexStackTop);
287*993b0882SAndroid Build Coastguard Worker       lua_pop(state_, 1);
288*993b0882SAndroid Build Coastguard Worker       return {};
289*993b0882SAndroid Build Coastguard Worker     }
290*993b0882SAndroid Build Coastguard Worker     lua_pushnil(state_);
291*993b0882SAndroid Build Coastguard Worker     while (Next(index - 1)) {
292*993b0882SAndroid Build Coastguard Worker       result.push_back(Read<T>(/*index=*/kIndexStackTop));
293*993b0882SAndroid Build Coastguard Worker       lua_pop(state_, 1);
294*993b0882SAndroid Build Coastguard Worker     }
295*993b0882SAndroid Build Coastguard Worker     return result;
296*993b0882SAndroid Build Coastguard Worker   }
297*993b0882SAndroid Build Coastguard Worker 
298*993b0882SAndroid Build Coastguard Worker   // Runs a closure in protected mode.
299*993b0882SAndroid Build Coastguard Worker   // `func`: closure to run in protected mode.
300*993b0882SAndroid Build Coastguard Worker   // `num_lua_args`: number of arguments from the lua stack to process.
301*993b0882SAndroid Build Coastguard Worker   // `num_results`: number of result values pushed on the stack.
302*993b0882SAndroid Build Coastguard Worker   template <typename F>
303*993b0882SAndroid Build Coastguard Worker   int RunProtected(const F& func, const int num_args = 0,
304*993b0882SAndroid Build Coastguard Worker                    const int num_results = 0) const {
305*993b0882SAndroid Build Coastguard Worker     PushFunction(func);
306*993b0882SAndroid Build Coastguard Worker     // Put the closure before the arguments on the stack.
307*993b0882SAndroid Build Coastguard Worker     if (num_args > 0) {
308*993b0882SAndroid Build Coastguard Worker       lua_insert(state_, -(1 + num_args));
309*993b0882SAndroid Build Coastguard Worker     }
310*993b0882SAndroid Build Coastguard Worker     return lua_pcall(state_, num_args, num_results, /*errorfunc=*/0);
311*993b0882SAndroid Build Coastguard Worker   }
312*993b0882SAndroid Build Coastguard Worker 
313*993b0882SAndroid Build Coastguard Worker   // Auxiliary methods to handle model results.
314*993b0882SAndroid Build Coastguard Worker   // Provides an annotation to lua.
315*993b0882SAndroid Build Coastguard Worker   void PushAnnotation(const ClassificationResult& classification,
316*993b0882SAndroid Build Coastguard Worker                       const reflection::Schema* entity_data_schema) const;
317*993b0882SAndroid Build Coastguard Worker   void PushAnnotation(const ClassificationResult& classification,
318*993b0882SAndroid Build Coastguard Worker                       StringPiece text,
319*993b0882SAndroid Build Coastguard Worker                       const reflection::Schema* entity_data_schema) const;
320*993b0882SAndroid Build Coastguard Worker   void PushAnnotation(const ActionSuggestionAnnotation& annotation,
321*993b0882SAndroid Build Coastguard Worker                       const reflection::Schema* entity_data_schema) const;
322*993b0882SAndroid Build Coastguard Worker 
323*993b0882SAndroid Build Coastguard Worker   template <typename Annotation>
PushAnnotations(const std::vector<Annotation> * annotations,const reflection::Schema * entity_data_schema)324*993b0882SAndroid Build Coastguard Worker   void PushAnnotations(const std::vector<Annotation>* annotations,
325*993b0882SAndroid Build Coastguard Worker                        const reflection::Schema* entity_data_schema) const {
326*993b0882SAndroid Build Coastguard Worker     PushIterator(
327*993b0882SAndroid Build Coastguard Worker         annotations ? annotations->size() : 0,
328*993b0882SAndroid Build Coastguard Worker         [this, annotations, entity_data_schema](const int64 index) {
329*993b0882SAndroid Build Coastguard Worker           PushAnnotation(annotations->at(index), entity_data_schema);
330*993b0882SAndroid Build Coastguard Worker           return 1;
331*993b0882SAndroid Build Coastguard Worker         },
332*993b0882SAndroid Build Coastguard Worker         [this, annotations, entity_data_schema](StringPiece name) {
333*993b0882SAndroid Build Coastguard Worker           if (const Annotation* annotation =
334*993b0882SAndroid Build Coastguard Worker                   GetAnnotationByName(*annotations, name)) {
335*993b0882SAndroid Build Coastguard Worker             PushAnnotation(*annotation, entity_data_schema);
336*993b0882SAndroid Build Coastguard Worker             return 1;
337*993b0882SAndroid Build Coastguard Worker           } else {
338*993b0882SAndroid Build Coastguard Worker             return 0;
339*993b0882SAndroid Build Coastguard Worker           }
340*993b0882SAndroid Build Coastguard Worker         });
341*993b0882SAndroid Build Coastguard Worker   }
342*993b0882SAndroid Build Coastguard Worker 
343*993b0882SAndroid Build Coastguard Worker   // Pushes a span to the lua stack.
344*993b0882SAndroid Build Coastguard Worker   void PushAnnotatedSpan(const AnnotatedSpan& annotated_span,
345*993b0882SAndroid Build Coastguard Worker                          const reflection::Schema* entity_data_schema) const;
346*993b0882SAndroid Build Coastguard Worker   void PushAnnotatedSpans(const std::vector<AnnotatedSpan>* annotated_spans,
347*993b0882SAndroid Build Coastguard Worker                           const reflection::Schema* entity_data_schema) const;
348*993b0882SAndroid Build Coastguard Worker 
349*993b0882SAndroid Build Coastguard Worker   // Reads a message text span from lua.
350*993b0882SAndroid Build Coastguard Worker   MessageTextSpan ReadSpan() const;
351*993b0882SAndroid Build Coastguard Worker 
352*993b0882SAndroid Build Coastguard Worker   ActionSuggestionAnnotation ReadAnnotation(
353*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* entity_data_schema) const;
354*993b0882SAndroid Build Coastguard Worker   int ReadAnnotations(
355*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* entity_data_schema,
356*993b0882SAndroid Build Coastguard Worker       std::vector<ActionSuggestionAnnotation>* annotations) const;
357*993b0882SAndroid Build Coastguard Worker   ClassificationResult ReadClassificationResult(
358*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* entity_data_schema) const;
359*993b0882SAndroid Build Coastguard Worker 
360*993b0882SAndroid Build Coastguard Worker   // Provides an action to lua.
361*993b0882SAndroid Build Coastguard Worker   void PushAction(
362*993b0882SAndroid Build Coastguard Worker       const ActionSuggestion& action,
363*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* actions_entity_data_schema,
364*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* annotations_entity_data_schema) const;
365*993b0882SAndroid Build Coastguard Worker 
366*993b0882SAndroid Build Coastguard Worker   void PushActions(
367*993b0882SAndroid Build Coastguard Worker       const std::vector<ActionSuggestion>* actions,
368*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* actions_entity_data_schema,
369*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* annotations_entity_data_schema) const;
370*993b0882SAndroid Build Coastguard Worker 
371*993b0882SAndroid Build Coastguard Worker   ActionSuggestion ReadAction(
372*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* actions_entity_data_schema,
373*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* annotations_entity_data_schema) const;
374*993b0882SAndroid Build Coastguard Worker 
375*993b0882SAndroid Build Coastguard Worker   int ReadActions(const reflection::Schema* actions_entity_data_schema,
376*993b0882SAndroid Build Coastguard Worker                   const reflection::Schema* annotations_entity_data_schema,
377*993b0882SAndroid Build Coastguard Worker                   std::vector<ActionSuggestion>* actions) const;
378*993b0882SAndroid Build Coastguard Worker 
379*993b0882SAndroid Build Coastguard Worker   // Conversation message iterator.
380*993b0882SAndroid Build Coastguard Worker   void PushConversation(
381*993b0882SAndroid Build Coastguard Worker       const std::vector<ConversationMessage>* conversation,
382*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* annotations_entity_data_schema) const;
383*993b0882SAndroid Build Coastguard Worker 
state()384*993b0882SAndroid Build Coastguard Worker   lua_State* state() const { return state_; }
385*993b0882SAndroid Build Coastguard Worker 
386*993b0882SAndroid Build Coastguard Worker  protected:
387*993b0882SAndroid Build Coastguard Worker   // Wrapper for handling iteration over containers.
388*993b0882SAndroid Build Coastguard Worker   class Iterator {
389*993b0882SAndroid Build Coastguard Worker    public:
390*993b0882SAndroid Build Coastguard Worker     // Starts a new key-value pair iterator.
391*993b0882SAndroid Build Coastguard Worker     template <typename ItemCallback>
IterItems(const LuaEnvironment * env,const int length,const ItemCallback & callback)392*993b0882SAndroid Build Coastguard Worker     static int IterItems(const LuaEnvironment* env, const int length,
393*993b0882SAndroid Build Coastguard Worker                          const ItemCallback& callback) {
394*993b0882SAndroid Build Coastguard Worker       env->PushFunction([env, callback, length, pos = 0]() mutable {
395*993b0882SAndroid Build Coastguard Worker         if (pos >= length) {
396*993b0882SAndroid Build Coastguard Worker           lua_pushnil(env->state());
397*993b0882SAndroid Build Coastguard Worker           return 1;
398*993b0882SAndroid Build Coastguard Worker         }
399*993b0882SAndroid Build Coastguard Worker 
400*993b0882SAndroid Build Coastguard Worker         // Push key.
401*993b0882SAndroid Build Coastguard Worker         lua_pushinteger(env->state(), pos + 1);
402*993b0882SAndroid Build Coastguard Worker 
403*993b0882SAndroid Build Coastguard Worker         // Push item.
404*993b0882SAndroid Build Coastguard Worker         return 1 + callback(pos++);
405*993b0882SAndroid Build Coastguard Worker       });
406*993b0882SAndroid Build Coastguard Worker       return 1;  // Num. results.
407*993b0882SAndroid Build Coastguard Worker     }
408*993b0882SAndroid Build Coastguard Worker 
409*993b0882SAndroid Build Coastguard Worker     // Gets the next element.
410*993b0882SAndroid Build Coastguard Worker     template <typename ItemCallback>
Next(const LuaEnvironment * env,const int length,const ItemCallback & item_callback)411*993b0882SAndroid Build Coastguard Worker     static int Next(const LuaEnvironment* env, const int length,
412*993b0882SAndroid Build Coastguard Worker                     const ItemCallback& item_callback) {
413*993b0882SAndroid Build Coastguard Worker       int64 pos = lua_isnil(env->state(), /*idx=*/kIndexStackTop)
414*993b0882SAndroid Build Coastguard Worker                       ? 0
415*993b0882SAndroid Build Coastguard Worker                       : env->Read<int64>(/*index=*/kIndexStackTop);
416*993b0882SAndroid Build Coastguard Worker       if (pos < length) {
417*993b0882SAndroid Build Coastguard Worker         // Push next key.
418*993b0882SAndroid Build Coastguard Worker         lua_pushinteger(env->state(), pos + 1);
419*993b0882SAndroid Build Coastguard Worker 
420*993b0882SAndroid Build Coastguard Worker         // Push item.
421*993b0882SAndroid Build Coastguard Worker         return 1 + item_callback(pos);
422*993b0882SAndroid Build Coastguard Worker       } else {
423*993b0882SAndroid Build Coastguard Worker         lua_pushnil(env->state());
424*993b0882SAndroid Build Coastguard Worker         return 1;
425*993b0882SAndroid Build Coastguard Worker       }
426*993b0882SAndroid Build Coastguard Worker     }
427*993b0882SAndroid Build Coastguard Worker 
428*993b0882SAndroid Build Coastguard Worker     // Returns the length of the container the iterator processes.
Length(const LuaEnvironment * env,const int length)429*993b0882SAndroid Build Coastguard Worker     static int Length(const LuaEnvironment* env, const int length) {
430*993b0882SAndroid Build Coastguard Worker       lua_pushinteger(env->state(), length);
431*993b0882SAndroid Build Coastguard Worker       return 1;  // Num. results.
432*993b0882SAndroid Build Coastguard Worker     }
433*993b0882SAndroid Build Coastguard Worker 
434*993b0882SAndroid Build Coastguard Worker     // Handles item queries to the iterator.
435*993b0882SAndroid Build Coastguard Worker     // Elements of the container can either be queried by name or index.
436*993b0882SAndroid Build Coastguard Worker     // Dispatch will check how an element is accessed and
437*993b0882SAndroid Build Coastguard Worker     // calls `key_callback` for access by name and `item_callback` for access by
438*993b0882SAndroid Build Coastguard Worker     // index.
439*993b0882SAndroid Build Coastguard Worker     template <typename ItemCallback, typename KeyCallback>
Dispatch(const LuaEnvironment * env,const int length,const ItemCallback & item_callback,const KeyCallback & key_callback)440*993b0882SAndroid Build Coastguard Worker     static int Dispatch(const LuaEnvironment* env, const int length,
441*993b0882SAndroid Build Coastguard Worker                         const ItemCallback& item_callback,
442*993b0882SAndroid Build Coastguard Worker                         const KeyCallback& key_callback) {
443*993b0882SAndroid Build Coastguard Worker       switch (lua_type(env->state(), kIndexStackTop)) {
444*993b0882SAndroid Build Coastguard Worker         case LUA_TNUMBER: {
445*993b0882SAndroid Build Coastguard Worker           // Lua is one based, so adjust the index here.
446*993b0882SAndroid Build Coastguard Worker           const int64 index = env->Read<int64>(/*index=*/kIndexStackTop) - 1;
447*993b0882SAndroid Build Coastguard Worker           if (index < 0 || index >= length) {
448*993b0882SAndroid Build Coastguard Worker             TC3_LOG(ERROR) << "Invalid index: " << index;
449*993b0882SAndroid Build Coastguard Worker             lua_error(env->state());
450*993b0882SAndroid Build Coastguard Worker             return 0;
451*993b0882SAndroid Build Coastguard Worker           }
452*993b0882SAndroid Build Coastguard Worker           return item_callback(index);
453*993b0882SAndroid Build Coastguard Worker         }
454*993b0882SAndroid Build Coastguard Worker         case LUA_TSTRING: {
455*993b0882SAndroid Build Coastguard Worker           return key_callback(env->ReadString(kIndexStackTop));
456*993b0882SAndroid Build Coastguard Worker         }
457*993b0882SAndroid Build Coastguard Worker         default:
458*993b0882SAndroid Build Coastguard Worker           TC3_LOG(ERROR) << "Unexpected access type: "
459*993b0882SAndroid Build Coastguard Worker                          << lua_type(env->state(), kIndexStackTop);
460*993b0882SAndroid Build Coastguard Worker           lua_error(env->state());
461*993b0882SAndroid Build Coastguard Worker           return 0;
462*993b0882SAndroid Build Coastguard Worker       }
463*993b0882SAndroid Build Coastguard Worker     }
464*993b0882SAndroid Build Coastguard Worker 
465*993b0882SAndroid Build Coastguard Worker     template <typename ItemCallback>
Dispatch(const LuaEnvironment * env,const int length,const ItemCallback & item_callback)466*993b0882SAndroid Build Coastguard Worker     static int Dispatch(const LuaEnvironment* env, const int length,
467*993b0882SAndroid Build Coastguard Worker                         const ItemCallback& item_callback) {
468*993b0882SAndroid Build Coastguard Worker       switch (lua_type(env->state(), kIndexStackTop)) {
469*993b0882SAndroid Build Coastguard Worker         case LUA_TNUMBER: {
470*993b0882SAndroid Build Coastguard Worker           // Lua is one based, so adjust the index here.
471*993b0882SAndroid Build Coastguard Worker           const int64 index = env->Read<int64>(/*index=*/kIndexStackTop) - 1;
472*993b0882SAndroid Build Coastguard Worker           if (index < 0 || index >= length) {
473*993b0882SAndroid Build Coastguard Worker             TC3_LOG(ERROR) << "Invalid index: " << index;
474*993b0882SAndroid Build Coastguard Worker             lua_error(env->state());
475*993b0882SAndroid Build Coastguard Worker             return 0;
476*993b0882SAndroid Build Coastguard Worker           }
477*993b0882SAndroid Build Coastguard Worker           return item_callback(index);
478*993b0882SAndroid Build Coastguard Worker         }
479*993b0882SAndroid Build Coastguard Worker         default:
480*993b0882SAndroid Build Coastguard Worker           TC3_LOG(ERROR) << "Unexpected access type: "
481*993b0882SAndroid Build Coastguard Worker                          << lua_type(env->state(), kIndexStackTop);
482*993b0882SAndroid Build Coastguard Worker           lua_error(env->state());
483*993b0882SAndroid Build Coastguard Worker           return 0;
484*993b0882SAndroid Build Coastguard Worker       }
485*993b0882SAndroid Build Coastguard Worker     }
486*993b0882SAndroid Build Coastguard Worker   };
487*993b0882SAndroid Build Coastguard Worker 
488*993b0882SAndroid Build Coastguard Worker   // Calls the deconstructor from a previously pushed function.
489*993b0882SAndroid Build Coastguard Worker   template <typename T>
ReleaseFunction(lua_State * state)490*993b0882SAndroid Build Coastguard Worker   static int ReleaseFunction(lua_State* state) {
491*993b0882SAndroid Build Coastguard Worker     static_cast<T*>(lua_touserdata(state, 1))->~T();
492*993b0882SAndroid Build Coastguard Worker     return 0;
493*993b0882SAndroid Build Coastguard Worker   }
494*993b0882SAndroid Build Coastguard Worker 
495*993b0882SAndroid Build Coastguard Worker   template <typename T>
CallFunction(lua_State * state)496*993b0882SAndroid Build Coastguard Worker   static int CallFunction(lua_State* state) {
497*993b0882SAndroid Build Coastguard Worker     return (*static_cast<T*>(lua_touserdata(state, lua_upvalueindex(1))))();
498*993b0882SAndroid Build Coastguard Worker   }
499*993b0882SAndroid Build Coastguard Worker 
500*993b0882SAndroid Build Coastguard Worker   // Auxiliary methods to expose (reflective) flatbuffer based data to Lua.
501*993b0882SAndroid Build Coastguard Worker   void PushFlatbuffer(const reflection::Schema* schema,
502*993b0882SAndroid Build Coastguard Worker                       const reflection::Object* type,
503*993b0882SAndroid Build Coastguard Worker                       const flatbuffers::Table* table) const;
504*993b0882SAndroid Build Coastguard Worker   int GetField(const reflection::Schema* schema, const reflection::Object* type,
505*993b0882SAndroid Build Coastguard Worker                const flatbuffers::Table* table) const;
506*993b0882SAndroid Build Coastguard Worker 
507*993b0882SAndroid Build Coastguard Worker   // Reads a repeated field from lua.
508*993b0882SAndroid Build Coastguard Worker   template <typename T>
ReadRepeatedField(const int index,RepeatedField * result)509*993b0882SAndroid Build Coastguard Worker   void ReadRepeatedField(const int index, RepeatedField* result) const {
510*993b0882SAndroid Build Coastguard Worker     for (const T& element : ReadVector<T>(index)) {
511*993b0882SAndroid Build Coastguard Worker       result->Add(element);
512*993b0882SAndroid Build Coastguard Worker     }
513*993b0882SAndroid Build Coastguard Worker   }
514*993b0882SAndroid Build Coastguard Worker 
515*993b0882SAndroid Build Coastguard Worker   template <>
516*993b0882SAndroid Build Coastguard Worker   void ReadRepeatedField<MutableFlatbuffer>(const int index,
517*993b0882SAndroid Build Coastguard Worker                                             RepeatedField* result) const {
518*993b0882SAndroid Build Coastguard Worker     lua_pushnil(state_);
519*993b0882SAndroid Build Coastguard Worker     while (Next(index - 1)) {
520*993b0882SAndroid Build Coastguard Worker       ReadFlatbuffer(index, result->Add());
521*993b0882SAndroid Build Coastguard Worker       lua_pop(state_, 1);
522*993b0882SAndroid Build Coastguard Worker     }
523*993b0882SAndroid Build Coastguard Worker   }
524*993b0882SAndroid Build Coastguard Worker 
525*993b0882SAndroid Build Coastguard Worker   // Pushes a repeated field to the lua stack.
526*993b0882SAndroid Build Coastguard Worker   template <typename T>
PushRepeatedField(const flatbuffers::Vector<T> * items)527*993b0882SAndroid Build Coastguard Worker   void PushRepeatedField(const flatbuffers::Vector<T>* items) const {
528*993b0882SAndroid Build Coastguard Worker     PushIterator(items ? items->size() : 0, [this, items](const int64 pos) {
529*993b0882SAndroid Build Coastguard Worker       Push(items->Get(pos));
530*993b0882SAndroid Build Coastguard Worker       return 1;  // Num. results.
531*993b0882SAndroid Build Coastguard Worker     });
532*993b0882SAndroid Build Coastguard Worker   }
533*993b0882SAndroid Build Coastguard Worker 
PushRepeatedFlatbufferField(const reflection::Schema * schema,const reflection::Object * type,const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::Table>> * items)534*993b0882SAndroid Build Coastguard Worker   void PushRepeatedFlatbufferField(
535*993b0882SAndroid Build Coastguard Worker       const reflection::Schema* schema, const reflection::Object* type,
536*993b0882SAndroid Build Coastguard Worker       const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::Table>>* items)
537*993b0882SAndroid Build Coastguard Worker       const {
538*993b0882SAndroid Build Coastguard Worker     PushIterator(items ? items->size() : 0,
539*993b0882SAndroid Build Coastguard Worker                  [this, schema, type, items](const int64 pos) {
540*993b0882SAndroid Build Coastguard Worker                    PushFlatbuffer(schema, type, items->Get(pos));
541*993b0882SAndroid Build Coastguard Worker                    return 1;  // Num. results.
542*993b0882SAndroid Build Coastguard Worker                  });
543*993b0882SAndroid Build Coastguard Worker   }
544*993b0882SAndroid Build Coastguard Worker 
545*993b0882SAndroid Build Coastguard Worker   // Overloads Lua next function to use __next key on the metatable.
546*993b0882SAndroid Build Coastguard Worker   // This allows us to treat lua objects and lazy objects provided by our
547*993b0882SAndroid Build Coastguard Worker   // callbacks uniformly.
Next(int index)548*993b0882SAndroid Build Coastguard Worker   int Next(int index) const {
549*993b0882SAndroid Build Coastguard Worker     // Check whether the (meta)table of this object has an associated "__next"
550*993b0882SAndroid Build Coastguard Worker     // entry. This means, we registered our own callback. So we explicitly call
551*993b0882SAndroid Build Coastguard Worker     // that.
552*993b0882SAndroid Build Coastguard Worker     if (luaL_getmetafield(state_, index, kNextKey)) {
553*993b0882SAndroid Build Coastguard Worker       // Callback is now on top of the stack, so adjust relative indices by 1.
554*993b0882SAndroid Build Coastguard Worker       if (index < 0) {
555*993b0882SAndroid Build Coastguard Worker         index--;
556*993b0882SAndroid Build Coastguard Worker       }
557*993b0882SAndroid Build Coastguard Worker 
558*993b0882SAndroid Build Coastguard Worker       // Copy the reference to the table.
559*993b0882SAndroid Build Coastguard Worker       lua_pushvalue(state_, index);
560*993b0882SAndroid Build Coastguard Worker 
561*993b0882SAndroid Build Coastguard Worker       // Move the key to top to have it as second argument for the callback.
562*993b0882SAndroid Build Coastguard Worker       // Copy the key to the top.
563*993b0882SAndroid Build Coastguard Worker       lua_pushvalue(state_, -3);
564*993b0882SAndroid Build Coastguard Worker 
565*993b0882SAndroid Build Coastguard Worker       // Remove the copy of the key.
566*993b0882SAndroid Build Coastguard Worker       lua_remove(state_, -4);
567*993b0882SAndroid Build Coastguard Worker 
568*993b0882SAndroid Build Coastguard Worker       // Call the callback with (key and table as arguments).
569*993b0882SAndroid Build Coastguard Worker       lua_pcall(state_, /*nargs=*/2 /* table, key */,
570*993b0882SAndroid Build Coastguard Worker                 /*nresults=*/2 /* key, item */, 0);
571*993b0882SAndroid Build Coastguard Worker 
572*993b0882SAndroid Build Coastguard Worker       // Next returned nil, it's the end.
573*993b0882SAndroid Build Coastguard Worker       if (lua_isnil(state_, kIndexStackTop)) {
574*993b0882SAndroid Build Coastguard Worker         // Remove nil value.
575*993b0882SAndroid Build Coastguard Worker         // Results will be padded to `nresults` specified above, so we need
576*993b0882SAndroid Build Coastguard Worker         // to remove two elements here.
577*993b0882SAndroid Build Coastguard Worker         lua_pop(state_, 2);
578*993b0882SAndroid Build Coastguard Worker         return 0;
579*993b0882SAndroid Build Coastguard Worker       }
580*993b0882SAndroid Build Coastguard Worker 
581*993b0882SAndroid Build Coastguard Worker       return 2;  // Num. results.
582*993b0882SAndroid Build Coastguard Worker     } else if (lua_istable(state_, index)) {
583*993b0882SAndroid Build Coastguard Worker       return lua_next(state_, index);
584*993b0882SAndroid Build Coastguard Worker     }
585*993b0882SAndroid Build Coastguard Worker 
586*993b0882SAndroid Build Coastguard Worker     // Remove the key.
587*993b0882SAndroid Build Coastguard Worker     lua_pop(state_, 1);
588*993b0882SAndroid Build Coastguard Worker     return 0;
589*993b0882SAndroid Build Coastguard Worker   }
590*993b0882SAndroid Build Coastguard Worker 
GetAnnotationByName(const std::vector<ClassificationResult> & annotations,StringPiece name)591*993b0882SAndroid Build Coastguard Worker   static const ClassificationResult* GetAnnotationByName(
592*993b0882SAndroid Build Coastguard Worker       const std::vector<ClassificationResult>& annotations, StringPiece name) {
593*993b0882SAndroid Build Coastguard Worker     // Lookup annotation by collection.
594*993b0882SAndroid Build Coastguard Worker     for (const ClassificationResult& annotation : annotations) {
595*993b0882SAndroid Build Coastguard Worker       if (name.Equals(annotation.collection)) {
596*993b0882SAndroid Build Coastguard Worker         return &annotation;
597*993b0882SAndroid Build Coastguard Worker       }
598*993b0882SAndroid Build Coastguard Worker     }
599*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "No annotation with collection: " << name << " found.";
600*993b0882SAndroid Build Coastguard Worker     return nullptr;
601*993b0882SAndroid Build Coastguard Worker   }
602*993b0882SAndroid Build Coastguard Worker 
GetAnnotationByName(const std::vector<ActionSuggestionAnnotation> & annotations,StringPiece name)603*993b0882SAndroid Build Coastguard Worker   static const ActionSuggestionAnnotation* GetAnnotationByName(
604*993b0882SAndroid Build Coastguard Worker       const std::vector<ActionSuggestionAnnotation>& annotations,
605*993b0882SAndroid Build Coastguard Worker       StringPiece name) {
606*993b0882SAndroid Build Coastguard Worker     // Lookup annotation by name.
607*993b0882SAndroid Build Coastguard Worker     for (const ActionSuggestionAnnotation& annotation : annotations) {
608*993b0882SAndroid Build Coastguard Worker       if (name.Equals(annotation.name)) {
609*993b0882SAndroid Build Coastguard Worker         return &annotation;
610*993b0882SAndroid Build Coastguard Worker       }
611*993b0882SAndroid Build Coastguard Worker     }
612*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "No annotation with name: " << name << " found.";
613*993b0882SAndroid Build Coastguard Worker     return nullptr;
614*993b0882SAndroid Build Coastguard Worker   }
615*993b0882SAndroid Build Coastguard Worker 
616*993b0882SAndroid Build Coastguard Worker   lua_State* state_;
617*993b0882SAndroid Build Coastguard Worker };  // namespace libtextclassifier3
618*993b0882SAndroid Build Coastguard Worker 
619*993b0882SAndroid Build Coastguard Worker bool Compile(StringPiece snippet, std::string* bytecode);
620*993b0882SAndroid Build Coastguard Worker 
621*993b0882SAndroid Build Coastguard Worker }  // namespace libtextclassifier3
622*993b0882SAndroid Build Coastguard Worker 
623*993b0882SAndroid Build Coastguard Worker #endif  // LIBTEXTCLASSIFIER_UTILS_LUA_UTILS_H_
624