khanat-opennel-code/code/ryzom/tools/pd_parser/parser.cpp
2014-09-03 06:38:38 +02:00

4909 lines
139 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "parser.h"
#include "cpp_output.h"
#include "templatizer.h"
#include "parser_rules.h"
#include <nel/misc/path.h>
#include <nel/misc/sha1.h>
using namespace std;
using namespace NLMISC;
//using namespace RY_PDS;
bool GenerateCpp = true;
bool GenerateXmlDescription = true;
bool VerboseMode = false;
bool GenerateDebugMessages = false;
bool GenerateHAuto = false;
bool GenerateOnlyLogs = false;
CTokenizer Tokenizer;
CTemplatizer Templatizer;
CHashKey HashKey;
string CurrentEnum;
CEnumNode *CurrentEnumNode = NULL;
string DbDescriptionVersion("0.0");
string formatDescription(const string &str)
{
string result;
uint pos = 0;
while (pos < str.size() && (str[pos] == ' ' || str[pos] == '\t' || str[pos] == '\r' || str[pos] == '\n'))
++pos;
bool first = true;
while (pos < str.size())
{
if (!first)
result += "\n";
first = false;
result += "* ";
while (pos < str.size() && str[pos] != '\n')
result += str[pos++];
while (pos < str.size() && (str[pos] == ' ' || str[pos] == '\t' || str[pos] == '\r' || str[pos] == '\n'))
++pos;
}
return result;
}
string strReplace(string str, const string &search, const string &replace)
{
std::string::size_type pos = 0;
while ((pos = str.find(search)) != string::npos)
str.replace(pos, search.size(), replace);
return str;
}
string xmlSpecialChars(string str)
{
str = strReplace(str, "&", "&amp;");
str = strReplace(str, "<", "&lt;");
str = strReplace(str, ">", "&gt;");
str = strReplace(str, "\"", "&quot;");
str = strReplace(str, "'", "&apos;");
return str;
}
string getFullStdPathNoExt(const string &path)
{
string dir = NLMISC::toLower(NLMISC::CFile::getPath(path));
string file = NLMISC::toLower(NLMISC::CFile::getFilenameWithoutExtension(path));
return dir.empty() ? file : NLMISC::CPath::standardizePath(dir)+file;
}
string getFullStdPath(const string &path)
{
string dir = NLMISC::toLower(NLMISC::CFile::getPath(path));
string file = NLMISC::toLower(NLMISC::CFile::getFilename(path));
return dir.empty() ? file : NLMISC::CPath::standardizePath(dir)+file;
}
string appendArg(const std::string& firstArgs, const std::string& nextArg)
{
if (firstArgs.empty())
return nextArg;
return firstArgs + ", " + nextArg;
}
/*
* Start parsing
*/
CParseNode *parse(const string &file)
{
HashKey = getSHA1(file);
Tokenizer.readFile(file);
if (Tokenizer.tokenize())
return parseMain(Tokenizer);
return NULL;
}
/*
* Execute nodes
*/
// DB Node
bool CDbNode::prolog()
{
addTypeNode("CSheetId", "NLMISC::CSheetId", "NLMISC::CSheetId::Unknown");
addTypeNode("CEntityId", "NLMISC::CEntityId", "NLMISC::CEntityId::Unknown");
addTypeNode("double", "double", "0.0");
addTypeNode("float", "float", "0.0f");
addTypeNode("sint64", "sint64", "(sint64)0");
addTypeNode("uint64", "uint64", "(uint64)0");
addTypeNode("sint32", "sint32", "0");
addTypeNode("uint32", "uint32", "0");
addTypeNode("sint16", "sint16", "0");
addTypeNode("uint16", "uint16", "0");
addTypeNode("sint8", "sint8", "0");
addTypeNode("uint8", "uint8", "0");
addTypeNode("ucchar", "ucchar", "0");
addTypeNode("char", "char", "0");
addTypeNode("bool", "bool", "false");
return true;
}
bool inlineAccessors = false;
string getFunctionPrefix = "get";
string setFunctionPrefix = "set";
string newFunction = "addTo";
string deleteFunction = "deleteFrom";
string indexVariable = "__i";
string valueVariable = "__v";
string keyVariable = "__k";
string objectVariable = "__o";
bool inlineUserInitDefaultCode = false;
string userInitFunction = "init";
string userReleaseFunction = "release";
bool inlineStaticPublic = false;
string staticCreateFunction = "create";
string staticRemoveFunction = "remove";
string staticSetUserFactoryFunction = "setFactory";
string staticLoadFunction = "load";
string staticUnloadFunction = "unload";
string staticSetLoadCbFunction = "setLoadCallback";
string staticGetFunction = "get";
string staticCastFunction = "cast";
string staticConstCastFunction = "cast";
string staticBeginFunction = "begin";
string staticEndFunction = "end";
bool inlineInternal = false;
string initFunction = "pds__init";
string destroyFunction = "pds__destroy";
string registerFunction = "pds__register";
string registerAttributesFunction = "pds__registerAttributes";
string unregisterFunction = "pds__unregister";
string unregisterAttributesFunction = "pds__unregisterAttributes";
string fetchFunction = "pds__fetch";
string setParentFunction = "pds__setParent";
string setUnnotifiedParentFunction = "pds__setParentUnnotified";
string getTableFunction = "pds__getTable";
string unlinkFunction = "pds__unlink";
string notifyInitFunction = "pds__notifyInit";
string notifyReleaseFunction = "pds__notifyRelease";
string clearFunction = "clear";
string storeFunction = "store";
string applyFunction = "apply";
string declareTokensFunction = "pds__declareTokens";
bool inlineStaticInternal = false;
string staticInitFactoryFunction = "pds_static__setFactory";
string staticFactoryFunction = "pds_static__factory";
string staticFetchFunction = "pds_static__fetch";
string staticInitFunction = "pds_static__init";
string staticNotifyLoadFailure = "pds_static__notifyFailure";
string staticLoadCbAttribute = "__pds__LoadCallback";
bool inlineLog = false;
string logStartFunction = "pds__startLog";
string logStopFunction = "pds__stopLog";
string PDSNamespace = "RY_PDS";
string CPDSLibName = PDSNamespace+"::CPDSLib";
string objectIndexName = PDSNamespace+"::CObjectIndex";
string nullIndexName = PDSNamespace+"::CObjectIndex::null()";
string TTableIndexName = PDSNamespace+"::TTableIndex";
string TRowIndexName = PDSNamespace+"::TRowIndex";
string TColumnIndexName = PDSNamespace+"::TColumnIndex";
string INVALID_TABLE_INDEXName = PDSNamespace+"::INVALID_TABLE_INDEX";
string INVALID_ROW_INDEXName = PDSNamespace+"::INVALID_ROW_INDEX";
string indexAllocatorName = PDSNamespace+"::CIndexAllocator";
string pdBaseDataName = PDSNamespace+"::IPDBaseData";
//string pdBaseInheritDataName = PDSNamespace+"::IPDBaseInheritData";
string CPDataName = PDSNamespace+"::CPData";
string TPDFactoryName = PDSNamespace+"::TPDFactory";
string TPDFetchName = PDSNamespace+"::TPDFetch";
string TPDFetchFailureName = PDSNamespace+"::TPDFetchFailure";
bool inlineLogFunctions = false;
string pdslibFunc(const std::string& func)
{
//return CPDSLibName+"::"+func;
return "PDSLib."+func;
}
bool CDbNode::epilog()
{
uint i;
Env = Templatizer.RootEnv;
setEnv("db", Name);
string fullfile = getFullStdPathNoExt(MainFile.empty() ? Name : MainFile);
string filename = NLMISC::toLower(NLMISC::CFile::getFilenameWithoutExtension(fullfile));
setEnv("filename", filename);
setEnv("fullfilename", fullfile);
setEnv("headerfilename", strReplace(strupr(filename+".h"), ".", "_"));
DbHpp.setFileHeader(filename+".h", "Initialisation of the "+Name+" database, declarations\n"+Description);
DbCpp.setFileHeader(filename+".cpp", "Initialisation of the "+Name+" database, implementation\n"+Description);
DbHppInline.setFileHeader(filename+"_inline.h", "Initialisation of the "+Name+" database, inline implementation\n"+Description);
DbSummary << "\n\n";
DbSummary << "Summary of " << Name << " database classes of database\n";
DbSummary << "-----------------------------------------------------------------------------\n\n";
DbSummary << "This file is automatically generated.\n";
DbSummary << "This is a reminder of all classes generated and methods implemented.\n\n\n";
DbSummary << "Database " << Name << " is managed through 4 functions located in " << fullfile << ".h:\n\n";
DbSummary << Name << "::init():\n";
DbSummary << "Initialises database context and connection towards database server (refered as PDS).\n";
DbSummary << "All user factories must have been set before call to this function.\n";
DbSummary << "Call this function in service init method.\n\n";
DbSummary << Name << "::ready():\n";
DbSummary << "Tells whether the whole database engine is ready to work.\n";
DbSummary << "You must not update any value nor call update() unless ready() is true.\n\n";
DbSummary << Name << "::update():\n";
DbSummary << "Updates the database engine and sends updates to the PDS.\n";
DbSummary << "Call this function each tick, provided ready() returned true.\n\n";
DbSummary << Name << "::release():\n";
DbSummary << "Releases the database engine. Drops all data, closes the connection to the PDS.\n";
DbSummary << "Call this function in service release method.\n\n";
DbSummary << "\n\n";
DbSummary << "Summary of generated classes for " << Name << "\n\n";
DbHpp << "\n#ifndef " << strReplace(strupr(filename+".h"), ".", "_") << "\n";
DbHpp << "#define " << strReplace(strupr(filename+".h"), ".", "_") << "\n";
DbHpp << "\n";
DbHpp << "#include <nel/misc/types_nl.h>\n";
DbHpp << "#include <pd_lib/pd_lib.h>\n";
DbHpp << "\n";
DbHpp << "namespace " << Name << "\n{\n\n";
DbHpp.unindent();
if (!Pch.empty())
{
DbCpp << "\n#include \"" << Pch << "\"\n\n";
}
DbCpp << "#include \"" << filename << ".h\"\n\n";
DbCpp << "namespace " << Name << "\n{\n\n";
DbCpp.unindent();
DbCpp << "RY_PDS::CPDSLib PDSLib;\n";
DbHppInline << "namespace " << Name << "\n{\n\n";
DbHppInline.unindent();
uint maxClassId = 0;
for (i=0; i<ClassNodes.size(); ++i)
{
CClassNode *classnd = ClassNodes[i];
++maxClassId;
}
uint maxTypeId = 0;
for (i=0; i<TypeNodes.size(); ++i)
{
CTypeNode *typend = TypeNodes[i];
++maxTypeId;
}
xmlDescription.clear();
xmlDescription.push_back("<?xml version='1.0'?>");
xmlDescription.push_back("<dbdescription version='"+DbDescriptionVersion+"'>");
//xmlDescription.push_back("<db name='"+Name+"' types='"+toString(maxTypeId)+"' classes='"+toString(maxClassId)+"' hashkey='"+HashKey.toString()+"'>");
xmlDescription.push_back("<db name='"+Name+"' types='"+toString(maxTypeId)+"' classes='"+toString(maxClassId)+"'>");
pass1();
pass2();
pass3();
// Check dependencies order
vector<CClassNode*> classesOrder;
vector<CFileNode*> filesOrder;
buildClassOrder(classesOrder, filesOrder);
// generate all file prologs
for (i=0; i<FileNodes.size(); ++i)
{
CFileNode *child = FileNodes[i];
child->generateProlog();
}
pass4();
//
initDb.init("init");
initDb.IsInline = false;
initDb.Proto = "uint32 overrideDbId";
initDb.Type = "void";
initDb.Description = "Initialise the whole database engine.\nCall this function at service init.";
readyDb.init("ready");
readyDb.IsInline = false;
readyDb.Proto = "";
readyDb.Type = "bool";
readyDb.Description = "Tells if database engine is ready to work.\nEngine may not be ready because PDS is down, not yet ready\nor message queue to PDS is full.";
updateDb.init("update");
updateDb.IsInline = false;
updateDb.Proto = "";
updateDb.Type = "void";
updateDb.Description = "Update the database engine.\nCall this method once per tick, only if engine is ready (see also ready() above).";
logChatDb.init("logChat");
logChatDb.IsInline = false;
logChatDb.Proto = "const ucstring& sentence, const NLMISC::CEntityId& from, const std::vector<NLMISC::CEntityId>& to";
logChatDb.Type = "void";
logChatDb.Description = "Logs chat sentence with sender and receipiants.";
logTellDb.init("logTell");
logTellDb.IsInline = false;
logTellDb.Proto = "const ucstring& sentence, const NLMISC::CEntityId& from, const NLMISC::CEntityId& to";
logTellDb.Type = "void";
logTellDb.Description = "Logs tell sentence with sender and single recipient (might be player or group).";
releaseDb.init("release");
releaseDb.IsInline = false;
releaseDb.Proto = "";
releaseDb.Type = "void";
releaseDb.Description = "Release the whole database engine.\nCall this function at service release.";
//
generateClassesDeclaration();
//
generateClassesContent(classesOrder);
//
generateLogContent();
xmlDescription.push_back("</db>");
xmlDescription.push_back("</dbdescription>");;
initDb.add("std::string\txmlDescription;");
DbXml.setXmlMode();
for (i=0; i<xmlDescription.size(); ++i)
{
initDb.add("xmlDescription += \""+xmlDescription[i]+"\\n\";");
DbXml << xmlDescription[i] << "\n";
}
DbXml.flush(fullfile+".xml");
DbHpp << "/// \\name Public API for " << Name << " database\n";
DbHpp << "// @{\n";
DbHpp.unindent();
initDb.add(pdslibFunc("init")+"(xmlDescription, overrideDbId);");
initDb.flush(DbHpp, DbCpp, DbHppInline);
readyDb.add("return "+pdslibFunc("PDSReady")+"();");
readyDb.flush(DbHpp, DbCpp, DbHppInline);
updateDb.add(pdslibFunc("update")+"();");
updateDb.flush(DbHpp, DbCpp, DbHppInline);
logChatDb.add(pdslibFunc("logChat")+"(sentence, from, to);");
logChatDb.flush(DbHpp, DbCpp, DbHppInline);
logTellDb.add("std::vector<NLMISC::CEntityId>\tids;");
logTellDb.add("ids.push_back(to);");
logTellDb.add(pdslibFunc("logChat")+"(sentence, from, ids);");
logTellDb.flush(DbHpp, DbCpp, DbHppInline);
releaseDb.add(pdslibFunc("release")+"();");
releaseDb.flush(DbHpp, DbCpp, DbHppInline);
DbHpp << "\n// @}\n\n";
DbHpp << "extern RY_PDS::CPDSLib PDSLib;\n";
DbHpp.indent();
DbHpp << "\n} // End of " << Name <<"\n";
generateIncludes(filesOrder);
DbHpp << "\n#include \"" << filename << "_inline.h\"\n\n";
DbHpp << "\n#endif\n";
DbHpp.flush(fullfile+".h");
DbCpp.indent();
DbCpp << "\n} // End of " << Name <<"\n";
DbCpp.flush(fullfile+".cpp");
DbHppInline.indent();
DbHppInline << "\n} // End of " << Name <<"\n";
DbHppInline.flush(fullfile+"_inline.h");
DbSummary.flush(fullfile+"_summary.txt");
for (i=0; i<FileNodes.size(); ++i)
{
CFileNode *child = FileNodes[i];
child->generateEpilog();
}
return true;
}
void CDbNode::pass1()
{
/*
* PASS 1
* - all type names and class names are known
* -> look for classes in set or backreferences
*/
uint i;
uint classId = 0;
uint typeId = 0;
for (i=0; i<ClassNodes.size(); ++i)
{
CClassNode *classnd = ClassNodes[i];
classnd->checkClassReferences();
classnd->Id = classId++;
classnd->getFileNode()->IncludeStandard = true;
classnd->getFileNode()->IncludeDbFile = true;
}
for (i=0; i<TypeNodes.size(); ++i)
{
CTypeNode *typend = TypeNodes[i];
typend->Id = typeId++;
uint tsize = 0;
if (typend->StorageType == "bool") tsize = 1;
if (typend->StorageType == "char") tsize = 1;
if (typend->StorageType == "ucchar") tsize = 2;
if (typend->StorageType == "uint8") tsize = 1;
if (typend->StorageType == "sint8") tsize = 1;
if (typend->StorageType == "uint16") tsize = 2;
if (typend->StorageType == "sint16") tsize = 2;
if (typend->StorageType == "uint32") tsize = 4;
if (typend->StorageType == "sint32") tsize = 4;
if (typend->StorageType == "uint64") tsize = 8;
if (typend->StorageType == "sint64") tsize = 8;
if (typend->StorageType == "float") tsize = 4;
if (typend->StorageType == "double") tsize = 8;
if (typend->StorageType == "CEntityId") tsize = 8;
if (typend->StorageType == "CSheetId") tsize = 4;
typend->Size = tsize;
string xmlnode = "<typedef name='"+typend->Name+"' id='"+toString(typend->Id)+"' size='"+toString(tsize)+"' storage='"+typend->StorageType+"'";
if (typend->isEnum())
{
CEnumNode *enumnd = static_cast<CEnumNode*>(typend);
xmlnode += " type='enum'>";
xmlDescription.push_back(xmlnode);
uint j;
for (j=0; j<enumnd->Values.size(); ++j)
xmlDescription.push_back("<enumvalue name='"+enumnd->Values[j].first+"' value='"+toString(enumnd->Values[j].second)+"'/>");
xmlDescription.push_back("</typedef>");
}
else if (typend->isDimension())
{
CDimensionNode *dimnd = static_cast<CDimensionNode*>(typend);
xmlnode += " type='dimension' dimension='"+toString(dimnd->Dimension)+"'/>";
xmlDescription.push_back(xmlnode);
}
else
{
xmlnode += " type='type'/>";
xmlDescription.push_back(xmlnode);
}
}
}
void CDbNode::pass2()
{
/*
* PASS 2
* - class hierarchy, backreferences and in set information are known
* -> fill up attributes
*/
uint i;
for (i=0; i<ClassNodes.size(); ++i)
{
CClassNode *child = ClassNodes[i];
if (!child->Inherited.empty() && child->MappedFlag && !child->HasParent)
child->error("class cannot inherit another class and be mapped. Try to map base class instead.");
if (child->MappedFlag && child->getClassKey() == NULL)
child->error("class is mapped and has no key defined");
child->ForceReference = (child->HasInheritance || child->MappedFlag || child->DerivatedFlag || (child->HasParent && !child->ParentIsHidden));
if (child->ForceReference && child->ParentIsHidden)
child->error("Parent attribute cannot be hidden because class has inheritance, is mapped or is derivated.");
child->getFileNode()->IncludePDSLib = true;
if (!child->Inherited.empty())
{
CClassNode *icln = child;
CClassNode *lastMapped = (child->MappedFlag ? child : NULL);
while (!icln->Inherited.empty())
{
icln = getClassNode(icln->Inherited);
if (icln->MappedFlag)
{
if (lastMapped != NULL)
lastMapped->error("class cannot be remapped since parent "+icln->Name+" is already mapped");
lastMapped = icln;
}
}
/*
if (icln->MappedFlag)
child->MapClass = icln;
*/
child->MapClass = lastMapped;
}
else if (child->MappedFlag)
{
child->MapClass = child;
}
child->fillAttributes();
}
}
void CDbNode::pass3()
{
/*
* PASS 3
* - attributes are known
* -> fill up backrefs and array/set forwardrefs
*/
uint i;
for (i=0; i<ClassNodes.size(); ++i)
{
CClassNode *child = ClassNodes[i];
child->fillRefs();
}
for (i=0; i<ClassNodes.size(); ++i)
{
CClassNode *child = ClassNodes[i];
child->computeFriends();
}
}
void CDbNode::pass4()
{
/*
* PASS 4
* - everything is ok in database descriptor
* -> output c++ code
*/
uint i;
for (i=0; i<FileNodes.size(); ++i)
{
CFileNode* file = FileNodes[i];
file->Hpp << "\n\n//\n// Typedefs & Enums\n//\n\n";
}
for (i=0; i<TypeNodes.size(); ++i)
{
CTypeNode *type = TypeNodes[i];
if (type->ExternFlag || type->InternFlag)
continue;
type->generateContent();
}
}
void CDbNode::generateClassesDeclaration()
{
uint i;
DbHpp << "\n//\n";
DbHpp << "// Global Forward Declarations\n";
DbHpp << "//\n\n";
for (i=0; i<ClassNodes.size(); ++i)
{
DbHpp << "class " << ClassNodes[i]->Name << ";\n";
}
DbHpp << "\n";
DbHpp << "//\n\n";
}
void CDbNode::generateIncludes(vector<CFileNode*>& filesOrder)
{
uint i;
DbHpp << "\n//\n";
DbHpp << "// Includes\n";
DbHpp << "//\n\n";
for (i=0; i<filesOrder.size(); ++i)
{
if (!filesOrder[i]->SeparatedFlag)
{
filesOrder[i]->setEnv("as", getFileNoExtPath(filesOrder[i]->IncludeAs));
DbHpp << "#include \"" << getFileNoExtPath(filesOrder[i]->IncludeAs) << ".h\"\n";
}
}
DbHpp << "\n";
for (i=0; i<filesOrder.size(); ++i)
{
if (filesOrder[i]->IncludeDbFile && !filesOrder[i]->SeparatedFlag)
{
filesOrder[i]->define("incinline");
DbHpp << "#include \"" << getFileNoExtPath(filesOrder[i]->IncludeAs) << "_inline.h\"\n";
}
}
DbHpp << "\n";
DbHpp << "//\n\n";
}
void CDbNode::generateClassesContent(vector<CClassNode*>& classesOrder)
{
uint i;
//
// output classes content
//
for (i=0; i<classesOrder.size(); ++i)
{
CClassNode *cln = classesOrder[i];
initDb.add(pdslibFunc("registerClassMapping")+"("+toString(cln->Id)+", \""+cln->Name+"\");");
cln->generateContent();
}
}
void CDbNode::buildClassOrder(vector<CClassNode*>& classesOrder, vector<CFileNode*>& filesOrder)
{
set<CClassNode*> checkedClasses;
uint i;
for (i=0; i<ClassNodes.size(); ++i)
{
CClassNode *child = ClassNodes[i];
if (checkedClasses.find(child) != checkedClasses.end())
continue;
set<CClassNode*> beingChecked;
child->checkDependencies(beingChecked, checkedClasses, classesOrder);
}
set<CFileNode*> checkedFiles;
filesOrder.clear();
for (i=0; i<FileNodes.size(); ++i)
{
CFileNode *child = FileNodes[i];
if (checkedFiles.find(child) != checkedFiles.end())
continue;
set<CFileNode*> beingChecked;
child->checkDependencies(beingChecked, checkedFiles, filesOrder);
}
for (i=0; i<filesOrder.size(); ++i)
filesOrder[i]->Env = Env->nextArrayNode("files");
for (i=0; i<classesOrder.size(); ++i)
classesOrder[i]->Env = classesOrder[i]->getFileNode()->Env->nextArrayNode("classes");
}
void CDbNode::generateLogContent()
{
uint logid = 0;
uint i;
for (i=0; i<LogNodes.size(); ++i)
{
CLogMsgNode *child = LogNodes[i];
child->Id = logid;
logid += (uint)child->Logs.size();
child->generateContent();
}
}
// get file path from this file
string CDbNode::getFileNoExtPath(const std::string& file)
{
string thisPath = NLMISC::CFile::getPath(NLMISC::toLower(getDbFile()));
string filePath = NLMISC::CFile::getPath(NLMISC::toLower(file));
string fileName = NLMISC::CFile::getFilename(NLMISC::toLower(file));
if (thisPath == filePath)
return CFile::getFilenameWithoutExtension(fileName);
else
return CPath::standardizePath(filePath)+CFile::getFilenameWithoutExtension(NLMISC::toLower(file));
}
// File Node
bool CFileNode::prolog()
{
CDbNode* db = getDbNode();
db->FileNodes.push_back(this);
if (GenerateOnlyLogs)
Generate = false;
return true;
}
bool CFileNode::epilog()
{
return true;
}
bool CFileNode::generateProlog()
{
CDbNode* db = getDbNode();
if (!db->Description.empty())
Hpp << db->Description << "\n";
string filename = NLMISC::toLower(CFile::getFilenameWithoutExtension(Name));
setEnv("fullfilename", getFullStdPathNoExt(Name));
setEnv("filename", filename);
setEnv("headerfilename", strReplace(strupr(filename+".h"), ".", "_"));
setEnv("description", Description);
Hpp.setFileHeader(filename+".h", Description);
Cpp.setFileHeader(filename+".cpp", Description);
HppInline.setFileHeader(filename+"_inline.h", Description);
Hpp << "\n#ifndef " << strReplace(strupr(filename+".h"), ".", "_") << "\n";
Hpp << "#define " << strReplace(strupr(filename+".h"), ".", "_") << "\n\n";
Hpp << "#include <nel/misc/types_nl.h>\n";
Hpp << "#include <nel/misc/debug.h>\n";
Hpp << "#include <nel/misc/common.h>\n";
if (GenerateHAuto)
{
Hpp << "#include <nel/misc/hierarchical_timer.h>\n";
}
if (IncludeStandard)
{
define("incstd");
Hpp << "#include <nel/misc/entity_id.h>\n";
Hpp << "#include <nel/misc/sheet_id.h>\n";
}
Hpp << "#include <vector>\n";
Hpp << "#include <map>\n";
if (IncludePDSLib)
{
define("incpdslib");
Hpp << "#include <pd_lib/pd_lib.h>\n";
Hpp << "#include <game_share/persistent_data.h>\n";
}
Hpp << "\n";
if (SeparatedFlag)
{
string fullfile = getFullStdPathNoExt(db->MainFile.empty() ? db->Name : db->MainFile);
string filename = NLMISC::toLower(NLMISC::CFile::getFilenameWithoutExtension(fullfile));
Hpp << "#include \"" << filename << ".h\"\n";
Hpp << "\n";
}
Hpp << "// User #includes\n";
uint i;
for (i=0; i<IncludeNodes.size(); ++i)
{
Env->nextArrayNode("incuser")->set("as", IncludeNodes[i]->Name);
Hpp << "#include \"" << IncludeNodes[i]->Name << "\"\n";
}
Hpp << "\nnamespace " << db->Name << "\n{\n\n";
Hpp.unindent();
if (!db->Description.empty())
HppInline << db->Description;
HppInline << "namespace " << db->Name << "\n{\n\n";
HppInline.unindent();
Hpp << "//\n// Forward declarations\n//\n\n";
if (!db->Pch.empty())
{
Cpp << "\n";
Cpp << "#include \""+db->Pch+"\"";
}
Cpp << "\n";
if (SeparatedFlag || !IncludeDbFile)
{
Cpp << "#include \"" << filename << ".h\"\n";
}
else
{
Cpp << "#include \"" << getFileNoExtPath(getDbNode()->getDbFile()) << ".h\"\n";
}
Cpp << "\n";
Cpp << "namespace " << db->Name << "\n{\n\n";
Cpp.unindent();
return true;
}
bool CFileNode::generateEpilog()
{
CDbNode* db = getDbNode();
string fullfile = getFullStdPathNoExt(Name);
string filename = NLMISC::toLower(CFile::getFilenameWithoutExtension(Name));
Hpp.indent();
Hpp << "\n} // End of " << db->Name <<"\n";
if (!IncludeDbFile || SeparatedFlag)
{
// add inline #include
Hpp << "\n\n//\n// Inline implementations\n//\n\n";
Hpp << "#include \"" << filename << "_inline.h\"\n";
}
Hpp << "\n#endif\n";
HppInline.indent();
HppInline << "\n} // End of " << db->Name <<"\n";
Cpp.indent();
Cpp << "\n} // End of " << db->Name <<"\n";
if (Generate)
writeFile();
return true;
}
string CFileNode::getFileNoExtPath(const string& file)
{
string thisPath = NLMISC::CFile::getPath(NLMISC::toLower(Name));
string filePath = NLMISC::CFile::getPath(NLMISC::toLower(file));
string fileName = NLMISC::CFile::getFilename(NLMISC::toLower(file));
if (thisPath == filePath)
return CFile::getFilenameWithoutExtension(fileName);
else
return CFile::getFilenameWithoutExtension(NLMISC::toLower(file));
}
void CFileNode::writeFile()
{
string fullfile = getFullStdPathNoExt(Name);
Hpp.flush(fullfile+".h");
Cpp.flush(fullfile+".cpp");
HppInline.flush(fullfile+"_inline.h");
}
void CFileNode::checkDependencies(set<CFileNode*> &beingChecked,
set<CFileNode*> &checkedFiles,
vector<CFileNode*> &filesOrder)
{
if (beingChecked.find(this) != beingChecked.end())
error("circular dependency in file '"+Name+"'");
if (checkedFiles.find(this) != checkedFiles.end())
return;
beingChecked.insert(this);
checkedFiles.insert(this);
set<CFileNode*>::iterator it;
for (it=Dependencies.begin(); it!=Dependencies.end(); ++it)
{
CFileNode *fileNode = *it;
if (fileNode == this)
continue;
fileNode->checkDependencies(beingChecked, checkedFiles, filesOrder);
}
filesOrder.push_back(this);
}
// Type Node
bool CTypeNode::prolog()
{
CDbNode* db = getDbNode();
db->TypeNodes.push_back(this);
return true;
}
bool CTypeNode::generateContent()
{
hOutput() << "/** " << Name << "\n";
if (!Description.empty())
{
hOutput() << Description << "\n";
}
uint line, col;
string file;
getFileLine(line, col, file);
hOutput() << "defined at " << file << ":" << line << "\n";
hOutput() << "*/\n";
hOutput() << "typedef " << getCppType() << " " << Name << ";\n\n";
if (ToCppType != NULL)
{
CCppCodeNode *tocpp = static_cast<CCppCodeNode*>(ToCppType);
CFunctionGenerator toCppFunc;
toCppFunc.init(storageToCpp());
toCppFunc.setType(getName());
toCppFunc.IsInline = true;
toCppFunc.Proto = StorageType+" _v";
toCppFunc.add(getName()+"\t__res;");
toCppFunc.add(strReplace(strReplace(tocpp->RawCode, "$("+CppType+")", "__res"), "$("+StorageType+")", "_v"));
toCppFunc.add("return __res;");
toCppFunc.flush(hOutput(), cppOutput(), inlineOutput());
}
if (ToStorageType != NULL)
{
CCppCodeNode *tostorage = static_cast<CCppCodeNode*>(ToStorageType);
CFunctionGenerator toStorageFunc;
toStorageFunc.init(cppToStorage());
toStorageFunc.setType(StorageType);
toStorageFunc.IsInline = true;
toStorageFunc.Proto = getName()+" _v";
toStorageFunc.add(StorageType+"\t__res;");
toStorageFunc.add(strReplace(strReplace(tostorage->RawCode, "$("+StorageType+")", "__res"), "$("+CppType+")", "_v"));
toStorageFunc.add("return __res;");
toStorageFunc.flush(hOutput(), cppOutput(), inlineOutput());
}
hOutput() << "\n";
return true;
}
// Include Node
bool CIncludeNode::prolog()
{
CFileNode* file = getFileNode();
file->IncludeNodes.push_back(this);
return true;
}
// Include Node
bool CUsePchNode::prolog()
{
CDbNode* db = getDbNode();
db->Pch = Name;
return true;
}
// CppCode Node
bool CCppCodeNode::prolog()
{
return true;
}
// Dimension Nodes
bool CDimensionNode::prolog()
{
CDbNode* db = getDbNode();
db->TypeNodes.push_back(this);
if (Dimension < 256)
StorageType = "uint8";
else if (Dimension < 65536)
StorageType = "uint16";
else
StorageType = "uint32";
CppType = "uint32";
return true;
}
bool CDimensionNode::epilog()
{
return true;
}
bool CDimensionNode::generateContent()
{
hOutput() << "/** " << Name << "\n";
if (!Description.empty())
{
hOutput() << Description << "\n";
}
uint line, col;
string file;
getFileLine(line, col, file);
hOutput() << "defined at " << file << ":" << line << "\n";
hOutput() << "*/\n";
hOutput() << "typedef " << CppType << " " << Name << ";\n";
hOutput() << "const " << getName() << "\t" << getSizeName() << " = " << Dimension << ";\n\n";
return true;
}
// Enum Nodes
bool CEnumNode::prolog()
{
CDbNode* db = getDbNode();
db->TypeNodes.push_back(this);
if (Name.empty() || Name[0] != 'T')
error("enum name '"+Name+"' is invalid, must begin with a 'T'");
CurrentValue = 0;
CurrentEnum = Name;
CurrentEnumNode = this;
MinValue = 0;
MaxValue = 0;
return true;
}
bool CEnumNode::epilog()
{
uint i;
for (i=0; i<Nodes.size(); ++i)
{
CEnumNode *nd = dynamic_cast<CEnumNode*>(Nodes[i]);
if (!nd)
continue;
Values.insert(Values.end(), nd->Values.begin(), nd->Values.end());
}
for (i=0; i<Values.size(); ++i)
{
if (MinValue > Values[i].second)
MinValue = Values[i].second;
if (MaxValue < Values[i].second)
MaxValue = Values[i].second;
}
CurrentEnumNode = NULL;
return true;
}
bool CEnumSimpleValueNode::prolog()
{
CEnumNode *parent = dynamic_cast<CEnumNode*>(Parent);
if (parent != NULL)
{
CurrentValue = parent->CurrentValue;
}
else
{
CurrentValue = 0;
}
uint i;
for (i=0; i<Names.size(); ++i)
{
CurrentEnumNode->Values.push_back(make_pair<string, uint32>(Names[i], CurrentValue));
}
if (parent != NULL)
++(parent->CurrentValue);
return true;
}
bool CEnumSimpleValueNode::epilog()
{
return true;
}
bool CEnumRangeNode::prolog()
{
CEnumNode *parent = dynamic_cast<CEnumNode*>(Parent);
if (parent != NULL)
{
CurrentValue = parent->CurrentValue;
}
else
{
CurrentValue = 0;
}
CurrentEnumNode->Values.push_back(make_pair<string, uint32>(Name, CurrentValue));
return true;
}
bool CEnumRangeNode::epilog()
{
CEnumNode *parent = dynamic_cast<CEnumNode*>(Parent);
if (parent != NULL)
{
parent->CurrentValue = CurrentValue;
}
uint i;
for (i=0; i<Nodes.size(); ++i)
{
CEnumNode *nd = dynamic_cast<CEnumNode*>(Nodes[i]);
if (!nd)
continue;
Values.insert(Values.end(), nd->Values.begin(), nd->Values.end());
}
if (!EndRange.empty())
{
CurrentEnumNode->Values.push_back(make_pair<string, uint32>(EndRange, CurrentValue));
}
return true;
}
bool CEnumNode::generateContent()
{
hOutput() << "/** " << Name << "\n";
if (!Description.empty())
{
hOutput() << Description << "\n";
}
uint line, col;
string file;
getFileLine(line, col, file);
hOutput() << "defined at " << file << ":" << line << "\n";
hOutput() << "*/\n";
string enumTruncName = Name.substr(1);
CClassGenerator gen;
gen.init("C"+enumTruncName);
gen.createPublic("enum", "Enum values", "");
gen.createPublic("conv", "Conversion methods", "Use these methods to convert from enum value to string (and vice versa)");
gen.createPrivate("init", "Enum initialisation", "");
uint j;
gen.addOther("enum "+Name+"\n", "enum");
gen.addOther("{\n", "enum");
for (j=0; j<Values.size(); ++j)
gen.addOther(Values[j].first+" = "+toString(Values[j].second)+",\n", "enum");
gen.addOther(getUnscopedUseSize()+" = "+toString(MaxValue-MinValue+1)+",\n", "enum");
gen.addOther(getUnknownValue()+" = "+toString(MaxValue-MinValue+1)+",\n", "enum");
if (!EndRange.empty())
gen.addOther(EndRange+" = "+toString(MaxValue-MinValue+1)+",\n", "enum");
gen.addOther("};\n", "enum");
gen.startMethod("const std::string&", "toString", Name+" v", "conv", false, true, true);
gen.add("if (v < 0 || v >= "+getUnscopedUseSize()+")");
gen.add("{");
gen.add("nlwarning(\""+Name+"::toString(): value '%u' is not matched, \\\"Unknown\\\" string returned\", v);");
gen.add("return _UnknownString;");
gen.add("}");
//gen.add(checkCode("v"));
gen.add("if (!_Initialised)");
gen.add("{");
gen.add("init();");
gen.add("}");
gen.add("return _StrTable[v];");
gen.startMethod(getName(), "fromString", "const std::string& v", "conv", false, true, true);
gen.add("if (!_Initialised)");
gen.add("{");
gen.add("init();");
gen.add("}");
gen.add("if(v==_UnknownString)");
gen.add("{");
gen.add("return Unknown;");
gen.add("}");
gen.add("const std::map<std::string, "+Name+">::const_iterator\tit = _ValueMap.find(NLMISC::toLower(v));");
gen.add("if (it == _ValueMap.end())");
gen.add("{");
gen.add("nlwarning(\""+Name+"::toString(): string '%s' is not matched, 'Unknown' enum value returned\", v.c_str());");
gen.add("return "+getUnknownValue()+";");
gen.add("}");
gen.add("return (*it).second;");
gen.startMethod("void", "init", "", "init", false, false, true);
gen.add("_StrTable.clear();");
gen.add("_ValueMap.clear();");
gen.add("_StrTable.resize("+toString(getSize()+1)+");");
gen.add("uint\ti;");
gen.add("for (i=0; i<"+toString(Values.size())+"; ++i)");
gen.add("{");
gen.add("_StrTable["+Name+"Convert[i].Value] = "+Name+"Convert[i].Name;");
gen.add("_ValueMap[NLMISC::toLower(std::string("+Name+"Convert[i].Name))] = "+Name+"Convert[i].Value;");
gen.add("}");
gen.add("_Initialised = true;");
gen.addAttribute("bool", "_Initialised", "init", true, "false");
gen.addAttribute("std::string", "_UnknownString", "init", true, "\""+getUnknownValue()+"\"");
gen.addAttribute("std::vector<std::string>", "_StrTable", "init", true);
gen.addAttribute("std::map<std::string, "+Name+">", "_ValueMap", "init", true, "", false, "std::map<std::string, "+getName()+">");
cppOutput() << "static const struct { char* Name; " << getName() << " Value; } " << Name << "Convert[] =\n";
cppOutput() << "{\n";
for (j=0; j<Values.size(); ++j)
cppOutput() << "{ \"" << Values[j].first << "\", C"+enumTruncName+"::"+Values[j].first+" },\n";
cppOutput() << "};\n";
gen.flush(hOutput(), cppOutput(), inlineOutput());
return true;
}
// Class Node
bool CClassNode::prolog()
{
CDbNode* db = getDbNode();
db->ClassNodes.push_back(this);
return true;
}
bool CClassNode::epilog()
{
return true;
}
string CClassNode::getUserCode(const string& name)
{
uint i;
for (i=0; i<Nodes.size(); ++i)
{
CCppCodeNode *code = dynamic_cast<CCppCodeNode*>(Nodes[i]);
if (!code)
continue;
if (code->Name == name)
return code->RawCode;
}
return "";
}
void CClassNode::checkClassReferences()
{
if (!Implements.empty())
{
Gen.Inherit += (HasRowAccess ? string(", ") : string(""))+"public "+Implements;
getDbNode()->Implemented.insert(Implements);
}
if (!Inherited.empty())
{
HasInheritance = true;
CClassNode *nd = getClassNode(Inherited);
nd->HasInheritance = true;
nd->ChildrenClasses.push_back(Name);
Dependencies.insert(nd);
getFileNode()->Dependencies.insert(nd->getFileNode());
}
CClassNode* inherit = this;
while (inherit != NULL)
{
if (MappedFlag)
inherit->PDSMapped = true;
inherit->Legacy.insert(this);
inherit = getClassNode(inherit->Inherited, false);
}
uint i;
uint id = 0;
for (i=0; i<Nodes.size(); ++i)
{
CDeclarationNode *decl = dynamic_cast<CDeclarationNode*>(Nodes[i]);
if (!decl)
continue;
decl->Id = id++;
if (decl->ParentFlag)
{
if (HasParent)
decl->error("class '"+Name+"' already has a parent");
//if (MappedFlag)
// decl->error("class '"+Name+"' can't have a parent and be mapped at the same time");
CClassNode* inherit = this;
while (inherit != NULL)
{
inherit->PDSMapped = false;
inherit = getClassNode(inherit->Inherited, false);
}
ParentClass = decl->ParentClass;
HasParent = true;
ParentIsHidden = decl->HiddenFlag;
decl->getClassNode(decl->ParentClass)->IsBackReferenced = true;
}
else if (decl->SetFlag)
{
decl->getClassNode(decl->Type)->IsInSet = true;
}
}
}
void CClassNode::fillAttributes()
{
if (HasParent && !IsBackReferenced && !HasInheritance && !IsInSet && !DerivatedFlag && !MappedFlag)
error("class '"+Name+"' has a parent whereas it is not backreferenced, has no inherited link and is not mapped");
uint i;
for (i=0; i<Nodes.size(); ++i)
{
CDeclarationNode *decl = dynamic_cast<CDeclarationNode*>(Nodes[i]);
if (!decl)
continue;
uint j;
for (j=0; j<Nodes.size(); ++j)
if (j != i && dynamic_cast<CDeclarationNode*>(Nodes[j]) != NULL && Nodes[j]->Name == decl->Name)
decl->error("attribute '"+decl->Name+"' already defined");
if (decl->ParentFlag)
{
decl->DeclarationType = BackRef;
}
else if (decl->ArrayFlag)
{
CClassNode *classNd = NULL;
CTypeNode *typeNd = NULL;
if ( (classNd = decl->getClassNode(decl->Type, false)) )
{
if (classNd->IsBackReferenced || classNd->ForceReference)
{
if (decl->ForwardRefAttribute.empty())
decl->error("no forward reference to parent in array declaration, class '"+decl->Type+"' is backref'd or has inheritance");
classNd->IsInArrayRef = true;
decl->IsRef = true;
decl->DeclarationType = ArrayRef;
if (classNd->ParentIsHidden)
Dependencies.insert(classNd);
}
else
{
if (!decl->ForwardRefAttribute.empty())
decl->error("forward reference declared whereas subclass is not backreferenced and has no inheritance link");
Dependencies.insert(classNd);
classNd->IsInArray = true;
decl->IsRef = false;
decl->DeclarationType = ArrayClass;
}
}
else if ( (typeNd = decl->getTypeNode(decl->Type, false)) )
{
decl->DeclarationType = ArrayType;
}
else
{
decl->error("type or class '"+decl->Type+"' not found");
}
}
else if (decl->SetFlag)
{
decl->IsRef = true;
decl->DeclarationType = Set;
}
else
{
CClassNode *classNd = NULL;
CTypeNode *typeNd = NULL;
if ( (classNd = decl->getClassNode(decl->Type, false)) )
{
if (classNd->IsBackReferenced || classNd->ForceReference)
{
if (decl->ForwardRefAttribute.empty())
decl->error("no forward reference to parent in array declaration, class '"+decl->Type+"' is backref'd or has inheritance");
decl->IsRef = true;
decl->DeclarationType = ForwardRef;
}
else
{
if (!decl->ForwardRefAttribute.empty())
decl->error("forward reference declared whereas subclass is not backreferenced and has no inheritance link");
Dependencies.insert(classNd);
decl->IsRef = false;
decl->DeclarationType = SimpleClass;
}
}
else if ( (typeNd = decl->getTypeNode(decl->Type, false)) )
{
decl->IsType = true;
decl->DeclarationType = SimpleType;
}
else
{
decl->error("type or class '"+decl->Type+"' not found");
}
}
}
CDeclarationNode *declNd = getClassKey();
if (declNd != NULL)
{
if (!declNd->IsType)
error("attribute '"+declNd->Name+"' can't be a key, only simple type allowed");
declNd->IsKey = true;
}
}
void CClassNode::fillRefs()
{
uint i;
for (i=0; i<Nodes.size(); ++i)
{
CDeclarationNode *decl = dynamic_cast<CDeclarationNode*>(Nodes[i]);
if (!decl)
continue;
switch (decl->DeclarationType)
{
case BackRef:
{
// check parent is a valid class
CClassNode *cln = decl->getClassNode(decl->ParentClass);
CDeclarationNode *dln = dynamic_cast<CDeclarationNode*>(cln->getNode(decl->ParentField));
if (!dln) decl->error("attribute '"+decl->ParentField+"' not found in class '"+decl->ParentClass+"'");
if (!dln->ArrayFlag && !dln->SetFlag && !ForceReference)
decl->error("back reference 'parent "+decl->ParentClass+":"+decl->ParentField+" "+decl->Name+"' is not forwarded in class '"+decl->ParentClass+"' with an array or a set");
if (dln->Type != Name || dln->ForwardRefAttribute != decl->Name)
decl->error("back reference 'parent "+decl->ParentClass+":"+decl->ParentField+" "+decl->Name+"' is not correctly forwarded in class '"+decl->ParentClass+"'");
Friends.insert(cln->Name);
}
break;
case Set:
{
CClassNode *cln = decl->getClassNode(decl->Type);
CDeclarationNode *dln = dynamic_cast<CDeclarationNode*>(cln->getNode(decl->ForwardRefAttribute));
if (!dln) decl->error("attribute '"+decl->ForwardRefAttribute+"' not found in class '"+decl->Type+"'");
if (!dln->ParentFlag)
decl->error("set '"+decl->Type+":"+decl->ForwardRefAttribute+"<> "+decl->Name+"' is not backref'd in class '"+decl->Type+"'");
if (dln->ParentClass != Name || dln->ParentField != decl->Name)
decl->error("set '"+decl->Type+":"+decl->ForwardRefAttribute+"<> "+decl->Name+"' is not correctly backref'd in class '"+decl->Type+"'");
if (cln->getClassKey() == NULL)
decl->error("class '"+decl->Type+"' has no key defined, whereas it is used in a set");
cln->Friends.insert(Name);
ForwardFriends.insert(cln->Name);
}
break;
case ArrayRef:
{
if (decl->ForwardRefAttribute.empty())
decl->error("No forward reference defined");
CClassNode *cln = decl->getClassNode(decl->Type);
CDeclarationNode *dln = dynamic_cast<CDeclarationNode*>(cln->getNode(decl->ForwardRefAttribute));
CTypeNode *tln = decl->getTypeNode(decl->ArrayIndex);
getFileNode()->Dependencies.insert(tln->getFileNode());
if (!dln) decl->error("attribute '"+decl->ForwardRefAttribute+"' not found in class '"+decl->Type+"'");
if (!dln->ParentFlag)
decl->error("array '"+decl->Type+":"+decl->ForwardRefAttribute+"["+decl->ArrayIndex+"] "+decl->Name+"' is not backref'd in class '"+decl->Type+"'");
if (dln->ParentClass != Name || dln->ParentField != decl->Name)
decl->error("array '"+decl->Type+":"+decl->ForwardRefAttribute+"["+decl->ArrayIndex+"] "+decl->Name+"' is not correctly backref'd in class '"+decl->Type+"'");
if (cln->getClassKey() == NULL)
decl->error("class '"+decl->Type+"' has no key defined, whereas it is used in an array of ref");
CDeclarationNode *kdn = dynamic_cast<CDeclarationNode*>(cln->getClassKey());
if (!kdn) decl->error("attribute '"+cln->ClassKey+"' not found in class '"+cln->Name+"'");
if (kdn->Type != decl->ArrayIndex)
decl->error("type in array definition mismatch class '"+cln->Name+"' key definition");
cln->Friends.insert(Name);
ForwardFriends.insert(cln->Name);
}
break;
case ForwardRef:
{
if (decl->ForwardRefAttribute.empty())
decl->error("No forward reference defined");
CClassNode *cln = decl->getClassNode(decl->Type);
CDeclarationNode *dln = dynamic_cast<CDeclarationNode*>(cln->getNode(decl->ForwardRefAttribute));
if (!dln) decl->error("attribute '"+decl->ForwardRefAttribute+"' not found in class '"+decl->Type+"'");
if (!dln->ParentFlag)
decl->error("set '"+decl->Type+":"+decl->ForwardRefAttribute+"<> "+decl->Name+"' is not backref'd in class '"+decl->Type+"'");
if (dln->ParentClass != Name || dln->ParentField != decl->Name)
decl->error("set '"+decl->Type+":"+decl->ForwardRefAttribute+"<> "+decl->Name+"' is not correctly backref'd in class '"+decl->Type+"'");
cln->Friends.insert(Name);
ForwardFriends.insert(cln->Name);
}
break;
case ArrayType:
{
CTypeNode *tln = decl->getTypeNode(decl->ArrayIndex);
getFileNode()->Dependencies.insert(tln->getFileNode());
}
case SimpleType:
break;
case ArrayClass:
{
CTypeNode *tln = decl->getTypeNode(decl->ArrayIndex);
getFileNode()->Dependencies.insert(tln->getFileNode());
}
case SimpleClass:
{
CClassNode *cln = decl->getClassNode(decl->Type);
cln->Friends.insert(Name);
}
break;
default:
decl->error("Can't decide declaration type");
break;
}
}
}
void CClassNode::computeFriends()
{
bool added;
do
{
added = false;
set<string>::iterator itf, itsf;
for (itf=Friends.begin(); !added && itf!=Friends.end(); ++itf)
{
CClassNode* pfriend = getClassNode(*itf);
for (itsf=pfriend->Friends.begin(); !added && itsf!=pfriend->Friends.end(); ++itsf)
{
const string& sfriend = *itsf;
if (Friends.find(*itsf) == Friends.end())
{
Friends.insert(*itsf);
added = true;
}
}
}
}
while (added);
}
void CClassNode::checkDependencies(set<CClassNode*> &beingChecked,
set<CClassNode*> &checkedClasses,
vector<CClassNode*> &classesOrder)
{
if (beingChecked.find(this) != beingChecked.end())
error("circular dependency in class '"+Name+"'");
if (checkedClasses.find(this) != checkedClasses.end())
return;
beingChecked.insert(this);
checkedClasses.insert(this);
set<CClassNode*>::iterator it;
for (it=Dependencies.begin(); it!=Dependencies.end(); ++it)
{
CClassNode *classNode = *it;
classNode->checkDependencies(beingChecked, checkedClasses, classesOrder);
}
classesOrder.push_back(this);
}
//
void CClassNode::buildInit()
{
CDbNode *db = getDbNode();
if (!Init.empty())
return;
if (!Inherited.empty())
{
CClassNode *mother = getClassNode(Inherited);
if (mother)
{
mother->buildInit();
Init = mother->Init;
uint i;
for (i=0; i<Init.size(); ++i)
{
if (!InitProto.empty())
InitProto += ", ";
if (!InitCallArgs.empty())
InitCallArgs += ", ";
CTypeNode* typeNode = getTypeNode(Init[i]->Type);
InitProto += "const "+typeNode->getName()+" &"+Init[i]->Name;
InitCallArgs += Init[i]->Name;
}
}
}
if (!ClassKey.empty())
{
CDeclarationNode *decl = dynamic_cast<CDeclarationNode*>(getNode(ClassKey));
if (decl)
{
Init.push_back(decl);
if (!InitProto.empty())
InitProto += ", ";
CTypeNode* typeNode = getTypeNode(decl->Type);
InitProto += "const "+typeNode->getName()+" &"+decl->Name;
}
}
}
void CClassNode::computeAttributesColumns()
{
if (Columns >= 0)
return;
CDbNode *db = getDbNode();
Columns = 0;
if (!Inherited.empty())
{
CClassNode *mother = getClassNode(Inherited);
mother->computeAttributesColumns();
Columns = mother->Columns;
Attributes = mother->Attributes;
}
uint attribId = (uint)Attributes.size();
uint i;
for (i=0; i<Nodes.size(); ++i)
{
CDeclarationNode *decl = dynamic_cast<CDeclarationNode*>(Nodes[i]);
if (decl == NULL)
continue;
Attributes.push_back(decl);
decl->Column = Columns;
decl->Id = attribId++;
CColumn col;
// All for backref, set, forwardref, type
switch (decl->DeclarationType)
{
case ForwardRef:
decl->Columns = 1;
col.Name = decl->Name;
col.Type = ForwardRef;
col.TypeStr = "forwardref";
col.TypeId = decl->getClassNode(decl->Type)->Id;
col.ByteSize = 8;
decl->ColumnList.push_back(col);
break;
case BackRef:
decl->Columns = 1;
col.Name = decl->Name;
col.Type = BackRef;
col.TypeStr = "backref";
col.TypeId = decl->getClassNode(decl->ParentClass)->Id;
col.ByteSize = 8;
decl->ColumnList.push_back(col);
break;
case SimpleType:
decl->Columns = 1;
col.Name = decl->Name;
col.Type = SimpleType;
col.TypeStr = "type";
col.TypeId = decl->getTypeNode(decl->Type)->Id;
col.ByteSize = decl->getTypeNode(decl->Type)->Size;
decl->ColumnList.push_back(col);
break;
case Set:
decl->Columns = 1;
col.Name = decl->Name;
col.Type = Set;
col.TypeStr = "set";
col.TypeId = decl->getClassNode(decl->Type)->Id;
col.ByteSize = 4;
decl->ColumnList.push_back(col);
break;
case SimpleClass:
{
CClassNode *sub = decl->getClassNode(decl->Type);
sub->computeAttributesColumns();
decl->Columns = sub->Columns;
uint i, j;
for (i=0; i<sub->Attributes.size(); ++i)
{
CDeclarationNode *attrib = sub->Attributes[i];
for (j=0; j<attrib->ColumnList.size(); ++j)
{
col.Name = decl->Name+"."+attrib->ColumnList[j].Name;
col.Type = attrib->ColumnList[j].Type;
col.TypeStr = attrib->ColumnList[j].TypeStr;
col.TypeId = attrib->ColumnList[j].TypeId;
col.ByteSize = attrib->ColumnList[j].ByteSize;
decl->ColumnList.push_back(col);
}
}
}
break;
case ArrayRef:
{
CIndexNode *indexNd = decl->getIndexNode(decl->ArrayIndex);
uint numInEnum = indexNd->getSize();
decl->Columns = numInEnum;
uint i;
for (i=0; i<numInEnum; ++i)
{
col.Name = decl->Name+"["+indexNd->getIndexName(i)+"]";
col.Type = ForwardRef;
col.TypeStr = "forwardref";
col.TypeId = decl->getClassNode(decl->Type)->Id;
col.ByteSize = 8;
decl->ColumnList.push_back(col);
}
}
break;
case ArrayType:
{
CIndexNode *indexNd = decl->getIndexNode(decl->ArrayIndex);
uint numInEnum = indexNd->getSize();
decl->Columns = numInEnum;
uint i;
for (i=0; i<numInEnum; ++i)
{
col.Name = decl->Name+"["+indexNd->getIndexName(i)+"]";
col.Type = SimpleType;
col.TypeStr = "type";
col.TypeId = decl->getTypeNode(decl->Type)->Id;
col.ByteSize = decl->getTypeNode(decl->Type)->Size;
decl->ColumnList.push_back(col);
}
}
break;
case ArrayClass:
{
CIndexNode *indexNd = decl->getIndexNode(decl->ArrayIndex);
CClassNode *sub = decl->getClassNode(decl->Type);
sub->computeAttributesColumns();
uint numInEnum = indexNd->getSize();
decl->Columns = numInEnum*sub->Columns;
uint i, j, k;
for (k=0; k<numInEnum; ++k)
{
for (i=0; i<sub->Attributes.size(); ++i)
{
CDeclarationNode *attrib = sub->Attributes[i];
for (j=0; j<attrib->ColumnList.size(); ++j)
{
col.Name = decl->Name+"["+indexNd->getIndexName(k)+"]."+attrib->ColumnList[j].Name;
col.Type = attrib->ColumnList[j].Type;
col.TypeStr = attrib->ColumnList[j].TypeStr;
col.TypeId = attrib->ColumnList[j].TypeId;
col.ByteSize = attrib->ColumnList[j].ByteSize;
decl->ColumnList.push_back(col);
}
}
}
}
break;
}
Columns += decl->Columns;
}
}
bool CClassNode::generateContent()
{
nlassert(Env != NULL);
uint line, col;
string file;
getFileLine(line, col, file);
setEnv("name", Name);
if (!Description.empty())
setEnv("description", Description);
setEnv("deffile", file);
setEnv("defline", line);
computeAttributesColumns();
uint j;
//
// generate description
//
hOutput() << "/** " << Name << "\n";
if (!Description.empty())
hOutput() << Description << "\n";
hOutput() << "defined at " << file << ":" << line << "\n";
hOutput() << "*/\n";
CCppOutput& DbSummary = getDbNode()->DbSummary;
DbSummary << "Class " << getDbNode()->Name << "::" << Name << ":\n";
DbSummary << "----------------------------------------------------------\n";
DbSummary << "located in file \"" << getFullStdPathNoExt(getFileNode()->Name) << ".h\"\n";
DbSummary << "defined in file \"" << getFullStdPath(file) << "\"\n";
DbSummary << "The class contains:\n\n";
Gen.init(Name);
Gen.createPublic("methods", "Accessors and Mutators methods", "Use these methods to change a value, add or delete elements.");
Gen.createPublic("map", "Public Management methods", "Use these methods to create, load, unload and get\nan object from database.");
Gen.createPublic("user", "User defined attributes and methods", "This code was verbatim copied from source file");
Gen.createPublic("construct", "Public constructor", "This constructor is public to allow direct instanciation of the class");
Gen.createPublic("persist", "Persistent methods declaration", "");
Gen.createProtected("userinit", "User defined init and release methods", "Overload those methods to implement init and release behaviours");
Gen.createProtected("attributes", "Attributes", "Don't modify those value manually, use accessors and mutators above");
Gen.createProtected("internal", "Internal Management methods");
Gen.createProtected("inherit map");
Gen.createProtected("factories", "Default Factory and Fetch methods");
Gen.createProtected("friends");
// EGS Compat
// -- begin
Gen.startRaw("persist", false);
ApplyId = Gen.startMethod("void", applyFunction, "CPersistentDataRecord &__pdr", "persist", false, inlineInternal, false, false, "", HasInheritance);
StoreId = Gen.startMethod("void", storeFunction, "CPersistentDataRecord &__pdr", "persist", true, inlineInternal, false, false, "", HasInheritance);
ClearId = Gen.startMethod("void", clearFunction, "", "map", false, inlineStaticPublic, false, false, "", HasInheritance);
Gen.setDescription("Clear whole object content but key (delete subobjects if there are, key is left unmodified), default clear value is 0.");
StoreId.add("uint16\t__Tok_MapKey = __pdr.addString(\"__Key__\");");
StoreId.add("uint16\t__Tok_MapVal = __pdr.addString(\"__Val__\");");
StoreId.add("uint16\t__Tok_ClassName = __pdr.addString(\"__Class__\");");
ApplyId.add("uint16\t__Tok_MapKey = __pdr.addString(\"__Key__\");");
ApplyId.add("uint16\t__Tok_MapVal = __pdr.addString(\"__Val__\");");
ApplyId.add("uint16\t__Tok_ClassName = __pdr.addString(\"__Class__\");");
if (!Inherited.empty())
{
StoreId.add("uint16\t__Tok_Parent = __pdr.addString(\"__Parent__\");");
ApplyId.add("uint16\t__Tok_Parent = __pdr.addString(\"__Parent__\");");
}
for (j=0; j<Attributes.size(); ++j)
{
CDeclarationNode* decl = Attributes[j];
if (decl->Parent != this)
continue;
if (decl->DeclarationType == BackRef)
{
ApplyId.add(decl->cppName()+" = NULL;");
}
else
{
StoreId.add("uint16\t"+decl->tokenName()+" = __pdr.addString(\""+decl->Name+"\");");
ApplyId.add("uint16\t"+decl->tokenName()+" = __pdr.addString(\""+decl->Name+"\");");
}
}
ApplyId.add("while (!__pdr.isEndOfStruct())");
ApplyId.add("{");
ApplyId.add( "if (false) {}");
if (!Inherited.empty())
{
StoreId.add("__pdr.pushStructBegin(__Tok_Parent);");
StoreId.add(Inherited+"::store(__pdr);");
StoreId.add("__pdr.pushStructEnd(__Tok_Parent);");
ApplyId.add("else if (__pdr.peekNextToken() == __Tok_Parent)");
ApplyId.add("{");
ApplyId.add( "__pdr.popStructBegin(__Tok_Parent);");
ApplyId.add( Inherited+"::apply(__pdr);");
ApplyId.add( "__pdr.popStructEnd(__Tok_Parent);");
ApplyId.add("}");
}
// -- end
for (j=0; j<Nodes.size(); ++j)
{
CCppCodeNode* cpp = dynamic_cast<CCppCodeNode*>(Nodes[j]);
if (cpp == NULL || !cpp->Name.empty())
continue;
Gen.addOther(cpp->RawCode, "user");
}
HasRowAccess = false;
HasTableAccess = false;
if (!Inherited.empty())
{
setEnv("inherit", Inherited);
setEnv("inheritclass", Inherited);
Gen.Inherit += "public "+Inherited;
HasRowAccess = true;
HasTableAccess = true;
}
else if (HasInheritance || IsBackReferenced || IsInSet || ForceReference)
{
setEnv("inherit", pdBaseDataName);
Gen.Inherit += "public "+pdBaseDataName;
HasTableAccess = true;
HasRowAccess = true;
}
if (Legacy.size() > 1 && HasTableAccess)
{
CClassGenerator::SMethodId castId = Gen.startMethod(Name+"*", staticCastFunction, pdBaseDataName+"* obj", "map", false, inlineStaticPublic, true, false, "", false, false);
Gen.setDescription("Cast base object to "+Name);
castId.add("switch (obj->getTable())");
castId.add("{");
std::set<CClassNode*>::iterator itl;
for (itl=Legacy.begin(); itl!=Legacy.end(); ++itl)
{
CClassNode* child = (*itl);
castId.add("case "+toString(child->Id)+":");
}
castId.add("return static_cast<"+Name+"*>(obj);");
castId.add("}");
castId.add("return NULL;");
CClassGenerator::SMethodId constCastId = Gen.startMethod("const "+Name+"*", staticConstCastFunction, "const "+pdBaseDataName+"* obj", "map", false, inlineStaticPublic, true, false, "", false, false);
Gen.setDescription("Cast base object to const "+Name);
constCastId.add("switch (obj->getTable())");
constCastId.add("{");
for (itl=Legacy.begin(); itl!=Legacy.end(); ++itl)
{
CClassNode* child = (*itl);
constCastId.add("case "+toString(child->Id)+":");
}
constCastId.add("return static_cast<const "+Name+"*>(obj);");
constCastId.add("}");
constCastId.add("return NULL;");
}
else if (Legacy.size() == 1 && HasTableAccess)
{
CClassGenerator::SMethodId castId = Gen.startMethod(Name+"*", staticCastFunction, pdBaseDataName+"* obj", "map", false, inlineStaticPublic, true, false, "", false, false);
std::set<CClassNode*>::iterator itl = Legacy.begin();
Gen.setDescription("Cast base object to "+Name);
castId.add("return (obj->getTable() == "+toString((*itl)->Id)+") ? static_cast<"+Name+"*>(obj) : NULL;");
CClassGenerator::SMethodId constCastId = Gen.startMethod("const "+Name+"*", staticConstCastFunction, "const "+pdBaseDataName+"* obj", "map", false, inlineStaticPublic, true, false, "", false, false);
Gen.setDescription("Cast base object to const "+Name);
constCastId.add("return (obj->getTable() == "+toString((*itl)->Id)+") ? static_cast<const "+Name+"*>(obj) : NULL;");
}
else
{
}
if (HasRowAccess)
define("hasrowaccess");
if (HasTableAccess)
define("hastableaccess");
if (!Implements.empty())
{
setEnv("implements", Implements);
Gen.Inherit += (HasRowAccess ? string(", ") : string(""))+"public "+Implements;
}
//
// generate init method
//
buildInit();
setEnv("initproto", InitProto);
InitId = Gen.startMethod("void", initFunction, InitProto, "internal", false, inlineInternal, false, false, "", HasInheritance);
if (!Inherited.empty())
{
InitId.add(Inherited + "::" + initFunction + "(" + InitCallArgs + ");");
setEnv("initcallargs", InitCallArgs);
}
DestroyId = Gen.startMethod("void", destroyFunction, "", "internal", false, inlineInternal, false, false, "", HasInheritance);
FetchId = Gen.startMethod("void", fetchFunction, CPDataName+" &data", "internal", false, inlineInternal, false, false, "", HasInheritance);
RegisterId = Gen.startMethod("void", registerFunction, "", "internal", false, inlineInternal, false, false, "", HasInheritance);
RegisterAttributesId = Gen.startMethod("void", registerAttributesFunction, "", "internal", false, inlineInternal, false, false, "", HasInheritance);
UnregisterId = Gen.startMethod("void", unregisterFunction, "", "internal", false, inlineInternal, false, false, "", HasInheritance);
UnregisterAttributesId = Gen.startMethod("void", unregisterAttributesFunction, "", "internal", false, inlineInternal, false, false, "", HasInheritance);
SetParentId;
SetUnnotifiedParentId;
if (HasParent)
{
SetParentId = Gen.startMethod("void", setParentFunction, ParentClass+"* __parent", "internal", false, inlineInternal);
SetUnnotifiedParentId = Gen.startMethod("void", setUnnotifiedParentFunction, ParentClass+"* __parent", "internal", false, inlineInternal);
}
if (HasRowAccess && GenerateDebugMessages)
{
DestroyId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": destroy %u:%u\", "+getId()+", __BaseRow);");
FetchId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": fetch %u:%u\", "+getId()+", __BaseRow);");
}
if (!Inherited.empty())
{
FetchId.add(Inherited+"::"+fetchFunction+"(data);");
}
if (DerivatedFlag)
{
UserInitId = Gen.startMethod("void", userInitFunction, "", "userinit", false, inlineUserInitDefaultCode, false, false, "", true);
UserReleaseId = Gen.startMethod("void", userReleaseFunction, "", "userinit", false, inlineUserInitDefaultCode, false, false, "", true);
}
NotifyInitId = Gen.startMethod("void", notifyInitFunction, "", "internal", false, inlineInternal, false, false, "", HasInheritance);
string initUCode = getUserCode("onInit");
if (!Inherited.empty())
Gen.add(Inherited+"::"+notifyInitFunction+"();");
if (DerivatedFlag)
Gen.add(userInitFunction+"();");
if (!initUCode.empty())
{
Gen.add("{");
uint line, col;
string file;
getFileLine(line, col, file);
Gen.add("// "+Name+" init user code, defined at "+file+":"+toString(line));
Gen.add(initUCode);
Gen.add("}");
}
NotifyReleaseId = Gen.startMethod("void", notifyReleaseFunction, "", "internal", false, inlineInternal, false, false, "", HasInheritance);
string releaseUCode = getUserCode("onRelease");
if (!releaseUCode.empty())
{
Gen.add("{");
uint line, col;
string file;
getFileLine(line, col, file);
Gen.add("// "+Name+" release user code, defined at "+file+":"+toString(line));
Gen.add(releaseUCode);
Gen.add("}");
}
if (DerivatedFlag)
Gen.add(userReleaseFunction+"();");
if (!Inherited.empty())
Gen.add(Inherited+"::"+notifyReleaseFunction+"();");
else if (HasRowAccess)
Gen.add(pdslibFunc("release")+"("+getId()+", __BaseRow);");
if (!Inherited.empty())
{
DestroyId.add(Inherited+"::"+destroyFunction+"();");
ClearId.add(Inherited+"::"+clearFunction+"();");
}
//
// Generate XML description
//
string xmlnode;
xmlnode += "<classdef";
xmlnode += " name='"+Name+"'";
xmlnode += " id='"+toString(Id)+"'";
if (!Inherited.empty())
{
CClassNode *inh = getClassNode(Inherited);
xmlnode += " inherit='"+toString(inh->Id)+"'";
}
CDeclarationNode *dln = getClassKey();
if (dln != NULL)
{
xmlnode += " key='"+toString(dln->Id)+"'";
}
if (MapClass && !MapClass->HasParent)
{
xmlnode += " mapped='"+toString(MapClass->Id)+"'";
}
if (HasRowAccess)
{
/*
if (!Reserve.empty())
{
xmlnode += " allocate='"+(Reserve)+"'";
}
else
{
xmlnode += " allocate='10000'";
}
*/
}
xmlnode += " columns='"+toString(Columns)+"'";
xmlnode += ">";
getDbNode()->xmlDescription.push_back(xmlnode);
indexUsedInInit = false;
indexUsedInDestroy = false;
indexUsedInFetch = false;
tableAndRowIndicesUsedInFetch = false;
indexUsedInRegister = false;
indexUsedInUnregister = false;
// generate code for init of new index
if (HasRowAccess)
{
RegisterId.add("__BaseRow = _IndexAllocator.allocate();");
if (GenerateDebugMessages)
{
if (MapClass != NULL)
{
CDeclarationNode* key = MapClass->getKey();
RegisterId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": register %u:%u, key="+key->displayPrintfPrefix()+"\", "+getId()+", __BaseRow, "+key->displayCppCode()+");");
}
else
{
RegisterId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": register %u:%u\", "+getId()+", __BaseRow);");
}
}
string oeid;
if (useEntityId())
{
oeid = ", "+getClassKey()->cppName();
}
RegisterId.add(pdslibFunc("allocateRow")+"("+getId()+", __BaseRow, "+(PDSMapped ? MapClass->getKey()->toUint64() : "0")+oeid+");");
RegisterId.add(registerAttributesFunction + "();");
RegisterAttributesId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": registerAttributes %u:%u\", "+getId()+", __BaseRow);");
// send key to the pds (if key exists)
if (!ClassKey.empty())
{
CDeclarationNode *keyNode = getKey();
CTypeNode *keyTypeNode = getTypeNode(keyNode->Type);
///// TYPE CAST
RegisterAttributesId.add(pdslibFunc("set")+"("+getId()+", __BaseRow, ("+TColumnIndexName+")("+toString(keyNode->Column)+"), "+keyTypeNode->castToPDS(getKey()->cppName())+");");
}
if (!Inherited.empty())
{
RegisterAttributesId.add(Inherited + "::" + registerAttributesFunction + "();");
}
UnregisterAttributesId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": unregisterAttributes %u:%u\", "+getId()+", __BaseRow);");
if (!Inherited.empty())
{
UnregisterAttributesId.add(Inherited + "::" + unregisterAttributesFunction + "();");
}
if (HasParent)
{
UnregisterAttributesId.add(setParentFunction+"(NULL);");
}
if (GenerateDebugMessages)
{
if (MapClass != NULL)
{
CDeclarationNode* key = MapClass->getKey();
UnregisterId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": unregister %u:%u, key="+key->displayPrintfPrefix()+"\", "+getId()+", __BaseRow, "+key->displayCppCode()+");");
}
else
UnregisterId.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": unregister %u:%u\", "+getId()+", __BaseRow);");
}
UnregisterId.add(unregisterAttributesFunction + "();");
oeid = "";
if (useEntityId())
{
oeid = ", "+getClassKey()->cppName();
}
UnregisterId.add(pdslibFunc("deallocateRow")+"("+getId()+", __BaseRow"+oeid+");");
UnregisterId.add("_IndexAllocator.deallocate(__BaseRow);");
//UnregisterId.add(destroyFunction+"();");
}
//
// add attributes and methods
// - attributes are in private part
// - read accessor are public
// - write accessor are public or delegated in public accessor objects
//
for (j=0; j<Nodes.size(); ++j)
{
CDeclarationNode *dln = dynamic_cast<CDeclarationNode*>(Nodes[j]);
if (!dln)
continue;
dln->Env = Env->nextArrayNode("dcl");
dln->generateContent();
}
uint columnId = 0;
for (j=0; j<Attributes.size(); ++j)
{
CDeclarationNode *dln = Attributes[j];
getDbNode()->xmlDescription.push_back("<attribute "+dln->XmlNode+"/>");
uint k;
for (k=0; k<dln->ColumnList.size(); ++k)
{
CColumn &column = dln->ColumnList[k];
//getDbNode()->xmlDescription.push_back("<column id='"+toString(k)+"' name='"+column.Name+"' type='"+column.TypeStr+"' typeid='"+toString(column.TypeId)+"' size='"+toString(column.ByteSize)+"' columnid='"+toString(columnId)+"'/>");
++columnId;
}
//getDbNode()->xmlDescription.push_back("</attribute>");
}
getDbNode()->xmlDescription.push_back("</classdef>");
if (HasTableAccess)
{
Gen.startConstructor("", "construct");
Gen.add("__BaseTable = "+toString(Id)+";");
Gen.startDestructor("construct", true, DerivatedFlag || HasInheritance);
}
// when inited/fetched a mapped class, map id to object
if (MappedFlag)
{
InitId.add("_Map["+getKey()->getFunc()+"()] = this;");
FetchId.add("_Map["+getKey()->getFunc()+"()] = this;");
DestroyId.add("_Map.erase("+getKey()->getFunc()+"());");
}
//
// generate IPDBaseData API
//
if (MappedFlag || DerivatedFlag || HasInheritance || ForceReference)
{
if (DerivatedFlag)
{
Gen.startMethod("void", staticSetUserFactoryFunction, TPDFactoryName+" userFactory", "map", false, inlineStaticPublic, true);
Gen.setDescription("Set user factory for this class (as class is indicated as derived, a home made constructor must be provided)");
Gen.add(staticInitFactoryFunction+"(userFactory);");
}
Gen.startMethod("void", staticInitFactoryFunction, TPDFactoryName+" userFactory", "factories", false, inlineStaticInternal, true);
Gen.add("if (!_FactoryInitialised)");
Gen.add("{");
Gen.add(pdslibFunc("registerClass")+"(" + toString(Id) + ", userFactory, "+staticFetchFunction+", "+((MappedFlag && !HasParent) ? staticNotifyLoadFailure : string("NULL"))+");");
Gen.add("_FactoryInitialised = true;");
Gen.add("}");
Gen.addAttribute("bool", "_FactoryInitialised", "factories", true);
if (MappedFlag || HasInheritance || ForceReference)
{
//
// create: create an object, then init attributes and register
//
Gen.startMethod(Name+"*", staticCreateFunction, InitProto, "map", false, inlineStaticPublic, true);
Gen.setDescription("Create an object of the "+Name+" class, and declare it to the PDS.");
if (GenerateDebugMessages)
{
Gen.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": create\");");
}
if (DerivatedFlag)
{
Gen.add(Name + "\t*"+objectVariable+" = static_cast<" + Name + "*>("+pdslibFunc("create")+"("+toString(Id)+"));");
}
else
{
Gen.add(Name + "\t*"+objectVariable+" = static_cast<" + Name + "*>("+staticFactoryFunction+"());");
}
string str = objectVariable+"->" + initFunction + "(";
uint i;
for (i=0; i<Init.size(); ++i)
str += (i != 0 ? ", " : "") + Init[i]->Name;
str += ");";
Gen.add(str);
Gen.add(objectVariable+"->" + registerFunction + "();");
/*
if (MappedFlag)
{
Gen.add("_Map["+MapClass->ClassKey+"] = "+objectVariable+";");
}
*/
Gen.add(objectVariable+"->"+notifyInitFunction+"();");
Gen.add("return "+objectVariable+";");
}
if (MappedFlag)
{
CDeclarationNode *dln = (MapClass != NULL ? MapClass->getKey() : NULL);
CTypeNode *keyType = getTypeNode(dln->Type);
// only authorize remove/load/unload for mapped objects that are roots
if (!HasParent)
{
Gen.startMethod("void", staticRemoveFunction, "const "+keyType->getName()+"& "+dln->Name, "map", false, inlineStaticPublic, true);
Gen.setDescription("Destroy an object from the PDS. Caution! Object will no longer exist in database.\nAlso children (that is objects that belong to this object) are also destroyed.");
if (GenerateDebugMessages)
{
Gen.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": remove "+dln->displayPrintfPrefix()+"\", "+dln->displayCppCode(dln->Name)+");");
}
Gen.add("std::map<" + keyType->getName() + "," + Name + "*>::iterator\tit = _Map.find("+dln->Name+");");
Gen.add("if (it != _Map.end())");
Gen.add("{");
Gen.add(Name + "*\t__o = (*it).second;");
Gen.add("__o->"+notifyReleaseFunction+"();");
Gen.add("__o->"+unregisterFunction+"();");
Gen.add("__o->"+destroyFunction+"();");
Gen.add("delete __o;");
//Gen.add("_Map.erase(it);");
Gen.add("}");
Gen.startMethod("void", staticLoadFunction, "const "+keyType->getName()+"& "+dln->Name, "map", false, inlineStaticPublic, true);
Gen.setDescription("Retrieve an object from the database.\nData are sent asynchronously, so the load callback is called when data are ready.\nUse get() to access to the loaded object.");
if (GenerateDebugMessages)
{
Gen.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": load "+dln->displayPrintfPrefix()+"\", "+dln->displayCppCode(dln->Name)+");");
}
Gen.add(pdslibFunc("load")+"("+toString(Id)+", "+dln->toUint64(dln->Name)+");");
Gen.startMethod("void", staticSetLoadCbFunction, "void (*callback)(const "+keyType->getName()+"& key, "+Name+"* object)", "map", false, inlineStaticPublic, true);
Gen.setDescription("Setup load callback so client is warned that load succeded or failed.");
Gen.add(staticLoadCbAttribute+" = callback;");
Gen.startMethod("void", staticNotifyLoadFailure, "uint64 key", "factories", false, inlineStaticInternal, true);
Gen.add("if ("+staticLoadCbAttribute+" != NULL)");
Gen.add("{");
Gen.add(staticLoadCbAttribute+"("+keyType->castFromUser("key")+", NULL);");
Gen.add("}");
Gen.addAttribute("void", staticLoadCbAttribute, "factories", true, "NULL", true, "const "+keyType->getName()+"& key, "+Name+"* object");
//
Gen.startMethod("void", staticUnloadFunction, "const " + keyType->getName() + " &" + dln->Name, "map", false, inlineStaticPublic, true);
Gen.setDescription("Unload an object from the client memory. Object still exists in database and can be retrieved again using load.");
if (GenerateDebugMessages)
{
Gen.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": unload "+dln->displayPrintfPrefix()+"\", "+dln->displayCppCode(dln->Name)+");");
}
Gen.add("std::map<" + keyType->getName() + "," + Name + "*>::iterator\tit = _Map.find("+dln->Name+");");
Gen.add("if (it != _Map.end())");
Gen.add("{");
Gen.add(Name + "*\t__o = (*it).second;");
Gen.add("__o->"+notifyReleaseFunction+"();");
Gen.add("__o->"+destroyFunction+"();");
Gen.add("delete __o;");
//Gen.add("_Map.erase(it);");
Gen.add("}");
}
std::string mapType = "std::map<"+keyType->getName()+", "+Name+"*>";
Gen.startMethod(Name+"*", staticGetFunction, "const " + keyType->getName() + " &" + dln->Name, "map", false, inlineStaticPublic, true);
Gen.setDescription("Get an object in client. Object must have been previously loaded from database with a load.");
if (GenerateDebugMessages)
{
Gen.add("if (RY_PDS::PDVerbose)\tnldebug(\""+Name+": get "+dln->displayPrintfPrefix()+"\", "+dln->displayCppCode(dln->Name)+");");
}
Gen.add(mapType+"::iterator\t__it = _Map.find("+dln->Name+");");
if (GenerateDebugMessages)
{
Gen.add("if (__it == _Map.end())");
Gen.add("nlwarning(\""+Name+": unable to get %\"NL_I64\"u, not found in map.\", "+dln->toUint64(dln->Name)+");");
}
Gen.add("return (__it != _Map.end()) ? (*__it).second : NULL;");
Gen.startMethod(mapType+"::iterator", staticBeginFunction, "", "map", false, inlineStaticPublic, true);
Gen.setDescription("Return the begin iterator of the global map of "+Name);
Gen.add("return _Map.begin();");
Gen.startMethod(mapType+"::iterator", staticEndFunction, "", "map", false, inlineStaticPublic, true);
Gen.setDescription("Return the end iterator of the global map of "+Name);
Gen.add("return _Map.end();");
}
}
//
// generate internal management functions
//
if (HasRowAccess || MappedFlag)
{
if (MappedFlag)
{
CDeclarationNode *dln = (MappedFlag ? getKey() : NULL);
CTypeNode *keyType = getTypeNode(dln->Type);
Gen.addAttribute("std::map<" + keyType->getName() + "," + Name + "*>", "_Map", "inherit map", true);
}
Gen.addAttribute(indexAllocatorName, "_IndexAllocator", "factories", true);
Gen.startMethod("void", staticInitFunction, "", "internal", false, inlineInternal, true, false, "", false);
Gen.add(pdslibFunc("setIndexAllocator")+"("+toString(Id)+", _IndexAllocator);");
if (MappedFlag || DerivatedFlag || HasInheritance || ForceReference)
{
if (DerivatedFlag)
{
// check factory has been set
Gen.add("nlassertex(_FactoryInitialised, (\"User Factory for class "+Name+" not set!\"));");
Gen.add("// factory must have been set by user before database init called!");
Gen.add("// You must provide a factory for the class "+Name+" as it is marked as derived");
Gen.add("// Call "+getDbNode()->Name+"::"+Name+"::"+staticSetUserFactoryFunction+"() with a factory before any call to "+getDbNode()->Name+"::init()!");
}
else
{
Gen.add(staticInitFactoryFunction+"("+staticFactoryFunction+");");
}
}
getDbNode()->initDb.add(Name+"::"+staticInitFunction+"();");
if (ForceReference)
{
if (!DerivatedFlag) // forbid factory function for derivated classes
{
Gen.startMethod(pdBaseDataName+"*", staticFactoryFunction, "", "factories", false, inlineStaticInternal, true);
Gen.add("return new " + Name + "();");
}
if (Inherited.empty())
{
Gen.startMethod("void", staticFetchFunction, pdBaseDataName+" *object, "+CPDataName+" &data", "factories", false, inlineStaticInternal, true);
Gen.add(Name + "\t*"+objectVariable+" = static_cast<" + Name + "*>(object);");
Gen.add(objectVariable+"->"+fetchFunction+"(data);");
if (MappedFlag)
{
//Gen.add("_Map["+objectVariable+"->"+getKey()->getFunc()+"()] = "+objectVariable+";");
if (!HasParent)
{
Gen.add("if ("+staticLoadCbAttribute+" != NULL)");
Gen.add("{");
Gen.add(staticLoadCbAttribute+"("+objectVariable+"->"+getKey()->getFunc()+"(), "+objectVariable+");");
Gen.add("}");
}
}
Gen.add(objectVariable+"->"+notifyInitFunction+"();");
}
}
}
// EGS Compat
// -- begin
ApplyId.add( "else");
ApplyId.add( "{");
ApplyId.add( "nlwarning(\"Skipping unrecognised token: %s\", __pdr.peekNextTokenName().c_str());");
ApplyId.add( "__pdr.skipData();");
ApplyId.add( "}");
ApplyId.add("}");
if (MappedFlag && !HasParent)
{
ApplyId.add(notifyInitFunction+"();");
}
//EGSImplId.add("\n#include \"game_share/persistent_data_template.h\"");
//EGSImplId.add("#undef PERSISTENT_CLASS");
//EGSImplId.add("#undef PERSISTENT_DATA");
// -- end
set<string>::iterator itf;
for (itf=Friends.begin(); itf!=Friends.end(); ++itf)
if (*itf != Name)
Gen.addOther("friend class "+(*itf)+";\n", "friends");
for (itf=ForwardFriends.begin(); itf!=ForwardFriends.end(); ++itf)
if (*itf != Name)
Gen.addOther("friend class "+(*itf)+";\n", "friends");
Gen.addOther("friend class "+CPDSLibName+";\n", "friends");
CDbNode* dbNode = getDbNode();
Gen.addOther("friend void "+dbNode->Name+"::init(uint32);\n", "friends");
Gen.flush(hOutput(), cppOutput(), inlineOutput());
DbSummary << "\n\n";
return true;
}
void CClassNode::generateContentInCall(CCallContext *context)
{
uint j;
for (j=0; j<Nodes.size(); ++j)
{
CDeclarationNode *dln = dynamic_cast<CDeclarationNode*>(Nodes[j]);
if (!dln)
continue;
dln->generateContent(context);
}
}
// Declaration Node
bool CDeclarationNode::prolog()
{
return true;
}
bool CDeclarationNode::epilog()
{
return true;
}
void CDeclarationNode::generateContent(CCallContext *context)
{
ClassNode = static_cast<CClassNode*>(Parent);
nlassert(Env != NULL);
setEnv("name", Name);
XmlNode = "name='"+Name+"' id='"+toString(Id)+"' columnid='"+toString(Column)+"' columns='"+toString(Columns)+"'";
if (context == NULL)
{
CCppOutput& DbSummary = getDbNode()->DbSummary;
DbSummary << "Attribute " << Name << ":\n";
}
switch (DeclarationType)
{
case SimpleType:
generateTypeContent(context);
break;
case SimpleClass:
generateClassContent(context);
break;
case BackRef:
generateBackRefContent();
break;
case ForwardRef:
generateForwardRefContent();
break;
case ArrayType:
generateArrayTypeContent(context);
break;
case ArrayClass:
generateArrayClassContent(context);
break;
case ArrayRef:
generateArrayRefContent(context);
break;
case Set:
generateSetContent(context);
break;
default:
error("Can't decide declaration type");
break;
}
if (context == NULL)
{
ClassNode->Gen.separator("methods");
}
}
std::string CDeclarationNode::getAccessorName(CCallContext *context, const std::string& accessortype, const std::string& sep)
{
return context->getRootCaller()->Name + sep +accessortype + context->getCallString();
}
void CDeclarationNode::generateTypeContent(CCallContext *context)
{
CClassGenerator& Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &SetUnnotifiedParentId = ClassNode->SetUnnotifiedParentId;
string UCodeContext;
if (context != NULL)
UCodeContext = context->getUserCodeContext();
string onGetUser = getUserCode("onGet", UCodeContext);
string onSetUser = getUserCode("onSet", UCodeContext);
string onChangeUser = getUserCode("onChange", UCodeContext);
CTypeNode *tnd = getTypeNode(Type);
XmlNode += " type='type' typeid='"+toString(tnd->Id)+"'";
setEnv("decltype", "type");
setEnv("type", tnd->getName());
define(IsKey, "iskey");
setEnv("defaultvalue", tnd->getDefaultValue());
setEnv("checkcode", tnd->checkCode(Name));
CCallContext ctx(this);
if (context != NULL)
ctx = context->getSubContext(this);
CClassGenerator &gen = ctx.getRootCaller()->Gen;
// EGS Compat
// -- begin
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
ApplyId.add("else if (__pdr.peekNextToken() == "+tokenName()+")");
ApplyId.add("{");
tnd->generateApplyCode(ApplyId, tokenName(), cppName());
ApplyId.add("}");
tnd->generateStoreCode(StoreId, tokenName(), cppName());
// -- end
CTemplatizerEnv* env = ctx.getRootDeclaration()->Env->nextArrayNode("accessors");
env->set("name", Name);
env->set("type", tnd->getName());
env->set("defaultvalue", tnd->getDefaultValue());
env->set("checkcode", tnd->checkCode(Name));
env->define(ctx.getRootCaller()->HasRowAccess, "rowaccess");
env->define(IsKey, "iskey");
env->set("rootcallerid", ctx.getRootCaller()->getId());
env->set("callstr", ctx.getCallString());
env->set("callargs", ctx.getCallArgList());
env->set("callpath", ctx.getCallPath());
env->set("column", ctx.getColumn());
env->set("valuevar", valueVariable);
env->set("castcpp", tnd->castToCpp(valueVariable));
env->set("castpds", tnd->castToPDS(valueVariable));
vector<string> checks = ctx.getCheckCode();
for (uint i=0; i<checks.size(); ++i)
env->nextArrayNode("checks")->set("check", checks[i]);
env->nextArrayNode("checks")->set("check", tnd->checkCode(valueVariable));
if (!onGetUser.empty()) env->set("onget", onGetUser);
if (!onSetUser.empty()) env->set("onset", onSetUser);
if (!onChangeUser.empty()) env->set("onchange", onChangeUser);
//
// generate read accessor
//
if (ctx.getRootCaller()->HasRowAccess)
{
string arglist = ctx.getCallArgList();
gen.startMethod(tnd->getName(), getFunctionPrefix+ctx.getCallString(), arglist, "methods", true, inlineAccessors);
DbSummary << "\t" << getFunctionPrefix+ctx.getCallString() << "\n";
uint i;
vector<string> checks = ctx.getCheckCode();
for (i=0; i<checks.size(); ++i)
{
gen.add(checks[i]);
}
if (!onGetUser.empty())
{
gen.add("{");
gen.add(onGetUser);
gen.add("}");
}
gen.add("return "+ctx.getCallPath()+";");
}
//
// generate write accessor
//
if (ctx.getRootCaller()->HasRowAccess && !IsKey)
{
string arglist = ctx.getCallArgList();
if (!arglist.empty())
arglist += ", ";
arglist += tnd->getName()+" "+valueVariable;
gen.startMethod("void", setFunctionPrefix+ctx.getCallString(), appendArg(arglist, "bool forceWrite=false"), "methods", false, inlineAccessors);
DbSummary << "\t" << setFunctionPrefix << ctx.getCallString() << "\n";
if (GenerateHAuto)
{
gen.add("H_AUTO("+getAccessorName(&ctx, setFunctionPrefix, "_")+")");
}
if (VerboseMode)
{
string verbStr;
string callStr;
verbStr = "nlinfo(\"" + ctx.getRootCaller()->Name + "(%d:%d)::" +setFunctionPrefix + ctx.getCallString() + "(";
callStr = ctx.getDebugCallStringFmt();
if (!callStr.empty())
callStr += ", ";
callStr += valueVariable+"="+tnd->getPrintfFmt();
verbStr += callStr;
verbStr += ")\", __BaseTable, __BaseRow, ";
callStr = ctx.getDebugCallStringVal();
if (!callStr.empty())
callStr += ", ";
callStr += tnd->getPrintfVal(valueVariable);
verbStr += callStr;
verbStr += ");";
gen.add(verbStr);
}
uint i;
vector<string> checks = ctx.getCheckCode();
for (i=0; i<checks.size(); ++i)
{
gen.add(checks[i]);
}
gen.add(tnd->checkCode(valueVariable));
///// TYPE CAST
if (!onChangeUser.empty())
{
gen.add("if ("+ctx.getCallPath()+" != "+tnd->castToCpp(valueVariable)+")");
gen.add("{");
gen.add(onChangeUser);
gen.add("}");
}
if (!onSetUser.empty())
{
gen.add("{");
gen.add(onSetUser);
gen.add("}");
}
if (WriteTriggerFlag)
{
gen.add("if (forceWrite && ("+ctx.getCallPath()+" != "+tnd->castToCpp(valueVariable)+"))");
}
else
{
gen.add("if (("+ctx.getCallPath()+" != "+tnd->castToCpp(valueVariable)+") || forceWrite)");
}
gen.add("{");
bool useEntityId = ctx.hasRootEntityIdKey();
if (useEntityId)
{
gen.add(pdslibFunc("set")+"("+ctx.getRootCaller()->getId()+", __BaseRow, ("+TColumnIndexName+")("+ctx.getColumn()+"), "+tnd->castToPDS(valueVariable)+", "+ctx.getRootCaller()->getKey()->cppName()+");");
}
else
{
gen.add(pdslibFunc("set")+"("+ctx.getRootCaller()->getId()+", __BaseRow, ("+TColumnIndexName+")("+ctx.getColumn()+"), "+tnd->castToPDS(valueVariable)+");");
}
gen.add("}");
gen.add(ctx.getCallPath()+" = "+tnd->castToCpp(valueVariable)+";");
}
//
// generate attribute
//
Gen.addAttribute(tnd->getName(), cppName(), "attributes");
string defaultValue;
if (!DefaultValue.empty())
defaultValue = DefaultValue;
else
defaultValue = tnd->getDefaultValue();
//
// generate init
//
if (!IsKey)
{
InitId.add(cppName()+" = "+defaultValue+";");
}
else
{
InitId.add(tnd->checkCode(Name));
InitId.add(cppName()+" = "+Name+";");
}
//
// generate create code
//
//
// generate fetch code
//
if (tnd->isEnum())
FetchId.add("data.serialEnum("+cppName()+");");
else if (tnd->CppType != tnd->StorageType)
{
FetchId.add("{");
FetchId.add(tnd->StorageType+"\t_v;");
FetchId.add("data.serial(_v);");
FetchId.add(cppName()+" = "+tnd->castToCpp("_v")+";");
FetchId.add("}");
}
else
{
FetchId.add("data.serial("+cppName()+");");
}
//
// generate clear code
//
if (ctx.getRootCaller()->HasRowAccess && !IsKey)
{
ctx.getRootCaller()->ClearId.add(ctx.getCallPath()+" = "+defaultValue+";");
ctx.getRootCaller()->ClearId.add(pdslibFunc("set")+"("+ctx.getRootCaller()->getId()+", __BaseRow, ("+TColumnIndexName+")("+ctx.getColumn()+"), "+tnd->castToPDS(defaultValue)+");");
}
}
void CDeclarationNode::generateClassContent(CCallContext *context)
{
setEnv("decltype", "class");
CClassGenerator &Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &SetUnnotifiedParentId = ClassNode->SetUnnotifiedParentId;
CClassNode *cnd = getClassNode(Type);
XmlNode += " type='class' classid='"+toString(cnd->Id)+"'";
setEnv("type", Type);
// EGS Compat
// -- begin
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
StoreId.add("__pdr.pushStructBegin("+tokenName()+");");
StoreId.add(cppName()+".store(__pdr);");
StoreId.add("__pdr.pushStructEnd("+tokenName()+");");
ApplyId.add("else if (__pdr.peekNextToken() == "+tokenName()+")");
ApplyId.add("{");
ApplyId.add("__pdr.popStructBegin("+tokenName()+");");
ApplyId.add(cppName()+".apply(__pdr);");
ApplyId.add("__pdr.popStructEnd("+tokenName()+");");
ApplyId.add("}");
// -- end
//
// export class accessors into root caller
//
CCallContext ctx;
if (context != NULL)
ctx = *context;
ctx.Context.push_back(this);
cnd->generateContentInCall(&ctx);
//
// generate attribute
//
Gen.addAttribute(Type, cppName(), "attributes");
//
// generate init
//
InitId.add(cppName()+"."+initFunction+"();");
//
// generate create code
//
//
// generate fetch code
//
FetchId.add(cppName()+"."+fetchFunction+"(data);");
//
// generate clear code
//
//ClearId.add(cppName()+"."+clearFunction+"();");
}
void CDeclarationNode::generateBackRefContent()
{
setEnv("decltype", "backref");
define(HiddenFlag, "hidden");
CClassGenerator &Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &SetUnnotifiedParentId = ClassNode->SetUnnotifiedParentId;
CClassNode *cnd = getClassNode(ParentClass);
CDeclarationNode *dnd = cnd->getDeclarationNode(ParentField);
CDeclarationNode *knd = (ClassNode->ClassKey.empty() ? NULL : ClassNode->getKey());
XmlNode += " type='backref' classid='"+toString(cnd->Id)+"' backreferentid='"+toString(dnd->Id)+"'";
if (knd != NULL)
XmlNode += " key='"+toString(knd->Id)+"'";
setEnv("type", ParentClass);
//
// generate read accessor
//
Gen.startMethod(ParentClass+"*", getFunc(), "", "methods", false, inlineAccessors);
Gen.add("return "+cppName()+";");
Gen.startMethod("const "+ParentClass+"*", getFunc(), "", "methods", true, inlineAccessors);
Gen.add("return "+cppName()+";");
DbSummary << "\t" << getFunc() << "\n";
//
// generate write accessor
//
//
// generate attribute
//
Gen.addAttribute(ParentClass+"*", cppName(), "attributes");
//
// generate init
//
InitId.add(cppName()+" = NULL;");
//
// generate create code
//
//
// generate fetch code
//
FetchId.add(cppName()+" = NULL;");
//
// generate set parent code
//
bool useId = ClassNode->useEntityId();
bool parentUseId = cnd->useEntityId();
if (parentUseId)
SetParentId.add("NLMISC::CEntityId\tprevId;");
if (!HiddenFlag)
{
//SetParentId.add(pdslibFunc("set")+"("+ClassNode->getId()+", getRow(), ("+TColumnIndexName+")("+toString(Column)+"), (__parent != NULL ? "+objectIndexName+"("+(cnd->HasInheritance ? toString("__parent->getTable()") : toString(cnd->Id))+", __parent->getRow()) : "+nullIndexName+"));");
SetParentId.add("if ("+cppName()+" != NULL)");
SetParentId.add("{");
if (parentUseId)
SetParentId.add("prevId = "+cppName()+"->"+getFunctionPrefix+cnd->getKey()->Name+"();");
if (ClassNode->getClassKey() == NULL)
{
SetParentId.add(cppName()+"->"+dnd->unlinkFunc()+"();");
}
else
{
SetParentId.add(cppName()+"->"+dnd->unlinkFunc()+"("+ClassNode->getKey()->cppName()+");");
}
SetParentId.add("}");
}
else
{
if (parentUseId)
{
SetParentId.add("if ("+cppName()+" != NULL)");
SetParentId.add("{");
SetParentId.add("prevId = "+cppName()+"->"+cnd->getKey()->cppName()+";");
SetParentId.add("}");
}
}
string oeid;
string peid;
if (useId)
oeid = ", "+ClassNode->getKey()->cppName();
if (parentUseId)
peid = ", ("+cppName()+" != NULL ? "+cppName()+"->"+getFunctionPrefix+cnd->getKey()->Name+"() : NLMISC::CEntityId::Unknown), prevId";
SetParentId.add(cppName()+" = __parent;");
SetParentId.add(pdslibFunc("setParent")+"("+ClassNode->getId()+", getRow(), ("+TColumnIndexName+")("+toString(Column)+"), (__parent != NULL ? "+objectIndexName+"("+(cnd->HasInheritance ? toString("__parent->getTable()") : toString(cnd->Id))+", __parent->getRow()) : "+nullIndexName+")"+oeid+peid+");");
SetUnnotifiedParentId.add(cppName()+" = __parent;");
}
void CDeclarationNode::generateClassPtrApplyCode(const std::string& value)
{
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
ApplyId.add(value+" = NULL;");
ApplyId.add("if (__pdr.peekNextToken() == __Tok_ClassName)");
ApplyId.add("{");
ApplyId.add( "std::string\t__className;");
ApplyId.add( "__pdr.pop(__Tok_ClassName, __className);");
ApplyId.add( value+" = "+Type+"::cast("+pdslibFunc("create")+"(__className));");
ApplyId.add( "if ("+value+" != NULL)");
ApplyId.add( "{");
ApplyId.add( "__pdr.popStructBegin("+tokenName()+");");
ApplyId.add( value+"->apply(__pdr);");
ApplyId.add( value+"->"+setUnnotifiedParentFunction+"(this);");
ApplyId.add( "__pdr.popStructEnd("+tokenName()+");");
ApplyId.add( "}");
ApplyId.add( "else");
ApplyId.add( "{");
ApplyId.add( "__pdr.skipStruct();");
ApplyId.add( "}");
ApplyId.add("}");
}
void CDeclarationNode::generateClassPtrStoreCode(const std::string& value)
{
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
StoreId.add("if ("+value+" != NULL)");
StoreId.add("{");
StoreId.add( "std::string\t__className = "+pdslibFunc("getClassName")+"("+value+");");
StoreId.add( "__pdr.push(__Tok_ClassName, __className);");
StoreId.add( "__pdr.pushStructBegin("+tokenName()+");");
StoreId.add( value+"->store(__pdr);");
StoreId.add( "__pdr.pushStructEnd("+tokenName()+");");
StoreId.add("}");
}
void CDeclarationNode::generateForwardRefContent()
{
setEnv("decltype", "forwardref");
CClassGenerator &Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &NotifyInitId = ClassNode->NotifyInitId;
CClassGenerator::SMethodId &NotifyReleaseId = ClassNode->NotifyReleaseId;
CClassNode *cnd = getClassNode(Type);
CDeclarationNode *dnd = cnd->getDeclarationNode(ForwardRefAttribute);
CDeclarationNode *knd = (cnd->ClassKey.empty() ? NULL : cnd->getKey());
XmlNode += " type='forwardref' classid='"+toString(cnd->Id)+"' forwardreferedid='"+toString(dnd->Id)+"'";
if (knd != NULL)
XmlNode += " key='"+toString(knd->Id)+"'";
setEnv("type", Type);
// EGS Compat
// -- begin
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
StoreId.add("// store "+Name);
StoreId.add("__pdr.pushStructBegin("+tokenName()+");");
generateClassPtrStoreCode(cppName());
StoreId.add("__pdr.pushStructEnd("+tokenName()+");");
ApplyId.add("// apply "+Name);
ApplyId.add("else if (__pdr.peekNextToken() == "+tokenName()+")");
ApplyId.add("{");
ApplyId.add( "__pdr.popStructBegin("+tokenName()+");");
generateClassPtrApplyCode(cppName());
ApplyId.add( "__pdr.popStructEnd("+tokenName()+");");
ApplyId.add("}");
// -- end
//
// generate read accessor
//
Gen.startMethod(Type+"*", getFunc(), "", "methods", false, inlineAccessors);
Gen.add("return "+cppName()+";");
Gen.startMethod("const "+Type+"*", getFunc(), "", "methods", true, inlineAccessors);
Gen.add("return "+cppName()+";");
DbSummary << "\t" << getFunc() << "\n";
//
// generate write accessor
//
Gen.startMethod("void", setFunc(), Type+"* "+valueVariable, "methods", false, inlineAccessors);
Gen.add("if ("+cppName()+" != NULL)");
Gen.add("{");
Gen.add(cppName()+"->"+setParentFunction+"(NULL);");
Gen.add("}");
Gen.add(valueVariable+"->"+setParentFunction+"(this);");
Gen.add(cppName()+" = "+valueVariable+";");
DbSummary << "\t" << setFunc() << "\n";
//
// generate attribute
//
Gen.addAttribute(Type+"*", cppName(), "attributes");
//
// generate init
//
InitId.add(cppName()+" = NULL;");
//
// generate destroy code
//
DestroyId.add("if ("+cppName()+" != NULL)");
DestroyId.add("{");
DestroyId.add(Type+"*\t__o = "+cppName()+";");
DestroyId.add("__o->"+destroyFunction+"();");
DestroyId.add("delete __o;");
DestroyId.add("}");
//
// generate create code
//
//
// generate fetch code
//
FetchId.add("// read table and row, create an object, affect to the ref, and fetch it");
if (!ClassNode->tableAndRowIndicesUsedInFetch)
{
FetchId.add(TTableIndexName+"\ttableIndex;\n"+TRowIndexName+"\trowIndex;");
ClassNode->tableAndRowIndicesUsedInFetch = true;
}
FetchId.add(cppName()+" = NULL;");
FetchId.add("data.serial(tableIndex, rowIndex);");
FetchId.add("if (rowIndex != "+INVALID_ROW_INDEXName+" && tableIndex != "+INVALID_TABLE_INDEXName+")");
FetchId.add("{");
FetchId.add(cppName()+" = static_cast<"+Type+"*>("+pdslibFunc("create")+"(tableIndex));");
FetchId.add(pdslibFunc("setRowIndex")+"(rowIndex, "+cppName()+");");
FetchId.add(cppName()+"->"+fetchFunction+"(data);");
FetchId.add(cppName()+"->"+setUnnotifiedParentFunction+"(this);");
FetchId.add("}");
//
// generate register/unregister code
//
UnregisterAttributesId.add("if ("+cppName()+" != NULL)");
UnregisterAttributesId.add("{");
UnregisterAttributesId.add(Type+"*\t"+objectVariable+" = "+cppName()+";");
UnregisterAttributesId.add(objectVariable+"->"+unregisterFunction+"();");
UnregisterAttributesId.add(objectVariable+"->"+destroyFunction+"();");
UnregisterAttributesId.add("delete "+objectVariable+";");
UnregisterAttributesId.add("}");
//
// generate init/release notification
//
NotifyInitId.add("if ("+cppName()+" != NULL)");
NotifyInitId.add("{");
NotifyInitId.add(cppName()+"->"+notifyInitFunction+"();");
NotifyInitId.add("}");
NotifyReleaseId.add("if ("+cppName()+" != NULL)");
NotifyReleaseId.add("{");
NotifyReleaseId.add(cppName()+"->"+notifyReleaseFunction+"();");
NotifyReleaseId.add("}");
//
// generate unlink code
//
string unlinkProto;
if (cnd->getClassKey() != NULL)
{
CDeclarationNode* kd = cnd->getClassKey();
CTypeNode* keyType = getTypeNode(kd->Type);
unlinkProto = keyType->getName()+" dummy";
}
Gen.startMethod("void", unlinkFunc(), unlinkProto, "internal", false, inlineInternal);
Gen.add("{");
Gen.add(cppName()+" = NULL;");
Gen.add("}");
//
// generate clear code
//
//ClearId.add(cppName()+"->"+setParentFunction+"(NULL);");
ClearId.add(Type+"*\t"+objectVariable+" = "+cppName()+";");
ClearId.add(objectVariable+"->"+unregisterFunction+"();");
ClearId.add(objectVariable+"->"+destroyFunction+"();");
ClearId.add("delete "+objectVariable+";");
}
void CDeclarationNode::generateArrayApplyCode()
{
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
ApplyId.add("// apply "+Name);
ApplyId.add("else if (__pdr.peekNextToken() == "+tokenName()+")");
ApplyId.add("{");
ApplyId.add( "__pdr.popStructBegin("+tokenName()+");");
ApplyId.add( "uint\tindex = 0;");
ApplyId.add( "while (!__pdr.isEndOfStruct())");
ApplyId.add( "{");
CIndexNode *ind = getIndexNode(ArrayIndex);
if (ind->isEnum())
{
ApplyId.add("std::string\tindexname;");
ApplyId.add("__pdr.pop(__Tok_MapKey, indexname);");
ApplyId.add("index = "+ind->getFromStringCode("indexname")+";");
}
}
void CDeclarationNode::generateArrayStoreCode()
{
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
StoreId.add("// store "+Name);
StoreId.add("__pdr.pushStructBegin("+tokenName()+");");
CIndexNode *ind = getIndexNode(ArrayIndex);
StoreId.add("for (uint index=0; index<"+ind->getSizeName()+"; ++index)");
StoreId.add("{");
if (ind->isEnum())
{
StoreId.add("std::string\tindexname = "+ind->getToStringCode(ind->castFromUser("index"))+";");
StoreId.add("__pdr.push(__Tok_MapKey, indexname);");
}
}
void CDeclarationNode::generateArrayEndCode()
{
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
ApplyId.add( "++index;");
ApplyId.add( "}");
ApplyId.add( "__pdr.popStructEnd("+tokenName()+");");
ApplyId.add("}");
StoreId.add("}");
StoreId.add("__pdr.pushStructEnd("+tokenName()+");");
}
void CDeclarationNode::generateArrayTypeContent(CCallContext *context)
{
setEnv("decltype", "arraytype");
CClassGenerator &Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &SetUnnotifiedParentId = ClassNode->SetUnnotifiedParentId;
string UCodeContext;
if (context != NULL)
UCodeContext = context->getUserCodeContext();
string onGetUser = getUserCode("onGet", UCodeContext);
string onSetUser = getUserCode("onSet", UCodeContext);
string onChangeUser = getUserCode("onChange", UCodeContext);
CTypeNode *tnd = getTypeNode(Type);
CIndexNode *ind = getIndexNode(ArrayIndex);
XmlNode += " type='arraytype' typeid='"+toString(tnd->Id)+"' indexid='"+toString(ind->Id)+"'";
CCallContext ctx(this);
if (context != NULL)
ctx = context->getSubContext(this);
CClassGenerator &gen = ctx.getRootCaller()->Gen;
setEnv("type", tnd->getName());
setEnv("indexsize", ind->getSizeName());
// EGS Compat
// -- begin
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
generateArrayApplyCode();
generateArrayStoreCode();
ApplyId.add(tnd->getName()+"\tvalue;");
tnd->generateApplyCode(ApplyId, "__Tok_MapVal", "value");
ApplyId.add("if (index != "+toString(ind->getSize())+")");
ApplyId.add("{");
ApplyId.add( cppName()+"[index] = value;");
ApplyId.add("}");
tnd->generateStoreCode(ApplyId, "__Tok_MapVal", cppName()+"[index]");
generateArrayEndCode();
// -- end
//
// generate read accessor
//
if (ctx.getRootCaller()->HasRowAccess)
{
string arglist = ctx.getCallArgList();
ctx.getRootCaller()->Gen.startMethod(tnd->getName(), getFunctionPrefix+ctx.getCallString(), arglist, "methods", true, inlineAccessors);
DbSummary << "\t" << getFunctionPrefix+ctx.getCallString() << "\n";
uint i;
vector<string> checks = ctx.getCheckCode();
for (i=0; i<checks.size(); ++i)
gen.add(checks[i]);
if (!onGetUser.empty())
{
gen.add("{");
gen.add(onGetUser);
gen.add("}");
}
gen.add("return "+ctx.getCallPath()+";");
}
//
// generate write accessor
//
if (ctx.getRootCaller()->HasRowAccess)
{
string arglist = ctx.getCallArgList();
if (!arglist.empty())
arglist += ", ";
arglist += tnd->getName()+" "+valueVariable;
gen.startMethod("void", setFunctionPrefix+ctx.getCallString(), appendArg(arglist, "bool forceWrite=false"), "methods", false, inlineAccessors);
DbSummary << "\t" << setFunctionPrefix+ctx.getCallString() << "\n";
if (GenerateHAuto)
{
gen.add("H_AUTO("+getAccessorName(&ctx, getFunctionPrefix, "_")+")");
}
if (VerboseMode)
{
string verbStr;
string callStr;
verbStr = "nlinfo(\"" + ctx.getRootCaller()->Name + "(%d:%d)::" +setFunctionPrefix + ctx.getCallString() + "(";
callStr = ctx.getDebugCallStringFmt();
if (!callStr.empty())
callStr += ", ";
callStr += valueVariable+"="+tnd->getPrintfFmt();
verbStr += callStr;
verbStr += ")\", __BaseTable, __BaseRow, ";
callStr = ctx.getDebugCallStringVal();
if (!callStr.empty())
callStr += ", ";
callStr += tnd->getPrintfVal(valueVariable);
verbStr += callStr;
verbStr += ");";
gen.add(verbStr);
}
uint i;
vector<string> checks = ctx.getCheckCode();
for (i=0; i<checks.size(); ++i)
gen.add(checks[i]);
gen.add(tnd->checkCode(valueVariable));
if (!onChangeUser.empty())
{
gen.add("if ("+ctx.getCallPath()+" != "+tnd->castToCpp(valueVariable)+")");
gen.add("{");
gen.add(onChangeUser);
gen.add("}");
}
if (!onSetUser.empty())
{
gen.add("{");
gen.add(onGetUser);
gen.add("}");
}
if (WriteTriggerFlag)
{
gen.add("if (forceWrite && ("+ctx.getCallPath()+" != "+tnd->castToCpp(valueVariable)+"))");
}
else
{
gen.add("if (("+ctx.getCallPath()+" != "+tnd->castToCpp(valueVariable)+") || forceWrite)");
}
gen.add("{");
bool useEntityId = ctx.hasRootEntityIdKey();
if (useEntityId)
{
gen.add(pdslibFunc("set")+"("+ctx.getRootCaller()->getId()+", __BaseRow, ("+TColumnIndexName+")("+ctx.getColumn()+"), "+tnd->castToPDS(valueVariable)+", "+ctx.getRootCaller()->getKey()->cppName()+");");
}
else
{
gen.add(pdslibFunc("set")+"("+ctx.getRootCaller()->getId()+", __BaseRow, ("+TColumnIndexName+")("+ctx.getColumn()+"), "+tnd->castToPDS(valueVariable)+");");
}
//gen.add(pdslibFunc("set")+"("+ctx.getRootCaller()->getId()+", __BaseRow, ("+TColumnIndexName+")("+ctx.getColumn()+"), "+tnd->castToPDS(valueVariable)+");");
gen.add("}");
gen.add(ctx.getCallPath()+" = "+tnd->castToCpp(valueVariable)+";");
}
//
// generate attribute
//
Gen.addAttribute(tnd->getName(), cppName()+"["+ind->getSizeName()+"]", "attributes");
//
// generate init
//
if (!ClassNode->indexUsedInInit)
{
InitId.add("uint\ti;");
ClassNode->indexUsedInInit = true;
}
InitId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)\t"+cppName()+"[i] = "+tnd->getDefaultValue()+";");
//
// generate create code
//
//
// generate fetch code
//
if (!ClassNode->indexUsedInFetch)
{
FetchId.add("uint\ti;");
ClassNode->indexUsedInFetch = true;
}
if (tnd->isEnum())
FetchId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)\tdata.serialEnum("+cppName()+"[i]);");
else if (tnd->CppType != tnd->StorageType)
{
FetchId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
FetchId.add("{");
FetchId.add(tnd->StorageType+"\t_v;");
FetchId.add("data.serial(_v);");
FetchId.add(cppName()+"[i] = "+tnd->castToCpp("_v")+";");
FetchId.add("}");
}
else
{
FetchId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)\tdata.serial("+cppName()+"[i]);");
}
//
// generate clear code
//
if (ctx.getRootCaller()->HasRowAccess)
{
string forIndex = "__i"+toString(ctx.getContextIndex());
ctx.getRootCaller()->ClearId.add("for (uint "+forIndex+"=0; "+forIndex+"<"+ind->getSizeName()+"; ++"+forIndex+")");
ctx.getRootCaller()->ClearId.add("{");
ctx.getRootCaller()->ClearId.add(ctx.getCallPath()+" = "+tnd->getDefaultValue()+";");
ctx.getRootCaller()->ClearId.add(pdslibFunc("set")+"("+ctx.getRootCaller()->getId()+", __BaseRow, ("+TColumnIndexName+")("+ctx.getColumn()+"), "+tnd->castToPDS(tnd->getDefaultValue())+");");
ctx.getRootCaller()->ClearId.add("}");
}
}
void CDeclarationNode::generateArrayClassContent(CCallContext *context)
{
setEnv("decltype", "arrayclass");
CClassGenerator &Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &SetUnnotifiedParentId = ClassNode->SetUnnotifiedParentId;
CClassNode *sub = getClassNode(Type);
CIndexNode *ind = getIndexNode(ArrayIndex);
XmlNode += " type='arrayclass' classid='"+toString(sub->Id)+"' indexid='"+toString(ind->Id)+"'";
setEnv("type", Type);
setEnv("indexsize", ind->getSizeName());
// EGS Compat
// -- begin
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
generateArrayApplyCode();
generateArrayStoreCode();
// StoreId.add("__pdr.pushStructBegin("+tokenName()+");");
StoreId.add("__pdr.pushStructBegin(__Tok_MapVal);");
StoreId.add(cppName()+"[index].store(__pdr);");
StoreId.add("__pdr.pushStructEnd(__Tok_MapVal);");
// StoreId.add("__pdr.pushStructEnd("+tokenName()+");");
ApplyId.add("if (index < "+ind->getSizeName()+")");
ApplyId.add("{");
// ApplyId.add("__pdr.popStructBegin("+tokenName()+");");
ApplyId.add("__pdr.popStructBegin(__pdr.peekNextToken());");
ApplyId.add(cppName()+"[index].apply(__pdr);");
ApplyId.add("__pdr.popStructEnd(__pdr.peekNextToken());");
// ApplyId.add("__pdr.popStructEnd("+tokenName()+");");
ApplyId.add("}");
ApplyId.add("else");
ApplyId.add("{");
ApplyId.add( "__pdr.skipStruct();");
ApplyId.add("}");
generateArrayEndCode();
// -- end
//
// export class accessors into root caller
//
CCallContext ctx;
if (context != NULL)
ctx = *context;
ctx.Context.push_back(this);
if (ctx.getRootCaller()->HasRowAccess)
{
string forIndex = "__i"+toString(ctx.getContextIndex());
ctx.getRootCaller()->ClearId.add("for (uint "+forIndex+"=0; "+forIndex+"<"+ind->getSizeName()+"; ++"+forIndex+")");
ctx.getRootCaller()->ClearId.add("{");
}
sub->generateContentInCall(&ctx);
if (ctx.getRootCaller()->HasRowAccess)
{
ctx.getRootCaller()->ClearId.add("}");
}
//
// generate attribute
//
Gen.addAttribute(Type, cppName()+"["+ind->getSizeName()+"]", "attributes");
//
// generate init
//
//
// generate create code
//
//
// generate fetch code
//
if (!ClassNode->indexUsedInFetch)
{
FetchId.add("uint\ti;");
ClassNode->indexUsedInFetch = true;
}
FetchId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)\t"+cppName()+"[i]."+fetchFunction+"(data);");
//
// generate clear code
//
}
void CDeclarationNode::generateArrayRefContent(CCallContext *context)
{
setEnv("decltype", "arrayref");
CClassGenerator &Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &SetUnnotifiedParentId = ClassNode->SetUnnotifiedParentId;
CClassGenerator::SMethodId &NotifyInitId = ClassNode->NotifyInitId;
CClassGenerator::SMethodId &NotifyReleaseId = ClassNode->NotifyReleaseId;
CClassNode *cnd = getClassNode(Type);
bool useReference = cnd->ForceReference;
CDeclarationNode *dnd = cnd->getDeclarationNode(ForwardRefAttribute);
CIndexNode *ind = getIndexNode(ArrayIndex);
CDeclarationNode *knd = cnd->getKey();
XmlNode += " type='arrayref' classid='"+toString(cnd->Id)+"' forwardreferedid='"+toString(dnd->Id)+"' key='"+toString(knd->Id)+"' indexid='"+toString(ind->Id)+"' allownull='"+(useReference ? "true" : "false")+"'";
string arrayType = Type+(useReference ? "*" : "");
string access = (useReference ? "->" : ".");
setEnv("type", Type);
setEnv("indexsize", ind->getSizeName());
define(useReference, "useref");
string UCodeContext;
if (context != NULL)
UCodeContext = context->getUserCodeContext();
string onChangeUser = getUserCode("onChange", UCodeContext);
// EGS Compat
// -- begin
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
generateArrayStoreCode();
generateArrayApplyCode();
StoreId.add("__pdr.pushStructBegin("+tokenName()+");");
ApplyId.add("if (index < "+ind->getSizeName()+")");
ApplyId.add("{");
ApplyId.add( "if (__pdr.peekNextToken() == "+tokenName()+")");
ApplyId.add( "{");
ApplyId.add( "__pdr.popStructBegin("+tokenName()+");");
if (useReference)
{
generateClassPtrStoreCode(cppName()+"[index]");
generateClassPtrApplyCode(cppName()+"[index]");
}
else
{
StoreId.add(cppName()+"[index].store(__pdr);");
ApplyId.add(cppName()+"[index].apply(__pdr);");
ApplyId.add(cppName()+"[index]."+setUnnotifiedParentFunction+"(this);");
}
StoreId.add("__pdr.pushStructEnd("+tokenName()+");");
ApplyId.add( "__pdr.popStructEnd("+tokenName()+");");
ApplyId.add( "}");
ApplyId.add("}");
ApplyId.add("else");
ApplyId.add("{");
ApplyId.add( "__pdr.skipStruct();");
ApplyId.add("}");
generateArrayEndCode();
// -- end
//
// generate read accessor
//
Gen.startMethod((useReference ? arrayType : Type+"&"), getFunc(), ind->getName()+" "+indexVariable, "methods", false, inlineAccessors);
Gen.add(ind->checkCode(indexVariable));
Gen.add("return "+cppName()+"["+indexVariable+"];");
Gen.startMethod(string("const ")+(useReference ? arrayType : Type+"&"), getFunc(), ind->getName()+" "+indexVariable, "methods", true, inlineAccessors);
Gen.add(ind->checkCode(indexVariable));
Gen.add("return "+cppName()+"["+indexVariable+"];");
DbSummary << "\t" << getFunc() << "\n";
//
// generate write accessor
//
if (useReference)
{
Gen.startMethod("void", setFunc(), arrayType+" "+valueVariable, "methods", false, inlineAccessors);
DbSummary << "\t" << setFunc() << "\n";
Gen.add("if ("+valueVariable+" == NULL)\treturn;");
Gen.add(ind->getName()+"\t"+keyVariable+" = "+valueVariable+"->"+cnd->getKey()->getFunc()+"();");
Gen.add(ind->checkCode(keyVariable));
Gen.add(Type+"*\t__prev = "+cppName()+"["+keyVariable+"];");
Gen.add("if (__prev != NULL)");
Gen.add("{");
Gen.add("__prev->"+setParentFunction+"(NULL);");
if (cnd->MapClass == NULL)
{
Gen.add("__prev->"+unregisterFunction+"();");
Gen.add("__prev->"+destroyFunction+"();");
Gen.add("delete __prev;");
}
Gen.add("}");
Gen.add(valueVariable+"->"+setParentFunction+"(this);");
Gen.add(cppName()+"["+keyVariable+"] = "+valueVariable+";");
}
if (cnd->MapClass == NULL && useReference && !cnd->HasInheritance && !cnd->DerivatedFlag)
{
Gen.startMethod(Type+"*", newFunc(), ind->getName()+" "+indexVariable, "methods", false, inlineAccessors);
DbSummary << "\t" << newFunc() << "\n";
Gen.add(ind->checkCode(indexVariable));
Gen.add(Type+"*\t"+objectVariable+" = new "+Type+"();");
Gen.add(objectVariable+"->"+initFunction+"("+indexVariable+");");
Gen.add(objectVariable+"->"+registerFunction+"();");
Gen.add(setFunc()+"("+objectVariable+");");
}
if (cnd->MapClass == NULL && useReference)
{
Gen.startMethod("void", deleteFunc(), ind->getName()+" "+indexVariable, "methods", false, inlineAccessors);
DbSummary << "\t" << deleteFunc() << "\n";
Gen.add(ind->checkCode(indexVariable));
Gen.add(Type+"*\t"+objectVariable+" = "+cppName()+"["+indexVariable+"];");
Gen.add(objectVariable+"->"+setParentFunction+"(NULL);");
Gen.add(objectVariable+"->"+unregisterFunction+"();");
Gen.add(objectVariable+"->"+destroyFunction+"();");
Gen.add("delete "+objectVariable+";");
}
//
// generate attribute
//
Gen.addAttribute(arrayType, cppName()+"["+ind->getSizeName()+"]", "attributes");
//
// generate init
//
if (!ClassNode->indexUsedInInit)
{
InitId.add("uint\ti;");
ClassNode->indexUsedInInit = true;
}
if (useReference)
{
InitId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)\t"+cppName()+"[i] = NULL;");
}
else
{
InitId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)\t"+cppName()+"[i]."+initFunction+"(("+ind->getName()+")i);");
}
//
// generate destroy code
//
if (!ClassNode->indexUsedInDestroy)
{
DestroyId.add("uint\ti;");
ClassNode->indexUsedInDestroy = true;
}
DestroyId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
DestroyId.add("{");
if (useReference)
{
DestroyId.add("if ("+cppName()+"[i] != NULL)");
DestroyId.add("{");
DestroyId.add(Type+"*\t"+objectVariable+" = "+cppName()+"[i];");
DestroyId.add(objectVariable+"->"+destroyFunction+"();");
DestroyId.add("delete "+objectVariable+";");
DestroyId.add("}");
}
else
{
DestroyId.add(cppName()+"[i]."+destroyFunction+"();");
}
DestroyId.add("}");
//
// generate create code
//
//
// generate fetch code
//
if (useReference)
{
if (!ClassNode->indexUsedInFetch)
{
FetchId.add("uint\ti;");
ClassNode->indexUsedInFetch = true;
}
if (!ClassNode->tableAndRowIndicesUsedInFetch)
{
FetchId.add(TTableIndexName+"\ttableIndex;\n"+TRowIndexName+"\trowIndex;");
ClassNode->tableAndRowIndicesUsedInFetch = true;
}
FetchId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
FetchId.add("{");
FetchId.add(cppName()+"[i] = NULL;");
FetchId.add("// read table and row, create an object, affect to the ref, and fetch it");
FetchId.add("data.serial(tableIndex, rowIndex);");
FetchId.add("if (rowIndex != "+INVALID_ROW_INDEXName+" && tableIndex != "+INVALID_TABLE_INDEXName+")");
FetchId.add("{");
FetchId.add(cppName()+"[i] = static_cast<"+Type+"*>("+pdslibFunc("create")+"(tableIndex));");
FetchId.add(pdslibFunc("setRowIndex")+"(rowIndex, "+cppName()+"[i]);");
FetchId.add(cppName()+"[i]->"+fetchFunction+"(data);");
FetchId.add(cppName()+"[i]->"+setUnnotifiedParentFunction+"(this);");
FetchId.add("}");
FetchId.add("}");
}
else
{
if (!ClassNode->indexUsedInFetch)
{
FetchId.add("uint\ti;");
ClassNode->indexUsedInFetch = true;
}
if (!ClassNode->tableAndRowIndicesUsedInFetch)
{
FetchId.add(TTableIndexName+"\ttableIndex;\n"+TRowIndexName+"\trowIndex;");
ClassNode->tableAndRowIndicesUsedInFetch = true;
}
FetchId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
FetchId.add("{");
FetchId.add("// read table and row, create an object, affect to the ref, and fetch it");
FetchId.add("data.serial(tableIndex, rowIndex);");
FetchId.add("if (rowIndex != "+INVALID_ROW_INDEXName+" && tableIndex != "+INVALID_TABLE_INDEXName+")");
FetchId.add("{");
FetchId.add(pdslibFunc("setRowIndex")+"(rowIndex, &"+cppName()+"[i]);");
FetchId.add(cppName()+"[i]."+fetchFunction+"(data);");
FetchId.add(cppName()+"[i]."+setUnnotifiedParentFunction+"(this);");
FetchId.add("}");
FetchId.add("}");
}
//
// generate register/unregister code
//
if (!useReference)
{
if (!ClassNode->indexUsedInRegister)
{
RegisterAttributesId.add("uint\ti;");
ClassNode->indexUsedInRegister = true;
}
RegisterAttributesId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
RegisterAttributesId.add("{");
RegisterAttributesId.add(cppName()+"[i]."+registerFunction+"();");
RegisterAttributesId.add(cppName()+"[i]."+setParentFunction+"(this);");
RegisterAttributesId.add("}");
if (!ClassNode->indexUsedInUnregister)
{
UnregisterAttributesId.add("uint\ti;");
ClassNode->indexUsedInUnregister = true;
}
UnregisterAttributesId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
UnregisterAttributesId.add("{");
UnregisterAttributesId.add(cppName()+"[i]."+unregisterFunction+"();");
UnregisterAttributesId.add("}");
}
else
{
if (!ClassNode->indexUsedInUnregister)
{
UnregisterAttributesId.add("uint\ti;");
ClassNode->indexUsedInUnregister = true;
}
UnregisterAttributesId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
UnregisterAttributesId.add("{");
UnregisterAttributesId.add("if ("+cppName()+"[i] != NULL)");
UnregisterAttributesId.add("{");
UnregisterAttributesId.add(Type+"*\t"+objectVariable+" = "+cppName()+"[i];");
UnregisterAttributesId.add(objectVariable+"->"+unregisterFunction+"();");
UnregisterAttributesId.add(objectVariable+"->"+destroyFunction+"();");
UnregisterAttributesId.add("delete "+objectVariable+";");
UnregisterAttributesId.add("}");
UnregisterAttributesId.add("}");
}
//
// generate init/release notification
//
if (!ClassNode->indexUsedInNotifyInit)
{
NotifyInitId.add("uint\ti;");
ClassNode->indexUsedInNotifyInit = true;
}
NotifyInitId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
NotifyInitId.add("{");
if (!ClassNode->indexUsedInNotifyRelease)
{
NotifyReleaseId.add("uint\ti;");
ClassNode->indexUsedInNotifyRelease = true;
}
NotifyReleaseId.add("for (i=0; i<"+ind->getSizeName()+"; ++i)");
NotifyReleaseId.add("{");
if (!useReference)
{
NotifyInitId.add(cppName()+"[i]."+notifyInitFunction+"();");
NotifyReleaseId.add(cppName()+"[i]."+notifyReleaseFunction+"();");
}
else
{
NotifyInitId.add("if ("+cppName()+"[i] != NULL)");
NotifyInitId.add("{");
NotifyInitId.add(cppName()+"[i]->"+notifyInitFunction+"();");
NotifyInitId.add("}");
NotifyReleaseId.add("if ("+cppName()+"[i] != NULL)");
NotifyReleaseId.add("{");
NotifyReleaseId.add(cppName()+"[i]->"+notifyReleaseFunction+"();");
NotifyReleaseId.add("}");
}
NotifyInitId.add("}");
NotifyReleaseId.add("}");
//
// generate unlink code
//
if (useReference)
{
Gen.startMethod("void", unlinkFunc(), ind->getName()+" "+keyVariable, "internal", false, inlineInternal);
Gen.add(cppName()+"["+keyVariable+"] = NULL;");
}
//
// generate clear code
//
ClearId.add("for (uint i=0; i<"+ind->getSizeName()+"; ++i)");
ClearId.add("{");
if (!useReference)
{
ClearId.add(cppName()+"[i]."+clearFunction+"();");
}
else
{
//ClearId.add(cppName()+"[i]->"+setParentFunction+"(NULL);");
ClearId.add(Type+"*\t"+objectVariable+" = "+cppName()+"[i];");
ClearId.add(objectVariable+"->"+unregisterFunction+"();");
ClearId.add(objectVariable+"->"+destroyFunction+"();");
ClearId.add("delete "+objectVariable+";");
}
ClearId.add("}");
}
void CDeclarationNode::generateSetContent(CCallContext *context)
{
setEnv("decltype", "set");
CClassGenerator &Gen = ClassNode->Gen;
CCppOutput& DbSummary = getDbNode()->DbSummary;
CClassGenerator::SMethodId &InitId = ClassNode->InitId;
CClassGenerator::SMethodId &ClearId = ClassNode->ClearId;
CClassGenerator::SMethodId &DestroyId = ClassNode->DestroyId;
CClassGenerator::SMethodId &FetchId = ClassNode->FetchId;
CClassGenerator::SMethodId &RegisterId = ClassNode->RegisterId;
CClassGenerator::SMethodId &RegisterAttributesId = ClassNode->RegisterAttributesId;
CClassGenerator::SMethodId &UnregisterId = ClassNode->UnregisterId;
CClassGenerator::SMethodId &UnregisterAttributesId = ClassNode->UnregisterAttributesId;
CClassGenerator::SMethodId &SetParentId = ClassNode->SetParentId;
CClassGenerator::SMethodId &SetUnnotifiedParentId = ClassNode->SetUnnotifiedParentId;
CClassGenerator::SMethodId &NotifyInitId = ClassNode->NotifyInitId;
CClassGenerator::SMethodId &NotifyReleaseId = ClassNode->NotifyReleaseId;
CClassNode *sub = getClassNode(Type);
CDeclarationNode *key = sub->getKey();
CTypeNode *keyType = getTypeNode(key->Type);
bool useReference = sub->ForceReference;
string access = (useReference ? "->" : ".");
string onChangeUser = getUserCode("onChange", context != NULL ? context->getUserCodeContext() : "");
string setType = "std::map<"+keyType->getName()+", " + Type + (useReference ? "*" : "") + ">";
CDeclarationNode *dnd = sub->getDeclarationNode(ForwardRefAttribute);
XmlNode += " type='set' classid='"+toString(sub->Id)+"' forwardreferedid='"+toString(dnd->Id)+"' key='"+toString(key->Id)+"' ";
setEnv("type", Type);
setEnv("keytype", keyType->getName());
define(useReference, "useref");
// EGS Compat
// -- begin
CClassGenerator::SMethodId& StoreId = ClassNode->StoreId;
CClassGenerator::SMethodId& ApplyId = ClassNode->ApplyId;
StoreId.add("// store "+Name);
StoreId.add("__pdr.pushStructBegin("+tokenName()+");");
StoreId.add("for ("+setType+"::const_iterator it="+cppName()+".begin(); it!="+cppName()+".end(); ++it)");
StoreId.add("{");
StoreId.add( keyType->getName()+"\tkey = (*it).first;");
keyType->generateStoreCode(StoreId, "__Tok_MapKey", "key");
StoreId.add( "__pdr.pushStructBegin(__Tok_MapVal);");
if (useReference)
{
generateClassPtrStoreCode("(*it).second");
}
else
{
StoreId.add("(*it).second.store(__pdr);");
}
StoreId.add( "__pdr.pushStructEnd(__Tok_MapVal);");
StoreId.add("}");
StoreId.add("__pdr.pushStructEnd("+tokenName()+");");
StoreId.add("// end of store "+Name);
ApplyId.add("// apply "+Name);
ApplyId.add("else if (__pdr.peekNextToken() == "+tokenName()+")");
ApplyId.add("{");
ApplyId.add( "__pdr.popStructBegin("+tokenName()+");");
ApplyId.add( "while (!__pdr.isEndOfStruct())");
ApplyId.add( "{");
ApplyId.add( keyType->getName()+"\tkey;");
keyType->generateApplyCode(ApplyId, "__Tok_MapKey", "key");
ApplyId.add( "__pdr.popStructBegin(__Tok_MapVal);");
if (useReference)
{
ApplyId.add( Type+"*\tobj;");
generateClassPtrApplyCode("obj");
ApplyId.add( "if (obj != NULL)");
ApplyId.add( "{");
ApplyId.add( cppName()+"[key] = obj;");
ApplyId.add( "}");
}
else
{
ApplyId.add( Type+"&\tobj = "+cppName()+"[key];");
ApplyId.add( "obj.apply(__pdr);");
ApplyId.add( "obj."+setUnnotifiedParentFunction+"(this);");
}
ApplyId.add( "__pdr.popStructEnd(__Tok_MapVal);");
ApplyId.add( "}");
ApplyId.add( "__pdr.popStructEnd("+tokenName()+");");
ApplyId.add("}");
ApplyId.add("// end of apply "+Name);
// -- end
//
// generate read accessor
//
Gen.startMethod(Type+"*", getFunc(), "const "+keyType->getName()+"& "+keyVariable, "methods", false, inlineAccessors);
DbSummary << "\t" << getFunc() << "\n";
Gen.add(setType+"::iterator _it = "+cppName()+".find("+keyVariable+");");
Gen.add("return (_it=="+cppName()+".end() ? NULL : "+(useReference ? "(*_it).second" : "&((*_it).second)")+");");
Gen.startMethod("const "+Type+"*", getFunc(), "const "+keyType->getName()+"& "+keyVariable, "methods", true, inlineAccessors);
Gen.add(setType+"::const_iterator _it = "+cppName()+".find("+keyVariable+");");
Gen.add("return (_it=="+cppName()+".end() ? NULL : "+(useReference ? "(*_it).second" : "&((*_it).second)")+");");
// generate map accessor
string stypedef = "T"+Name+"Map";
//Gen.addOther("typedef "+setType+"\t"+stypedef+";");
Gen.startMethod(setType+"::iterator", getFunc()+"Begin", "", "methods", false, inlineAccessors);
Gen.add("return "+cppName()+".begin();");
DbSummary << "\t" << getFunc() << "Begin" << "\n";
Gen.startMethod(setType+"::iterator", getFunc()+"End", "", "methods", false, inlineAccessors);
Gen.add("return "+cppName()+".end();");
DbSummary << "\t" << getFunc() << "End" << "\n";
Gen.startMethod(setType+"::const_iterator", getFunc()+"Begin", "", "methods", true, inlineAccessors);
Gen.add("return "+cppName()+".begin();");
Gen.startMethod(setType+"::const_iterator", getFunc()+"End", "", "methods", true, inlineAccessors);
Gen.add("return "+cppName()+".end();");
Gen.startMethod("const "+setType+" &", getFunc(), "", "methods", true, inlineAccessors);
Gen.add("return "+cppName()+";");
//
// generate write accessor
//
if (useReference)
{
Gen.startMethod("void", setFunc(), Type+"* "+valueVariable, "methods", false, inlineAccessors);
DbSummary << "\t" << setFunc() << "\n";
Gen.add("if ("+valueVariable+" == NULL)\treturn;");
Gen.add(keyType->getName()+"\t"+keyVariable+" = "+valueVariable+"->"+sub->getKey()->getFunc()+"();");
Gen.add(setType+"::iterator\t_it = "+cppName()+".find("+keyVariable+");");
Gen.add("if (_it != "+cppName()+".end())");
Gen.add("{");
Gen.add(Type+"*\t__prev = (*_it).second;");
Gen.add("if (__prev == "+valueVariable+")\treturn;");
Gen.add("__prev->"+setParentFunction+"(NULL);");
Gen.add("__prev->"+unregisterFunction+"();");
Gen.add("__prev->"+destroyFunction+"();");
Gen.add("delete __prev;");
Gen.add("}");
Gen.add(valueVariable+"->"+setParentFunction+"(this);");
Gen.add(cppName()+"["+keyVariable+"] = "+valueVariable+";");
if (!onChangeUser.empty())
{
Gen.add("{");
Gen.add(onChangeUser);
Gen.add("}");
}
}
if (sub->MapClass == NULL && !sub->HasInheritance && !sub->DerivatedFlag)
{
Gen.startMethod(Type+"*", newFunc(), "const "+keyType->getName()+" &"+keyVariable, "methods", false, inlineAccessors);
DbSummary << "\t" << newFunc() << "\n";
Gen.add(setType+"::iterator\t__it = "+cppName()+".find("+keyVariable+");");
Gen.add("if (__it == "+cppName()+".end())");
Gen.add("{");
Gen.add("__it = "+cppName()+".insert("+setType+"::value_type("+keyVariable+", "+(useReference ? toString("new ") : toString(""))+Type+"())).first;");
Gen.add(Type+"*\t"+objectVariable+" = "+(useReference ? toString("") : toString("&"))+"((*__it).second);");
Gen.add(objectVariable+"->"+initFunction+"("+keyVariable+");");
Gen.add(objectVariable+"->"+registerFunction+"();");
Gen.add(objectVariable+"->"+setParentFunction+"(this);");
Gen.add("}");
if (!onChangeUser.empty())
{
Gen.add("{");
Gen.add(onChangeUser);
Gen.add("}");
}
Gen.add("return "+(useReference ? toString("") : toString("&"))+"((*__it).second);");
}
Gen.startMethod("void", deleteFunc(), "const "+keyType->getName()+" &"+keyVariable, "methods", false, inlineAccessors);
DbSummary << "\t" << deleteFunc() << "\n";
Gen.add(setType+"::iterator\t__it = "+cppName()+".find("+keyVariable+");");
Gen.add("if (__it == "+cppName()+".end())\treturn;");
if (useReference)
{
Gen.add(Type+"*\t"+objectVariable+" = (*__it).second;");
Gen.add(objectVariable+"->"+unregisterFunction+"();");
Gen.add(objectVariable+"->"+destroyFunction+"();");
Gen.add("delete "+objectVariable+";");
}
else
{
Gen.add(Type+"&\t"+objectVariable+" = (*__it).second;");
Gen.add(objectVariable+"."+unregisterFunction+"();");
Gen.add(cppName()+".erase(__it);");
}
if (!onChangeUser.empty())
{
Gen.add("{");
Gen.add(onChangeUser);
Gen.add("}");
}
//
// generate attribute
//
Gen.addAttribute(setType, cppName(), "attributes");
//
// generate init
//
//
// generate destroy code
//
DestroyId.add("for ("+setType+"::iterator __it="+cppName()+".begin(); __it!="+cppName()+".end(); )");
DestroyId.add("{");
DestroyId.add(setType+"::iterator __itr=__it++;");
if (useReference)
{
DestroyId.add(Type+"*\t"+objectVariable+" = ((*__itr).second);");
DestroyId.add("if ("+objectVariable+" != NULL)");
DestroyId.add("{");
DestroyId.add(objectVariable+"->"+destroyFunction+"();");
DestroyId.add("delete "+objectVariable+";");
DestroyId.add("}");
}
else
{
DestroyId.add("((*__itr).second)."+destroyFunction+"();");
}
DestroyId.add("}");
DestroyId.add(cppName()+".clear();");
//
// generate create code
//
//
// generate fetch code
//
if (!ClassNode->tableAndRowIndicesUsedInFetch)
{
FetchId.add(TTableIndexName+"\ttableIndex;\n"+TRowIndexName+"\trowIndex;");
ClassNode->tableAndRowIndicesUsedInFetch = true;
}
FetchId.add("do");
FetchId.add("{");
FetchId.add("// read table and row, create an object, affect to the ref, and fetch it");
FetchId.add("data.serial(tableIndex, rowIndex);");
FetchId.add("if (rowIndex == "+INVALID_ROW_INDEXName+" || tableIndex == "+INVALID_TABLE_INDEXName+")\tbreak;");
FetchId.add(keyType->getName()+"\t"+keyVariable+";");
if (keyType->isEnum())
{
FetchId.add("data.serialEnum("+keyVariable+");");
}
else if (keyType->CppType != keyType->StorageType)
{
FetchId.add("{");
FetchId.add(keyType->StorageType+"\t_v;");
FetchId.add("data.serial(_v);");
FetchId.add(keyVariable+" = "+keyType->castToCpp("_v")+";");
FetchId.add("}");
}
else
{
FetchId.add("data.serial("+keyVariable+");");
}
if (useReference)
{
FetchId.add(Type+"*\t"+objectVariable+" = static_cast<"+Type+"*>("+pdslibFunc("create")+"(tableIndex));");
FetchId.add(cppName()+".insert(std::make_pair<"+keyType->getName()+","+Type+"*>("+keyVariable+", "+objectVariable+"));");
}
else
{
FetchId.add(cppName()+".insert(std::make_pair<"+keyType->getName()+","+Type+">("+keyVariable+", "+Type+"()));");
FetchId.add(Type+"*\t"+objectVariable+" = &("+cppName()+"["+keyVariable+"]);");
}
FetchId.add(pdslibFunc("setRowIndex")+"(rowIndex, "+objectVariable+");");
FetchId.add(objectVariable+"->"+fetchFunction+"(data);");
FetchId.add(objectVariable+"->"+setUnnotifiedParentFunction+"(this);");
FetchId.add("}");
FetchId.add("while (true);");
//
// generate register/unregister code
//
UnregisterAttributesId.add("for ("+setType+"::iterator __it="+cppName()+".begin(); __it!="+cppName()+".end(); )");
UnregisterAttributesId.add("{");
UnregisterAttributesId.add(setType+"::iterator __itr=__it++;");
if (useReference)
{
UnregisterAttributesId.add(Type+"*\t"+objectVariable+" = (*__itr).second;");
UnregisterAttributesId.add(objectVariable+"->"+unregisterFunction+"();");
UnregisterAttributesId.add(objectVariable+"->"+destroyFunction+"();");
UnregisterAttributesId.add("delete "+objectVariable+";");
}
else
{
UnregisterAttributesId.add(Type+"&\t"+objectVariable+" = (*__itr).second;");
UnregisterAttributesId.add(objectVariable+"."+unregisterFunction+"();");
}
UnregisterAttributesId.add("}");
//
// generate init/release notification
//
NotifyInitId.add("for ("+setType+"::iterator __it="+cppName()+".begin(); __it!="+cppName()+".end(); )");
NotifyInitId.add("{");
NotifyInitId.add(setType+"::iterator __itr=__it++;");
NotifyReleaseId.add("for ("+setType+"::iterator __it="+cppName()+".begin(); __it!="+cppName()+".end(); )");
NotifyReleaseId.add("{");
NotifyReleaseId.add(setType+"::iterator __itr=__it++;");
if (!useReference)
{
NotifyInitId.add("(*__itr).second."+notifyInitFunction+"();");
NotifyReleaseId.add("(*__itr).second."+notifyReleaseFunction+"();");
}
else
{
NotifyInitId.add("(*__itr).second->"+notifyInitFunction+"();");
NotifyReleaseId.add("(*__itr).second->"+notifyReleaseFunction+"();");
}
NotifyInitId.add("}");
NotifyReleaseId.add("}");
//
// generate unlink code
//
if (useReference)
{
Gen.startMethod("void", unlinkFunc(), keyType->getName()+" "+keyVariable, "internal", false, inlineInternal);
Gen.add(cppName()+".erase("+keyVariable+");");
}
//
// generate clear code
//
ClearId.add("for ("+setType+"::iterator __it="+cppName()+".begin(); __it!="+cppName()+".end(); )");
ClearId.add("{");
ClearId.add(setType+"::iterator __itr=__it++;");
if (!useReference)
{
ClearId.add(Type+"*\t"+objectVariable+" = &((*__itr).second);");
}
else
{
ClearId.add(Type+"*\t"+objectVariable+" = (*__itr).second;");
}
//ClearId.add(objectVariable+"->"+setParentFunction+"(NULL);");
ClearId.add(objectVariable+"->"+unregisterFunction+"();");
ClearId.add(objectVariable+"->"+destroyFunction+"();");
if (useReference)
{
ClearId.add("delete "+objectVariable+";");
}
ClearId.add("}");
ClearId.add(cppName()+".clear();");
}
//
string CDeclarationNode::displayPrintfPrefix()
{
if (DeclarationType != SimpleType)
error("can't display other declaration than simple type", "internal");
CTypeNode* type = getTypeNode(Type);
if (type->CppType == "CEntityId" || type->CppType == "CSheetId")
return "%s";
else if (type->CppType == "uint64" || type->CppType == "sint64")
return "%\"NL_I64\"d";
else if (type->CppType == "float" || type->CppType == "double")
return "%g";
else
return "%d";
}
string CDeclarationNode::displayCppCode(string replVar)
{
if (DeclarationType != SimpleType)
error("can't display other declaration than simple type", "internal");
if (replVar.empty())
replVar = cppName();
CTypeNode* type = getTypeNode(Type);
if (type->CppType == "CEntityId" || type->CppType == "CSheetId")
return replVar+".toString().c_str()";
else
return replVar;
}
string CDeclarationNode::toUint64(string replVar)
{
if (DeclarationType != SimpleType)
error("can't display other declaration than simple type", "internal");
if (replVar.empty())
replVar = cppName();
CTypeNode* type = getTypeNode(Type);
if (type->CppType == "CEntityId")
return replVar+".asUint64()";
else if (type->CppType == "CSheetId")
return "(uint64)("+replVar+".asInt())";
else
return "(uint64)"+replVar;
}
bool CLogMsgNode::prolog()
{
getDbNode()->LogNodes.push_back(this);
getFileNode()->IncludeDbFile = true;
getFileNode()->IncludeStandard = true;
getFileNode()->IncludePDSLib = true;
return true;
}
void CLogMsgNode::generateContent()
{
//
uint j;
CFunctionGenerator logfunc;
CClassGenerator logclass;
string argcall;
CFunctionGenerator& initDb = getDbNode()->initDb;
logfunc.init(Name);
logfunc.setType("void");
logfunc.IsInline = inlineLogFunctions;
logclass.init("Log"+Name);
logclass.createPublic("pub");
logclass.createPrivate("priv");
CClassGenerator::SMethodId startlogid = logclass.startMethod("void", logStartFunction, "", "priv", false, inlineLogFunctions);
CClassGenerator::SMethodId stoplogid = logclass.startMethod("void", logStopFunction, "", "priv", false, inlineLogFunctions);
startlogid.add(pdslibFunc("pushContext")+"();");
stoplogid.add(pdslibFunc("popContext")+"();");
map<string, CParseNode*> params;
for (j=0; j<Params.size(); ++j)
{
string type = Params[j].first;
string name = Params[j].second;
CTypeNode *tnd;
CClassNode *cnd;
if ( (tnd = getTypeNode(type, false)) )
{
pair<map<string, CParseNode*>::iterator, bool> res = params.insert(make_pair<string, CParseNode*>(name, tnd));
if (!res.second)
error("log parameter '"+name+"' already defined");
if (!logfunc.Proto.empty())
logfunc.Proto += ", ";
if (!argcall.empty())
argcall += ", ";
logfunc.Proto += tnd->getName()+" "+name;
argcall += name;
}
else if ( (cnd = getClassNode(type, false)) )
{
pair<map<string, CParseNode*>::iterator, bool> res = params.insert(make_pair<string, CParseNode*>(name, cnd));
if (!res.second)
error("log parameter '"+name+"' already defined");
if (!logfunc.Proto.empty())
logfunc.Proto += ", ";
if (!argcall.empty())
argcall += ", ";
logfunc.Proto += "const "+type+"& "+name;
argcall += name;
}
else if (type == "string")
{
CExtLogTypeNode* extnd = new CExtLogTypeNode();
extnd->ExtLogType = "string";
pair<map<string, CParseNode*>::iterator, bool> res = params.insert(make_pair<string, CParseNode*>(name, extnd));
if (!res.second)
error("log parameter '"+name+"' already defined");
if (!logfunc.Proto.empty())
logfunc.Proto += ", ";
if (!argcall.empty())
argcall += ", ";
logfunc.Proto += "const std::string& "+name;
argcall += name;
}
else
{
error("'"+type+"' not found as a class or a type");
}
}
//
initDb.add("// Init "+Name+" log message and parameters");
for (j=0; j<Logs.size(); ++j)
{
uint logId = Id+j;
logfunc.add(pdslibFunc("log")+"("+toString(logId)+");");
startlogid.add(pdslibFunc("log")+"("+toString(logId)+");");
const char *cptr = Logs[j].c_str();
string log;
// parse log line
getDbNode()->xmlDescription.push_back("<logmsg id='"+toString(logId)+"' context='"+string(Context ? "true" : "false")+"'>");
uint paramNum = 0;
initDb.add(pdslibFunc("initLog")+"("+toString(logId)+");");
while (*cptr != '\0')
{
if (*cptr == '$')
{
++cptr;
if (*cptr == '\0')
error("log format corrupted in line \""+Logs[j]+"\"");
if (*cptr == '$')
{
log += "$$";
++cptr;
continue;
}
string param;
string var;
while (*cptr!='\0' && *cptr!='$' && *cptr!='.')
param += *(cptr++);
if (*cptr == '\0')
error("log format corrupted in line \""+Logs[j]+"\"");
if (*cptr == '.')
{
++cptr;
while (*cptr!='\0' && *cptr!='$')
var += *(cptr++);
}
if (*cptr != '$')
error("log format corrupted in line \""+Logs[j]+"\"");
++cptr;
map<string, CParseNode*>::iterator it = params.find(param);
if (it == params.end())
error("'"+param+"' ot found in prototype, at line \""+Logs[j]+"\"");
CTypeNode *tnd = NULL;
CExtLogTypeNode* extnd = NULL;
if (var.empty())
{
// is simple type
tnd = dynamic_cast<CTypeNode*>((*it).second);
extnd = dynamic_cast<CExtLogTypeNode*>((*it).second);
if (tnd != NULL)
{
logfunc.add(pdslibFunc("logPush")+"("+tnd->castToPDS(param)+");");
startlogid.add(pdslibFunc("logPush")+"("+tnd->castToPDS(param)+");");
}
else if (extnd != NULL && extnd->ExtLogType == "string")
{
logfunc.add(pdslibFunc("logPush")+"("+param+");");
startlogid.add(pdslibFunc("logPush")+"("+param+");");
}
else
{
error("misuse of parameter '"+param+"' at line \""+Logs[j]+"\", missing attribute name");
}
}
else
{
// is class
CClassNode *cnd = dynamic_cast<CClassNode*>((*it).second);
if (!cnd)
error("misuse of parameter '"+param+"' at line \""+Logs[j]+"\", should be a class");
CDeclarationNode *dnd = cnd->getDeclaration(var);
if (!dnd->IsType)
error("attribute '"+var+"' is not a simple type");
tnd = getTypeNode(dnd->Type);
logfunc.add(pdslibFunc("logPush")+"("+tnd->castToPDS(param+"."+dnd->getFunc()+"()")+");");
startlogid.add(pdslibFunc("logPush")+"("+tnd->castToPDS(param+"."+dnd->getFunc()+"()")+");");
}
if (tnd != NULL)
{
getDbNode()->xmlDescription.push_back("<param id='"+toString(paramNum)+"' typeid='"+toString(tnd->Id)+"'/>");
initDb.add(pdslibFunc("initLogParam")+"("+toString(logId)+", "+toString(paramNum)+", "+toString(tnd->Size)+");");
}
else
{
getDbNode()->xmlDescription.push_back("<param id='"+toString(paramNum)+"' typeid='"+extnd->ExtLogType+"'/>");
initDb.add(pdslibFunc("initLogParam")+"("+toString(logId)+", "+toString(paramNum)+", "+toString(sizeof(uint16))+");");
}
log += "$"+toString(paramNum);
++paramNum;
}
else
{
log += *(cptr++);
}
}
getDbNode()->xmlDescription.push_back("<msg>"+xmlSpecialChars(log)+"</msg>");
getDbNode()->xmlDescription.push_back("</logmsg>");
}
logclass.get(startlogid).Proto = logfunc.Proto;
CClassGenerator::SMethodId construct = logclass.startConstructor(logfunc.Proto, "pub", inlineLogFunctions, "");
construct.add(logStartFunction+"("+argcall+");");
CClassGenerator::SMethodId destruct = logclass.startDestructor("pub", inlineLogFunctions);
destruct.add(logStopFunction+"();");
CFileNode* file = getFileNode();
if (Context)
{
logclass.flush(file->hOutput(), file->cppOutput(), file->inlineOutput());
file->hOutput() << "\n";
}
else
{
logfunc.flush(file->hOutput(), file->cppOutput(), file->inlineOutput());
file->hOutput() << "\n";
}
}