Files
SourcetrailDB/examples/cpp_poetry_indexer/src/main.cpp
T

219 lines
5.7 KiB
C++

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <regex>
#include "SourcetrailDBWriter.h"
#include "NameHierarchy.h"
#include "SourceRange.h"
sourcetrail::NameHierarchy toNameHierarchy(const std::vector<std::string>& strs)
{
sourcetrail::NameHierarchy name = { " - ", { } };
for (auto str : strs)
{
if (str.size())
{
name.nameElements.emplace_back( sourcetrail::NameElement({ "", str, "" }) );
}
}
return name;
}
int main(int argc, const char *argv[])
{
sourcetrail::SourcetrailDBWriter dbWriter;
std::cout << "\nSourcetrailDB Poetry Indexer" << std::endl;
std::cout << std::endl;
std::cout << "SourcetrailDB version: " << dbWriter.getVersionString() << std::endl;
std::cout << "Supported database version: " << dbWriter.getSupportedDatabaseVersion() << std::endl;
std::cout << std::endl;
if (argc < 3 || argc > 4)
{
std::cout << "usage: poetry_indexer <database_path> <source_path> <optional:database_version>";
return 1;
}
std::string dbPath = argv[1];
std::string sourcePath = argv[2];
int dbVersion = 0;
if (argc == 4)
{
char* end;
dbVersion = strtol(argv[3], &end, 10);
}
if (dbVersion && dbVersion != dbWriter.getSupportedDatabaseVersion())
{
std::cerr << "error: binary only supports database version: " << dbWriter.getSupportedDatabaseVersion()
<< ". Requested version: " << dbVersion << std::endl;
return 1;
}
std::ifstream fileStream(sourcePath.c_str());
if (!fileStream.good())
{
std::cerr << "error: opening file failed: " << sourcePath << std::endl;
return 1;
}
std::cout << "Opening Database: " << dbPath << std::endl;
if (!dbWriter.open(dbPath))
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
std::cout << "Starting Indexing: " << sourcePath << std::endl;
if (!dbWriter.beginTransaction())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
int fileId = dbWriter.recordFile(sourcePath);
if (fileId == 0)
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
std::string author;
struct {
int id = 0;
std::string name;
} poem;
struct {
int id = 0;
int number = 0;
sourcetrail::SourceRange range;
} paragraph;
struct {
int number = 0;
std::string content;
} line;
int symbolId = 0;
// foreach poem line
while (getline(fileStream, line.content, '\n'))
{
line.number++;
// first line: author
// second line: title
if (line.number <= 2)
{
// store the author as namespace, the title as type
symbolId = dbWriter.recordSymbol(toNameHierarchy({ author, line.content }));
dbWriter.recordSymbolDefinitionKind(symbolId, sourcetrail::DefinitionKind::EXPLICIT);
dbWriter.recordSymbolKind(symbolId, line.number == 1 ? sourcetrail::SymbolKind::NAMESPACE : sourcetrail::SymbolKind::TYPE);
sourcetrail::SourceRange range = { fileId, line.number, 1, line.number, static_cast<int>(line.content.size()) };
dbWriter.recordSymbolLocation(symbolId, range);
if (line.number == 1)
{
author = line.content;
}
else
{
poem.id = symbolId;
poem.name = line.content;
}
continue;
}
else if (line.content.size() <= 1) // empty line
{
if (paragraph.id) // if paragraph exists then close it
{
dbWriter.recordSymbolScopeLocation(paragraph.id, paragraph.range);
dbWriter.recordSymbolSignatureLocation(paragraph.id, paragraph.range);
paragraph.id = 0;
}
}
else if (!paragraph.id) // start new paragraph
{
paragraph.number++;
// store each paragraph as method
paragraph.id = dbWriter.recordSymbol(toNameHierarchy({ author, poem.name, "paragraph " + std::to_string(paragraph.number) }));
dbWriter.recordSymbolDefinitionKind(paragraph.id, sourcetrail::DefinitionKind::EXPLICIT);
dbWriter.recordSymbolKind(paragraph.id, sourcetrail::SymbolKind::METHOD);
paragraph.range = { fileId, line.number, 1, 0, 0 };
symbolId = paragraph.id;
}
if (line.content.size() > 1)
{
// match every word in the line
std::string str = line.content;
std::smatch match;
std::regex regExp("[\\w']+");
size_t pos = 0;
while (std::regex_search(str, match, regExp))
{
std::string m = match[0];
std::string word;
std::transform(m.begin(), m.end(), std::back_inserter(word), tolower);
int wordPos = match.position(0) + 1;
int wordLen = match.length(0);
// store each word as global variable
int wordId = dbWriter.recordSymbol(toNameHierarchy({ word }));
dbWriter.recordSymbolDefinitionKind(wordId, sourcetrail::DefinitionKind::EXPLICIT);
dbWriter.recordSymbolKind(wordId, sourcetrail::SymbolKind::GLOBAL_VARIABLE);
// create a reference between word and paragraph
int referenceId = dbWriter.recordReference(symbolId, wordId, sourcetrail::ReferenceKind::USAGE);
sourcetrail::SourceRange range = { fileId, line.number, static_cast<int>(pos + wordPos), line.number, static_cast<int>(pos + wordPos + wordLen) - 1 };
dbWriter.recordReferenceLocation(referenceId, range);
str = match.suffix();
pos += wordPos + wordLen - 1;
}
}
paragraph.range.endLine = line.number;
paragraph.range.endColumn = line.content.size();
}
if (paragraph.id)
{
dbWriter.recordSymbolScopeLocation(paragraph.id, paragraph.range);
dbWriter.recordSymbolSignatureLocation(paragraph.id, paragraph.range);
paragraph.id = 0;
}
sourcetrail::SourceRange range = { fileId, 2, 1, line.number, int(line.content.size()) };
dbWriter.recordSymbolScopeLocation(poem.id, range);
fileStream.close();
if (!dbWriter.commitTransaction())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
if (dbWriter.getLastError().size())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
std::cout << "done!" << std::endl;
return 0;
}