Urho3D/Source/Tools/BindingGenerator/ASGlobalFunctionBinder.cpp
2021-07-17 16:43:46 +00:00

253 lines
8.3 KiB
C++

//
// Copyright (c) 2008-2021 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.
//
#include "ASResult.h"
#include "ASUtils.h"
#include "Tuning.h"
#include "Utils.h"
#include "XmlAnalyzer.h"
#include "XmlSourceData.h"
#include <cassert>
#include <map>
#include <regex>
namespace ASBindingGenerator
{
static string GetAliasMark(const GlobalFunctionAnalyzer& functionAnalyzer)
{
string comment = functionAnalyzer.GetComment();
smatch match;
regex_match(comment, match, regex(".*\\b(BIND_AS_ALIAS_.+?)\\b.*"));
if (match.size() == 2)
return match[1].str();
return "";
}
static vector<map<string, string>> GetSpecializations(const GlobalFunctionAnalyzer& functionAnalyzer)
{
vector<string> templateParams = functionAnalyzer.GetTemplateParams();
vector<map<string, string>> result;
string comment = functionAnalyzer.GetComment();
smatch match;
if (templateParams.size() == 1)
{
regex rgx("\\bSPECIALIZATION_([^_]+?)\\b");
string::const_iterator searchStart(comment.cbegin());
while (regex_search(searchStart, comment.cend(), match, rgx))
{
map<string, string> specialization;
specialization[templateParams[0]] = match[1].str();
searchStart = match.suffix().first;
result.push_back(specialization);
}
}
else if (templateParams.size() == 2)
{
regex rgx("\\bSPECIALIZATION_([^_]+?)_([^_]+?)\\b");
string::const_iterator searchStart(comment.cbegin());
while (regex_search(searchStart, comment.cend(), match, rgx))
{
map<string, string> specialization;
specialization[templateParams[0]] = match[1].str();
specialization[templateParams[1]] = match[2].str();
searchStart = match.suffix().first;
result.push_back(specialization);
}
}
else if (templateParams.size() == 3)
{
regex rgx("\\bSPECIALIZATION_([^_]+?)_([^_]+?)_([^_]+?)\\b");
string::const_iterator searchStart(comment.cbegin());
while (regex_search(searchStart, comment.cend(), match, rgx))
{
map<string, string> specialization;
specialization[templateParams[0]] = match[1].str();
specialization[templateParams[1]] = match[2].str();
specialization[templateParams[2]] = match[3].str();
searchStart = match.suffix().first;
result.push_back(specialization);
}
}
return result;
}
static void BindGlobalFunction(const GlobalFunctionAnalyzer& functionAnalyzer)
{
vector<ParamAnalyzer> params = functionAnalyzer.GetParams();
string outGlue;
bool needWrapper = false;
vector<ConvertedVariable> convertedParams;
ProcessedGlobalFunction processedGlobalFunction;
processedGlobalFunction.name_ = functionAnalyzer.GetName();
processedGlobalFunction.comment_ = functionAnalyzer.GetLocation();
processedGlobalFunction.insideDefine_ = InsideDefine(functionAnalyzer.GetHeaderFile());
for (const ParamAnalyzer& param : params)
{
ConvertedVariable conv;
try
{
conv = CppVariableToAS(param.GetType(), VariableUsage::FunctionParameter, param.GetDeclname(), param.GetDefval());
}
catch (const Exception& e)
{
processedGlobalFunction.registration_ = "// " + string(e.what());
Result::globalFunctions_.push_back(processedGlobalFunction);
return;
}
if (conv.NeedWrapper())
needWrapper = true;
convertedParams.push_back(conv);
}
ConvertedVariable retConv;
try
{
retConv = CppVariableToAS(functionAnalyzer.GetReturnType(), VariableUsage::FunctionReturn);
}
catch (const Exception& e)
{
processedGlobalFunction.registration_ = "// " + string(e.what());
Result::globalFunctions_.push_back(processedGlobalFunction);
return;
}
if (retConv.NeedWrapper())
needWrapper = true;
if (needWrapper)
processedGlobalFunction.glue_ = GenerateWrapper(functionAnalyzer, convertedParams, retConv);
string asReturnType = retConv.asDeclaration_;
string asFunctionName = functionAnalyzer.GetName();
string decl = asReturnType + " " + asFunctionName + "(" + JoinASDeclarations(convertedParams) + ")";
processedGlobalFunction.registration_ = "engine->RegisterGlobalFunction(\"" + decl + "\", ";
if (needWrapper)
processedGlobalFunction.registration_ += "AS_FUNCTION(" + GenerateWrapperName(functionAnalyzer) + "), AS_CALL_CDECL);";
else
processedGlobalFunction.registration_ += Generate_asFUNCTIONPR(functionAnalyzer) + ", AS_CALL_CDECL);";
Result::globalFunctions_.push_back(processedGlobalFunction);
// Also register alias if needed
string aliasMark = GetAliasMark(functionAnalyzer);
if (!aliasMark.empty())
{
asFunctionName = CutStart(aliasMark, "BIND_AS_ALIAS_");
decl = asReturnType + " " + asFunctionName + "(" + JoinASDeclarations(convertedParams) + ")";
processedGlobalFunction.registration_ = "engine->RegisterGlobalFunction(\"" + decl + "\", ";
if (needWrapper)
processedGlobalFunction.registration_ += "AS_FUNCTION(" + GenerateWrapperName(functionAnalyzer) + "), AS_CALL_CDECL);";
else
processedGlobalFunction.registration_ += Generate_asFUNCTIONPR(functionAnalyzer) + ", AS_CALL_CDECL);";
Result::globalFunctions_.push_back(processedGlobalFunction);
}
}
static void ProcessGlobalFunction(const GlobalFunctionAnalyzer& globalFunctionAnalyzer)
{
if (globalFunctionAnalyzer.IsDefine())
return;
vector<map<string, string>> specializations;
if (globalFunctionAnalyzer.IsTemplate())
{
specializations = GetSpecializations(globalFunctionAnalyzer);
if (!specializations.size())
return;
}
if (Contains(globalFunctionAnalyzer.GetName(), "operator"))
return;
string header = globalFunctionAnalyzer.GetHeaderFile();
Result::AddHeader(header);
if (IsIgnoredHeader(header))
return;
if (Contains(globalFunctionAnalyzer.GetComment(), "NO_BIND"))
{
ProcessedGlobalFunction processedGlobalFunction;
processedGlobalFunction.name_ = globalFunctionAnalyzer.GetName();
processedGlobalFunction.insideDefine_ = InsideDefine(header);
processedGlobalFunction.comment_ = globalFunctionAnalyzer.GetLocation();
processedGlobalFunction.registration_ = "// Not registered because have @nobind mark";
Result::globalFunctions_.push_back(processedGlobalFunction);
return;
}
if (globalFunctionAnalyzer.IsTemplate())
{
for (const TemplateSpecialization& specialization : specializations)
{
GlobalFunctionAnalyzer specializedAnalyzer(globalFunctionAnalyzer.GetMemberdef(), specialization);
BindGlobalFunction(specializedAnalyzer);
}
}
else
{
BindGlobalFunction(globalFunctionAnalyzer);
}
}
void ProcessAllGlobalFunctions()
{
NamespaceAnalyzer namespaceAnalyzer(SourceData::namespaceUrho3D_);
vector<GlobalFunctionAnalyzer> globalFunctionAnalyzers = namespaceAnalyzer.GetFunctions();
for (const GlobalFunctionAnalyzer& globalFunctionAnalyzer : globalFunctionAnalyzers)
ProcessGlobalFunction(globalFunctionAnalyzer);
}
}