Browse Source

Made the proxy tables act just like regular tables

Added some pseudo-metatables named __pairs and __ipairs that types can implement to intercept calls from pairs and ipairs to iterate over values that don't exist in the actual Lua table.

Moved the print override to the GlobalLuaFunctions.cpp file, where the global function pairs and ipairs are overriden to respect the pseudo-metamethods.
Nate Starkey 13 years ago
parent
commit
b39640892c

+ 8 - 0
Build/RocketCoreLua.vcproj

@@ -187,6 +187,14 @@
 		<Filter
 			Name="Core"
 			>
+			<File
+				RelativePath="..\Source\Core\Lua\GlobalLuaFunctions.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\Source\Core\Lua\GlobalLuaFunctions.h"
+				>
+			</File>
 			<File
 				RelativePath="..\Source\Core\Lua\Interpreter.cpp"
 				>

+ 36 - 22
Source/Controls/Lua/SelectOptionsProxy.cpp

@@ -33,6 +33,10 @@ template<> void Rocket::Core::Lua::ExtraInit<Rocket::Controls::Lua::SelectOption
 {
     lua_pushcfunction(L,Rocket::Controls::Lua::SelectOptionsProxy__index);
     lua_setfield(L,metatable_index,"__index");
+    lua_pushcfunction(L,Rocket::Controls::Lua::SelectOptionsProxy__pairs);
+    lua_setfield(L,metatable_index,"__pairs");
+    lua_pushcfunction(L,Rocket::Controls::Lua::SelectOptionsProxy__ipairs);
+    lua_setfield(L,metatable_index,"__ipairs");
 }
 
 
@@ -63,38 +67,48 @@ int SelectOptionsProxy__index(lua_State* L)
         return LuaType<SelectOptionsProxy>::index(L);
 }
 
-//method
-int SelectOptionsProxyGetTable(lua_State* L, SelectOptionsProxy* obj)
+//since there are no string keys, just use __ipairs
+int SelectOptionsProxy__pairs(lua_State* L)
 {
-    int numOptions = obj->owner->GetNumOptions();
+    return SelectOptionsProxy__ipairs(L);
+}
 
-    //local variables for the loop
-    Rocket::Controls::SelectOption* opt; 
-    Rocket::Core::Element* ele;
-    Rocket::Core::String value;
-    lua_newtable(L); //table to return
-    int retindex = lua_gettop(L);
-    for(int index = 0; index < numOptions; index++)
+//[1] is the object, [2] is the previous key, [3] is the userdata
+int SelectOptionsProxy__ipairs(lua_State* L)
+{
+    SelectOptionsProxy* proxy = LuaType<SelectOptionsProxy>::check(L,1);
+    LUACHECKOBJ(proxy);
+    int* pindex = (int*)lua_touserdata(L,3);
+    if((*pindex) == -1)
+        *pindex = 0;
+    SelectOption* opt = NULL;
+    while((*pindex) < proxy->owner->GetNumOptions())
     {
-        opt = obj->owner->GetOption(index);
-        if(opt == NULL) continue;
-    
-        ele = opt->GetElement();
-        value = opt->GetValue();
-
-        lua_newtable(L);
-        LuaType<Rocket::Core::Element>::push(L,ele,false);
+        opt = proxy->owner->GetOption((*pindex)++);
+        if(opt != NULL) 
+            break;
+    }
+    //we got to the end without finding an option
+    if(opt == NULL)
+    {
+        lua_pushnil(L);
+        lua_pushnil(L);
+    }
+    else //we found an option
+    {
+        lua_pushinteger(L,(*pindex)-1); //key
+        lua_newtable(L); //value
+        //fill the value
+        LuaType<Rocket::Core::Element>::push(L,opt->GetElement());
         lua_setfield(L,-2,"element");
-        lua_pushstring(L,value.CString());
+        lua_pushstring(L,opt->GetValue().CString());
         lua_setfield(L,-2,"value");
-        lua_rawseti(L,retindex,index); //sets the table that is being returned's 'index' to be the table with element and value
     }
-    return 1;
+    return 2;
 }
 
 Rocket::Core::Lua::RegType<SelectOptionsProxy> SelectOptionsProxyMethods[] =
 {
-    LUAMETHOD(SelectOptionsProxy,GetTable)
     { NULL, NULL },
 };
 

