2012-04-13 10:38:12 +00:00
|
|
|
mw = mw or {}
|
|
|
|
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
local packageCache
|
|
|
|
local packageModuleFunc
|
2012-05-22 03:56:07 +00:00
|
|
|
local php
|
2012-05-23 06:51:59 +00:00
|
|
|
local allowEnvFuncs = false
|
2012-07-14 04:23:42 +00:00
|
|
|
local logBuffer = ''
|
2012-09-06 04:54:26 +00:00
|
|
|
local currentFrame
|
2013-02-21 21:31:23 +00:00
|
|
|
local loadedData = {}
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
|
2012-12-27 21:21:04 +00:00
|
|
|
-- Extend pairs and ipairs to recognize __pairs and __ipairs, if they don't already
|
|
|
|
( function ()
|
|
|
|
local t = {}
|
|
|
|
setmetatable( t, { __pairs = function() return 1, 2, 3 end } )
|
|
|
|
local f = pairs( t )
|
|
|
|
if f ~= 1 then
|
|
|
|
local old_pairs = pairs
|
|
|
|
pairs = function ( t )
|
|
|
|
local mt = getmetatable( t )
|
|
|
|
local f, s, var = ( mt and mt.__pairs or old_pairs )( t )
|
|
|
|
return f, s, var
|
|
|
|
end
|
|
|
|
local old_ipairs = ipairs
|
|
|
|
ipairs = function ( t )
|
|
|
|
local mt = getmetatable( t )
|
|
|
|
local f, s, var = ( mt and mt.__ipairs or old_ipairs )( t )
|
|
|
|
return f, s, var
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end )()
|
|
|
|
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
--- Put an isolation-friendly package module into the specified environment
|
|
|
|
-- table. The package module will have an empty cache, because caching of
|
|
|
|
-- module functions from other cloned environments would break module isolation.
|
|
|
|
--
|
|
|
|
-- @param env The cloned environment
|
|
|
|
local function makePackageModule( env )
|
|
|
|
-- Create the package globals in the given environment
|
|
|
|
setfenv( packageModuleFunc, env )()
|
|
|
|
|
|
|
|
-- Make a loader function
|
|
|
|
local function loadPackage( modName )
|
|
|
|
local init
|
|
|
|
if packageCache[modName] == 'missing' then
|
|
|
|
return nil
|
|
|
|
elseif packageCache[modName] == nil then
|
2012-05-22 03:56:07 +00:00
|
|
|
init = php.loadPackage( modName )
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
if init == nil then
|
|
|
|
packageCache[modName] = 'missing'
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
packageCache[modName] = init
|
|
|
|
else
|
|
|
|
init = packageCache[modName]
|
|
|
|
end
|
|
|
|
|
|
|
|
setfenv( init, env )
|
|
|
|
return init
|
|
|
|
end
|
|
|
|
|
|
|
|
table.insert( env.package.loaders, loadPackage )
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Set up the base environment. The PHP host calls this function after any
|
|
|
|
-- necessary host-side initialisation has been done.
|
2013-01-25 17:53:18 +00:00
|
|
|
function mw.setupInterface( options )
|
|
|
|
-- Don't allow any more calls
|
|
|
|
mw.setupInterface = nil
|
2012-05-22 03:56:07 +00:00
|
|
|
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
-- Don't allow getmetatable() on a non-table, since if you can get the metatable,
|
|
|
|
-- you can set values in it, breaking isolation
|
|
|
|
local old_getmetatable = getmetatable
|
|
|
|
function getmetatable(obj)
|
|
|
|
if type(obj) == 'table' then
|
|
|
|
return old_getmetatable(obj)
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-05-23 06:51:59 +00:00
|
|
|
if options.allowEnvFuncs then
|
|
|
|
allowEnvFuncs = true
|
|
|
|
end
|
|
|
|
|
2013-01-25 17:53:18 +00:00
|
|
|
-- Store the interface table
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
--
|
2013-01-25 17:53:18 +00:00
|
|
|
-- mw_interface.loadPackage() returns function values with their environment
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
-- set to the base environment, which would violate module isolation if they
|
|
|
|
-- were run from a cloned environment. We can only allow access to
|
2013-01-25 17:53:18 +00:00
|
|
|
-- mw_interface.loadPackage via our environment-setting wrapper.
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
--
|
2013-01-25 17:53:18 +00:00
|
|
|
php = mw_interface
|
|
|
|
mw_interface = nil
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
packageModuleFunc = php.loadPackage( 'package' )
|
2012-12-20 21:09:24 +00:00
|
|
|
makePackageModule( _G )
|
2012-12-27 16:22:44 +00:00
|
|
|
package.loaded.mw = mw
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
packageCache = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Do a "deep copy" of a table or other value.
|
2012-04-13 10:38:12 +00:00
|
|
|
function mw.clone( val )
|
|
|
|
local tableRefs = {}
|
|
|
|
local function recursiveClone( val )
|
|
|
|
if type( val ) == 'table' then
|
|
|
|
-- Encode circular references correctly
|
|
|
|
if tableRefs[val] ~= nil then
|
|
|
|
return tableRefs[val]
|
|
|
|
end
|
|
|
|
|
|
|
|
local retVal
|
|
|
|
retVal = {}
|
|
|
|
tableRefs[val] = retVal
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
|
|
|
|
-- Copy metatable
|
|
|
|
if getmetatable( val ) then
|
2012-04-19 07:40:56 +00:00
|
|
|
setmetatable( retVal, recursiveClone( getmetatable( val ) ) )
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
end
|
|
|
|
|
2012-04-13 10:38:12 +00:00
|
|
|
for key, elt in pairs( val ) do
|
|
|
|
retVal[key] = recursiveClone( elt )
|
|
|
|
end
|
|
|
|
return retVal
|
|
|
|
else
|
|
|
|
return val
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return recursiveClone( val )
|
|
|
|
end
|
|
|
|
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
--- Set up a cloned environment for execution of a module chunk, then execute
|
|
|
|
-- the module in that environment. This is called by the host to implement
|
|
|
|
-- {{#invoke}}.
|
|
|
|
--
|
|
|
|
-- @param chunk The module chunk
|
2013-04-12 14:38:14 +00:00
|
|
|
-- @param isConsole Whether this is the debug console
|
|
|
|
function mw.executeModule( chunk, isConsole )
|
2012-04-13 10:38:12 +00:00
|
|
|
local env = mw.clone( _G )
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
makePackageModule( env )
|
2012-05-23 06:51:59 +00:00
|
|
|
|
2013-04-12 14:38:14 +00:00
|
|
|
-- These are unsafe
|
2013-02-14 20:44:50 +00:00
|
|
|
env.mw.makeProtectedEnvFuncs = nil
|
2013-04-12 14:38:14 +00:00
|
|
|
env.mw.executeModule = nil
|
|
|
|
if not isConsole then
|
|
|
|
env.mw.getLogBuffer = nil
|
|
|
|
env.mw.clearLogBuffer = nil
|
|
|
|
end
|
2013-02-14 20:44:50 +00:00
|
|
|
|
2012-05-23 06:51:59 +00:00
|
|
|
if allowEnvFuncs then
|
|
|
|
env.setfenv, env.getfenv = mw.makeProtectedEnvFuncs( {[_G] = true}, {} )
|
|
|
|
else
|
|
|
|
env.setfenv = nil
|
|
|
|
env.getfenv = nil
|
|
|
|
end
|
|
|
|
|
2012-04-13 10:38:12 +00:00
|
|
|
setfenv( chunk, env )
|
|
|
|
return chunk()
|
|
|
|
end
|
|
|
|
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
--- Make isolation-safe setfenv and getfenv functions
|
|
|
|
--
|
|
|
|
-- @param protectedEnvironments A table where the keys are protected environment
|
|
|
|
-- tables. These environments cannot be accessed with getfenv(), and
|
|
|
|
-- functions with these environments cannot be modified or accessed using
|
|
|
|
-- integer indexes to setfenv(). However, functions with these environments
|
|
|
|
-- can have their environment set with setfenv() with a function value
|
|
|
|
-- argument.
|
|
|
|
--
|
|
|
|
-- @param protectedFunctions A table where the keys are protected functions,
|
|
|
|
-- which cannot have their environments set by setfenv() with a function
|
|
|
|
-- value argument.
|
|
|
|
--
|
|
|
|
-- @return setfenv
|
|
|
|
-- @return getfenv
|
|
|
|
function mw.makeProtectedEnvFuncs( protectedEnvironments, protectedFunctions )
|
|
|
|
local old_setfenv = setfenv
|
|
|
|
local old_getfenv = getfenv
|
|
|
|
|
|
|
|
local function my_setfenv( func, newEnv )
|
|
|
|
if type( func ) == 'number' then
|
|
|
|
local stackIndex = math.floor( func )
|
|
|
|
if stackIndex <= 0 then
|
|
|
|
error( "'setfenv' cannot set the global environment, it is protected", 2 )
|
|
|
|
end
|
|
|
|
if stackIndex > 10 then
|
2012-04-19 07:40:56 +00:00
|
|
|
error( "'setfenv' cannot set an environment at a level greater than 10", 2 )
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Add one because we are still in Lua and 1 is right here
|
|
|
|
stackIndex = stackIndex + 1
|
2012-04-24 02:33:06 +00:00
|
|
|
|
|
|
|
local env = old_getfenv( stackIndex )
|
|
|
|
if env == nil or protectedEnvironments[ env ] then
|
|
|
|
error( "'setfenv' cannot set the requested environment, it is protected", 2 )
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
end
|
|
|
|
func = old_setfenv( stackIndex, newEnv )
|
|
|
|
elseif type( func ) == 'function' then
|
|
|
|
if protectedFunctions[func] then
|
|
|
|
error( "'setfenv' cannot be called on a protected function", 2 )
|
|
|
|
end
|
2013-02-14 20:44:50 +00:00
|
|
|
local env = old_getfenv( func )
|
|
|
|
if env == nil or protectedEnvironments[ env ] then
|
|
|
|
error( "'setfenv' cannot set the requested environment, it is protected", 2 )
|
|
|
|
end
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
old_setfenv( func, newEnv )
|
|
|
|
else
|
|
|
|
error( "'setfenv' can only be called with a function or integer as the first argument", 2 )
|
|
|
|
end
|
|
|
|
return func
|
|
|
|
end
|
|
|
|
|
|
|
|
local function my_getfenv( func )
|
2012-04-19 07:40:56 +00:00
|
|
|
local env
|
|
|
|
if type( func ) == 'number' then
|
|
|
|
if func <= 0 then
|
|
|
|
error( "'getfenv' cannot get the global environment" )
|
|
|
|
end
|
|
|
|
env = old_getfenv( func + 1 )
|
|
|
|
elseif type( func ) == 'function' then
|
|
|
|
env = old_getfenv( func )
|
|
|
|
else
|
|
|
|
error( "'getfenv' cannot get the global environment" )
|
|
|
|
end
|
|
|
|
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
if protectedEnvironments[env] then
|
|
|
|
return nil
|
|
|
|
else
|
|
|
|
return env
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return my_setfenv, my_getfenv
|
|
|
|
end
|
|
|
|
|
2013-02-19 00:49:08 +00:00
|
|
|
local function newFrame( frameId, ... )
|
|
|
|
if not php.frameExists( frameId ) then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
local frame = {}
|
2013-02-19 00:49:08 +00:00
|
|
|
local parentFrameIds = { ... }
|
2012-05-22 03:56:07 +00:00
|
|
|
local argCache = {}
|
|
|
|
local argNames
|
2012-12-27 22:58:39 +00:00
|
|
|
local args_mt = {}
|
2012-05-22 03:56:07 +00:00
|
|
|
|
2012-07-02 07:27:18 +00:00
|
|
|
local function checkSelf( self, method )
|
|
|
|
if self ~= frame then
|
|
|
|
error( "frame:" .. method .. ": invalid frame object. " ..
|
|
|
|
"Did you call " .. method .. " with a dot instead of a colon, i.e. " ..
|
|
|
|
"frame." .. method .. "() instead of frame:" .. method .. "()?",
|
|
|
|
3 )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-27 22:58:39 +00:00
|
|
|
-- Getter for args
|
2012-05-22 03:56:07 +00:00
|
|
|
local function getExpandedArgument( dummy, name )
|
|
|
|
name = tostring( name )
|
|
|
|
if argCache[name] == nil then
|
|
|
|
local arg = php.getExpandedArgument( frameId, name )
|
|
|
|
if arg == nil then
|
|
|
|
argCache[name] = false
|
|
|
|
else
|
|
|
|
argCache[name] = arg
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if argCache[name] == false then
|
|
|
|
return nil
|
|
|
|
else
|
|
|
|
return argCache[name]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-27 22:58:39 +00:00
|
|
|
args_mt.__index = getExpandedArgument
|
|
|
|
|
|
|
|
-- pairs handler for args
|
|
|
|
args_mt.__pairs = function ()
|
|
|
|
if not argNames then
|
|
|
|
local arguments = php.getAllExpandedArguments( frameId )
|
|
|
|
argNames = {}
|
|
|
|
for name, value in pairs( arguments ) do
|
|
|
|
table.insert( argNames, name )
|
|
|
|
argCache[name] = value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local index = 0
|
|
|
|
return function ()
|
|
|
|
index = index + 1
|
|
|
|
if argNames[index] then
|
|
|
|
return argNames[index], argCache[argNames[index]]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- ipairs 'next' function for args
|
|
|
|
local function argsInext( dummy, i )
|
|
|
|
local value = getExpandedArgument( dummy, i + 1 )
|
|
|
|
if value then
|
|
|
|
return i + 1, value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
args_mt.__ipairs = function () return argsInext, nil, 0 end
|
|
|
|
|
|
|
|
frame.args = {}
|
|
|
|
setmetatable( frame.args, args_mt )
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
local function newCallbackParserValue( callback )
|
2013-02-13 04:40:18 +00:00
|
|
|
local value = {}
|
2012-05-22 03:56:07 +00:00
|
|
|
local cache
|
|
|
|
|
|
|
|
function value:expand()
|
|
|
|
if not cache then
|
|
|
|
cache = callback()
|
|
|
|
end
|
|
|
|
return cache
|
|
|
|
end
|
|
|
|
|
|
|
|
return value
|
|
|
|
end
|
|
|
|
|
|
|
|
function frame:getArgument( opt )
|
2012-07-02 07:27:18 +00:00
|
|
|
checkSelf( self, 'getArgument' )
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
local name
|
|
|
|
if type( opt ) == 'table' then
|
|
|
|
name = opt.name
|
|
|
|
else
|
|
|
|
name = opt
|
|
|
|
end
|
|
|
|
|
|
|
|
return newCallbackParserValue(
|
|
|
|
function ()
|
|
|
|
return getExpandedArgument( nil, name )
|
|
|
|
end
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function frame:getParent()
|
2012-07-02 07:27:18 +00:00
|
|
|
checkSelf( self, 'getParent' )
|
|
|
|
|
2013-02-19 00:49:08 +00:00
|
|
|
return newFrame( unpack( parentFrameIds ) )
|
|
|
|
end
|
|
|
|
|
|
|
|
function frame:newChild( opt )
|
|
|
|
checkSelf( self, 'newChild' )
|
|
|
|
|
|
|
|
if type( opt ) ~= 'table' then
|
|
|
|
error( "frame:newChild: the first parameter must be a table", 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
local title, args
|
|
|
|
if opt.title == nil then
|
|
|
|
title = false
|
2012-05-22 03:56:07 +00:00
|
|
|
else
|
2013-02-19 00:49:08 +00:00
|
|
|
title = tostring( opt.title )
|
2012-05-22 03:56:07 +00:00
|
|
|
end
|
2013-02-19 00:49:08 +00:00
|
|
|
if opt.args == nil then
|
|
|
|
args = {}
|
|
|
|
elseif type( opt.args ) ~= 'table' then
|
|
|
|
error( "frame:newChild: args must be a table", 2 )
|
|
|
|
else
|
|
|
|
args = {}
|
|
|
|
for k, v in pairs( opt.args ) do
|
|
|
|
local tp = type( k )
|
|
|
|
if tp ~= 'string' and tp ~= 'number' then
|
|
|
|
error( "frame:newChild: arg keys must be strings or numbers, " .. tp .. " given", 2 )
|
|
|
|
end
|
|
|
|
local tp = type( v )
|
|
|
|
if tp == 'boolean' then
|
|
|
|
args[k] = v and '1' or ''
|
|
|
|
elseif tp == 'string' or tp == 'number' then
|
|
|
|
args[k] = tostring( v )
|
|
|
|
else
|
|
|
|
error( "frame:newChild: invalid type " .. tp .. " for arg '" .. k .. "'", 2 )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local newFrameId = php.newChildFrame( frameId, title, args )
|
|
|
|
return newFrame( newFrameId, frameId, unpack( parentFrameIds ) )
|
2012-05-22 03:56:07 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function frame:expandTemplate( opt )
|
2012-07-02 07:27:18 +00:00
|
|
|
checkSelf( self, 'expandTemplate' )
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
local title
|
|
|
|
|
|
|
|
if type( opt ) ~= 'table' then
|
|
|
|
error( "frame:expandTemplate: the first parameter must be a table" )
|
|
|
|
end
|
|
|
|
if opt.title == nil then
|
|
|
|
error( "frame:expandTemplate: a title is required" )
|
|
|
|
else
|
|
|
|
title = tostring( opt.title )
|
|
|
|
end
|
|
|
|
local args
|
|
|
|
if opt.args == nil then
|
|
|
|
args = {}
|
|
|
|
elseif type( opt.args ) ~= 'table' then
|
2013-02-19 00:49:08 +00:00
|
|
|
error( "frame:expandTemplate: args must be a table" )
|
2012-05-22 03:56:07 +00:00
|
|
|
else
|
|
|
|
args = opt.args
|
|
|
|
end
|
|
|
|
|
|
|
|
return php.expandTemplate( frameId, title, args )
|
|
|
|
end
|
|
|
|
|
2013-03-04 05:42:17 +00:00
|
|
|
function frame:callParserFunction( name, args, ... )
|
|
|
|
checkSelf( self, 'callParserFunction' )
|
|
|
|
|
|
|
|
if type( name ) == 'table' then
|
|
|
|
name, args = name.name, name.args
|
|
|
|
if type( args ) ~= 'table' then
|
|
|
|
args = { args }
|
|
|
|
end
|
|
|
|
elseif type( args ) ~= 'table' then
|
|
|
|
args = { args, ... }
|
|
|
|
end
|
|
|
|
|
|
|
|
if name == nil then
|
|
|
|
error( "frame:callParserFunction: a function name is required", 2 )
|
|
|
|
elseif type( name ) == 'string' or type( name ) == 'number' then
|
|
|
|
name = tostring( name )
|
|
|
|
else
|
|
|
|
error( "frame:callParserFunction: function name must be a string or number", 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
for k, v in pairs( args ) do
|
|
|
|
if type( k ) ~= 'string' and type( k ) ~= 'number' then
|
|
|
|
error( "frame:callParserFunction: arg keys must be strings or numbers", 2 )
|
|
|
|
end
|
|
|
|
if type( v ) ~= 'string' and type( v ) ~= 'number' then
|
|
|
|
error( "frame:callParserFunction: args must be strings or numbers", 2 )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return php.callParserFunction( frameId, name, args )
|
|
|
|
end
|
|
|
|
|
|
|
|
function frame:extensionTag( name, content, args )
|
|
|
|
checkSelf( self, 'extensionTag' )
|
|
|
|
|
|
|
|
if type( name ) == 'table' then
|
|
|
|
name, content, args = name.name, name.content, name.args
|
|
|
|
end
|
|
|
|
|
|
|
|
if name == nil then
|
|
|
|
error( "frame:extensionTag: a function name is required", 2 )
|
|
|
|
elseif type( name ) == 'string' or type( name ) == 'number' then
|
|
|
|
name = tostring( name )
|
|
|
|
else
|
|
|
|
error( "frame:extensionTag: tag name must be a string or number", 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
if content == nil then
|
|
|
|
content = ''
|
|
|
|
elseif type( content ) == 'string' or type( content ) == 'number' then
|
|
|
|
content = tostring( content )
|
|
|
|
else
|
|
|
|
error( "frame:extensionTag: content must be a string or number", 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
if args == nil then
|
|
|
|
args = {}
|
|
|
|
elseif type( args ) == 'string' or type( args ) == 'number' then
|
|
|
|
args = { content, args }
|
|
|
|
elseif type( args ) == 'table' then
|
|
|
|
local tmp = args
|
|
|
|
args = {}
|
|
|
|
for k, v in pairs( tmp ) do
|
|
|
|
if type( k ) ~= 'string' and type( k ) ~= 'number' then
|
|
|
|
error( "frame:extensionTag: arg keys must be strings or numbers", 2 )
|
|
|
|
end
|
|
|
|
if type( v ) ~= 'string' and type( v ) ~= 'number' then
|
|
|
|
error( "frame:extensionTag: arg values must be strings or numbers", 2 )
|
|
|
|
end
|
|
|
|
args[k] = v
|
|
|
|
end
|
|
|
|
table.insert( args, 1, content )
|
|
|
|
else
|
|
|
|
error( "frame:extensionTag: args must be a string, number, or table", 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
return php.callParserFunction( frameId, '#tag:' .. name, args )
|
|
|
|
end
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
function frame:preprocess( opt )
|
2012-07-02 07:27:18 +00:00
|
|
|
checkSelf( self, 'preprocess' )
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
local text
|
|
|
|
if type( opt ) == 'table' then
|
|
|
|
text = opt.text
|
|
|
|
else
|
|
|
|
text = opt
|
|
|
|
end
|
|
|
|
text = tostring( text )
|
|
|
|
return php.preprocess( frameId, text )
|
|
|
|
end
|
|
|
|
|
|
|
|
function frame:newParserValue( opt )
|
2012-07-02 07:27:18 +00:00
|
|
|
checkSelf( self, 'newParserValue' )
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
local text
|
|
|
|
if type( opt ) == 'table' then
|
|
|
|
text = opt.text
|
|
|
|
else
|
|
|
|
text = opt
|
|
|
|
end
|
|
|
|
|
|
|
|
return newCallbackParserValue(
|
|
|
|
function ()
|
|
|
|
return self:preprocess( text )
|
|
|
|
end
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function frame:newTemplateParserValue( opt )
|
2012-07-02 07:27:18 +00:00
|
|
|
checkSelf( self, 'newTemplateParserValue' )
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
if type( opt ) ~= 'table' then
|
|
|
|
error( "frame:newTemplateParserValue: the first parameter must be a table" )
|
|
|
|
end
|
|
|
|
if opt.title == nil then
|
|
|
|
error( "frame:newTemplateParserValue: a title is required" )
|
|
|
|
end
|
|
|
|
return newCallbackParserValue(
|
|
|
|
function ()
|
|
|
|
return self:expandTemplate( opt )
|
|
|
|
end
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2012-12-27 22:58:39 +00:00
|
|
|
-- For backwards compat
|
2012-05-22 03:56:07 +00:00
|
|
|
function frame:argumentPairs()
|
2012-07-02 07:27:18 +00:00
|
|
|
checkSelf( self, 'argumentPairs' )
|
2012-12-27 22:58:39 +00:00
|
|
|
return pairs( self.args )
|
2012-05-22 03:56:07 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
return frame
|
|
|
|
end
|
|
|
|
|
|
|
|
function mw.executeFunction( chunk )
|
2013-02-19 00:49:08 +00:00
|
|
|
local frame = newFrame( 'current', 'parent' )
|
2012-09-06 04:54:26 +00:00
|
|
|
local oldFrame = currentFrame
|
2012-05-22 03:56:07 +00:00
|
|
|
|
2012-09-06 04:54:26 +00:00
|
|
|
currentFrame = frame
|
2012-05-22 03:56:07 +00:00
|
|
|
local results = { chunk( frame ) }
|
2012-09-06 04:54:26 +00:00
|
|
|
currentFrame = oldFrame
|
|
|
|
|
2012-05-22 03:56:07 +00:00
|
|
|
local stringResults = {}
|
|
|
|
for i, result in ipairs( results ) do
|
|
|
|
stringResults[i] = tostring( result )
|
|
|
|
end
|
|
|
|
return table.concat( stringResults )
|
|
|
|
end
|
|
|
|
|
2012-12-20 16:16:36 +00:00
|
|
|
function mw.allToString( ... )
|
|
|
|
local t = { ... }
|
2012-12-24 15:41:36 +00:00
|
|
|
for i = 1, select( '#', ... ) do
|
2012-12-20 16:16:36 +00:00
|
|
|
t[i] = tostring( t[i] )
|
|
|
|
end
|
|
|
|
return table.concat( t, '\t' )
|
|
|
|
end
|
|
|
|
|
|
|
|
function mw.log( ... )
|
|
|
|
logBuffer = logBuffer .. mw.allToString( ... ) .. '\n'
|
2012-07-14 04:23:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function mw.clearLogBuffer()
|
|
|
|
logBuffer = ''
|
|
|
|
end
|
|
|
|
|
|
|
|
function mw.getLogBuffer()
|
|
|
|
return logBuffer
|
|
|
|
end
|
|
|
|
|
2012-09-06 04:54:26 +00:00
|
|
|
function mw.getCurrentFrame()
|
2013-02-19 00:49:08 +00:00
|
|
|
if not currentFrame then
|
|
|
|
currentFrame = newFrame( 'current', 'parent' )
|
|
|
|
end
|
2012-09-06 04:54:26 +00:00
|
|
|
return currentFrame
|
|
|
|
end
|
2012-07-14 04:23:42 +00:00
|
|
|
|
2013-02-01 20:43:32 +00:00
|
|
|
function mw.incrementExpensiveFunctionCount()
|
|
|
|
php.incrementExpensiveFunctionCount()
|
|
|
|
end
|
|
|
|
|
2013-02-21 21:31:23 +00:00
|
|
|
---
|
|
|
|
-- Wrapper for mw.loadData. This creates the read-only dummy table for
|
|
|
|
-- accessing the real data.
|
|
|
|
--
|
|
|
|
-- @param data table Data to access
|
|
|
|
-- @param seen table|nil Table of already-seen tables.
|
|
|
|
-- @return table
|
|
|
|
local function dataWrapper( data, seen )
|
|
|
|
local t = {}
|
|
|
|
seen = seen or { [data] = t }
|
|
|
|
|
|
|
|
local function pairsfunc( s, k )
|
|
|
|
k = next( data, k )
|
|
|
|
if k ~= nil then
|
|
|
|
return k, t[k]
|
|
|
|
end
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
local function ipairsfunc( s, i )
|
|
|
|
i = i + 1
|
|
|
|
if data[i] ~= nil then
|
|
|
|
return i, t[i]
|
|
|
|
end
|
|
|
|
return -- no nil to match default ipairs()
|
|
|
|
end
|
|
|
|
|
|
|
|
local mt = {
|
|
|
|
__index = function ( tt, k )
|
|
|
|
assert( t == tt )
|
|
|
|
local v = data[k]
|
|
|
|
if type( v ) == 'table' then
|
|
|
|
seen[v] = seen[v] or dataWrapper( v, seen )
|
|
|
|
return seen[v]
|
|
|
|
end
|
|
|
|
return v
|
|
|
|
end,
|
|
|
|
__newindex = function ( t, k, v )
|
|
|
|
error( "table from mw.loadData is read-only", 2 )
|
|
|
|
end,
|
|
|
|
__pairs = function ( tt )
|
|
|
|
assert( t == tt )
|
|
|
|
return pairsfunc, t, nil
|
|
|
|
end,
|
|
|
|
__ipairs = function ( tt )
|
|
|
|
assert( t == tt )
|
|
|
|
return ipairsfunc, t, 0
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
-- This is just to make setmetatable() fail
|
|
|
|
mt.__metatable = mt
|
|
|
|
|
|
|
|
return setmetatable( t, mt )
|
|
|
|
end
|
|
|
|
|
|
|
|
---
|
|
|
|
-- Validator for mw.loadData. This scans through the data looking for things
|
|
|
|
-- that are not supported, e.g. functions (which may be closures).
|
|
|
|
--
|
|
|
|
-- @param d table Data to access.
|
|
|
|
-- @param seen table|nil Table of already-seen tables.
|
|
|
|
-- @return string|nil Error message, if any
|
|
|
|
local function validateData( d, seen )
|
|
|
|
seen = seen or {}
|
|
|
|
local tp = type( d )
|
|
|
|
if tp == 'nil' or tp == 'boolean' or tp == 'number' or tp == 'string' then
|
|
|
|
return nil
|
|
|
|
elseif tp == 'table' then
|
|
|
|
if seen[d] then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
seen[d] = true
|
|
|
|
if getmetatable( d ) ~= nil then
|
|
|
|
return "data for mw.loadData contains a table with a metatable"
|
|
|
|
end
|
|
|
|
for k, v in pairs( d ) do
|
|
|
|
if type( k ) == 'table' then
|
|
|
|
return "data for mw.loadData contains a table as a key"
|
|
|
|
end
|
|
|
|
local err = validateData( k, seen ) or validateData( v, seen )
|
|
|
|
if err then
|
|
|
|
return err
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return nil
|
|
|
|
else
|
|
|
|
return "data for mw.loadData contains unsupported data type '" .. tp .. "'"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function mw.loadData( module )
|
|
|
|
local data = loadedData[module]
|
|
|
|
if type( data ) == 'string' then
|
|
|
|
-- No point in re-validating
|
|
|
|
error( data, 2 )
|
|
|
|
end
|
|
|
|
if not data then
|
|
|
|
-- The point of this is to load big data, so don't save it in package.loaded
|
|
|
|
-- where it will have to be copied for all future modules.
|
|
|
|
local l = package.loaded[module]
|
|
|
|
data = require( module )
|
|
|
|
package.loaded[module] = l
|
|
|
|
|
|
|
|
-- Validate data
|
|
|
|
local err
|
|
|
|
if type( data ) == 'table' then
|
|
|
|
err = validateData( data )
|
|
|
|
else
|
|
|
|
err = module .. ' returned ' .. type( data ) .. ', table expected'
|
|
|
|
end
|
|
|
|
if err then
|
|
|
|
loadedData[module] = err
|
|
|
|
error( err, 2 )
|
|
|
|
end
|
|
|
|
loadedData[module] = data
|
|
|
|
end
|
|
|
|
|
|
|
|
return dataWrapper( data )
|
|
|
|
end
|
|
|
|
|
2012-04-13 10:38:12 +00:00
|
|
|
return mw
|