| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- --
- -- Copyright (c) 2008-2014 the Urho3D project.
- --
- -- Permission is hereby granted, free of charge, to any person obtaining a copy
- -- of this software and associated documentation files (the "Software"), to deal
- -- in the Software without restriction, including without limitation the rights
- -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- -- copies of the Software, and to permit persons to whom the Software is
- -- furnished to do so, subject to the following conditions:
- --
- -- The above copyright notice and this permission notice shall be included in
- -- all copies or substantial portions of the Software.
- --
- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- -- THE SOFTWARE.
- --
- classes = {}
- enumerates = {}
- globalConstants = {}
- globalFunctions = {}
- globalProperties = {}
- currentClass = nil
- currentFunction = nil
- curDir = nil
- function classClass:print(ident,close)
- local class = {}
- class.name = self.name
- class.base = self.base
- class.lname = self.lname
- class.type = self.type
- class.btype = self.btype
- class.ctype = self.ctype
- currentClass = class
- local i = 1
- while self[i] do
- self[i]:print(ident.." ",",")
- i = i + 1
- end
- currentClass = nil
- table.insert(classes, class)
- end
- function classCode:print(ident,close)
- end
- function classDeclaration:print(ident,close)
- local declaration = {}
- declaration.mod = self.mod
- declaration.type = self.type
- declaration.ptr = self.ptr
- declaration.name = self.name
- declaration.dim = self.dim
- declaration.def = self.def
- declaration.ret = self.ret
- if currentFunction ~= nil then
- if currentFunction.declarations == nil then
- currentFunction.declarations = { declaration }
- else
- table.insert(currentFunction.declarations, declaration)
- end
- end
- end
- function classEnumerate:print(ident,close)
- local enumerate = {}
- enumerate.name = self.name
-
- local i = 1
- while self[i] do
- if self[i] ~= "" then
- if enumerate.values == nil then
- enumerate.values = { self[i] }
- else
- table.insert(enumerate.values, self[i])
- end
- end
- i = i + 1
- end
- if enumerate.values ~= nil then
- table.insert(enumerates, enumerate)
- end
- end
- function deepCopy(t)
- if type(t) ~= "table" then
- return t
- end
- local mt = getmetatable(t)
- local ret = {}
- for k, v in pairs(t) do
- if type(v) == "table" then
- v = deepCopy(v)
- end
- ret[k] = v
- end
- setmetatable(ret, mt)
- return ret
- end
- function printFunction(self,ident,close,isfunc)
- local func = {}
- func.mod = self.mod
- func.type = self.type
- func.ptr = self.ptr
- func.name = self.name
- func.lname = self.lname
- func.const = self.const
- func.cname = self.cname
- func.lname = self.lname
- if isfunc then
- func.name = func.lname
- end
- currentFunction = func
- local i = 1
- while self.args[i] do
- self.args[i]:print(ident.." ",",")
- i = i + 1
- end
- currentFunction = nil
- if currentClass == nil then
- table.insert(globalFunctions, func)
- else
- if func.name == "new" then
- -- add construct function
- local ctor = deepCopy(func)
- ctor.type = ""
- ctor.ptr = ""
- ctor.name = currentClass.name
- ctor.lname = currentClass.name
- ctor.const = "(GC)"
- ctor.cname = currentClass.name
- ctor.lname = currentClass.name
- if currentClass.functions == nil then
- currentClass.functions = { ctor }
- else
- table.insert(currentClass.functions, ctor)
- end
- end
- if func.name == "delete" then
- func.type = "void"
- end
- if currentClass.functions == nil then
- currentClass.functions = { func }
- else
- table.insert(currentClass.functions, func)
- end
- end
- end
- function classFunction:print(ident,close)
- printFunction(self,ident,close, true)
- end
- function classOperator:print(ident,close)
- printFunction(self,ident,close, false)
- end
- function classVariable:print(ident,close)
- local property = {}
- property.mod = self.mod
- property.type = self.type
- property.ptr = self.ptr
- property.name = self.lname
- property.def = self.def
- property.ret = self.ret
-
- if currentClass == nil then
- if property.mod:find("tolua_property__") == nil then
- table.insert(globalConstants, property)
- else
- table.insert(globalProperties, property)
- end
- else
- if currentClass.properties == nil then
- currentClass.properties = { property }
- else
- table.insert(currentClass.properties, property)
- end
- end
- end
- function classVerbatim:print(ident,close)
- end
- function sortByName(t)
- table.sort(t, function(a, b) return a.name < b.name end)
- end
- function getCurrentDirectory()
- local separator = (package.config):gsub("\n.*","")
- local path = ""
- local tmpFile = os.tmpname()
- if separator == "\\" then
- -- Workaround broken os.tmpname() on Windows platform
- tmpFile = os.getenv('TMP') .. tmpFile
- os.execute("cd > " .. tmpFile)
- else
- os.execute("pwd > " .. tmpFile)
- end
- local tmpHandler = io.open(tmpFile, "r")
- path = tmpHandler:read("*a"):gsub("\n.*","")
- tmpHandler:close()
- os.remove(tmpFile)
- return {path = path, separator = separator}
- end
- function isTypeEquivalent(headerType, packageType)
- -- {["headerType"] = {"packageType1", "packageType2", ...}}
- --local equivalenceTable = {["StringHash"] = {"const String"}}
- if headerType == packageType then
- return true
- else
- if equivalenceTable ~= nil then
- for headerEqType, packageEqTypes in pairs(equivalenceTable) do
- if headerEqType == headerType then
- if packageEqTypes ~= nil then
- for i, packageEqType in ipairs(packageEqTypes) do
- if packageEqType == packageType then
- return true
- end
- end
- end
- return false
- end
- end
- end
- end
- return false
- end
- function isSameFilename(str1, str2, excludeExtensions)
- str1 = str1:gsub("^.*" .. curDir.separator.. "(.*)$", "%1", 1)
- str2 = str2:gsub("^.*" .. curDir.separator.. "(.*)$", "%1", 1)
- if excludeExtensions == true then
- str1 = str1:gsub("^(.*)%..*$", "%1", 1)
- str2 = str2:gsub("^(.*)%..*$", "%1", 1)
- end
- if str1 == str2 then
- return true
- else
- return false
- end
- end
- function isSameFunction(headerFunc, packageFunc, strict)
- if headerFunc.name == packageFunc.name then
- if strict == true then
- if headerFunc.declarations ~= nil and packageFunc.declarations ~= nil then
- --for _, decl in ipairs(headerFunc.declarations) do print("FuncHeader Param: \""..decl.type.."\", \""..decl.ptr.."\", \""..decl.name.."\", \""..decl.def.."\"") end
- --for _, decl in ipairs(packageFunc.declarations) do print("FuncPackage Param: \""..decl.type.."\", \""..decl.ptr.."\", \""..decl.name.."\", \""..decl.def.."\"") end
- for i, headerDecl in ipairs(headerFunc.declarations) do
- if packageFunc.declarations[i] ~= nil then
- if not isTypeEquivalent(headerDecl.type, packageFunc.declarations[i].type) then
- return false
- end
- else
- if headerDecl.def == "" then
- return false
- end
- end
- end
- return true
- else
- return true
- end
- else
- return true
- end
- end
- return false
- end
- function printDescriptionsFromPackageFile(filename, directory)
- for line in io.lines(filename) do
- line = line:gsub("%c", "")
- if line:find("^%s*%$pfile%s+\"(.+)\"") ~= nil then
- -- If it's another package file, load it (recursive)
- local nextPath = curDir.path .. curDir.separator
- nextPath = nextPath .. line:gsub("^%s*%$pfile%s+\"(.+)\"", "%1", 1):gsub("/", curDir.separator)
- local nextDirectory = line:gsub("^%s*%$pfile%s+\"(.+)\"", "%1", 1):gsub("/.*$", ""):gsub("/", curDir.separator)
- printDescriptionsFromPackageFile(nextPath, nextDirectory)
- elseif line:find("^%s*%$#include%s+\"(.+)\"") ~= nil then
- -- If it's an include, load it to fetch the descriptions
- local nextFilename = line:gsub("^%s*%$#include%s+\"(.+)\"", "%1", 1):gsub("/", curDir.separator)
- if isSameFilename(filename, nextFilename, true) then
- -- Must be same as Package Name
- printDescriptions(nextFilename, directory)
- end
- end
- end
- end
- function printDescriptions(filename, directory)
- -- Search Descriptions
- local className = nil
- local classScope = nil
- local description = nil
- local sourceEnginePath = curDir.path .. curDir.separator .. ".." .. curDir.separator .. ".." .. curDir.separator
- if directory ~= nil then
- sourceEnginePath = sourceEnginePath .. directory .. curDir.separator
- end
- for line in io.lines(sourceEnginePath .. filename) do
- line = line:gsub("%c", "")
- -- Entering Class
- if line:find("^%s*[Cc]lass%s+(.+)") ~= nil then
- local classDefine = line:gsub("^%s*[Cc]lass%s+([%w_][^:;]*)%s*:*.*", "%1")
- className = classDefine:gsub("[%w_]+%s+([%w_]+).*", "%1")
- -- Struct Defined (same as Class)
- elseif line:find("^%s*[Ss]truct%s+(.+)") ~= nil then
- local classDefine = line:gsub("^%s*[Ss]truct%s+([%w_][^:;]*)%s*:*.*", "%1")
- className = classDefine:gsub("[%w_]+%s+([%w_]+).*", "%1")
- elseif className ~= nil then
- -- Detecting Scope
- if line:find("^%s*(%w+)%s*:%s*$") ~= nil then
- classScope = line:gsub("^%s*(%w)%s*:%s*$", "%1")
- -- Leaving Class
- elseif line:find("^%s*}%s*$") ~= nil then
- className = nil
- classScope = nil
- description = nil
- -- Gather Informations
- elseif className ~= nil and classScope ~= nil then
- -- Line stating with "///" (Description)
- if line:find("^%s*///") ~= nil then
- description = line:gsub("^%s*///%s*", "")
- -- Not Empty Line (Function)
- elseif line:find("^%s*$") == nil and description ~= nil then
- printElementDescription(className, classScope, line, description)
- description = nil
- end
- end
- end
- end
- end
- function getElementFromLine(line)
- local element = {}
- element.name = nil
- element.params = nil
- element.type = nil
- -- Type Detect (Function)
- if line:find("^.*%s*([%w_~]+)%s*%(.*%).*$") ~= nil then
- element.name = line:gsub("^.*%s+([%w_~]+)%s*%(.*%).*$", "%1")
- element.type = "functions"
- if line:find("^.+%(.*%)") ~= nil then
- element.params = {}
- local params_str = line:gsub("^.+%((.*)%).*$", "%1", 1)
- --print("Current Params: "..params_str)
- if params_str ~= "" then
- for param_str in params_str:gmatch("[^,;]+") do
- local param = {}
- param.type = ""
- if param_str:find("^%s*(const%s+)") ~= nil then
- param.type = "const "
- param_str = param_str:gsub("^%s*((const%s+)", "")
- end
- param.type = param.type..param_str:gsub("^%s*([%w_]+).*$", "%1")
- param.ptr = param_str:gsub("^%s*[%w_]+([%*&]?).*$", "%1")
- param.name = param_str:gsub("^%s*[%w_]+[%*&]?%s+([%w_]+).*$", "%1")
- param.def = ""
- if param_str:find(".+=.+") then
- param.def = param_str:gsub("^.*=%s*(.*)$", "%1")
- end
- table.insert(element.params, param)
- end
- else
- local param = {}
- param.type = "void"
- param.ptr = ""
- param.name = ""
- param.def = ""
- table.insert(element.params, param)
- end
- end
- -- Type Detect (Property)
- elseif line:find("^.*%s+([%w_]+)%s*.*;%s*$") ~= nil then
- element.name = line:gsub("^.*%s+([%w_]+)%s*.*;%s*$", "%1")
- element.type = "properties"
- end
- return element
- end
- function printElementDescription(className, classScope, line, description)
- if description ~= "" then
- local currentElement = getElementFromLine(line)
- -- Search Class & Function/Property, Then Map
- if currentElement.name ~= nil and currentElement.type ~= nil then
- --print("Name: " .. currentElement.name)
- --print("ok (name = \"" .. currentElement.name .. "\", type = \"" .. currentElement.type .. "\", className = \"" .. className .. "\")")
- for i, class in ipairs(classes) do
- if class.name == className then
- --print("Class: "..class.name.." = "..className)
- if class[currentElement.type] ~= nil then
- for j, storedElement in ipairs(class[currentElement.type]) do
- local isSameName = false
- if storedElement.name == currentElement.name then
- isSameName = true
- -- Consider that the name is the same if it has an additionnal "_" at the end and if it's a property
- elseif storedElement.name .. "_" == currentElement.name and currentElement.type == "properties" then
- isSameName = true
- end
- if isSameName == true then
- --print("Element: " .. storedElement.name .. " = " .. currentElement.name)
- -- Confirm that the function is the same and not an overloading one
- local isSameElement = true
- if currentElement.type == "functions" then
- local candidateElement = {declarations = currentElement.params}
- candidateElement.name = currentElement.name
- isSameElement = isSameFunction(candidateElement, storedElement, true)
- --if isSameElement == true then print("Is same element? True") else print("Is same element? False") end
- end
- if isSameElement == true then
- --print("Element: " .. storedElement.name .. " = " .. currentElement.name)
- if storedElement.descriptions == nil then
- --print("[New description table]")
- classes[i][currentElement.type][j].descriptions = {}
- end
- --print("Description: "..description)
- --print("")
- table.insert(classes[i][currentElement.type][j].descriptions, description)
- return
- end
- end
- end
- end
- end
- end
- --print("")
- end
- end
- end
- function writeClass(file, class)
- file:write("<a name=\"Class_" .. class.name .. "\"></a>\n")
- if class.base == "" then
- file:write("### " .. class.name .. "\n\n")
- else
- file:write("### " .. class.name .. " : " .. class.base .. "\n")
- end
- if class.functions ~= nil then
- file:write("\nMethods:\n\n")
- for i, func in ipairs(class.functions) do
- writeFunction(file, func)
- end
- end
- if class.properties ~= nil then
- file:write("\nProperties:\n\n")
- for i, property in ipairs(class.properties) do
- writeProperty(file, property)
- end
- end
- file:write("\n")
- end
- function writeTableOfContents(file)
- file:write("\n\\section LuaScriptAPI_TableOfContents Table of contents\n\n")
- file:write("\\ref LuaScriptAPI_ClassList \"Class list\"<br>\n")
- file:write("\\ref LuaScriptAPI_Classes \"Classes\"<br>\n")
- file:write("\\ref LuaScriptAPI_Enums \"Enumerations\"<br>\n")
- file:write("\\ref LuaScriptAPI_GlobalFunctions \"Global functions\"<br>\n")
- file:write("\\ref LuaScriptAPI_GlobalProperties \"Global properties\"<br>\n")
- file:write("\\ref LuaScriptAPI_GlobalConstants \"Global constants\"<br>\n")
- end
- function writeClassList(file)
- sortByName(classes)
- file:write("\n\\section LuaScriptAPI_ClassList Class list\n\n")
- for i, class in ipairs(classes) do
- file:write("<a href=\"#Class_" .. class.name .. "\"><b>" .. class.name .. "</b></a>\n")
- end
- end
- function writeClasses(file)
- file:write("\n\\section LuaScriptAPI_Classes Classes\n\n")
- for i, class in ipairs(classes) do
- writeClass(file, class)
- end
- end
- function writeEnumerates(file)
- sortByName(enumerates)
- file:write("\\section LuaScriptAPI_Enums Enumerations\n\n")
- for i, enumerate in ipairs(enumerates) do
- file:write("### " .. enumerate.name .. "\n\n")
- for i, value in ipairs(enumerate.values) do
- file:write("- int " .. value .. "\n")
- end
- file:write("\n")
- end
- end
- function writeFunction(file, func)
- local line = "- "
- -- construct function
- if func.type == "" and func.ptr == "" then
- line = line .. func.name .. "("
- else
- line = line .. func.type .. func.ptr .. " " .. func.name .. "("
- end
- -- write parameters
- if func.declarations ~= nil then
- local count = table.maxn(func.declarations)
- for i = 1, count do
- local declaration = func.declarations[i]
- if declaration.type ~= "void" then
- line = line .. declaration.type .. declaration.ptr .. " " .. declaration.name
- -- add paramter default value
- if declaration.def ~= "" then
- line = line .. " = " .. declaration.def
- end
- end
- if i ~= count then
- line = line .. ", "
- end
- end
- end
- line = line .. ")"
- -- add const
- if func.const ~= "" then
- line = line .. " " .. func.const
- end
- file:write(line .. "\n")
- end
- function writeGlobalConstants(file)
- sortByName(globalConstants)
- file:write("\n\\section LuaScriptAPI_GlobalConstants Global constants\n")
- for i, constant in ipairs(globalConstants) do
- local line = "- " .. constant.type:gsub("const ", "") .. constant.ptr .. " " .. constant.name
- file:write(line .. "\n")
- end
- file:write("\n")
- end
- function writeGlobalFunctions(file)
- sortByName(globalFunctions)
- file:write("\n\\section LuaScriptAPI_GlobalFunctions Global functions\n")
- for i, func in ipairs(globalFunctions) do
- writeFunction(file, func)
- end
- file:write("\n")
- end
- function writeGlobalProperties(file)
- sortByName(globalProperties)
- file:write("\n\\section LuaScriptAPI_GlobalProperties Global properties\n")
- for i, property in ipairs(globalProperties) do
- writeProperty(file, property)
- end
- end
- function writeProperty(file, property)
- file:write("- " .. property.type .. property.ptr .. " " .. property.name)
- if property.mod:find("tolua_readonly") == nil then
- file:write("\n")
- else
- file:write(" (readonly)\n")
- end
- end
- function classPackage:print()
- curDir = getCurrentDirectory()
-
- if flags.o == nil then
- print("Invalid output filename");
- return
- end
- local filename = flags.o
- local file = io.open(filename, "wt")
- file:write("namespace Urho3D\n")
- file:write("{\n")
- file:write("\n")
- file:write("/**\n")
- file:write("\\page LuaScriptAPI Lua scripting API\n")
- local i = 1
- while self[i] do
- self[i]:print("","")
- i = i + 1
- end
- printDescriptionsFromPackageFile(flags.f)
- writeTableOfContents(file)
- writeClassList(file)
- writeClasses(file)
- writeEnumerates(file)
- writeGlobalFunctions(file)
- writeGlobalProperties(file)
- writeGlobalConstants(file)
-
- file:write("*/\n")
- file:write("\n")
- file:write("}\n")
- file:close()
- end
|