+ 2 - 3
Source/Controls/Lua/SelectOptionsProxy.h

@@ -40,9 +40,8 @@ namespace Lua {
 struct SelectOptionsProxy { Rocket::Controls::ElementFormControlSelect* owner;  };
 
 int SelectOptionsProxy__index(lua_State* L);
-
-//method
-int SelectOptionsProxyGetTable(lua_State* L, SelectOptionsProxy* obj);
+int SelectOptionsProxy__pairs(lua_State* L);
+int SelectOptionsProxy__ipairs(lua_State* L);
 
 Rocket::Core::Lua::RegType<SelectOptionsProxy> SelectOptionsProxyMethods[];
 luaL_reg SelectOptionsProxyGetters[];

+ 65 - 17
Source/Core/Lua/ContextDocumentsProxy.cpp

@@ -37,6 +37,10 @@ template<> void ExtraInit<ContextDocumentsProxy>(lua_State* L, int metatable_ind
 {
     lua_pushcfunction(L,ContextDocumentsProxy__index);
     lua_setfield(L,metatable_index,"__index");
+    lua_pushcfunction(L,ContextDocumentsProxy__pairs);
+    lua_setfield(L,metatable_index,"__pairs");
+    lua_pushcfunction(L,ContextDocumentsProxy__ipairs);
+    lua_setfield(L,metatable_index,"__ipairs");
 }
 
 int ContextDocumentsProxy__index(lua_State* L)
@@ -59,33 +63,77 @@ int ContextDocumentsProxy__index(lua_State* L)
     
 }
 
-//method
-int ContextDocumentsProxyGetTable(lua_State* L, ContextDocumentsProxy* obj)
+//[1] is the object, [2] is the last used key, [3] is the userdata
+int ContextDocumentsProxy__pairs(lua_State* L)
 {
-    Context* cont = obj->owner;
-    Element* root = cont->GetRootElement();
+    Document* doc = NULL;
+    ContextDocumentsProxy* obj = LuaType<ContextDocumentsProxy>::check(L,1);
+    LUACHECKOBJ(obj);
+    int* pindex = (int*)lua_touserdata(L,3);
+    if((*pindex) == -1)
+        *pindex = 0;
 
-    lua_newtable(L);
-    int tableindex = lua_gettop(L);
-    for(int i = 0; i < root->GetNumChildren(); i++)
+    int num_docs = obj->owner->GetNumDocuments();
+    //because there can be missing indexes, make sure to continue until there
+    //is actually a document at the index
+    while((*pindex) < num_docs)
     {
-        Document* doc = root->GetChild(i)->GetOwnerDocument();
-        if(doc == NULL)
-            continue;
+        doc = obj->owner->GetDocument((*pindex)++);
+        if(doc != NULL)
+            break;
+    }
 
+    //If we found a document 
+    if(doc != NULL)
+    {
+        lua_pushstring(L,doc->GetId().CString());
         LuaType<Document>::push(L,doc);
-        lua_pushvalue(L,-1); //put it on the stack twice, since we assign it to 
-                                //both a string and integer index
-        lua_setfield(L, tableindex,doc->GetId().CString());
-        lua_rawseti(L,tableindex,i);
     }
-    lua_settop(L,tableindex); //to make sure
-    return 1;
+    else //if we were at the end and didn't find a document
+    {
+        lua_pushnil(L);
+        lua_pushnil(L);
+    }
+    return 2;
 }
 
+//same as __pairs, but putting an integer key instead of a string key
+int ContextDocumentsProxy__ipairs(lua_State* L)
+{
+    Document* doc = NULL;
+    ContextDocumentsProxy* obj = LuaType<ContextDocumentsProxy>::check(L,1);
+    LUACHECKOBJ(obj);
+    int* pindex = (int*)lua_touserdata(L,3);
+    if((*pindex) == -1)
+        *pindex = 0;
+
+    int num_docs = obj->owner->GetNumDocuments();
+    //because there can be missing indexes, make sure to continue until there
+    //is actually a document at the index
+    while((*pindex) < num_docs)
+    {
+        doc = obj->owner->GetDocument((*pindex)++);
+        if(doc != NULL)
+            break;
+    }
+
+    //we found a document
+    if(doc != NULL)
+    {
+        lua_pushinteger(L,(*pindex)-1);
+        LuaType<Document>::push(L,doc);
+    }
+    else //we got to the end and didn't find another document
+    {
+        lua_pushnil(L);
+        lua_pushnil(L);
+    }
+    return 2;
+}
+
+
 RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[] =
 {
-    LUAMETHOD(ContextDocumentsProxy,GetTable)
     { NULL, NULL },
 };
 

+ 2 - 3
Source/Core/Lua/ContextDocumentsProxy.h

@@ -40,9 +40,8 @@ struct ContextDocumentsProxy { Context* owner;  };
 
 template<> void ExtraInit<ContextDocumentsProxy>(lua_State* L, int metatable_index);
 int ContextDocumentsProxy__index(lua_State* L);
-
-//method
-int ContextDocumentsProxyGetTable(lua_State* L, ContextDocumentsProxy* obj);
+int ContextDocumentsProxy__pairs(lua_State* L);
+int ContextDocumentsProxy__ipairs(lua_State* L);
 
 RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[];
 luaL_reg ContextDocumentsProxyGetters[];

+ 30 - 14
Source/Core/Lua/ElementAttributesProxy.cpp

@@ -37,6 +37,10 @@ template<> void ExtraInit<ElementAttributesProxy>(lua_State* L, int metatable_in
 {
     lua_pushcfunction(L,ElementAttributesProxy__index);
     lua_setfield(L,metatable_index,"__index");
+    lua_pushcfunction(L,ElementAttributesProxy__pairs);
+    lua_setfield(L,metatable_index,"__pairs");
+    lua_pushcfunction(L,ElementAttributesProxy__ipairs);
+    lua_setfield(L,metatable_index,"__ipairs");
 }
 
 int ElementAttributesProxy__index(lua_State* L)
@@ -56,27 +60,39 @@ int ElementAttributesProxy__index(lua_State* L)
         return LuaType<ElementAttributesProxy>::index(L);
 }
 
-//method
-int ElementAttributesProxyGetTable(lua_State* L, ElementAttributesProxy* obj)
-{    
-    int index;
-    String key;
-    Variant* var;
-
-    lua_newtable(L);
-    int tbl = lua_gettop(L);
-    while(obj->owner->IterateAttributes(index,key,var))
+//[1] is the object, [2] is the key that was used previously, [3] is the userdata
+int ElementAttributesProxy__pairs(lua_State* L)
+{
+    ElementAttributesProxy* obj = LuaType<ElementAttributesProxy>::check(L,1);
+    LUACHECKOBJ(obj);
+    int* pindex = (int*)lua_touserdata(L,3);
+    if((*pindex) == -1) 
+        *pindex = 0;
+    String key = "";
+    Variant* val;
+    if(obj->owner->IterateAttributes((*pindex),key,val))
     {
         lua_pushstring(L,key.CString());
-        PushVariant(L,var);
-        lua_settable(L,tbl);
+        PushVariant(L,val);
+    }
+    else
+    {
+        lua_pushnil(L);
+        lua_pushnil(L);
     }
-    return 1;
+    return 2;
+}
+
+//Doesn't index by integer, so don't return anything
+int ElementAttributesProxy__ipairs(lua_State* L)
+{
+    lua_pushnil(L);
+    lua_pushnil(L);
+    return 2;
 }
 
 RegType<ElementAttributesProxy> ElementAttributesProxyMethods[] =
 {
-    LUAMETHOD(ElementAttributesProxy,GetTable)
     { NULL, NULL },
 };
 

+ 2 - 3
Source/Core/Lua/ElementAttributesProxy.h

@@ -40,9 +40,8 @@ struct ElementAttributesProxy { Element* owner;  };
 
 template<> void ExtraInit<ElementAttributesProxy>(lua_State* L, int metatable_index);
 int ElementAttributesProxy__index(lua_State* L);
-
-//method
-int ElementAttributesProxyGetTable(lua_State* L, ElementAttributesProxy* obj);
+int ElementAttributesProxy__pairs(lua_State* L);
+int ElementAttributesProxy__ipairs(lua_State* L);
 
 RegType<ElementAttributesProxy> ElementAttributesProxyMethods[];
 luaL_reg ElementAttributesProxyGetters[];

+ 29 - 18
Source/Core/Lua/ElementChildNodesProxy.cpp

@@ -37,6 +37,10 @@ template<> void ExtraInit<ElementChildNodesProxy>(lua_State* L, int metatable_in
 {
     lua_pushcfunction(L,ElementChildNodesProxy__index);
     lua_setfield(L,metatable_index,"__index");
+    lua_pushcfunction(L,ElementChildNodesProxy__pairs);
+    lua_setfield(L,metatable_index,"__pairs");
+    lua_pushcfunction(L,ElementChildNodesProxy__ipairs);
+    lua_setfield(L,metatable_index,"__ipairs");
 }
 
 int ElementChildNodesProxy__index(lua_State* L)
@@ -56,31 +60,38 @@ int ElementChildNodesProxy__index(lua_State* L)
         return LuaType<ElementChildNodesProxy>::index(L);
 }
 
-//method
-int ElementChildNodesProxyGetTable(lua_State* L, ElementChildNodesProxy* obj)
+int ElementChildNodesProxy__pairs(lua_State* L)
 {
-    Element* ele = obj->owner;
-    if(!ele->HasChildNodes())
-        lua_pushnil(L);
+    //because it is only indexed by integer, just go through ipairs
+    return ElementChildNodesProxy__ipairs(L);
+}
+
+
+//[1] is the object, [2] is the key that was just used, [3] is the userdata
+int ElementChildNodesProxy__ipairs(lua_State* L)
+{
+    ElementChildNodesProxy* obj = LuaType<ElementChildNodesProxy>::check(L,1);
+    LUACHECKOBJ(obj);
+    int* pindex = (int*)lua_touserdata(L,3);
+    if((*pindex) == -1) //initial value
+        (*pindex) = 0;
+    int num_children = obj->owner->GetNumChildren();
+    if((*pindex) < num_children)
+    {
+        lua_pushinteger(L,*pindex); //key
+        LuaType<Element>::push(L,obj->owner->GetChild(*pindex)); //value
+        (*pindex) += 1;
+    }
     else
     {
-        lua_newtable(L);
-        int index = 0;
-        int num_of_children = ele->GetNumChildren();
-        while(index < num_of_children)
-        {
-            lua_pushinteger(L,index);
-            LuaType<Element>::push(L,ele->GetChild(index),false);
-            lua_settable(L,-3);
-            ++index;
-        }
+        lua_pushnil(L);
+        lua_pushnil(L);
     }
-    return 1;
+    return 2;
 }
 
 RegType<ElementChildNodesProxy> ElementChildNodesProxyMethods[] = 
 {
-    LUAMETHOD(ElementChildNodesProxy,GetTable)
     { NULL, NULL },
 };
 luaL_reg ElementChildNodesProxyGetters[] = 
@@ -92,7 +103,7 @@ luaL_reg ElementChildNodesProxySetters[] =
     { NULL, NULL },
 };
 
-LUATYPEDEFINE(ElementChildNodesProxy,true)
+LUATYPEDEFINE(ElementChildNodesProxy,false)
 }
 }
 }

