Skip to content

Commit

Permalink
ApiLoader: distinguishing regular, static and global functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
madmaxoft committed Sep 19, 2016
1 parent 2d77770 commit 8f78174
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 34 deletions.
6 changes: 3 additions & 3 deletions APIImpl/File.lua
Expand Up @@ -8,7 +8,7 @@

return
{
["cFile:Copy(string, string)"] = function (a_Simulator, a_ThisClass, a_SrcFileName, a_DstFileName)
["<static> cFile:Copy(string, string)"] = function (a_Simulator, a_ThisClass, a_SrcFileName, a_DstFileName)
local fIn = io.open(a_SrcFileName, "rb")
if not(fIn) then
return false
Expand All @@ -24,8 +24,8 @@ return
return true
end,

["cFile:IsFile(string)"] = function (a_Simulator, a_ThisClass, a_FileName)
["<static> cFile:IsFile(string)"] = function (a_Simulator, a_ThisClass, a_FileName)
local mode = lfs.attributes(a_FileName, "mode")
return (mode == "file")
end,
}
}
2 changes: 1 addition & 1 deletion APIImpl/Misc.lua
Expand Up @@ -26,7 +26,7 @@ return
print("ERROR: " .. a_Text)
end,

["sqlite3:open(string)"] = function (a_Simulator, a_FileName)
["<static, global> sqlite3:open(string)"] = function (a_Simulator, a_FileName)
-- TODO: Add scenario-based filename redirects
return sqlite3.open(a_FileName)
end,
Expand Down
46 changes: 28 additions & 18 deletions APIImpl/PluginManager.lua
Expand Up @@ -5,38 +5,48 @@




--- Implementation of the cPluginManager:BindCommand function
-- There are two separate API endpoints for the same implementation, so the implementation is pulled into a common function
local function BindCommand(a_Simulator, a_Self, a_Command, a_Permission, a_Callback, a_HelpString)
if (a_Command:match("%s")) then
a_Simulator.logger:warning("Registering a command containing whitespace(%s), such a handler will never be called by Cuberite", a_Command)
end
if (a_Simulator.registeredCommandHandlers[a_Command]) then
a_Simulator.logger:info("Registering a command that is already registered (%s). The second handler will not be called / tested.", a_Command)
return
end
a_Simulator.registeredCommandHandlers[a_Command] =
{
permission = a_Permission,
callback = a_Callback,
helpString = a_HelpString,
}
return true
end





