[gst-debugger] gst-debugger: add filter parser
- From: Marcin Kolny <mkolny src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gst-debugger] gst-debugger: add filter parser
- Date: Tue, 15 Sep 2015 20:28:18 +0000 (UTC)
commit 2dfb687f35c0836c40a031ee5438c8a091684b78
Author: Marcin Kolny <marcin kolny gmail com>
Date: Tue Sep 15 22:27:45 2015 +0200
gst-debugger: add filter parser
src/gst-debugger/Makefile.am | 7 ++
src/gst-debugger/filter-parser/expression.h | 55 ++++++++++++
src/gst-debugger/filter-parser/lexer.cpp | 113 +++++++++++++++++++++++++
src/gst-debugger/filter-parser/lexer.h | 34 ++++++++
src/gst-debugger/filter-parser/parser.cpp | 10 ++
src/gst-debugger/filter-parser/parser.h | 63 ++++++++++++++
src/gst-debugger/filter-parser/tokens.cpp | 67 +++++++++++++++
src/gst-debugger/filter-parser/tokens.h | 109 ++++++++++++++++++++++++
src/gst-debugger/main.cpp | 2 +
src/gst-debugger/modules/base_main_module.cpp | 16 +++-
src/gst-debugger/modules/base_main_module.h | 5 +-
src/gst-debugger/modules/log_module.cpp | 33 +++++++-
src/gst-debugger/modules/main_module.cpp | 2 +-
13 files changed, 507 insertions(+), 9 deletions(-)
---
diff --git a/src/gst-debugger/Makefile.am b/src/gst-debugger/Makefile.am
index ab27b6e..34474ec 100644
--- a/src/gst-debugger/Makefile.am
+++ b/src/gst-debugger/Makefile.am
@@ -29,6 +29,10 @@ gst_debugger_headers = \
dialogs/enums_dialog.h \
dialogs/factories_dialog.h \
dialogs/remote_data_dialog.h \
+ filter-parser/expression.h \
+ filter-parser/lexer.h \
+ filter-parser/parser.cpp \
+ filter-parser/tokens.h \
graphviz-plugin/graphviz-gstdebugger.h \
gst-debugger-resources.h \
gvalue-converter/gvalue_base.h \
@@ -66,6 +70,9 @@ gst_debugger_ GST_API_VERSION@_SOURCES = \
dialogs/enums_dialog.cpp \
dialogs/factories_dialog.cpp \
graphviz-plugin/gvdevice_gstdebugger.c \
+ filter-parser/lexer.cpp \
+ filter-parser/parser.cpp \
+ filter-parser/tokens.cpp \
graphviz-plugin/gvplugin_gstdebugger.c \
gst-debugger-resources.c \
gvalue-converter/gvalue_base.cpp \
diff --git a/src/gst-debugger/filter-parser/expression.h b/src/gst-debugger/filter-parser/expression.h
new file mode 100644
index 0000000..0ef5100
--- /dev/null
+++ b/src/gst-debugger/filter-parser/expression.h
@@ -0,0 +1,55 @@
+/*
+ * expression.h
+ *
+ * Created on: Sep 3, 2015
+ * Author: loganek
+ */
+
+#ifndef SRC_GST_DEBUGGER_FILTER_PARSER_EXPRESSION_H_
+#define SRC_GST_DEBUGGER_FILTER_PARSER_EXPRESSION_H_
+
+#include <stdexcept>
+
+enum class ExprOperator
+{
+ EQ, // ==
+ NEQ, // !=
+ GE, // >=
+ LE, // <=
+ G, // >
+ L // <
+};
+
+template<typename T>
+class Expression
+{
+ T left;
+ T right;
+ ExprOperator op;
+
+public:
+ virtual ~Expression() {}
+
+ bool evaluate() const;
+};
+
+template<typename T>
+bool Expression<T>::evaluate() const
+{
+#define APPLY_OPERATOR(OP_ENUM, OP_REAL) \
+ case ExprOperator::OP_ENUM: return left OP_REAL right;
+ switch (op)
+ {
+ APPLY_OPERATOR(EQ, ==)
+ APPLY_OPERATOR(NEQ, !=)
+ APPLY_OPERATOR(GE, >=)
+ APPLY_OPERATOR(LE, <=)
+ APPLY_OPERATOR(G, >)
+ APPLY_OPERATOR(L, <)
+ }
+
+ throw std::runtime_error("unknown operator");
+}
+
+
+#endif /* SRC_GST_DEBUGGER_FILTER_PARSER_EXPRESSION_H_ */
diff --git a/src/gst-debugger/filter-parser/lexer.cpp b/src/gst-debugger/filter-parser/lexer.cpp
new file mode 100644
index 0000000..bc13c9b
--- /dev/null
+++ b/src/gst-debugger/filter-parser/lexer.cpp
@@ -0,0 +1,113 @@
+/*
+ * lexer.cpp
+ *
+ * Created on: Sep 3, 2015
+ * Author: loganek
+ */
+
+#include "lexer.h"
+
+#include <algorithm>
+
+enum class State
+{
+ NUMBER,
+ STRING,
+ VARIABLE,
+ OPERATOR
+};
+
+void Lexer::read_number()
+{
+ int tmp = pos--;
+ while (++pos < src_text.length() && isdigit(src_text[pos]));
+ tokens.push_back(std::make_shared<TokenNumber>(std::string(src_text.begin() + tmp, src_text.begin() +
pos--)));
+}
+
+void Lexer::read_operator()
+{
+ int tmp = pos--;
+ while (++pos < src_text.length() && TokenOperator::is_part_of_op(src_text[pos]));
+ tokens.push_back(std::make_shared<TokenOperator>(std::string(src_text.begin() + tmp, src_text.begin()
+ pos--)));
+}
+
+void Lexer::read_string()
+{
+ char quote = src_text[pos];
+ bool prev_esc = false;
+ std::string val;
+ char c = -1;
+ while (pos < src_text.length())
+ {
+ c = src_text[++pos];
+ if (prev_esc)
+ {
+ if (TokenString::is_quote(c) || c == '\\')
+ {
+ val += c;
+ prev_esc = false;
+ }
+ else
+ {
+ throw std::runtime_error("unknown escape sequence: '" + std::string("\\") + c
+ "'");
+ }
+ }
+ else if (c == '\\')
+ {
+ prev_esc = true;
+ }
+ else if (c == quote)
+ {
+ break;
+ }
+ else
+ {
+ val += c;
+ }
+ }
+
+ if (prev_esc)
+ {
+ throw std::runtime_error("incomplete escape sequence");
+ }
+ if (c != quote)
+ {
+ throw std::runtime_error("missing terminating " + std::string{quote} + " character");
+ }
+
+ tokens.push_back(std::make_shared<TokenString>(val));
+}
+
+void Lexer::read_identifier()
+{
+ int tmp = pos;
+
+ while (!isspace(src_text[pos]) &&
+ !TokenString::is_quote(src_text[pos]) &&
+ !TokenOperator::is_part_of_op(src_text[pos]) &&
+ pos < src_text.length())
+ {
+ pos++;
+ }
+
+ tokens.push_back(std::make_shared<TokenIdentifier>(std::string(src_text.begin() + tmp,
src_text.begin() + pos--)));
+}
+
+void Lexer::tokenize(const std::string &src)
+{
+ src_text = src;
+
+ for (pos = 0; pos < src_text.length(); pos++)
+ {
+ char c = src_text[pos];
+
+ if (isdigit(c))
+ read_number();
+ else if (TokenOperator::is_part_of_op(c))
+ read_operator();
+ else if (TokenString::is_quote(c))
+ read_string();
+ else if (TokenIdentifier::is_id_start(c))
+ read_identifier();
+ }
+}
diff --git a/src/gst-debugger/filter-parser/lexer.h b/src/gst-debugger/filter-parser/lexer.h
new file mode 100644
index 0000000..4380ee8
--- /dev/null
+++ b/src/gst-debugger/filter-parser/lexer.h
@@ -0,0 +1,34 @@
+/*
+ * lexer.h
+ *
+ * Created on: Sep 3, 2015
+ * Author: loganek
+ */
+
+#ifndef SRC_GST_DEBUGGER_FILTER_PARSER_LEXER_H_
+#define SRC_GST_DEBUGGER_FILTER_PARSER_LEXER_H_
+
+#include "tokens.h"
+
+#include <vector>
+#include <memory>
+
+class Lexer
+{
+ std::vector<std::shared_ptr<TokenBase>> tokens;
+ int pos;
+ std::string src_text;
+
+ void read_number();
+ void read_operator();
+ void read_string();
+ void read_identifier();
+
+public:
+ virtual ~Lexer() {}
+ void tokenize(const std::string &src);
+
+ decltype(tokens) get_tokens() const { return tokens; }
+};
+
+#endif /* SRC_GST_DEBUGGER_FILTER_PARSER_LEXER_H_ */
diff --git a/src/gst-debugger/filter-parser/parser.cpp b/src/gst-debugger/filter-parser/parser.cpp
new file mode 100644
index 0000000..f2a4740
--- /dev/null
+++ b/src/gst-debugger/filter-parser/parser.cpp
@@ -0,0 +1,10 @@
+/*
+ * parser.cpp
+ *
+ * Created on: Sep 13, 2015
+ * Author: loganek
+ */
+
+#include "parser.h"
+
+
diff --git a/src/gst-debugger/filter-parser/parser.h b/src/gst-debugger/filter-parser/parser.h
new file mode 100644
index 0000000..06a28fa
--- /dev/null
+++ b/src/gst-debugger/filter-parser/parser.h
@@ -0,0 +1,63 @@
+/*
+ * parser.h
+ *
+ * Created on: Sep 13, 2015
+ * Author: loganek
+ */
+
+#ifndef SRC_GST_DEBUGGER_FILTER_PARSER_PARSER_H_
+#define SRC_GST_DEBUGGER_FILTER_PARSER_PARSER_H_
+
+#include "lexer.h"
+
+#include <stack>
+
+struct Expression
+{
+ const std::shared_ptr<TokenOperator> op;
+ const std::shared_ptr<TokenBase> left;
+ const std::shared_ptr<TokenBase> right;
+
+ Expression(const std::shared_ptr<TokenOperator> &op,
+ const std::shared_ptr<TokenBase> &left,
+ const std::shared_ptr<TokenBase> &right)
+ : op(op), left(left), right(right)
+ {}
+
+ virtual ~Expression() {}
+};
+
+class Parser
+{
+ void check_token(const std::shared_ptr<TokenBase> &token, TokenType expected_type)
+ {
+ if ((token->get_type() & expected_type) == TokenType::INVALID)
+ {
+ throw std::runtime_error("expected token type " +
std::to_string(static_cast<int>(expected_type)) +
+ " (" + token->to_string() + ")");
+ }
+ }
+
+public:
+ virtual ~Parser() {}
+
+ Expression parse(const std::string &str)
+ {
+ Lexer lexer;
+ lexer.tokenize(str);
+ auto tokens = lexer.get_tokens();
+
+ if (tokens.size() != 3)
+ {
+ throw std::runtime_error("invalid number of tokens (3 expected)");
+ }
+
+ check_token(tokens[0], TokenType::LITERAL | TokenType::IDENTIFIER);
+ check_token(tokens[1], TokenType::OPERATOR);
+ check_token(tokens[2], TokenType::LITERAL | TokenType::IDENTIFIER);
+
+ return Expression(std::static_pointer_cast<TokenOperator>(tokens[1]), tokens[0], tokens[2]);
+ }
+};
+
+#endif /* SRC_GST_DEBUGGER_FILTER_PARSER_PARSER_H_ */
diff --git a/src/gst-debugger/filter-parser/tokens.cpp b/src/gst-debugger/filter-parser/tokens.cpp
new file mode 100644
index 0000000..cb7a863
--- /dev/null
+++ b/src/gst-debugger/filter-parser/tokens.cpp
@@ -0,0 +1,67 @@
+/*
+ * tokens.cpp
+ *
+ * Created on: Sep 13, 2015
+ * Author: loganek
+ */
+
+#include "tokens.h"
+
+#include <stdexcept>
+#include <algorithm>
+
+TokenNumber::TokenNumber(const std::string &number)
+ : Token(TokenType::NUMBER_LITERAL)
+{
+ value = atoi(number.c_str());
+}
+
+TokenString::TokenString(const std::string &str)
+ : Token(TokenType::STRING_LITERAL)
+{
+ value = str;
+}
+
+bool TokenString::is_quote(char c)
+{
+ return c == '"' || c == '\'';
+}
+
+TokenIdentifier::TokenIdentifier(const std::string &identifier)
+ : Token(TokenType::IDENTIFIER)
+{
+ value = identifier;
+}
+
+bool TokenIdentifier::is_id_start(char c)
+{
+ return isalpha(c);
+}
+
+TokenOperator::TokenOperator(const std::string &op)
+ : Token(TokenType::OPERATOR)
+{
+ if (op == "==") value = OpType::EQ;
+ else if (op == "!=") value = OpType::NEQ;
+ else if (op == "||") value = OpType::OR;
+ else if (op == "&&") value = OpType::AND;
+ else throw std::runtime_error ("invalid operator " + op);
+}
+
+bool TokenOperator::is_part_of_op(char c)
+{
+ auto v = {'=', '!', '&', '|'};
+ return std::find(v.begin(), v.end(), c) != v.end();
+}
+
+std::string TokenOperator::to_string() const
+{
+ switch (value)
+ {
+ case OpType::AND: return "&&";
+ case OpType::OR: return "||";
+ case OpType::EQ: return "==";
+ case OpType::NEQ: return "!=";
+ }
+ throw std::runtime_error("unknown operator");
+}
diff --git a/src/gst-debugger/filter-parser/tokens.h b/src/gst-debugger/filter-parser/tokens.h
new file mode 100644
index 0000000..c52108f
--- /dev/null
+++ b/src/gst-debugger/filter-parser/tokens.h
@@ -0,0 +1,109 @@
+/*
+ * tokens.h
+ *
+ * Created on: Sep 13, 2015
+ * Author: loganek
+ */
+
+#ifndef SRC_GST_DEBUGGER_FILTER_PARSER_TOKENS_H_
+#define SRC_GST_DEBUGGER_FILTER_PARSER_TOKENS_H_
+
+#include <string>
+
+enum class TokenType : int
+{
+ INVALID = 0x00,
+ IDENTIFIER = 0x01,
+ OPERATOR = 0x02,
+ LITERAL = 0x04,
+ NUMBER_LITERAL = 0x05,
+ STRING_LITERAL = 0x06,
+};
+
+inline TokenType operator|(const TokenType &t1, const TokenType &t2)
+{
+ return static_cast<TokenType>(static_cast<int>(t1) | static_cast<int>(t2));
+}
+
+inline TokenType operator&(const TokenType &t1, const TokenType &t2)
+{
+ return static_cast<TokenType>(static_cast<int>(t1) & static_cast<int>(t2));
+}
+
+class TokenBase
+{
+ TokenType type;
+
+public:
+ virtual ~TokenBase() {}
+ TokenBase(TokenType type) : type(type) {}
+
+ virtual std::string to_string() const = 0;
+
+ TokenType get_type() const { return type; }
+};
+
+template<typename T>
+class Token : public TokenBase
+{
+protected:
+ T value;
+
+public:
+ virtual ~Token() {}
+ Token(TokenType type) : TokenBase(type) {}
+
+ T get_value() const { return value; }
+};
+
+class TokenNumber : public Token<int>
+{
+public:
+ TokenNumber(const std::string &number);
+
+ std::string to_string() const override
+ {
+ return std::to_string(value);
+ }
+
+};
+
+class TokenString : public Token<std::string>
+{
+public:
+ TokenString(const std::string &str);
+
+ std::string to_string() const override { return value; }
+
+ static bool is_quote(char c);
+};
+
+class TokenIdentifier : public Token<std::string>
+{
+public:
+ TokenIdentifier(const std::string &identifier);
+
+ std::string to_string() const override { return value; }
+
+ static bool is_id_start(char c);
+};
+
+enum class OpType
+{
+ EQ,
+ NEQ,
+ OR,
+ AND
+};
+
+class TokenOperator : public Token<OpType>
+{
+public:
+ TokenOperator(const std::string &op);
+
+ std::string to_string() const override;
+
+ static bool is_part_of_op(char c);
+};
+
+#endif /* SRC_GST_DEBUGGER_FILTER_PARSER_TOKENS_H_ */
diff --git a/src/gst-debugger/main.cpp b/src/gst-debugger/main.cpp
index efbcf5b..3d6fc53 100644
--- a/src/gst-debugger/main.cpp
+++ b/src/gst-debugger/main.cpp
@@ -12,6 +12,8 @@
#include <gtkmm.h>
#include <gstreamermm.h>
+#include "filter-parser/parser.h"
+
int main(int argc, char** argv)
{
Gst::init(argc, argv);
diff --git a/src/gst-debugger/modules/base_main_module.cpp b/src/gst-debugger/modules/base_main_module.cpp
index a0bd7e4..896433b 100644
--- a/src/gst-debugger/modules/base_main_module.cpp
+++ b/src/gst-debugger/modules/base_main_module.cpp
@@ -32,10 +32,20 @@ void BaseMainModule::load_details(Gtk::TreeView *view, const Gtk::TreeModel::Pat
view->set_model(details_model);
}
-void BaseMainModule::update_filter_string(const std::string &filter_text)
+void BaseMainModule::update_filter_expression(const std::string &expr)
{
- this->filter_text = filter_text;
- filter->refilter();
+ Parser p;
+ auto prev = filter_expression;
+ try
+ {
+ filter_expression = std::make_shared<Expression>(p.parse(expr));
+ }
+ catch (...) { filter_expression = std::shared_ptr<Expression>(); }
+
+ if (prev != filter_expression)
+ {
+ filter->refilter();
+ }
}
void BaseMainModule::configure_details_view(Gtk::TreeView *view)
diff --git a/src/gst-debugger/modules/base_main_module.h b/src/gst-debugger/modules/base_main_module.h
index 60734be..6912f56 100644
--- a/src/gst-debugger/modules/base_main_module.h
+++ b/src/gst-debugger/modules/base_main_module.h
@@ -10,6 +10,7 @@
#include "controller/iview.h"
#include "common_model_columns.h"
+#include "filter-parser/parser.h"
#include <gtkmm/liststore.h>
#include <gtkmm/treeview.h>
@@ -18,7 +19,7 @@
class BaseMainModule : public IBaseView
{
protected:
- std::string filter_text;
+ std::shared_ptr<Expression> filter_expression;
static DetailsModelColumns detail_columns;
@@ -41,7 +42,7 @@ public:
static void configure_details_view(Gtk::TreeView *view);
- void update_filter_string(const std::string &filter_text);
+ void update_filter_expression(const std::string &expr);
Glib::RefPtr<Gtk::ListStore> get_model() const { return model; }
};
diff --git a/src/gst-debugger/modules/log_module.cpp b/src/gst-debugger/modules/log_module.cpp
index 6b87838..a6b101e 100644
--- a/src/gst-debugger/modules/log_module.cpp
+++ b/src/gst-debugger/modules/log_module.cpp
@@ -66,7 +66,7 @@ void LogModule::log_received_()
bool LogModule::filter_function(const Gtk::TreeModel::const_iterator& it)
{
- if (filter_text.empty())
+ if (!filter_expression)
return true;
auto log = it->get_value(columns.log);
@@ -74,9 +74,36 @@ bool LogModule::filter_function(const Gtk::TreeModel::const_iterator& it)
if (log == nullptr)
return true;
- int line = atoi(filter_text.c_str());
+ std::shared_ptr<TokenIdentifier> ident;
+ std::shared_ptr<TokenBase> value;
- return log->line() == line;
+ if (filter_expression->left->get_type() == TokenType::IDENTIFIER)
+ {
+ ident = std::static_pointer_cast<TokenIdentifier>(filter_expression->left);
+ value = filter_expression->right;
+ }
+ else
+ {
+ ident = std::static_pointer_cast<TokenIdentifier>(filter_expression->right);
+ value = filter_expression->left;
+ }
+
+#define MAKE_FIELD_FILTER(FIELD, GETTER, TOKEN_CLASS) \
+ do { \
+ if (ident->get_value() == FIELD) \
+ return filter_expression->op->get_value() == OpType::EQ ? (log->GETTER() ==
std::static_pointer_cast<TOKEN_CLASS>(value)->get_value()) : \
+ (log->GETTER() !=
std::static_pointer_cast<TOKEN_CLASS>(value)->get_value()); \
+ } while (false);
+
+ MAKE_FIELD_FILTER("line", line, TokenNumber);
+ MAKE_FIELD_FILTER("level", level, TokenNumber);
+ MAKE_FIELD_FILTER("category", category_name, TokenString);
+ MAKE_FIELD_FILTER("file", file, TokenString);
+ MAKE_FIELD_FILTER("function", function, TokenString);
+ MAKE_FIELD_FILTER("object_path", object_path, TokenString);
+ MAKE_FIELD_FILTER("message", message, TokenString);
+
+ return true;
}
LogControlModule::LogControlModule()
diff --git a/src/gst-debugger/modules/main_module.cpp b/src/gst-debugger/modules/main_module.cpp
index b62e2e8..93a1901 100644
--- a/src/gst-debugger/modules/main_module.cpp
+++ b/src/gst-debugger/modules/main_module.cpp
@@ -28,7 +28,7 @@ MainModule::MainModule(const Glib::RefPtr<Gtk::Builder> &builder)
builder->get_widget("dataFilterEntry", data_filter_entry);
data_filter_entry->signal_activate().connect([this]{
- current_module->update_filter_string(data_filter_entry->get_text());
+ current_module->update_filter_expression(data_filter_entry->get_text());
});
load_submodules(builder);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]