+ 2 - 3
Source/Core/Lua/ElementChildNodesProxy.h

@@ -41,9 +41,8 @@ struct ElementChildNodesProxy { Element* owner;  };
 
 template<> void ExtraInit<ElementChildNodesProxy>(lua_State* L, int metatable_index);
 int ElementChildNodesProxy__index(lua_State* L);
-
-//method
-int ElementChildNodesProxyGetTable(lua_State* L, ElementChildNodesProxy* obj);
+int ElementChildNodesProxy__pairs(lua_State* L);
+int ElementChildNodesProxy__ipairs(lua_State* L);
 
 RegType<ElementChildNodesProxy> ElementChildNodesProxyMethods[];
 luaL_reg ElementChildNodesProxyGetters[];

+ 32 - 12
Source/Core/Lua/ElementStyle.cpp

@@ -41,6 +41,12 @@ template<> void ExtraInit<ElementStyle>(lua_State* L, int metatable_index)
 
     lua_pushcfunction(L,ElementStyle__newindex);
     lua_setfield(L,metatable_index,"__newindex");
+
+    lua_pushcfunction(L,ElementStyle__pairs);
+    lua_setfield(L,metatable_index,"__pairs");
+
+    lua_pushcfunction(L,ElementStyle__ipairs);
+    lua_setfield(L,metatable_index,"__ipairs");
 }
 
 int ElementStyle__index(lua_State* L)
