Improved generation of c/cpp string from query

Extra lines before and after query are removed. Whitespace at end of line
is removed. SQL comments are converted to cpp style comments and are outside
the string literal.

To achieve this the function now uses the SQLLexer to know what is comment.
This also required the additional capability in the lexer to also return whitespace and newline tokens.
Also a few bugs in the lexer were fixed.
This commit is contained in:
eelke 2019-08-19 13:52:23 +02:00
parent fbd630489e
commit 48ac8c6bab
7 changed files with 247 additions and 34 deletions

View file

@ -1,5 +1,6 @@
#include "util.h"
#include "CsvWriter.h"
#include "SqlLexer.h"
#include <QApplication>
#include <QTextStream>
#include <QClipboard>
@ -106,32 +107,77 @@ void copySelectionToClipboard(const QTableView *view)
}
}
QString ConvertToMultiLineCString(const QString &in)
QString ConvertToMultiLineCString(const QString &in_)
{
// We need to atleast escape " and \ and also any multi byte utf8 char
QString out;
out.append('"');
QByteArray ba = in.toUtf8();
for (auto c : ba) {
if (c == '\\') {
out.append("\\\\");
}
else if (c == '"') {
out.append("\\\"");
}
else if (uchar(c) > 127) {
out.append(QString("\\x%1").arg(uchar(c), 2, 16, QChar('0')));
}
else if (c == '\n') {
// at end of line we add a space and a new line in the string then we put in the end quote go to the next line and put the open quote
out.append(" \\n\"\n\"");
}
else {
out.append(c);
// remove empty lines at start
int last_nl_idx = 0;
for (int idx = 0; idx < in_.length(); ++idx) {
QChar c = in_[idx];
if (c == '\n') last_nl_idx = idx+1;
if (!c.isSpace()) {
break;
}
}
QString in = in_.right(in_.length() - last_nl_idx);
int idx;
for (idx = in.length() - 1; idx >= 0 && in[idx].isSpace(); --idx) ;
++idx;
in.truncate(idx);
SqlLexer lexer(in, LexerState::Null, true);
QString out;
QString line = "\"";
QString comment;
while (true) {
SqlToken token = lexer.nextBasicToken();
if (token.ok) {
if (token.tokenType == BasicTokenType::Comment) {
// save comment is seperate variable
comment = "//" + token.out.rightRef(token.out.length()-2);
// Trim whitespace on right
int idx;
for (idx = comment.length() - 1; idx >= 0 && comment[idx].isSpace(); --idx) ;
++idx;
comment.truncate(idx);
}
else if (token.tokenType == BasicTokenType::End || token.tokenType == BasicTokenType::NewLine) {
// trim right
{
int idx;
for (idx = line.length() - 1; idx >= 0 && line[idx].isSpace(); --idx) ;
++idx;
if (!comment.isEmpty()) {
// put the whitespace in front of the comment so it will be outside the contents of the string literal but alignment of comments is preserved
comment = line.rightRef(line.length() - (idx)) + comment;
}
line.truncate(idx);
}
out += line;
if (token.tokenType == BasicTokenType::End) {
out += "\"";
out += comment;
break;
}
else {
out += "\\n\"";
out += comment;
out += "\n";
line = "\"";
}
comment.clear();
}
else {
line += token.out;
}
}
else {
// error during lexical analysis, need to recover
throw std::runtime_error("Unrecognized input");
}
}
out.append('"');
return out;
}