diff options
Diffstat (limited to 'Source')
23 files changed, 389 insertions, 117 deletions
diff --git a/Source/3rdParty/Luax/luax.h b/Source/3rdParty/Luax/luax.h index 9a6b0b9..6935e71 100644 --- a/Source/3rdParty/Luax/luax.h +++ b/Source/3rdParty/Luax/luax.h @@ -6,9 +6,9 @@ #include "luax_namespace.h" #include "luax_ref.h" #include "luax_reftable.h" -#include "luax_memberref.h" #include "luax_enum.h" #include "luax_class.hpp" +#include "luax_memberref.h" #include "luax_class.inl" #include "luax_state.inl" diff --git a/Source/3rdParty/Luax/luax_cfunctions.cpp b/Source/3rdParty/Luax/luax_cfunctions.cpp new file mode 100644 index 0000000..d93a0ee --- /dev/null +++ b/Source/3rdParty/Luax/luax_cfunctions.cpp @@ -0,0 +1,19 @@ +#include "luax_cfunctions.h" +#include "luax_config.h" + +namespace Luax +{ + + int luax_c_getupvalue(lua_State* L) + { + lua_pushvalue(L, lua_upvalueindex(1)); + return 1; + } + + int luax_c_errfunc(lua_State* L) + { + cc8* msg = luaL_optstring(L, lua_upvalueindex(1), ""); + return luaL_error(L, msg); + } + +}
\ No newline at end of file diff --git a/Source/3rdParty/Luax/luax_cfunctions.h b/Source/3rdParty/Luax/luax_cfunctions.h new file mode 100644 index 0000000..2570bb9 --- /dev/null +++ b/Source/3rdParty/Luax/luax_cfunctions.h @@ -0,0 +1,25 @@ +#ifndef __LUAX_CFUNCTIONS_H__ +#define __LUAX_CFUNCTIONS_H__ + +#include "luax_config.h" + +/** + * luax_cfunctionĺעluaһЩܵͨú +*/ + +namespace Luax +{ + + /// + /// õһupvalue + /// + extern int luax_c_getupvalue(lua_State* L); + + /// + /// ô˺ʱᱨupvalue(1)ǴϢ + /// + extern int luax_c_errfunc(lua_State* L); + +} + +#endif
\ No newline at end of file diff --git a/Source/3rdParty/Luax/luax_class.hpp b/Source/3rdParty/Luax/luax_class.hpp index a76d501..539093c 100644 --- a/Source/3rdParty/Luax/luax_class.hpp +++ b/Source/3rdParty/Luax/luax_class.hpp @@ -5,6 +5,7 @@ #include "luax_config.h" #include "luax_ref.h" +#include "luax_memberref.h" namespace Luax { @@ -30,6 +31,7 @@ namespace Luax /// #define LUAX_DECL_SINGLETON(type) \ static void RegisterLuaxClass(Luax::LuaxState&); \ + static void RegisterLuaxPostprocess(Luax::LuaxState&); \ static const char* GetLuaxSingletonName() { return #type; }; \ static const char* GetLuaxClassName() { return #type; }; \ static bool IsLuaxClassSingleton() { return true; }; @@ -42,8 +44,15 @@ namespace Luax { public: - void Retain(); - void Release(); + /// + /// userdataΪkeyref tableuserdataһãάuserdataڡ + /// + template<class U> void LuaRetain(LuaxState& state, U* userdata); + + /// + /// userdataһref tableԳԻuserdata + /// + template<class U> void LuaRelease(LuaxState& state, U* userdata); protected: @@ -57,6 +66,13 @@ namespace Luax bool PushLuaxMemberTable(LuaxState& state); bool PushLuaxRefTable(LuaxState& state); + /// + /// Աùʵref tableáȡ + /// + void SetMemberRef(LuaxState& state, LuaxMemberRef& memRef, int idx); + bool PushMemberRef(LuaxState& state, LuaxMemberRef& memRef); + void ClearMemberRef(LuaxState& state, LuaxMemberRef& memRef); + private: friend class LuaxState; @@ -80,7 +96,7 @@ namespace Luax void* operator &(); /// - /// userdataʵstateǹ + /// userdataʵstate /// void BindToLua(LuaxState& state); @@ -102,30 +118,22 @@ namespace Luax /// LuaxWeakRef mUserdata; - /// - /// ü̼߳乲 - /// - int mRC; - - /// - /// ȷֻͨReleaseõsaferֻҪ̳LuaxClass࣬ʹdeleteֱͻᱨ - /// - bool mSafer; - public: //------------------------------------------------------------------------------------------------------------ // - LUAX_DECL_METHOD( l_GetClassName ); - LUAX_DECL_METHOD( l_GetInterfaceTable ); - LUAX_DECL_METHOD( l___tostring ); + LUAX_DECL_METHOD( l___tostring ); + LUAX_DECL_METHOD( l_GetClassName ); //------------------------------------------------------------------------------------------------------------ // - LUAX_DECL_METHOD( l_ExtendFactory ); - LUAX_DECL_METHOD( l___gc ); + LUAX_DECL_METHOD( l___gc ); + LUAX_DECL_METHOD( l_ExtendFactory ); + LUAX_DECL_METHOD( l_GetClass ); + LUAX_DECL_METHOD( l_GetInterfaceTable ); + LUAX_DECL_METHOD( l_GetRefTable ); //------------------------------------------------------------------------------------------------------------ // diff --git a/Source/3rdParty/Luax/luax_class.inl b/Source/3rdParty/Luax/luax_class.inl index 8cf0f55..bbda6de 100644 --- a/Source/3rdParty/Luax/luax_class.inl +++ b/Source/3rdParty/Luax/luax_class.inl @@ -5,7 +5,7 @@ namespace Luax // ӿ /// - /// ԲͬͣͨGetLuaClassName + /// ԲͬͣͨGetLuaClassName࣬GetClassNameᱻǣָluax_c_getupvalue /// template<typename T> int LuaxClass<T>::l_GetClassName(lua_State* L) @@ -33,7 +33,6 @@ namespace Luax state.RegisterMethods(regTable); } - /// /// ijԱעclass table /// @@ -48,7 +47,6 @@ namespace Luax state.RegisterMethods(regTable); } - /// /// ʵijԱעinterface table /// @@ -56,14 +54,14 @@ namespace Luax void LuaxClass<T>::RegisterLuaxInterface(LuaxState& state) { luaL_Reg regTable[] = { - { "__gc", l___gc }, - { NULL, NULL } + { "GetClass", l_GetClass }, + { "GetRefTable", l_GetRefTable }, + { NULL, NULL } }; state.RegisterMethods(regTable); } - /// /// ijԱעclass table /// @@ -107,30 +105,55 @@ namespace Luax template<typename T> LuaxClass<T>::LuaxClass() - : mRC(1) // ʱĬһ - , mSafer(false) { } template<typename T> LuaxClass<T>::~LuaxClass() { - assert(mSafer); } template<typename T> - void LuaxClass<T>::Retain() + template<typename U> + void LuaxClass<T>::LuaRetain(LuaxState& state, U* userdata) { - ++mRC; + if (PushLuaxRefTable(state)) + { + if (userdata->PushLuaxUserdata(state)) + { + lua_pushvalue(state, -1); // copy the userdata + lua_gettable(state, -3); // get the count (or nil) + u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0) + lua_pop(state, 1); // pop the old count + lua_pushnumber(state, count + 1); // push the new count + lua_settable(state, -3); // save it in the table: reftable[userdata] = count + } + } } template<typename T> - void LuaxClass<T>::Release() + template<typename U> + void LuaxClass<T>::LuaRelease(LuaxState& state, U* userdata) { - if (--mRC <= 0) + if (PushLuaxRefTable(state)) { - mSafer = true; // safer - delete this; + if (userdata->PushLuaxUserdata(state)) + { + lua_pushvalue(state, -1); // copy the userdata + lua_gettable(state, -3); // get the count (or nil) + u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0) + lua_pop(state, 1); // pop the old count + + if (count == 0) return; // nothing to do + + if (count > 1) { + lua_pushnumber(state, count - 1); // push the new count + } + else { + lua_pushnil(state); // maybe cause gc + } + lua_settable(state, -3); // save it in the table + } } } @@ -197,6 +220,12 @@ namespace Luax return false; } + /// + /// userdataԴref tablemember tableinterface table + /// ref table kvǿtableuserdataüͨuserdataΪkeyΪvalueԼԱ + /// member table luaʵijԱ + /// interface table б͵ʵеijԱ + /// template<typename T> void LuaxClass<T>::BindToLua(LuaxState& state) { @@ -221,14 +250,14 @@ namespace Luax int memberTable = top - 1; int refTable = top - 2; - // ref table ע __gc__tostring + // ref table ע __gc __tostring lua_pushcfunction(state, l___gc); lua_setfield(state, refTable, "__gc"); lua_pushcfunction(state, l___tostring); lua_setfield(state, refTable, "__tostring"); - // member table Ϊ ref table __index __newindex + // ref table __index __newindex Ϊ member table lua_pushvalue(state, memberTable); lua_setfield(state, refTable, "__index"); @@ -245,6 +274,59 @@ namespace Luax assert(mUserdata); } + /// + /// Աù + /// + template<typename T> + void LuaxClass<T>::SetMemberRef(LuaxState& state, LuaxMemberRef& memRef, int idx) + { + ClearMemberRef(state, memRef); + if (!lua_isnil(state, idx)) + { + idx = state.AbsIndex(idx); + if (PushLuaxRefTable(state)) + { + lua_pushvalue(state, idx); + memRef.refID = luaL_ref(state, -2); + state.Pop(); // ref table + } + } + } + + template<typename T> + bool LuaxClass<T>::PushMemberRef(LuaxState& state, LuaxMemberRef& memRef) + { + if (memRef) + { + if (PushLuaxRefTable(state)) + { + lua_rawgeti(state, -1, memRef.refID); + lua_replace(state, -2); // ref table + if (lua_isnil(state, -1)) + goto failed; + return true; + } + } + lua_pushnil(state); + failed: + memRef.refID = LUA_NOREF; + return false; + } + + template<typename T> + void LuaxClass<T>::ClearMemberRef(LuaxState& state, LuaxMemberRef& memRef) + { + if (memRef) + { + if (PushLuaxRefTable(state)) + { + luaL_unref(state, -1, memRef.refID); + state.Pop(); // ref table + } + memRef.refID = LUA_NOREF; + } + } + //-------------------------------------------------------------------------------------------------------------- /// @@ -258,15 +340,51 @@ namespace Luax return 0; } + /// + /// ʽ: + /// ַ + /// template<typename T> int LuaxClass<T>::l___tostring(lua_State* L) { + LUAX_STATE(L); + T* self = state.GetLuaUserdata<T>(1); + if (self) + { + char buf[1024] = {0}; + const char* fmt = "%p <%s>"; + cc8* classname = ""; + lua_getfield(state, 1, "GetClassName"); + if (state.IsType(-1, LUA_TFUNCTION)) + { + lua_pushvalue(L, 1); // userdata + state.Call(1, 1); // GetClassName + classname = state.GetValue<cc8*>(-1, ""); + } + else + { + classname = T::GetLuaxClassName(); + } + sprintf(buf, fmt, self, classname); + lua_pushstring(L, buf); + return 1; + } return 0; } template<typename T> int LuaxClass<T>::l_ExtendFactory(lua_State* L) { + + + return 0; + } + + template<typename T> + int LuaxClass<T>::l_ExtendSingleton(lua_State* L) + { + + return 0; } @@ -274,9 +392,33 @@ namespace Luax int LuaxClass<T>::l_GetInterfaceTable(lua_State* L) { LUAX_STATE(L); - assert(mInterfaceTable); - mInterfaceTable.PushRef(state); - return 0; + if (!mInterfaceTable) + lua_pushnil(L); + else + mInterfaceTable.PushRef(state); + return 1; + } + + template<typename T> + int LuaxClass<T>::l_GetClass(lua_State* L) + { + LUAX_STATE(L); + if (!mClassTable) + lua_pushnil(L); + else + mClassTable.PushRef(state); + return 1; + } + + template<typename T> + int LuaxClass<T>::l_GetRefTable(lua_State* L) + { + LUAX_STATE(L); + T* self = state.GetLuaUserdata<T>(1); + bool success = self->PushLuaxRefTable(state); + if (!success) + lua_pushnil(L); + return 1; } template<typename T> LuaxStrongRef LuaxClass<T>::mInterfaceTable; // interface table diff --git a/Source/3rdParty/Luax/luax_function.cpp b/Source/3rdParty/Luax/luax_function.cpp deleted file mode 100644 index e69de29..0000000 --- a/Source/3rdParty/Luax/luax_function.cpp +++ /dev/null diff --git a/Source/3rdParty/Luax/luax_function.h b/Source/3rdParty/Luax/luax_function.h deleted file mode 100644 index f4cc98b..0000000 --- a/Source/3rdParty/Luax/luax_function.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __LUAX_FUNCTION_H__ -#define __LUAX_FUNCTION_H__ - -namespace Luax -{ - - - -} - -#endif
\ No newline at end of file diff --git a/Source/3rdParty/Luax/luax_memberref.cpp b/Source/3rdParty/Luax/luax_memberref.cpp index e69de29..a8a09ba 100644 --- a/Source/3rdParty/Luax/luax_memberref.cpp +++ b/Source/3rdParty/Luax/luax_memberref.cpp @@ -0,0 +1,16 @@ +#include "luax_memberref.h" + +namespace Luax +{ + + LuaxMemberRef::LuaxMemberRef() + : refID(LUA_NOREF) + { + } + + LuaxMemberRef::~LuaxMemberRef() + { + + } + +}
\ No newline at end of file diff --git a/Source/3rdParty/Luax/luax_memberref.h b/Source/3rdParty/Luax/luax_memberref.h index a7ff1f6..bb373ab 100644 --- a/Source/3rdParty/Luax/luax_memberref.h +++ b/Source/3rdParty/Luax/luax_memberref.h @@ -1,14 +1,23 @@ #ifndef __LUAX_MEMBER_REF_H__ #define __LUAX_MEMBER_REF_H__ +#include "luax_config.h" + namespace Luax { /// - /// LuaxClassijԱãref table֤ȷͷţǿá + /// ʵref tablemember refluax classĹʵref tableǿãmemberڡ /// class LuaxMemberRef { + public: + LuaxMemberRef(); + ~LuaxMemberRef(); + + inline operator bool() { return refID != LUA_NOREF; }; + + int refID; }; diff --git a/Source/3rdParty/Luax/luax_state.cpp b/Source/3rdParty/Luax/luax_state.cpp index 1414591..a60a021 100644 --- a/Source/3rdParty/Luax/luax_state.cpp +++ b/Source/3rdParty/Luax/luax_state.cpp @@ -100,9 +100,9 @@ namespace Luax return idx; } - int LuaxState::Call(int nArgs, int nResults) + void LuaxState::Call(int nArgs, int nResults) { - return 0; + lua_pcall(mState, nArgs, nResults, 0); } void LuaxState::PushNil() diff --git a/Source/3rdParty/Luax/luax_state.h b/Source/3rdParty/Luax/luax_state.h index a936ea6..2bcfd9b 100644 --- a/Source/3rdParty/Luax/luax_state.h +++ b/Source/3rdParty/Luax/luax_state.h @@ -54,7 +54,7 @@ namespace Luax int GetTop(); bool CheckParams(int idx, cc8* format); int AbsIndex(int idx); - int Call(int nArgs, int nResults); + void Call(int nArgs, int nResults); //------------------------------------------------------------------------------------------------------------ diff --git a/Source/3rdParty/Luax/luax_state.inl b/Source/3rdParty/Luax/luax_state.inl index bd7ca9a..c9a95f6 100644 --- a/Source/3rdParty/Luax/luax_state.inl +++ b/Source/3rdParty/Luax/luax_state.inl @@ -56,7 +56,7 @@ namespace Luax LuaxClass<T>::SetLuaxClassTableRef(state, -1); - const char* type = T::GetLuaxFactoryName(); + cc8* type = T::GetLuaxFactoryName(); SetField(top, type); // reset top @@ -78,8 +78,6 @@ namespace Luax int top = lua_gettop(L); // namespace table assert(lua_istable(L, top)); - const char* type = T::GetLuaxSingletonName(); - // class table. lua_newtable(L); LuaxClass<T>::RegisterLuaxClass(state); @@ -94,10 +92,14 @@ namespace Luax lua_pushvalue(state, -1); lua_setfield(state, -2, "__newindex"); + cc8* type = T::GetLuaxSingletonName(); SetField(top, type); // reset top lua_settop(L, top); + + // + T::RegisterLuaxPostprocess(state); } template<typename T> diff --git a/Source/Asura.Engine/Graphics/Image.h b/Source/Asura.Engine/Graphics/Image.h index 2607969..916c365 100644 --- a/Source/Asura.Engine/Graphics/Image.h +++ b/Source/Asura.Engine/Graphics/Image.h @@ -2,13 +2,14 @@ #define __ASURA_ENGINE_IMAGE_H__ #include "math/vector2.hpp" -#include "scripting/portable.h" +#include "scripting/portable.hpp" #include "fileSystem/reloadable.h" #include "stringmap.hpp" #include "manager.hpp" #include "texture.h" #include "color.h" #include "image_data.h" +#include "render_state.h" namespace AsuraEngine { diff --git a/Source/Asura.Engine/Scripting/Portable.cpp b/Source/Asura.Engine/Scripting/Portable.cpp deleted file mode 100644 index 0aa5f08..0000000 --- a/Source/Asura.Engine/Scripting/Portable.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Portable.h" - -namespace AsuraEngine -{ - namespace Scripting - { - - } -} diff --git a/Source/Asura.Engine/Scripting/Portable.h b/Source/Asura.Engine/Scripting/Portable.h deleted file mode 100644 index 0527308..0000000 --- a/Source/Asura.Engine/Scripting/Portable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __ASURA_ENGINE_PORTABLE_H__ -#define __ASURA_ENGINE_PORTABLE_H__ - -#include "Luax.hpp" -#include "Config.h" -#include "Type.h" - -namespace AsuraEngine -{ - namespace Scripting - { - - template<typename T> - using Portable = Luax::LuaxClass<T>; - - } -} - -#endif
\ No newline at end of file diff --git a/Source/Asura.Engine/graphics/image.h b/Source/Asura.Engine/graphics/image.h index 2607969..916c365 100644 --- a/Source/Asura.Engine/graphics/image.h +++ b/Source/Asura.Engine/graphics/image.h @@ -2,13 +2,14 @@ #define __ASURA_ENGINE_IMAGE_H__ #include "math/vector2.hpp" -#include "scripting/portable.h" +#include "scripting/portable.hpp" #include "fileSystem/reloadable.h" #include "stringmap.hpp" #include "manager.hpp" #include "texture.h" #include "color.h" #include "image_data.h" +#include "render_state.h" namespace AsuraEngine { diff --git a/Source/Asura.Engine/graphics/render_state.h b/Source/Asura.Engine/graphics/render_state.h index f313296..a80efd3 100644 --- a/Source/Asura.Engine/graphics/render_state.h +++ b/Source/Asura.Engine/graphics/render_state.h @@ -6,7 +6,7 @@ #include "Math/Transform.h" #include "Shader.h" -#include "BlendMode.h" +#include "blend_mode.h" namespace AsuraEngine { diff --git a/Source/Asura.Engine/scripting/portable.cpp b/Source/Asura.Engine/scripting/portable.cpp deleted file mode 100644 index 0aa5f08..0000000 --- a/Source/Asura.Engine/scripting/portable.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Portable.h" - -namespace AsuraEngine -{ - namespace Scripting - { - - } -} diff --git a/Source/Asura.Engine/scripting/portable.h b/Source/Asura.Engine/scripting/portable.h deleted file mode 100644 index 0527308..0000000 --- a/Source/Asura.Engine/scripting/portable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __ASURA_ENGINE_PORTABLE_H__ -#define __ASURA_ENGINE_PORTABLE_H__ - -#include "Luax.hpp" -#include "Config.h" -#include "Type.h" - -namespace AsuraEngine -{ - namespace Scripting - { - - template<typename T> - using Portable = Luax::LuaxClass<T>; - - } -} - -#endif
\ No newline at end of file diff --git a/Source/Asura.Engine/scripting/portable.hpp b/Source/Asura.Engine/scripting/portable.hpp new file mode 100644 index 0000000..773e7ad --- /dev/null +++ b/Source/Asura.Engine/scripting/portable.hpp @@ -0,0 +1,43 @@ +#ifndef __ASURA_ENGINE_PORTABLE_H__ +#define __ASURA_ENGINE_PORTABLE_H__ + +#include "Config.h" +#include "Luax.hpp" +#include "Type.h" + +namespace AsuraEngine +{ + namespace Scripting + { + + template<typename T> + class Portable : public Luax::LuaxClass<T> + { + public: + + Portable(); + virtual ~Portable(); + + void Retain(); + void Release(); + + private: + + /// + /// ̱߳luagc߳˴native objectdelete + /// + int mRefCount; + + /// + /// deleteգ̳portable࣬ʹdeleteֻʹRelease + /// + bool mSafer; + + }; + +#include "portable.inl" + + } +} + +#endif
\ No newline at end of file diff --git a/Source/Asura.Engine/scripting/portable.inl b/Source/Asura.Engine/scripting/portable.inl new file mode 100644 index 0000000..a27b2e8 --- /dev/null +++ b/Source/Asura.Engine/scripting/portable.inl @@ -0,0 +1,30 @@ + +template<typename T> +Portable<T>::Portable() + : mRefCount(1) + , mSafer(false) +{ +} + +template<typename T> +Portable<T>::~Portable() +{ + ASSERT(mSafer); +} + +template<typename T> +void Portable<T>::Retain() +{ + ++mRefCount; +} + +template<typename T> +void Portable<T>::Release() +{ + if (--mRefCount <= 0) + { + mSafer = true; + delete this; + } +} + diff --git a/Source/Samples/LuaxTest/main.cpp b/Source/Samples/LuaxTest/main.cpp index 63daa1c..d9bd315 100644 --- a/Source/Samples/LuaxTest/main.cpp +++ b/Source/Samples/LuaxTest/main.cpp @@ -57,6 +57,10 @@ void School::RegisterLuaxClass(LuaxState& state) } +void School::RegisterLuaxPostprocess(Luax::LuaxState&) +{ +} + //---------------------------------------------------------------------------------------------------------------- class Boy : public LuaxClass<Boy> @@ -83,6 +87,13 @@ public: LUAX_DECL_METHOD(l_New); LUAX_DECL_METHOD(l_GetGender); + LUAX_DECL_METHOD(l_Write); + LUAX_DECL_METHOD(l_Speak); + +private: + + LuaxMemberRef mCallbak; + }; int Boy::l_New(lua_State* L) @@ -121,6 +132,25 @@ int Boy::l_GetGender(lua_State* L) return 1; } +int Boy::l_Speak(lua_State* L) +{ + LUAX_STATE(L); + + Boy* self = state.GetLuaUserdata<Boy>(1); + self->PushMemberRef(state, self->mCallbak); + state.Call(0, 1); + return 1; +} + +int Boy::l_Write(lua_State* L) +{ + LUAX_STATE(L); + // self, func + Boy* self = state.GetLuaUserdata<Boy>(1); + self->SetMemberRef(state, self->mCallbak, 2); + return 0; +} + void Boy::RegisterLuaxClass(LuaxState& state) { state.SetField(-1, "Class", 101); // 101 @@ -144,7 +174,6 @@ void Boy::RegisterLuaxClass(LuaxState& state) }; state.RegisterEnum("EHabits", EHabits); - } void Boy::RegisterLuaxInterface(LuaxState& state) @@ -152,6 +181,8 @@ void Boy::RegisterLuaxInterface(LuaxState& state) luaL_Reg regTable[] = { { "GetAge", l_GetAge }, { "GetName", l_GetName }, + { "Write", l_Write }, + { "Speak", l_Speak }, {NULL, NULL} }; diff --git a/Source/Samples/LuaxTest/script.lua b/Source/Samples/LuaxTest/script.lua index 84bcba9..32bd8e8 100644 --- a/Source/Samples/LuaxTest/script.lua +++ b/Source/Samples/LuaxTest/script.lua @@ -52,6 +52,18 @@ function main() print(Asura.EGender.BOY) print(Asura.SimBoy.EHabits.Girls) print(Asura.EHabits.Girls) + print(kid) + + kid:Write(function() + return "kid:Write()" + end ) + print(kid:Speak()) + + kid:Write(function() + return "kid:Write() 2" + end ) + print(kid:Speak()) + end function err(msg) print(msg) |