aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2014-12-06 17:33:25 -0500
committerLibravatarUnit 193 <unit193@ubuntu.com>2014-12-06 17:33:25 -0500
commit7167ce41b61d2ba2cdb526777a4233eb84a3b66a (patch)
treea35c14143716e1f2c98f808c81f89426045a946f /SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp
Imported Upstream version 2.99.6upstream/2.99.6
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp323
1 files changed, 323 insertions, 0 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp
new file mode 100644
index 0000000..23a4b55
--- /dev/null
+++ b/SQLiteStudio3/coreSQLiteStudio/parser/parser.cpp
@@ -0,0 +1,323 @@
+#include "parser.h"
+#include "parsercontext.h"
+#include "parsererror.h"
+#include "lexer.h"
+#include "../db/db.h"
+#include "ast/sqliteselect.h"
+#include <QStringList>
+#include <QDebug>
+
+// Generated in sqlite*_parse.c by lemon,
+// but not exported in any header
+void* sqlite3_parseAlloc(void *(*mallocProc)(size_t));
+void sqlite3_parseFree(void *p, void (*freeProc)(void*));
+void sqlite3_parse(void *yyp, int yymajor, Token* yyminor, ParserContext* parserContext);
+void sqlite3_parseTrace(FILE *stream, char *zPrefix);
+void* sqlite3_parseCopyParserState(void* other);
+void sqlite3_parseRestoreParserState(void* saved, void* target);
+void sqlite3_parseFreeSavedState(void* other);
+void sqlite3_parseAddToken(void* other, Token* token);
+
+void* sqlite2_parseAlloc(void *(*mallocProc)(size_t));
+void sqlite2_parseFree(void *p, void (*freeProc)(void*));
+void sqlite2_parse(void *yyp, int yymajor, Token* yyminor, ParserContext* parserContext);
+void sqlite2_parseTrace(FILE *stream, char *zPrefix);
+void* sqlite2_parseCopyParserState(void* other);
+void sqlite2_parseRestoreParserState(void* saved, void* target);
+void sqlite2_parseFreeSavedState(void* other);
+void sqlite2_parseAddToken(void* other, Token* token);
+
+Parser::Parser(Dialect dialect)
+{
+ this->dialect = dialect;
+ init();
+}
+
+Parser::~Parser()
+{
+ cleanUp();
+}
+
+void Parser::cleanUp()
+{
+ if (lexer)
+ {
+ delete lexer;
+ lexer = nullptr;
+ }
+
+ if (context)
+ {
+ delete context;
+ context = nullptr;
+ }
+}
+
+void Parser::fillSqliteDialect()
+{
+ foreach (SqliteQueryPtr query, context->parsedQueries)
+ query->setSqliteDialect(dialect);
+}
+
+void *Parser::parseAlloc(void *(*mallocProc)(size_t))
+{
+ if (dialect == Dialect::Sqlite2)
+ return sqlite2_parseAlloc(mallocProc);
+ else
+ return sqlite3_parseAlloc(mallocProc);
+}
+
+void Parser::parseFree(void *p, void (*freeProc)(void *))
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseFree(p, freeProc);
+ else
+ sqlite3_parseFree(p, freeProc);
+}
+
+void Parser::parse(void *yyp, int yymajor, TokenPtr yyminor, ParserContext *parserContext)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parse(yyp, yymajor, yyminor.data(), parserContext);
+ else
+ sqlite3_parse(yyp, yymajor, yyminor.data(), parserContext);
+}
+
+void Parser::parseTrace(FILE *stream, char *zPrefix)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseTrace(stream, zPrefix);
+ else
+ sqlite3_parseTrace(stream, zPrefix);
+}
+
+void *Parser::parseCopyParserState(void *other)
+{
+ if (dialect == Dialect::Sqlite2)
+ return sqlite2_parseCopyParserState(other);
+ else
+ return sqlite3_parseCopyParserState(other);
+}
+
+void Parser::parseRestoreParserState(void *saved, void *target)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseRestoreParserState(saved, target);
+ else
+ sqlite3_parseRestoreParserState(saved, target);
+}
+
+void Parser::parseFreeSavedState(void *other)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseFreeSavedState(other);
+ else
+ sqlite3_parseFreeSavedState(other);
+}
+
+void Parser::parseAddToken(void *other, TokenPtr token)
+{
+ if (dialect == Dialect::Sqlite2)
+ sqlite2_parseAddToken(other, token.data());
+ else
+ sqlite3_parseAddToken(other, token.data());
+}
+
+bool Parser::parse(const QString &sql, bool ignoreMinorErrors)
+{
+ context->ignoreMinorErrors = ignoreMinorErrors;
+ return parseInternal(sql, false);
+}
+
+bool Parser::parseInternal(const QString &sql, bool lookForExpectedToken)
+{
+ void* pParser = parseAlloc( malloc );
+ if (debugLemon)
+ {
+ char* label = nullptr;
+ if (dialect == Dialect::Sqlite2)
+ label = const_cast<char*>("[LEMON2]: ");
+ else
+ label = const_cast<char*>("[LEMON3]: ");
+
+ parseTrace(stderr, label);
+ }
+
+ reset();
+ lexer->prepare(sql);
+ context->setupTokens = !lookForExpectedToken;
+ context->executeRules = !lookForExpectedToken;
+ context->doFallbacks = !lookForExpectedToken;
+ context->dialect = dialect;
+
+ TokenPtr token = lexer->getToken();
+ if (!token.isNull())
+ context->addManagedToken(token);
+
+ bool endsWithSemicolon = false;
+
+ while (token)
+ {
+ if (token->type == Token::SPACE ||
+ token->type == Token::COMMENT ||
+ token->type == Token::INVALID)
+ {
+ parseAddToken(pParser, token);
+ token = lexer->getToken();
+ if (token)
+ context->addManagedToken(token);
+
+ continue;
+ }
+
+ endsWithSemicolon = (token->type == Token::OPERATOR && token->value == ";");
+
+ parse(pParser, token->lemonType, token, context);
+ token = lexer->getToken();
+ if (!token.isNull())
+ context->addManagedToken(token);
+ }
+
+ if (lookForExpectedToken)
+ {
+ expectedTokenLookup(pParser);
+ }
+ else
+ {
+ if (!endsWithSemicolon)
+ {
+ token = Lexer::getSemicolonToken(dialect);
+ parse(pParser, token->lemonType, token, context);
+ }
+
+ qint64 endIdx = sql.length();
+ TokenPtr endToken = TokenPtr::create(0, Token::INVALID, QString::null, endIdx, endIdx);
+ parse(pParser, 0, endToken, context);
+ }
+
+ fillSqliteDialect();
+
+ // Free all non-termials having destructors
+ parseFree(pParser, free);
+
+ context->flushErrors();
+
+ if (context->isSuccessful())
+ {
+ for (SqliteQueryPtr query : context->parsedQueries)
+ query->processPostParsing();
+ }
+
+ return context->isSuccessful();
+}
+
+TokenList Parser::getNextTokenCandidates(const QString &sql)
+{
+ context->ignoreMinorErrors = true;
+ parseInternal(sql, true);
+ TokenList results = acceptedTokens;
+ acceptedTokens.clear();
+ return results;
+}
+
+bool Parser::isSuccessful() const
+{
+ return context->isSuccessful();
+}
+
+void Parser::reset()
+{
+ acceptedTokens.clear();
+ lexer->cleanUp();
+ context->cleanUp();
+}
+
+SqliteExpr *Parser::parseExpr(const QString &sql)
+{
+ SqliteSelectPtr select = parse<SqliteSelect>("SELECT "+sql+";");
+ if (!select || select->coreSelects.size() == 0 || select->coreSelects.first()->resultColumns.size() == 0)
+ return nullptr;
+
+ SqliteExpr* expr = select->coreSelects.first()->resultColumns.first()->expr;
+ expr->setParent(nullptr);
+ return expr;
+}
+
+void Parser::expectedTokenLookup(void* pParser)
+{
+ void* savedParser = parseCopyParserState(pParser);
+
+ ParserContext tempContext;
+ tempContext.executeRules = false;
+ tempContext.executeRules = false;
+ tempContext.doFallbacks = false;
+ QSet<TokenPtr> tokenSet =
+ lexer->getEveryTokenType({
+ Token::KEYWORD, Token::OTHER, Token::PAR_LEFT, Token::PAR_RIGHT, Token::OPERATOR,
+ Token::CTX_COLLATION, Token::CTX_COLUMN, Token::CTX_DATABASE, Token::CTX_FUNCTION,
+ Token::CTX_INDEX, Token::CTX_JOIN_OPTS, Token::CTX_TABLE, Token::CTX_TRIGGER,
+ Token::CTX_VIEW, Token::CTX_FK_MATCH, Token::CTX_ERROR_MESSAGE, Token::CTX_PRAGMA,
+ Token::CTX_ALIAS, Token::CTX_TABLE_NEW, Token::CTX_INDEX_NEW, Token::CTX_TRIGGER_NEW,
+ Token::CTX_VIEW_NEW, Token::CTX_COLUMN_NEW, Token::CTX_TRANSACTION,
+ Token::CTX_CONSTRAINT, Token::CTX_COLUMN_TYPE, Token::CTX_OLD_KW, Token::CTX_NEW_KW,
+ Token::CTX_ROWID_KW, Token::INVALID
+ });
+
+ foreach (TokenPtr token, tokenSet)
+ {
+ parse(pParser, token->lemonType, token, &tempContext);
+
+ if (tempContext.isSuccessful())
+ acceptedTokens += token;
+
+ tempContext.cleanUp();
+ parseRestoreParserState(savedParser, pParser);
+ }
+ parseFreeSavedState(savedParser);
+}
+
+void Parser::init()
+{
+ lexer = new Lexer(dialect);
+ context = new ParserContext();
+}
+
+const QList<ParserError *> &Parser::getErrors()
+{
+ return context->getErrors();
+}
+
+QString Parser::getErrorString()
+{
+ QStringList msgs;
+ foreach (ParserError* error, getErrors())
+ {
+ msgs += error->getMessage();
+ }
+ return msgs.join(",\n");
+}
+
+TokenList Parser::getParsedTokens()
+{
+ return context->getManagedTokens();
+}
+
+void Parser::setLemonDebug(bool enabled)
+{
+ debugLemon = enabled;
+}
+
+void Parser::setDialect(Dialect dialect)
+{
+ if (this->dialect == dialect)
+ return;
+
+ this->dialect = dialect;
+ delete lexer;
+ lexer = new Lexer(dialect);
+}
+
+const QList<SqliteQueryPtr>& Parser::getQueries()
+{
+ return context->getQueries();
+}