SC user nodeables now use __index method does not report error on (allowable) nil table entries LYN-3664
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
This commit is contained in:
@@ -689,6 +689,81 @@ namespace AZ
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Class__IndexAllowNil(lua_State* l)
|
||||
{
|
||||
LSV_BEGIN(l, 1);
|
||||
|
||||
// calling format __index(table,key)
|
||||
lua_getmetatable(l, -2); // load the userdata metatable
|
||||
int metaTableIndex = lua_gettop(l);
|
||||
|
||||
// Check if the key is string, if so we expect it to be a function or property name
|
||||
// otherwise we allow users to provide custom index handlers
|
||||
// Technically we can allow strings too, but it will clash with function/property names and it be hard to figure
|
||||
// out what is going on from with in the system.
|
||||
if (lua_type(l, -2) == LUA_TSTRING)
|
||||
{
|
||||
lua_pushvalue(l, -2); // duplicate the key
|
||||
lua_rawget(l, -2); // load the value at this index
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushliteral(l, "__AZ_Index");
|
||||
lua_rawget(l, -2); // check if the user provided custom Index method in the class metatable
|
||||
if (lua_isnil(l, -1)) // if not report an error
|
||||
{
|
||||
lua_rawgeti(l, -2, AZ_LUA_CLASS_METATABLE_NAME_INDEX); // load the class name for a better error
|
||||
if (!lua_isstring(l, -1)) // if we failed it means we are the base metatable
|
||||
{
|
||||
lua_pop(l, 1);
|
||||
lua_rawgeti(l, 1, AZ_LUA_CLASS_METATABLE_NAME_INDEX);
|
||||
}
|
||||
ScriptContext::FromNativeContext(l)->Error(ScriptContext::ErrorType::Warning, true, "Invalid index type [], should be string! '%s:%s'!", lua_tostring(l, -1), lua_tostring(l, -4));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we have custom index handler
|
||||
lua_pushvalue(l, -4); // duplicate the table (class pointer)
|
||||
lua_pushvalue(l, -4); // duplicate the index value for the call
|
||||
lua_call(l, 2, 1); // call the function
|
||||
}
|
||||
|
||||
lua_remove(l, metaTableIndex); // remove the metatable
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lua_isnil(l, -1))
|
||||
{
|
||||
if (lua_tocfunction(l, -1) == &Internal::LuaPropertyTagHelper) // if it's a property
|
||||
{
|
||||
lua_getupvalue(l, -1, 1); // push on the stack the getter function
|
||||
lua_remove(l, -2); // remove property object
|
||||
|
||||
if (lua_isnil(l, -1))
|
||||
{
|
||||
lua_rawgeti(l, -2, AZ_LUA_CLASS_METATABLE_NAME_INDEX); // load the class name for a better error
|
||||
if (!lua_isstring(l, -1)) // if we failed it means we are the base metatable
|
||||
{
|
||||
lua_pop(l, 1);
|
||||
lua_rawgeti(l, 1, AZ_LUA_CLASS_METATABLE_NAME_INDEX);
|
||||
}
|
||||
|
||||
ScriptContext::FromNativeContext(l)->Error(ScriptContext::ErrorType::Warning, true, "Property '%s:%s' is write only", lua_tostring(l, -1), lua_tostring(l, -4));
|
||||
lua_pop(l, 1); // pop class name
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushvalue(l, -4); // copy the user data to be passed as a this pointer.
|
||||
lua_call(l, 1, 1); // call a function with one argument (this pointer) and 1 result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_remove(l, metaTableIndex); // remove the metatable
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// Class__NewIndex
|
||||
// [3/22/2012]
|
||||
@@ -826,30 +901,6 @@ namespace AZ
|
||||
return 1;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ClassMetatable__Index
|
||||
// [3/24/2012]
|
||||
//=========================================================================
|
||||
int ClassMetatable__Index(lua_State* l)
|
||||
{
|
||||
// since the Class__Index is generic function (ask for the class metatable)
|
||||
// we can reuse the code for the base metatable (which is a metatable
|
||||
// of the class metatable)
|
||||
return Class__Index(l);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ClassMetatable__NewIndex
|
||||
// [3/30/2012]
|
||||
//=========================================================================
|
||||
int ClassMetatable__NewIndex(lua_State* l)
|
||||
{
|
||||
// since the Class__NewIndex is generic function (ask for the class metatable)
|
||||
// we can reuse the code for the base metatable (which is a metatable
|
||||
// of the class metatable)
|
||||
return Class__NewIndex(l);
|
||||
}
|
||||
|
||||
inline size_t BufferStringCopy(const char* source, char* destination, size_t destinationSize)
|
||||
{
|
||||
size_t srcLen = strlen(source);
|
||||
@@ -5053,9 +5104,20 @@ LUA_API const Node* lua_getDummyNode()
|
||||
lua_pushcclosure(m_lua, &DefaultBehaviorCaller::Destroy, 0);
|
||||
lua_rawset(m_lua, -3);
|
||||
|
||||
lua_pushliteral(m_lua, "__index");
|
||||
lua_pushcclosure(m_lua, &Internal::Class__Index, 0);
|
||||
lua_rawset(m_lua, -3);
|
||||
{
|
||||
lua_pushliteral(m_lua, "__index");
|
||||
|
||||
if (FindAttribute(Script::Attributes::UseClassIndexAllowNil, behaviorClass->m_attributes))
|
||||
{
|
||||
lua_pushcclosure(m_lua, &Internal::Class__IndexAllowNil, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushcclosure(m_lua, &Internal::Class__Index, 0);
|
||||
}
|
||||
|
||||
lua_rawset(m_lua, -3);
|
||||
}
|
||||
|
||||
lua_pushliteral(m_lua, "__newindex");
|
||||
lua_pushcclosure(m_lua, &Internal::Class__NewIndex, 0);
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace AZ
|
||||
const static AZ::Crc32 Deprecated = AZ_CRC("Deprecated", 0xfe49a138); ///< Marks a reflected class, method, EBus or property as deprecated.
|
||||
const static AZ::Crc32 DisallowBroadcast = AZ_CRC("DisallowBroadcast", 0x389b0ac7); ///< Marks a reflected EBus as not allowing Broadcasts, only Events.
|
||||
const static AZ::Crc32 ClassConstantValue = AZ_CRC_CE("ClassConstantValue"); ///< Indicates the property is backed by a constant value
|
||||
const static AZ::Crc32 UseClassIndexAllowNil = AZ_CRC_CE("UseClassIndexAllowNil"); ///< Use the Class__IndexAllowNil method, which will not report an error on accessing undeclared values (allows for nil)
|
||||
|
||||
//! Attribute which stores BehaviorAzEventDescription structure which contains
|
||||
//! the script name of an AZ::Event and the name of it's parameter arguments
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace ScriptCanvas
|
||||
behaviorContext->Class<Nodeable>()
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AZ::AttributeIsValid::IfPresent)
|
||||
->Attribute(AZ::Script::Attributes::UseClassIndexAllowNil, AZ::AttributeIsValid::IfPresent)
|
||||
->Constructor<ExecutionStateWeakPtr>()
|
||||
->Method("Deactivate", &Nodeable::Deactivate)
|
||||
->Method("InitializeExecutionState", &Nodeable::InitializeExecutionState)
|
||||
|
||||
Reference in New Issue
Block a user