return
{
["cPluginManager:AddHook(cPluginManager#PluginHook, function)"] = function (a_Simulator, a_Self, a_HookType, a_Callback)
["<static> cPluginManager:AddHook(cPluginManager#PluginHook, function)"] = function (a_Simulator, a_Self, a_HookType, a_Callback)
local hooks = a_Simulator.hooks[a_HookType] or {}
a_Simulator.registeredHooks[a_HookType] = hooks
table.insert(hooks, a_Callback)
end,

["cPluginManager:BindCommand(string, string, function, string)"] = function (a_Simulator, a_Self, a_Command, a_Permission, a_Callback, a_HelpString)
if (a_Command:match("%s")) then
a_Simulator.logger:warning("Registering a command containing whitespace(%s), such a handler will never be called by Cuberite", a_Command)
end
if (a_Simulator.registeredCommandHandlers[a_Command]) then
a_Simulator.logger:info("Registering a command that is already registered (%s). The second handler will not be called / tested.", a_Command)
return
end
a_Simulator.registeredCommandHandlers[a_Command] =
{
permission = a_Permission,
callback = a_Callback,
helpString = a_HelpString,
}
return true
end,
["<static> cPluginManager:BindCommand(string, string, function, string)"] = BindCommand,
["cPluginManager:BindCommand(string, string, function, string)"] = BindCommand,

["cPluginManager:GetCurrentPlugin()"] = function (a_Simulator, a_Self)
local res = a_Simulator:createInstance({Type = "cPlugin"})
res.GetLocalPath = function (a_Self) return a_Simulator.options.pluginPath end -- Override the plugin to act as "self"
return res
end,

["cPluginManager:GetPluginsPath()"] = function (a_Simulator)
["<static> cPluginManager:GetPluginsPath()"] = function (a_Simulator)
return a_Simulator.options.pluginPath .. "/.."
end,

Expand Down
40 changes: 28 additions & 12 deletions ApiLoader.lua
Expand Up @@ -162,7 +162,7 @@ end
--- Sets the implementation of the specified function into the API description
-- a_Api is the API description into which the implementation is to be set
-- a_FnFullName is a string representation of the function's full name and signature ("cRoot:GetWorld(string)")
-- a_FnFullName is a string representation of the function's full name and signature ("<static> cPluginManager:AddHook(number, function)")
-- a_Fn is the function to set as the implementation
-- a_Logger is the logger to use for logging messages
-- Raises an error if the function name cannot be resolved or no such API function
Expand All @@ -174,7 +174,14 @@ local function setApiImplementation(a_Api, a_FnFullName, a_Fn, a_Logger)
assert(type(a_Logger) == "table")
-- Parse the function name:
local fnName, functionParamsStr = string.match(a_FnFullName, "([a-zA-Z0-9:]+)(%b())")
local fnPropertiesStr = string.match(a_FnFullName, "(%b<>)")
local fnProperties = {} -- Dictionary of "static" -> true, "global" = true where applicable
local fnFullName = a_FnFullName
if (fnPropertiesStr) then
fnFullName = string.sub(fnFullName, string.len(fnPropertiesStr) + 1)
string.gsub(fnPropertiesStr, "%w+", function (a_Match) fnProperties[a_Match] = true end)
end
local fnName, functionParamsStr = string.match(fnFullName, "([a-zA-Z0-9:]+)(%b())")
local idxColon = string.find(fnName, ":")
local className, functionName
if (idxColon) then
Expand All @@ -183,13 +190,6 @@ local function setApiImplementation(a_Api, a_FnFullName, a_Fn, a_Logger)
else
functionName = fnName
end
--[[
local className, functionName = string.match(fnName, "([a-zA-Z0-9]+):?([a-zA-Z0-9]+)")
-- local className, functionName = string.match(fnName, "(%a+):?(%a+)")
if (functionName == "") then
functionName, className = className, nil
end
--]]
local functionParams = {}
string.gsub(functionParamsStr, "[^,]+",
function (a_Match)
Expand All @@ -216,20 +216,36 @@ local function setApiImplementation(a_Api, a_FnFullName, a_Fn, a_Logger)
-- Find the right signature for the function:
for _, signature in ipairs(apiFnDesc) do
if (signatureMatchesParams(signature, functionParams)) then
if (
(signature.IsStatic == fnProperties.static) and
(signature.IsGlobal == fnProperties.global) and
(signatureMatchesParams(signature, functionParams))
) then
signature.Implementation = a_Fn
return
end
end
-- The signature was not found, build a list of string representations of all available signatures:
-- The signature was not found, log an error with representations of all available signatures:
local s = {}
for idxS, signature in ipairs(apiFnDesc) do
local params = {}
for idxP, param in ipairs(signature.Params or {}) do
params[idxP] = param.Type
end
s[idxS] = table.concat(params, ", ")
local props = {}
if (signature.IsStatic) then
table.insert(props, "static")
end
if (signature.IsGlobal) then
table.insert(props, "global")
end
if (props[1]) then
props = "<" .. table.concat(props, ", ") .. "> "
else
props = ""
end
s[idxS] = props .. fnName .. "(" .. table.concat(params, ", ") .. ")"
end
a_Logger:error("Cannot add custom implementation for function \"%s\", such a parameter combination is not present in the API. Available signatures:\n\t%s",
a_FnFullName, table.concat(s, "\n\t")
Expand Down

0 comments on commit 8f78174

Please sign in to comment.