@@ -108,28 +114,42 @@ int ElementStyle__newindex(lua_State* L)
 
 }
 
-
-int ElementStyleGetTable(lua_State* L, ElementStyle* obj)
+//[1] is the object, [2] is the last used key, [3] is the userdata
+int ElementStyle__pairs(lua_State* L)
 {
-    int index = 0;
-    String key,sval;
-    const Property* value;
+    ElementStyle* obj = LuaType<ElementStyle>::check(L,1);
+    LUACHECKOBJ(obj);
+    int* pindex = (int*)lua_touserdata(L,3);
+    if((*pindex) == -1)
+        *pindex = 0;
+    //iterate variables
+    String key,val;
+    const Property* prop;
     PseudoClassList pseudo;
-    lua_newtable(L);
-    while(obj->IterateProperties(index,pseudo,key,value))
+    if(obj->IterateProperties((*pindex),pseudo,key,prop))
     {
+        prop->definition->GetValue(val,*prop);
         lua_pushstring(L,key.CString());
-        value->definition->GetValue(sval,*value);
-        lua_pushstring(L,sval.CString());
-        lua_settable(L,-3);
+        lua_pushstring(L,val.CString());
     }
-    return 1;
+    else
+    {
+        lua_pushnil(L);
+        lua_pushnil(L);
+    }
+    return 2;
 }
 
