66 * Multi Theft Auto is available from http://www.multitheftauto.com/
77 *
88 *****************************************************************************/
9- #pragma once
9+ #pragma once
1010
1111#include < optional>
1212#include < variant>
@@ -23,8 +23,103 @@ template <bool ErrorOnFailure, typename Ret, typename... Args, auto (*Func)(Args
2323struct CLuaFunctionParser <ErrorOnFailure, Func>
2424{
2525 std::size_t iIndex = 1 ;
26- bool bFailed = false ;
27- std::string strError = " todo fix error message" ;
26+ std::string strError = " " ;
27+ std::string strErrorFoundType = " " ;
28+
29+ template <typename T>
30+ inline void typeToNameVariant (SString& accumulator)
31+ {
32+ using param = typename is_variant<T>::param1_t ;
33+ if (accumulator.length () == 0 )
34+ accumulator = typeToName<param>();
35+ else
36+ accumulator += " /" + typeToName<param>();
37+
38+ if constexpr (is_variant<T>::count != 1 )
39+ return typeToNameVariant<is_variant<T>::rest_t >(accumulator);
40+ }
41+
42+ template <typename T>
43+ inline SString typeToName ()
44+ {
45+ if constexpr (std::is_same_v<T, std::string>)
46+ return " string" ;
47+ else if constexpr (std::is_same_v<T, int > || std::is_same_v<T, float > || std::is_same_v<T, double > || std::is_same_v<T, short > ||
48+ std::is_same_v<T, unsigned int > || std::is_same_v<T, unsigned short >)
49+ return " number" ;
50+ else if constexpr (std::is_same_v<T, bool >)
51+ return " boolean" ;
52+ else if constexpr (std::is_enum_v<T>)
53+ return " enum" ;
54+ else if constexpr (is_specialization<T, std::optional>::value)
55+ {
56+ using param_t = typename is_specialization<T, std::optional>::param_t ;
57+ return typeToName<param_t >();
58+ }
59+ else if constexpr (is_2specialization<T, std::vector>::value)
60+ return " table" ;
61+ else if constexpr (is_5specialization<T, std::unordered_map>::value)
62+ return " table" ;
63+ else if constexpr (std::is_same_v<T, CLuaFunctionRef>)
64+ return " function" ;
65+ else if constexpr (std::is_same_v<T, lua_State*>)
66+ return " " ; // not reachable
67+ else if constexpr (is_variant<T>::value)
68+ {
69+ SString strTypes;
70+ typeToNameVariant<T>(strTypes);
71+ return strTypes;
72+ }
73+
74+ else if constexpr (std::is_pointer_v<T> && std::is_class_v<std::remove_pointer_t <T>>)
75+ return GetClassTypeName ((T)0 );
76+ }
77+
78+ static SString ResolveParameter (lua_State* L, std::size_t index)
79+ {
80+ switch (lua_type (L, index))
81+ {
82+ case LUA_TNUMBER:
83+ return SString (" number (%d)" , lua_tonumber (L, index));
84+ case LUA_TSTRING:
85+ {
86+ std::size_t iLen;
87+ const char * szValue = lua_tolstring (L, index, &iLen);
88+ std::string strValue (szValue, iLen);
89+ if (strValue.length () > 10 )
90+ {
91+ strValue.resize (10 ); // Limit to 10 characters
92+ strValue[9 ] = ' .' ;
93+ strValue[8 ] = ' .' ;
94+ strValue[7 ] = ' .' ;
95+ }
96+ // Avoid printing binary data
97+ if (std::find_if (strValue.begin (), strValue.end (), [](char ch) { return !(std::isprint (ch)); }) != strValue.end ())
98+ return " string" ;
99+ else
100+ {
101+ return SString (" string (\" %s\" )" , strValue.c_str ());
102+ }
103+ }
104+ case LUA_TBOOLEAN:
105+ return SString (" boolean (%s)" , lua_toboolean (L, index) == 1 ? " true" : " false" );
106+ case LUA_TNIL:
107+ return " nil" ;
108+ case LUA_TNONE:
109+ return " none" ;
110+ case LUA_TTABLE:
111+ return " table" ;
112+ case LUA_TFUNCTION:
113+ return " function" ;
114+ case LUA_TTHREAD:
115+ return " coroutine" ;
116+ case LUA_TUSERDATA:
117+ return GetUserDataClassName (*((void **)lua_touserdata (L, index)), L);
118+ case LUA_TLIGHTUSERDATA:
119+ return GetUserDataClassName (lua_touserdata (L, index), L);
120+ }
121+ return " " ;
122+ }
28123
29124 // Pop should remove a T from the Lua Stack after verifying that it is a valid type
30125 // Pop may also throw a LuaArgumentError to indicate failure
@@ -33,8 +128,10 @@ struct CLuaFunctionParser<ErrorOnFailure, Func>
33128 {
34129 if (!TypeMatch<T>(L, index))
35130 {
36- // TODO: resolve error
37- bFailed = true ;
131+ SString strReceived = ResolveParameter (L, index);
132+ SString strExpected = typeToName<T>();
133+ SString strMessage (" Expected %s at argument %d, got %s" , strExpected.c_str (), index, strReceived.c_str ());
134+ strError = strMessage;
38135 return T{};
39136 }
40137 return PopUnsafe<T>(L, index);
@@ -80,7 +177,7 @@ struct CLuaFunctionParser<ErrorOnFailure, Func>
80177 if constexpr (std::is_same_v<T, bool >)
81178 return (iArgument == LUA_TBOOLEAN);
82179
83- // advanced types
180+ // Advanced types
84181 // Enums are represented as strings to Lua
85182 if constexpr (std::is_enum_v<T>)
86183 return iArgument == LUA_TSTRING;
@@ -162,8 +259,10 @@ struct CLuaFunctionParser<ErrorOnFailure, Func>
162259 return eValue;
163260 else
164261 {
165- bFailed = true ;
166- // TODO: resolve error
262+ SString strReceived = ResolveParameter (L, index);
263+ SString strExpected = GetEnumTypeName ((T)0 );
264+ SString strMessage (" Expected %s at argument %d, got %s" , strExpected.c_str (), index, strReceived.c_str ());
265+ strError = strMessage;
167266 return static_cast <T>(0 );
168267 }
169268 }
@@ -184,11 +283,11 @@ struct CLuaFunctionParser<ErrorOnFailure, Func>
184283 lua_pushnil (L); /* first key */
185284 while (lua_next (L, index) != 0 )
186285 {
187- if (!TypeMatch<param>(L, -1 ) || !TypeMatch< int >(L, - 2 ) )
286+ if (!TypeMatch<param>(L, -1 ))
188287 {
189- bFailed = true ;
190- // TODO: resolve error
191- return vecData ;
288+ // skip
289+ lua_pop (L, 1 );
290+ continue ;
192291 }
193292
194293 std::size_t i = -1 ;
@@ -208,9 +307,9 @@ struct CLuaFunctionParser<ErrorOnFailure, Func>
208307 {
209308 if (!TypeMatch<value_t >(L, -1 ) || !TypeMatch<key_t >(L, -2 ))
210309 {
211- bFailed = true ;
212- // TODO: resolve error
213- return map ;
310+ // skip
311+ lua_pop (L, 1 );
312+ continue ;
214313 }
215314
216315 std::size_t i = -2 ;
@@ -243,29 +342,24 @@ struct CLuaFunctionParser<ErrorOnFailure, Func>
243342 bool isLightUserData = lua_type (L, index) == LUA_TLIGHTUSERDATA;
244343 void * pValue = lua::PopTrivial<void *>(L, index);
245344 using class_t = std::remove_pointer_t <T>;
246- T result = nullptr ;
247- if (isLightUserData)
248- {
249- result = UserDataCast<class_t >((class_t *)0 , pValue, L);
250- }
251- else
252- {
253- result = UserDataCast<class_t >((class_t *)0 , *reinterpret_cast <void **>(pValue), L);
254- }
345+ auto result =
346+ isLightUserData ? UserDataCast<class_t >((class_t *)0 , pValue, L) : UserDataCast<class_t >((class_t *)0 , *reinterpret_cast <void **>(pValue), L);
255347 if (result == nullptr )
256348 {
257- bFailed = true ;
258- // TODO: resolve error
349+ SString strReceived = isLightUserData ? GetUserDataClassName (pValue, L) : GetUserDataClassName (*(void **)pValue, L);
350+ SString strExpected = GetClassTypeName ((T)0 );
351+ SString strMessage (" Expected %s at argument %d, got %s" , strExpected.c_str (), index, strReceived.c_str ());
352+ strError = strMessage;
259353 return nullptr ;
260354 }
261- return result;
355+ return static_cast <T>( result) ;
262356 }
263357 }
264358
265359 template <typename ... Params>
266360 inline auto Call (lua_State* L, Params&&... ps)
267361 {
268- if (bFailed )
362+ if (strError. length () != 0 )
269363 {
270364 return -1 ;
271365 }
@@ -298,7 +392,7 @@ struct CLuaFunctionParser<ErrorOnFailure, Func>
298392 {
299393 strError = e.what ();
300394 }
301- if (bFailed )
395+ if (strError. length () != 0 )
302396 {
303397 if constexpr (ErrorOnFailure)
304398 {
0 commit comments