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:
Glenn Maynard
2006-10-09 00:49:30 +00:00
parent 2e3b047880
commit 3cae60d6fd
6 changed files with 166 additions and 15 deletions
+10 -9
View File
@@ -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. */
+3 -6
View File
@@ -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 );
}
+33
View File
@@ -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 );
+7
View File
@@ -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>
+111
View File
@@ -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.
+2
View File
@@ -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