+//only indexed by string
+int ElementStyle__ipairs(lua_State* L)
+{
+    lua_pushnil(L);
+    lua_pushnil(L);
+    return 2;
+}
 
 RegType<ElementStyle> ElementStyleMethods[] = 
 {
-    LUAMETHOD(ElementStyle,GetTable)
     { NULL, NULL },
 };
 

+ 2 - 3
Source/Core/Lua/ElementStyle.h

@@ -38,9 +38,8 @@ namespace Lua {
 template<> void ExtraInit<ElementStyle>(lua_State* L, int metatable_index);
 int ElementStyle__index(lua_State* L);
 int ElementStyle__newindex(lua_State* L);
-
-//methods
-int ElementStyleGetTable(lua_State* L, ElementStyle* obj);
+int ElementStyle__pairs(lua_State* L);
+int ElementStyle__ipairs(lua_State* L);
 
 RegType<ElementStyle> ElementStyleMethods[];
 luaL_reg ElementStyleGetters[];

+ 28 - 13
Source/Core/Lua/EventParametersProxy.cpp

@@ -40,6 +40,10 @@ template<> void ExtraInit<EventParametersProxy>(lua_State* L, int metatable_inde
 {
     lua_pushcfunction(L,EventParametersProxy__index);
     lua_setfield(L,metatable_index,"__index");
+    lua_pushcfunction(L,EventParametersProxy__pairs);
+    lua_setfield(L,metatable_index,"__pairs");
+    lua_pushcfunction(L,EventParametersProxy__ipairs);
+    lua_setfield(L,metatable_index,"__ipairs");
 }
 
 int EventParametersProxy__index(lua_State* L)
@@ -59,28 +63,39 @@ int EventParametersProxy__index(lua_State* L)
         return LuaType<EventParametersProxy>::index(L);
 }
 
-//method
-int EventParametersProxyGetTable(lua_State* L, EventParametersProxy* obj)
-{
-    const Dictionary* params = obj->owner->GetParameters();
-    int index = 0;
-    String key;
-    Variant* value;
 
-    lua_newtable(L);
-    int tableindex = lua_gettop(L);
-    while(params->Iterate(index,key,value))
+//[1] is the object, [2] is the last used key, [3] is the userdata
+int EventParametersProxy__pairs(lua_State* L)
+{
+    EventParametersProxy* obj = LuaType<EventParametersProxy>::check(L,1);
+    int* pindex = (int*)lua_touserdata(L,3);
+    if((*pindex) == -1)
+        *pindex = 0;
+    String key = "";
+    Variant* value = NULL;
+    if(obj->owner->GetParameters()->Iterate((*pindex),key,value))
     {
         lua_pushstring(L,key.CString());
         PushVariant(L,value);
-        lua_settable(L,tableindex);
     }
-    return 1;
+    else
+    {
+        lua_pushnil(L);
+        lua_pushnil(L);
+    }
+    return 2;
+}
+
+//only index by string
+int EventParametersProxy__ipairs(lua_State* L)
+{
+    lua_pushnil(L);
+    lua_pushnil(L);
+    return 2;
 }
 
 RegType<EventParametersProxy> EventParametersProxyMethods[] =
 {
-    LUAMETHOD(EventParametersProxy,GetTable)
     { NULL, NULL },
 };
 luaL_reg EventParametersProxyGetters[] =

+ 2 - 3
Source/Core/Lua/EventParametersProxy.h

@@ -40,9 +40,8 @@ struct EventParametersProxy { Event* owner;  };
 
 template<> void ExtraInit<EventParametersProxy>(lua_State* L, int metatable_index);
 int EventParametersProxy__index(lua_State* L);
-
-//method
-int EventParametersProxyGetTable(lua_State* L, EventParametersProxy* obj);
+int EventParametersProxy__pairs(lua_State* L);
+int EventParametersProxy__ipairs(lua_State* L);
 
 RegType<EventParametersProxy> EventParametersProxyMethods[];
 luaL_reg EventParametersProxyGetters[];

+ 165 - 0
Source/Core/Lua/GlobalLuaFunctions.cpp

@@ -0,0 +1,165 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+
+#include "precompiled.h"
+#include "GlobalLuaFunctions.h"
+#include <Rocket/Core/Lua/lua.hpp>
+
+namespace Rocket {
+namespace Core {
+namespace Lua {
+/*
+Below here are global functions and their helper functions that help overwrite the Lua global functions
+*/
+
+//__pairs should return two values.
+//upvalue 1 is the __pairs function, upvalue 2 is the userdata created in rocket_pairs
+//[1] is the object implementing __pairs
+//[2] is the key that was just read
+int rocket_pairsaux(lua_State* L)
+{
+    lua_pushvalue(L,lua_upvalueindex(1)); //push __pairs to top
+    lua_insert(L,1); //move __pairs to the bottom
+    lua_pushvalue(L,lua_upvalueindex(2)); //push userdata
+    //stack looks like [1] = __pairs, [2] = object, [3] = latest key, [4] = userdata
+    if(lua_pcall(L,lua_gettop(L)-1,LUA_MULTRET,0) != 0)
+        Report(L,"__pairs");
+    return lua_gettop(L);
+}
+
+//A version of paris that respects a __pairs metamethod.
+//"next" function is upvalue 1
+int rocket_pairs(lua_State* L)
+{
+    luaL_checkany(L,1); //[1] is the object given to us by pairs(object)
+    if(luaL_getmetafield(L,1,"__pairs"))
+    {
+        void* ud = lua_newuserdata(L,sizeof(void*)); //create a new block of memory to be used as upvalue 1
+        (*(int*)(ud)) = -1;
+        lua_pushcclosure(L,rocket_pairsaux,2); //uv 1 is __pairs, uv 2 is ud
+    }
+    else
+        lua_pushvalue(L,lua_upvalueindex(1)); //generator
+    lua_pushvalue(L,1); //state
+    lua_pushnil(L); //initial value
+    return 3;
+}
+
+//copy + pasted from Lua's lbaselib.c
+int ipairsaux (lua_State *L) {
+    int i = luaL_checkint(L, 2);
+    luaL_checktype(L, 1, LUA_TTABLE);
+    i++;  /* next value */
+    lua_pushinteger(L, i);
+    lua_rawgeti(L, 1, i);
+    return (lua_isnil(L, -1)) ? 0 : 2;
+}
+
+//__ipairs should return two values
+//upvalue 1 is the __ipairs function, upvalue 2 is the userdata created in rocket_ipairs
+//[1] is the object implementing __ipairs, [2] is the key last used
+int rocket_ipairsaux(lua_State* L)
+{
+    lua_pushvalue(L,lua_upvalueindex(1)); //push __ipairs
+    lua_insert(L,1); //move __ipairs to the bottom
+    lua_pushvalue(L,lua_upvalueindex(2)); //push userdata
+    //stack looks like [1] = __ipairs, [2] = object, [3] = latest key, [4] = userdata
+    if(lua_pcall(L,lua_gettop(L)-1,LUA_MULTRET,0) != 0)
+        Report(L,"__ipairs");
+    return lua_gettop(L);
+}
+
+
+//A version of paris that respects a __pairs metamethod.
+//ipairsaux function is upvalue 1
+int rocket_ipairs(lua_State* L)
+{
+    luaL_checkany(L,1); //[1] is the object given to us by ipairs(object)
+    if(luaL_getmetafield(L,1,"__ipairs"))
+    {
+        void* ud = lua_newuserdata(L,sizeof(void*)); //create a new block of memory to be used as upvalue 1
+        (*(int*)(ud)) = -1;
+        lua_pushcclosure(L,rocket_pairsaux,2); //uv 1 is __ipairs, uv 2 is ud
+    }
+    else
+        lua_pushvalue(L,lua_upvalueindex(1)); //generator
+    lua_pushvalue(L,1); //state
+    lua_pushnil(L); //initial value
+    return 3;
+}
+
+
+//Based off of the luaB_print function from Lua's lbaselib.c
+int LuaPrint(lua_State* L)
+{
+    int n = lua_gettop(L);  /* number of arguments */
+    int i;
+    lua_getglobal(L, "tostring");
+    StringList string_list = StringList();
+    String output = "";
+    for (i=1; i<=n; i++) 
+    {
+        const char *s;
+        lua_pushvalue(L, -1);  /* function to be called */
+        lua_pushvalue(L, i);   /* value to print */
+        lua_call(L, 1, 1);
+        s = lua_tostring(L, -1);  /* get result */
+        if (s == NULL)
+            return luaL_error(L, LUA_QL("tostring") " must return a string to "
+                                 LUA_QL("print"));
+        if (i>1) 
+            output += "\t";
+        output += String(s);
+        lua_pop(L, 1);  /* pop result */
+    }
+    output += "\n";
+    Log::Message(Log::LT_INFO, output.CString());
+    return 0;
+}
+
+void OverrideLuaGlobalFunctions(lua_State* L)
+{
+    lua_getglobal(L,"_G");
+
+    lua_getglobal(L,"next");
+    lua_pushcclosure(L,rocket_pairs,1);
+    lua_setfield(L,-2,"pairs");
+
+    lua_pushcfunction(L,ipairsaux);
+    lua_pushcclosure(L,rocket_ipairs,1);
+    lua_setfield(L,-2,"ipairs");
+
+    lua_pushcfunction(L,LuaPrint);
+    lua_setfield(L,-2,"print");
+
+    lua_pop(L,1); //pop _G
+}
+
+}
+}
+}

+ 42 - 0
Source/Core/Lua/GlobalLuaFunctions.h

@@ -0,0 +1,42 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCORELUAGLOBALLUAFUNCTIONS_H
+#define ROCKETCORELUAGLOBALLUAFUNCTIONS_H
+
+namespace Rocket {
+namespace Core {
+namespace Lua {
+void OverrideLuaGlobalFunctions(lua_State* L);
+//overrides pairs and ipairs to respect __pairs and __ipairs metamethods
+//overrdes print to print to the console
+}
+}
+}
+
+
+#endif

+ 5 - 1
Source/Core/Lua/Interpreter.cpp

@@ -53,6 +53,7 @@
 #include "ElementInstancer.h"
 #include "ElementChildNodesProxy.h"
 #include "ElementText.h"
+#include "GlobalLuaFunctions.h"
 
 namespace Rocket {
 namespace Core {
@@ -61,7 +62,6 @@ lua_State* Interpreter::_L = NULL;
 //typedefs for nicer Lua names
 typedef Rocket::Core::ElementDocument Document;
 
-
 void Interpreter::Startup()
 {
     Log::Message(Log::LT_INFO, "Loading Lua interpreter");
@@ -93,6 +93,7 @@ void Interpreter::RegisterCoreTypes(lua_State* L)
     LuaType<EventParametersProxy>::Register(L);
     LuaType<ElementAttributesProxy>::Register(L);
     LuaType<ElementChildNodesProxy>::Register(L);
+    OverrideLuaGlobalFunctions(L);
 }
 
 
@@ -210,6 +211,9 @@ void Interpreter::Shutdown()
 	lua_close(_L);
 }
 
+
+
+
 }
 }
 }

