diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/bind.lua | 3 | ||||
| -rw-r--r-- | util/generate-binding.lua | 147 | ||||
| -rw-r--r-- | util/test.lua | 57 | 
3 files changed, 149 insertions, 58 deletions
| diff --git a/util/bind.lua b/util/bind.lua new file mode 100644 index 0000000..1309e4e --- /dev/null +++ b/util/bind.lua @@ -0,0 +1,3 @@ +local b = require 'generate-binding' + +print(b.bind(arg[1])) diff --git a/util/generate-binding.lua b/util/generate-binding.lua index 1c5359f..23aa057 100644 --- a/util/generate-binding.lua +++ b/util/generate-binding.lua @@ -1,61 +1,132 @@  local b = {} -setmetatable(b, {__index=G}) +setmetatable(b, {__index=_G})  setfenv(1, b) ---===== enums =====-- -local Enum = {} --- create a single enum element -function Enum.new(name, id) -	local self = { -		name = string.upper(name), -		id = id, -	} -	setmetatable(self, Enum) -	return self -end --- create multiple enums -function Enum.new_multi(tbl) -	local enums = {} -	for id, name in ipairs(tbl) do -		table.insert(enums, Enum.new(name, id)) -	end -	return enums +function ExtractFunctionName(signature) +	return string.match(signature, "([%w_][%w_]*)%s-%(.*%)") +end + + +function ExtractFunctionType(signature) +	return string.match(signature, "(.+)%s%s-[%w_]+%s-%(.*%)") +end + + +local function trimWhitespace(s) +	s = string.gsub(s, "^%s*", "") +	s = string.gsub(s, "%s+$", "") +	return s  end --- make enums read-only -function Enum.__newindex(self) -	error("Attempted to set index on Enum") + + +function ExtractFunctionArgs(signature) +	local args = {} +	local argStr = string.match(signature, "%((.*)%)") +	for arg in string.gmatch(argStr, "([^,][^,]*),?") do +		-- handle pointers (e.g. void *q) +		arg = string.gsub(arg, "%*", " * ") + +		local type = string.match(arg, "(.+)%s%s-[%w_]+") +		type = string.gsub(type, "%s%s+", " ") +		type = string.gsub(type, "%* %*", "**") +		type = trimWhitespace(type) + +		local name = string.match(arg, "([%w_]+)%s-,?$") +		name = trimWhitespace(name) +		table.insert(args, { type=type, name=name }) +	end +	return args  end --- make enums print nicely -function Enum.__tostring(self) -	return self.name + + +function GetPointerLevel(ctype) +	local level = 0 +	for _ in string.gmatch(ctype, "%*") do +		level = level + 1 +	end +	return level  end --- allow comparinge enums -function Enum.__eq(self, other) -	return self.id == other.id + + +function GetLuaType(ctype) +	-- double (triple, etc) pointers +	if GetPointerLevel(ctype) > 1 then return "unknown" +	-- regular pointers +	elseif GetPointerLevel(ctype) == 1  then +		-- strings +		if string.match(ctype, "char") then return "string" +		else return "unknown" end +	-- ordinary variables +	else +		-- numbers +		if     string.match(ctype, "float$") then return "number" +		elseif string.match(ctype, "double$") then return "number" +		-- integers +		elseif string.match(ctype, "char$") then return "integer" +		elseif string.match(ctype, "int$") then return "integer" +		elseif string.match(ctype, "long$") then return "integer" +		-- void +		elseif string.match(ctype, "void$") then return "void" +		-- unknown +		else return "unknown" end +	end  end -local function check_match(string, pattern, rule) -	local match = string.match(string, '^' .. pattern) -	if match then -		return match, rule(match) +function PullArg(arg, index) +	local ltype = GetLuaType(arg.type) + +	local pull +	if ltype == "unknown" then +		pull = string.format("/* get: %s */", arg.type) +	else +		pull = string.format("luaL_check%s(L, %d);", ltype, index)  	end + +	return string.format("%s %s = %s", arg.type, arg.name, pull)  end -local function append_match(string, pattern, rule,  +function Call(ftype, fname, args) +	local callArgs = "(" +	for index, arg in ipairs(args) do +		callArgs = callArgs .. arg.name +		if index ~= #args then +			callArgs = callArgs .. ", " +		end +	end +	callArgs = callArgs .. ")" -local function lex(string) -	for _, typename in ipairs(c_int_types) do -		if (string.sub(string, 1, #typename) == typename) then -			return  +	local ltype = GetLuaType(ftype) +	if ltype == "void" then +		return string.format("%s%s;\n\treturn 0;", fname, callArgs) +	elseif ltype == "unknown" then +		return string.format( +			"%s bind_result = %s%s;\n\t/* push result */\n\treturn /* count */;", +			ftype, fname, callArgs +		) +	else +		return string.format( +			"%s bind_result = %s%s;\n\tlua_push%s(L, bind_result);\n\treturn 1;", +			ftype, fname, callArgs, ltype +		)  	end  end  function bind(signature) -	 +	local ftype = ExtractFunctionType(signature) +	local fname = ExtractFunctionName(signature) +	local args  = ExtractFunctionArgs(signature) + +	local result = string.format("int %s_bind(lua_State *L)\n{\n", fname) +	for index, arg in ipairs(args) do +		result = result .. "\t" .. PullArg(arg, index) .. "\n" +	end + +	result = result .. "\t" .. Call(ftype, fname, args) .. "\n}" +	return result  end diff --git a/util/test.lua b/util/test.lua index 9b9fc49..0b6a4b7 100644 --- a/util/test.lua +++ b/util/test.lua @@ -14,27 +14,44 @@ end  local b = require 'generate-binding' -test("simplest possible binding", function() -	local binding = b.bind("void some_function();") -	assert(binding == [[ -int some_function_bind(lua_State *L) -{ -	some_function(); -	return 0; -}]]) +test("extract function name from signature", function() +	local name = b.ExtractFunctionName("int some_name(void *qqq);") +	assert(name == "some_name") +	name = b.ExtractFunctionName("float quitGame(int a, int b, int c, int** m);") +	assert(name == "quitGame") +	name = b.ExtractFunctionName("void startGame ();") +	assert(name == "startGame")  end) -test("complicated binding", function() -	local binding = b.bind("const char * qqq(int a, float q, unsigned char m);") -	assert(binding == [[ -int qqq_bind(lua_State *L) -{ -	lua_Integer a = luaL_checkinteger(L, 1); -	lua_Number q = luaL_checknumber(L, 2); -	lua_Integer m = luaL_checkinteger(L, 3); -	const char *result = qqq(a, q, m); -	lua_pushstring(L, result); -	return 1; -}]]) +test("extract function type from signature", function() +	local ftype = b.ExtractFunctionType("int some_ftype(void *qqq);") +	assert(ftype == "int") +	ftype = b.ExtractFunctionType("float quitGame(int a, int b, int c, int** m);") +	assert(ftype == "float") +	ftype = b.ExtractFunctionType("void startGame ();") +	assert(ftype == "void") +end) + + +test("extract arguments from signature", function() +	local args = b.ExtractFunctionArgs("int some_args(void *qqq);") +	assert(args ~= nil) +	assert(#args == 1) +	assert(args[1].type == "void *") +	assert(args[1].name == "qqq") + +	args = b.ExtractFunctionArgs("float quitGame(int a, int b, int c, int** m);") +	assert(#args == 4) +	assert(args[1].type == "int") +	assert(args[1].name == "a") +	assert(args[2].type == "int") +	assert(args[2].name == "b") +	assert(args[3].type == "int") +	assert(args[3].name == "c") +	assert(args[4].type == "int **") +	assert(args[4].name == "m") + +	args = b.ExtractFunctionArgs("void startGame ();") +	assert(#args == 0)  end) | 
