diff --git a/LUA_API.rst b/LUA_API.rst index 542034f40..22130efd6 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -550,6 +550,16 @@ Exception handling The default value of the ``verbose`` argument of ``err:tostring()``. +Miscellaneous +------------- + +* ``dfhack.curry(func,args...)``, or ``curry(func,args...)`` + + Returns a closure that invokes the function with args combined + both from the curry call and the closure call itself. I.e. + ``curry(func,a,b)(c,d)`` equals ``func(a,b,c,d)``. + + Locking and finalization ------------------------ diff --git a/Lua API.html b/Lua API.html index 63a4c8547..f6f2d42b3 100644 --- a/Lua API.html +++ b/Lua API.html @@ -337,42 +337,43 @@ ul.auto-toc {
  • Native utilities
  • -
  • C++ function wrappers
    -

    Gui module

    +

    Gui module

    • dfhack.gui.getCurViewscreen([skip_dismissed])

      Returns the topmost viewscreen. If skip_dismissed is true, @@ -1032,7 +1043,7 @@ above operations accordingly. If enabled, pauses and zooms to position.

    -

    Job module

    +

    Job module

    • dfhack.job.cloneJobStruct(job)

      Creates a deep copy of the given job.

      @@ -1069,7 +1080,7 @@ a lua list containing them.

    -

    Units module

    +

    Units module

    • dfhack.units.getPosition(unit)

      Returns true x,y,z of the unit, or nil if invalid; may be not equal to unit.pos if caged.

      @@ -1130,7 +1141,7 @@ or raws. The ignore_noble boolean disables the
    -

    Items module

    +

    Items module

    • dfhack.items.getPosition(item)

      Returns true x,y,z of the item, or nil if invalid; may be not equal to item.pos if in inventory.

      @@ -1173,7 +1184,7 @@ Returns false in case of error.

    -

    Maps module

    +

    Maps module

    • dfhack.maps.getSize()

      Returns map size in blocks: x, y, z

      @@ -1221,7 +1232,7 @@ burrows, or the presence of invaders.

    -

    Burrows module

    +

    Burrows module

    • dfhack.burrows.findByName(name)

      Returns the burrow pointer or nil.

      @@ -1256,7 +1267,7 @@ burrows, or the presence of invaders.

    -

    Buildings module

    +

    Buildings module

    • dfhack.buildings.setOwner(item,unit)

      Replaces the owner of the building. If unit is nil, removes ownership. @@ -1400,7 +1411,7 @@ can be determined this way, constructBuilding

    -

    Constructions module

    +

    Constructions module

    • dfhack.constructions.designateNew(pos,type,item_type,mat_index)

      Designates a new construction at given position. If there already is @@ -1416,7 +1427,7 @@ Returns true, was_only_planned if removed; or false if none fo

    -

    Screen API

    +

    Screen API

    The screen module implements support for drawing to the tiled screen of the game. Note that drawing only has any effect when done from callbacks, so it can only be feasibly used in the core context.

    @@ -1555,7 +1566,7 @@ options; if multiple interpretations exist, the table will contain multiple keys
    -

    Internal API

    +

    Internal API

    These functions are intended for the use by dfhack developers, and are only documented here for completeness:

      @@ -1603,7 +1614,7 @@ Returns: found_index, or nil if end reached.

    -

    Core interpreter context

    +

    Core interpreter context

    While plugins can create any number of interpreter instances, there is one special context managed by dfhack core. It is the only context that can receive events from DF and plugins.

    @@ -1634,7 +1645,7 @@ Using timeout_active(id,nil) cancels the timer
  • -

    Event type

    +

    Event type

    An event is a native object transparently wrapping a lua table, and implementing a __call metamethod. When it is invoked, it loops through the table with next and calls all contained values. @@ -1666,7 +1677,7 @@ order using dfhack.safecall.

    -

    Lua Modules

    +

    Lua Modules

    DFHack sets up the lua interpreter so that the built-in require function can be used to load shared lua code from hack/lua/. The dfhack namespace reference itself may be obtained via @@ -1695,7 +1706,7 @@ in this document.

    -

    Global environment

    +

    Global environment

    A number of variables and functions are provided in the base global environment by the mandatory init file dfhack.lua:

      @@ -1736,7 +1747,7 @@ Returns nil if any of obj or indices is nil, or a numeric inde
    -

    utils

    +

    utils

    • utils.compare(a,b)

      Comparator function; returns -1 if a<b, 1 if a>b, 0 otherwise.

      @@ -1849,7 +1860,7 @@ throws an error.

    -

    dumper

    +

    dumper

    A third-party lua table dumper module from http://lua-users.org/wiki/DataDumper. Defines one function:

    @@ -1863,14 +1874,14 @@ the other arguments see the original documentation link above.

    -

    Plugins

    +

    Plugins

    DFHack plugins may export native functions and events to lua contexts. They are automatically imported by mkmodule('plugins.<name>'); this means that a lua module file is still necessary for require to read.

    The following plugins have lua support.

    -

    burrows

    +

    burrows

    Implements extended burrow manipulations.

    Events:

      @@ -1908,13 +1919,13 @@ set is the same as used by the command line.

      The lua module file also re-exports functions from dfhack.burrows.

    -

    sort

    +

    sort

    Does not export any native functions as of now. Instead, it calls lua code to perform the actual ordering of list items.

    -

    Scripts

    +

    Scripts

    Any files with the .lua extension placed into hack/scripts/* are automatically used by the DFHack core as commands. The matching command name consists of the name of the file sans diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 7c2c8f8d6..9f0477538 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -1211,6 +1211,39 @@ static int dfhack_open_plugin(lua_State *L) return 0; } +static int dfhack_curry_wrap(lua_State *L) +{ + int nargs = lua_gettop(L); + int ncurry = lua_tointeger(L, lua_upvalueindex(1)); + int scount = nargs + ncurry; + + luaL_checkstack(L, ncurry, "stack overflow in curry"); + + // Insert values in O(N+M) by first shifting the existing data + lua_settop(L, scount); + for (int i = 0; i < nargs; i++) + lua_copy(L, nargs-i, scount-i); + for (int i = 1; i <= ncurry; i++) + lua_copy(L, lua_upvalueindex(i+1), i); + + lua_callk(L, scount-1, LUA_MULTRET, 0, lua_gettop); + + return lua_gettop(L); +} + +static int dfhack_curry(lua_State *L) +{ + luaL_checkany(L, 1); + if (lua_isnil(L, 1)) + luaL_argerror(L, 1, "nil function in curry"); + if (lua_gettop(L) == 1) + return 1; + lua_pushinteger(L, lua_gettop(L)); + lua_insert(L, 1); + lua_pushcclosure(L, dfhack_curry_wrap, lua_gettop(L)); + return 1; +} + bool Lua::IsCoreContext(lua_State *state) { // This uses a private field of the lua state to @@ -1234,6 +1267,7 @@ static const luaL_Reg dfhack_funcs[] = { { "call_with_finalizer", dfhack_call_with_finalizer }, { "with_suspend", lua_dfhack_with_suspend }, { "open_plugin", dfhack_open_plugin }, + { "curry", dfhack_curry }, { NULL, NULL } }; diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 2cbd019a6..a1e899761 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -46,6 +46,7 @@ end -- Error handling safecall = dfhack.safecall +curry = dfhack.curry function dfhack.pcall(f, ...) return xpcall(f, dfhack.onerror, ...) @@ -118,7 +119,12 @@ function defclass(class,parent) if parent then setmetatable(class, parent) else - rawset_default(class, { init_fields = rawset_default }) + rawset_default(class, { + init_fields = rawset_default, + callback = function(self, name, ...) + return dfhack.curry(self[name], self, ...) + end + }) end return class end