+ 0 - 34
Source/Core/Lua/Log.cpp

@@ -67,11 +67,6 @@ template<> void ExtraInit<Log>(lua_State* L, int metatable_index)
     lua_setfield(L,logtype,"debug");
 
     lua_pop(L,1); //pop the logtype table
-
-
-    //overwrite the default 'print' function
-    lua_register(L,"print",OverwriteLuaPrint);
-
     return;
 }
 
@@ -84,35 +79,6 @@ int LogMessage(lua_State* L)
     return 0;
 }
 
-//Based off of the luaB_print function from lbaselib.c
-int OverwriteLuaPrint(lua_State* L)
-{
-    int n = lua_gettop(L);  /* number of arguments */
-    int i;
-    lua_getglobal(L, "tostring");
-    StringList string_list = StringList();
-    String output = "";
-    for (i=1; i<=n; i++) 
-    {
-        const char *s;
-        lua_pushvalue(L, -1);  /* function to be called */
-        lua_pushvalue(L, i);   /* value to print */
-        lua_call(L, 1, 1);
-        s = lua_tostring(L, -1);  /* get result */
-        if (s == NULL)
-            return luaL_error(L, LUA_QL("tostring") " must return a string to "
-                                 LUA_QL("print"));
-        if (i>1) 
-            output += "\t";
-        output += String(s);
-        lua_pop(L, 1);  /* pop result */
-    }
-    output += "\n";
-    Log::Message(Log::LT_INFO, output.CString());
-    return 0;
-}
-
-
 RegType<Log> LogMethods[] =
 {
     { NULL, NULL },

+ 0 - 1
Source/Core/Lua/Log.h

@@ -34,7 +34,6 @@ namespace Lua {
 
 template<> void ExtraInit<Log>(lua_State* L, int metatable_index);
 int LogMessage(lua_State* L);
-int OverwriteLuaPrint(lua_State* L);
 
 RegType<Log> LogMethods[];
 luaL_reg LogGetters[];