Implemented parser, although it does not support NULL replies nor is it integrated into the Client class.

This commit is contained in:
Nathan Osman 2013-07-15 21:50:32 -07:00
parent 76af55e20d
commit ac876e196e
5 changed files with 158 additions and 7 deletions

View File

@ -23,6 +23,7 @@ include_directories(include)
set(QREDIS_SRC
src/client.cpp
src/lexer.cpp
src/parser.cpp
src/request.cpp)
# QRedis header files requiring MOC.
@ -31,6 +32,7 @@ qt5_wrap_cpp(QREDIS_MOC
include/qredis/request.h
src/client_p.h
src/lexer.h
src/parser.h
src/request_p.h)
# Create the client library.

View File

@ -25,6 +25,9 @@ void Lexer::readData()
case ReadingUnsafeString: if(!readUnsafeString()) return; break;
case ReadingSafeString: if(!readSafeString()) return; break;
}
if(state != ReadingSafeString)
state = DoingNothing;
}
}
@ -41,12 +44,9 @@ bool Lexer::readCharacter()
{
case '+':
case '-':
case '*':
case ':': state = ReadingUnsafeString; break;
case ':':
case '*': state = ReadingUnsafeString; break;
case '$': state = ReadingLength; break;
default:
emit warning(tr("Unexpected character '%1' encountered").arg(static_cast<int>(c), 0, 16));
return true;
}
emit character(c);

View File

@ -19,8 +19,6 @@ class Lexer : public QObject
void unsafeString(const QString &);
void safeString(const QByteArray &);
void warning(const QString &);
private Q_SLOTS:
void readData();

85
src/parser.cpp Normal file
View File

@ -0,0 +1,85 @@
#include "parser.h"
Parser::Parser(Lexer * lexer, QObject * parent)
: QObject(parent)
{
connect(lexer, SIGNAL(character(char)), SLOT(readCharacter(char)));
connect(lexer, SIGNAL(unsafeString(QString)), SLOT(readUnsafeString(QString)));
connect(lexer, SIGNAL(safeString(QByteArray)), SLOT(readSafeString(QByteArray)));
}
Parser::~Parser()
{
}
void Parser::readCharacter(char c)
{
switch(c)
{
case '+': stack.append(Task(Task::ReadStatus)); break;
case '-': stack.append(Task(Task::ReadError)); break;
case ':': stack.append(Task(Task::ReadInteger)); break;
case '$': stack.append(Task(Task::ReadBulk)); break;
case '*': stack.append(Task(Task::ReadMultiBulk)); break;
default:
emit warning(tr("Skipping unexpected character '%1'").arg(static_cast<int>(c), 0, 16));
break;
}
}
void Parser::readUnsafeString(const QString & value)
{
if(tos().action == Task::ReadMultiBulk)
tos().count = value.toInt();
else
{
stack.removeLast();
if(tos().action == Task::ReadStatus)
emit status(value);
else if(tos().action == Task::ReadError)
{
int pos = value.indexOf(' ');
emit error(value.left(pos), value.right(pos + 1));
}
else if(!stack.count())
emit integer(value.toLongLong());
else
{
tos().value.toList().append(value);
descend();
}
}
}
void Parser::readSafeString(const QByteArray & value)
{
stack.removeLast();
if(!stack.count())
emit bulk(value);
else
{
tos().value.toList().append(value);
descend();
}
}
void Parser::descend()
{
while(true)
{
if(tos().value.toList().count() < tos().count)
break;
if(stack.count() == 1)
{
emit multiBulk(tos().value.toList());
stack.removeLast();
break;
}
Task task = stack.takeLast();
tos().value.toList().append(task.value);
}
}

66
src/parser.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef PARSER_H
#define PARSER_H
#include <QList>
#include <QObject>
#include <QVariant>
#include <QVariantList>
#include "lexer.h"
class Parser : public QObject
{
Q_OBJECT
public:
Parser(Lexer *, QObject * = 0);
virtual ~Parser();
Q_SIGNALS:
void status(const QString &);
void error(const QString &, const QString &);
void integer(qlonglong);
void bulk(const QByteArray &);
void multiBulk(const QVariantList &);
void warning(const QString &);
private Q_SLOTS:
void readCharacter(char);
void readUnsafeString(const QString &);
void readSafeString(const QByteArray &);
private:
void descend();
class Task
{
public:
enum Action {
ReadStatus,
ReadError,
ReadInteger,
ReadBulk,
ReadMultiBulk
};
enum { Unknown = -2 };
Task(Action action) : action(action), count(Unknown) {}
Action action;
int count;
QVariant value;
};
QList<Task> stack;
inline Task & tos() { return stack.last(); }
};
#endif // PARSER_H