Currently, expression handling in XML is spotting and inconsistent.
Each actor type needs to evaluate attributes; only a few do. Strings are handled with the "@foo()" notation. Instead, after loading an XML file for loading as an actor, precompile all XML attributes as Lua expressions. The primary difference to code is: - previously, Attr="string" would act as a string if it was being read as one. Now, specify Attr='"string"'. Attr="@string" is a shorthand. (note that @strings will not be parsed as Lua strings, so can not use Lua escape characters) - previously, Attr="@func()" would evaluate func(), and the value of the attribute would be the return value of the function. This was only supported for a few attributes. Now, say Attr="func()", and this will work for all fields. - Attributes of other types are unchanged, except that all attributes may be Lua expressions, eg. Width="SCREEN_WIDTH". - Attributes names ending with "Command" are special, like metrics. Prefix "%" to disable this. This brings XML handling in line with metric handling. (This is an intermediary step; I have another idea that follows from this that should eliminate the annoying "'foo'"/"@foo".)
This commit is contained in:
+10
-9
@@ -258,6 +258,7 @@ void Actor::LoadFromNode( const RString& sDir, const XNode* pNode )
|
||||
}
|
||||
}
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
FOREACH_CONST_Attr( pNode, pAttr )
|
||||
{
|
||||
// Load Name, if any.
|
||||
@@ -272,10 +273,11 @@ void Actor::LoadFromNode( const RString& sDir, const XNode* pNode )
|
||||
else if( sKeyName == "BaseZoomZ" ) SetBaseZoomZ( pValue->GetValue<float>() );
|
||||
else if( EndsWith(sKeyName,"Command") )
|
||||
{
|
||||
apActorCommands apac = ActorUtil::ParseActorCommands( pValue->GetValue<RString>(), ssprintf("%s: %s", sDir.c_str(), sKeyName.c_str()) );
|
||||
|
||||
LuaReference *pRef = new LuaReference;
|
||||
pValue->PushValue( L );
|
||||
pRef->SetFromStack( L );
|
||||
RString sCmdName = sKeyName.Left( sKeyName.size()-7 );
|
||||
AddCommand( sCmdName, apac );
|
||||
AddCommand( sCmdName, apActorCommands( pRef ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,14 +293,13 @@ void Actor::LoadFromNode( const RString& sDir, const XNode* pNode )
|
||||
|
||||
RString sName;
|
||||
c->GetAttrValue( "Name", sName );
|
||||
RString sValue;
|
||||
c->GetAttrValue( "Value", sValue );
|
||||
c->PushAttrValue( L, "Value" );
|
||||
|
||||
LuaHelpers::RunAtExpressionS( sName );
|
||||
apActorCommands apac = ActorUtil::ParseActorCommands( sValue, ssprintf("%s: %s", sDir.c_str(), sKeyName.c_str()) );
|
||||
|
||||
AddCommand( sName, apac );
|
||||
LuaReference *pRef = new LuaReference;
|
||||
pRef->SetFromStack( L );
|
||||
AddCommand( sName, apActorCommands( pRef ) );
|
||||
}
|
||||
LUA->Release( L );
|
||||
|
||||
/* There's an InitCommand. Run it now. This can be used to eg. change Z to
|
||||
* modify draw order between BGAs in a Foreground. */
|
||||
|
||||
@@ -200,14 +200,10 @@ Actor* ActorUtil::LoadFromNode( const RString& sDir, const XNode* pNode, Actor *
|
||||
if( !pChild->GetAttrValue( "Name", sName ) )
|
||||
Dialog::OK( ssprintf("Param node in '%s' is missing the attribute \"Name\"", sDir.c_str()), "MISSING_ATTRIBUTE" );
|
||||
|
||||
LuaHelpers::RunAtExpressionS( sName );
|
||||
|
||||
RString s;
|
||||
if( !pChild->GetAttrValue( "Value", s ) )
|
||||
Lua *L = LUA->Get();
|
||||
if( !pChild->PushAttrValue( L, "Value" ) )
|
||||
Dialog::OK( ssprintf("Param node in '%s' is missing the attribute \"Value\"", sDir.c_str()), "MISSING_ATTRIBUTE" );
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
LuaHelpers::RunExpression( L, s, sDir );
|
||||
SetParamFromStack( L, sName, &setOldParams[sName] );
|
||||
LUA->Release(L);
|
||||
}
|
||||
@@ -368,6 +364,7 @@ Actor* ActorUtil::MakeActor( const RString &sPath_, const XNode *pParent, Actor
|
||||
return new Actor;
|
||||
}
|
||||
|
||||
XmlFileUtil::CompileXNodeTree( &xml, sPath );
|
||||
MergeActorXML( &xml, pParent );
|
||||
return ActorUtil::LoadFromNode( sDir, &xml );
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "RageUtil.h"
|
||||
#include "DateTime.h"
|
||||
#include "Foreach.h"
|
||||
#include "LuaManager.h"
|
||||
|
||||
XNode::XNode()
|
||||
{
|
||||
@@ -62,11 +63,19 @@ void XNodeStringValue::GetValue( int &out ) const { out = atoi(m_sValue); }
|
||||
void XNodeStringValue::GetValue( float &out ) const { out = StringToFloat(m_sValue); }
|
||||
void XNodeStringValue::GetValue( bool &out ) const { out = atoi(m_sValue) != 0; }
|
||||
void XNodeStringValue::GetValue( unsigned &out ) const { out = strtoul(m_sValue,NULL,0); }
|
||||
void XNodeStringValue::PushValue( lua_State *L ) const
|
||||
{
|
||||
LuaHelpers::Push( L, m_sValue );
|
||||
}
|
||||
|
||||
void XNodeStringValue::SetValue( const RString &v ) { m_sValue = v; }
|
||||
void XNodeStringValue::SetValue( int v ) { m_sValue = ssprintf("%d",v); }
|
||||
void XNodeStringValue::SetValue( float v ) { m_sValue = ssprintf("%f",v); }
|
||||
void XNodeStringValue::SetValue( unsigned v ) { m_sValue = ssprintf("%u",v); }
|
||||
void XNodeStringValue::SetValueFromStack( lua_State *L )
|
||||
{
|
||||
LuaHelpers::Pop( L, m_sValue );
|
||||
}
|
||||
|
||||
const XNodeValue *XNode::GetAttr( const RString &attrname ) const
|
||||
{
|
||||
@@ -76,6 +85,18 @@ const XNodeValue *XNode::GetAttr( const RString &attrname ) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool XNode::PushAttrValue( lua_State *L, const RString &sName ) const
|
||||
{
|
||||
const XNodeValue *pAttr = GetAttr(sName);
|
||||
if( pAttr == NULL )
|
||||
{
|
||||
lua_pushnil( L );
|
||||
return false;
|
||||
}
|
||||
pAttr->PushValue( L );
|
||||
return true;
|
||||
}
|
||||
|
||||
XNodeValue *XNode::GetAttr( const RString &attrname )
|
||||
{
|
||||
XAttrs::iterator it = m_attrs.find( attrname );
|
||||
@@ -95,6 +116,18 @@ XNode *XNode::GetChild( const RString &sName )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool XNode::PushChildValue( lua_State *L, const RString &sName ) const
|
||||
{
|
||||
const XNode *pChild = GetChild(sName);
|
||||
if( pChild == NULL )
|
||||
{
|
||||
lua_pushnil( L );
|
||||
return false;
|
||||
}
|
||||
pChild->m_pValue->PushValue( L );
|
||||
return true;
|
||||
}
|
||||
|
||||
const XNode *XNode::GetChild( const RString &sName ) const
|
||||
{
|
||||
multimap<RString, XNode*>::const_iterator it = m_childs.find( sName );
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <map>
|
||||
struct DateTime;
|
||||
class RageFileBasic;
|
||||
struct lua_State;
|
||||
|
||||
class XNodeValue
|
||||
{
|
||||
@@ -18,6 +19,7 @@ public:
|
||||
virtual void GetValue( float &out ) const = 0;
|
||||
virtual void GetValue( bool &out ) const = 0;
|
||||
virtual void GetValue( unsigned &out ) const = 0;
|
||||
virtual void PushValue( lua_State *L ) const = 0;
|
||||
|
||||
template<typename T>
|
||||
T GetValue() const { T val; GetValue(val); return val; }
|
||||
@@ -26,6 +28,7 @@ public:
|
||||
virtual void SetValue( int v ) = 0;
|
||||
virtual void SetValue( float v ) = 0;
|
||||
virtual void SetValue( unsigned v ) = 0;
|
||||
virtual void SetValueFromStack( lua_State *L ) = 0;
|
||||
};
|
||||
|
||||
class XNodeStringValue: public XNodeValue
|
||||
@@ -40,11 +43,13 @@ public:
|
||||
void GetValue( float &out ) const;
|
||||
void GetValue( bool &out ) const;
|
||||
void GetValue( unsigned &out ) const;
|
||||
void PushValue( lua_State *L ) const;
|
||||
|
||||
void SetValue( const RString &v );
|
||||
void SetValue( int v );
|
||||
void SetValue( float v );
|
||||
void SetValue( unsigned v );
|
||||
void SetValueFromStack( lua_State *L );
|
||||
};
|
||||
|
||||
typedef map<RString,XNodeValue*> XAttrs;
|
||||
@@ -98,12 +103,14 @@ public:
|
||||
XNodeValue *GetAttr( const RString &sAttrName );
|
||||
template <typename T>
|
||||
bool GetAttrValue( const RString &sName, T &out ) const { const XNodeValue *pAttr=GetAttr(sName); if(pAttr==NULL) return false; pAttr->GetValue(out); return true; }
|
||||
bool PushAttrValue( lua_State *L, const RString &sName ) const;
|
||||
|
||||
// in one level child nodes
|
||||
const XNode *GetChild( const RString &sName ) const;
|
||||
XNode *GetChild( const RString &sName );
|
||||
template <typename T>
|
||||
bool GetChildValue( const RString &sName, T &out ) const { const XNode *pChild=GetChild(sName); if(pChild==NULL) return false; pChild->GetValue(out); return true; }
|
||||
bool PushChildValue( lua_State *L, const RString &sName ) const;
|
||||
|
||||
// modify DOM
|
||||
template <typename T>
|
||||
|
||||
@@ -529,6 +529,117 @@ bool XmlFileUtil::SaveToFile( const XNode *pNode, const RString &sFile, const RS
|
||||
return SaveToFile( pNode, f, sStylesheet, bWriteTabs );
|
||||
}
|
||||
|
||||
#include "LuaManager.h"
|
||||
#include "LuaReference.h"
|
||||
class XNodeLuaValue: public XNodeValue
|
||||
{
|
||||
public:
|
||||
LuaReference m_Value;
|
||||
XNodeValue *Copy() const { return new XNodeLuaValue( *this ); }
|
||||
|
||||
template<typename T>
|
||||
T GetValue() const { T val; GetValue(val); return val; }
|
||||
|
||||
void GetValue( RString &out ) const;
|
||||
void GetValue( int &out ) const;
|
||||
void GetValue( float &out ) const;
|
||||
void GetValue( bool &out ) const;
|
||||
void GetValue( unsigned &out ) const;
|
||||
void PushValue( lua_State *L ) const;
|
||||
|
||||
void SetValue( const RString &v );
|
||||
void SetValue( int v );
|
||||
void SetValue( float v );
|
||||
void SetValue( unsigned v );
|
||||
void SetValueFromStack( lua_State *L );
|
||||
};
|
||||
|
||||
void XNodeLuaValue::PushValue( lua_State *L ) const
|
||||
{
|
||||
m_Value.PushSelf( L );
|
||||
}
|
||||
|
||||
void XNodeLuaValue::GetValue( RString &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); }
|
||||
void XNodeLuaValue::GetValue( int &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); }
|
||||
void XNodeLuaValue::GetValue( float &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); }
|
||||
void XNodeLuaValue::GetValue( bool &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); }
|
||||
void XNodeLuaValue::GetValue( unsigned &out ) const { Lua *L = LUA->Get(); PushValue( L ); float fVal; LuaHelpers::Pop( L, fVal ); out = fVal; LUA->Release( L ); }
|
||||
|
||||
void XNodeLuaValue::SetValueFromStack( lua_State *L )
|
||||
{
|
||||
m_Value.SetFromStack( L );
|
||||
}
|
||||
|
||||
void XNodeLuaValue::SetValue( const RString &v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, v ); SetValueFromStack( L ); LUA->Release( L ); }
|
||||
void XNodeLuaValue::SetValue( int v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, v ); SetValueFromStack( L ); LUA->Release( L ); }
|
||||
void XNodeLuaValue::SetValue( float v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, v ); SetValueFromStack( L ); LUA->Release( L ); }
|
||||
void XNodeLuaValue::SetValue( unsigned v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, (float) v ); SetValueFromStack( L ); LUA->Release( L ); }
|
||||
|
||||
namespace
|
||||
{
|
||||
void CompileXMLNodeValue( Lua *L, const RString &sName, XNodeValue *&pValue, const RString &sFile )
|
||||
{
|
||||
RString sExpression;
|
||||
pValue->GetValue( sExpression );
|
||||
|
||||
if( EndsWith(sName, "Command") && sExpression.size() > 0 && sExpression[0] == '%' )
|
||||
{
|
||||
sExpression.erase( 0, 1 );
|
||||
if( !LuaHelpers::RunExpression(L, sExpression, sFile) )
|
||||
{
|
||||
/* Compiling or running failed. An error was already logged; just push a dummy
|
||||
* return value. */
|
||||
lua_pushnil( L );
|
||||
}
|
||||
}
|
||||
else if( EndsWith(sName, "Command") && (sExpression.size() == 0 || sExpression[0] != '%') )
|
||||
{
|
||||
LuaHelpers::ParseCommandList( L, sExpression, sFile );
|
||||
}
|
||||
else if( sExpression.size() > 0 && sExpression[0] == '@' )
|
||||
{
|
||||
/* This is a raw string. */
|
||||
sExpression.erase( 0, 1 );
|
||||
LuaHelpers::Push( L, sExpression );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !LuaHelpers::RunExpression(L, sExpression, sFile) )
|
||||
{
|
||||
/* Compiling or running failed. An error was already logged; just push a dummy
|
||||
* return value. */
|
||||
lua_pushnil( L );
|
||||
}
|
||||
}
|
||||
|
||||
delete pValue;
|
||||
pValue = new XNodeLuaValue;
|
||||
pValue->SetValueFromStack( L );
|
||||
}
|
||||
}
|
||||
|
||||
void XmlFileUtil::CompileXNodeTree( XNode *pNode, const RString &sFile )
|
||||
{
|
||||
vector<XNode *> aToCompile;
|
||||
aToCompile.push_back( pNode );
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
while( aToCompile.size() )
|
||||
{
|
||||
pNode = aToCompile.back();
|
||||
aToCompile.pop_back();
|
||||
FOREACH_Child( pNode, pChild )
|
||||
aToCompile.push_back( pChild );
|
||||
|
||||
CompileXMLNodeValue( L, pNode->GetName(), pNode->m_pValue, sFile );
|
||||
|
||||
FOREACH_Attr( pNode, pAttr )
|
||||
CompileXMLNodeValue( L, pAttr->first, pAttr->second, sFile );
|
||||
}
|
||||
|
||||
LUA->Release( L );
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2001-2004 Chris Danford
|
||||
* All rights reserved.
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace XmlFileUtil
|
||||
RString GetXML( const XNode *pNode );
|
||||
bool SaveToFile( const XNode *pNode, const RString &sFile, const RString &sStylesheet = "", bool bWriteTabs = true );
|
||||
bool SaveToFile( const XNode *pNode, RageFileBasic &f, const RString &sStylesheet = "", bool bWriteTabs = true );
|
||||
|
||||
void CompileXNodeTree( XNode *pNode, const RString &sFile );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user