diff options
| author | Leo Lam <leolino.lam@gmail.com> | 2017-09-15 19:11:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-09-15 19:11:57 +0200 |
| commit | 2b4bf8662a18b8b3a49e67133f3e2e2fa45322b6 (patch) | |
| tree | f7c161353249490421b2f0239d5d78ede901fc6b /Source/Core/InputCommon/ControlReference/ExpressionParser.cpp | |
| parent | 0d078219358b04266206ea1e2622396db7724136 (diff) | |
| parent | 294b1895ef2963cfc6fda1818d9a9f3b8b0af48f (diff) | |
Merge pull request #5577 from ligfx/separateexpressionparsingandbinding
ControlReference/ExpressionParser: separate parsing from binding
Diffstat (limited to 'Source/Core/InputCommon/ControlReference/ExpressionParser.cpp')
| -rw-r--r-- | Source/Core/InputCommon/ControlReference/ExpressionParser.cpp | 294 |
1 files changed, 138 insertions, 156 deletions
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp index d520015cf3..85eb86d598 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp @@ -10,6 +10,7 @@ #include <string> #include <vector> +#include "Common/StringUtil.h" #include "InputCommon/ControlReference/ExpressionParser.h" using namespace ciface::Core; @@ -207,64 +208,42 @@ public: } }; -class ExpressionNode -{ -public: - virtual ~ExpressionNode() {} - virtual ControlState GetValue() const { return 0; } - virtual void SetValue(ControlState state) {} - virtual int CountNumControls() const { return 0; } - virtual operator std::string() const { return ""; } -}; - -class DummyExpression : public ExpressionNode -{ -public: - std::string name; - - DummyExpression(const std::string& name_) : name(name_) {} - ControlState GetValue() const override { return 0.0; } - void SetValue(ControlState value) override {} - int CountNumControls() const override { return 0; } - operator std::string() const override { return "`" + name + "`"; } -}; - -class ControlExpression : public ExpressionNode +class ControlExpression : public Expression { public: ControlQualifier qualifier; - Device::Control* control; + Device::Control* control = nullptr; + // Keep a shared_ptr to the device so the control pointer doesn't become invalid + std::shared_ptr<Device> m_device; - ControlExpression(ControlQualifier qualifier_, std::shared_ptr<Device> device, - Device::Control* control_) - : qualifier(qualifier_), control(control_), m_device(device) + explicit ControlExpression(ControlQualifier qualifier_) : qualifier(qualifier_) {} + ControlState GetValue() const override { return control ? control->ToInput()->GetState() : 0.0; } + void SetValue(ControlState value) override { + if (control) + control->ToOutput()->SetState(value); } - - ControlState GetValue() const override { return control->ToInput()->GetState(); } - void SetValue(ControlState value) override { control->ToOutput()->SetState(value); } - int CountNumControls() const override { return 1; } - operator std::string() const override { return "`" + (std::string)qualifier + "`"; } -private: - std::shared_ptr<Device> m_device; + int CountNumControls() const override { return control ? 1 : 0; } + void UpdateReferences(ControlFinder& finder) override + { + m_device = finder.FindDevice(qualifier); + control = finder.FindControl(qualifier); + } + operator std::string() const override { return "`" + static_cast<std::string>(qualifier) + "`"; } }; -class BinaryExpression : public ExpressionNode +class BinaryExpression : public Expression { public: TokenType op; - ExpressionNode* lhs; - ExpressionNode* rhs; + std::unique_ptr<Expression> lhs; + std::unique_ptr<Expression> rhs; - BinaryExpression(TokenType op_, ExpressionNode* lhs_, ExpressionNode* rhs_) - : op(op_), lhs(lhs_), rhs(rhs_) + BinaryExpression(TokenType op_, std::unique_ptr<Expression>&& lhs_, + std::unique_ptr<Expression>&& rhs_) + : op(op_), lhs(std::move(lhs_)), rhs(std::move(rhs_)) { } - virtual ~BinaryExpression() - { - delete lhs; - delete rhs; - } ControlState GetValue() const override { @@ -297,20 +276,28 @@ public: return lhs->CountNumControls() + rhs->CountNumControls(); } + void UpdateReferences(ControlFinder& finder) override + { + lhs->UpdateReferences(finder); + rhs->UpdateReferences(finder); + } + operator std::string() const override { return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")"; } }; -class UnaryExpression : public ExpressionNode +class UnaryExpression : public Expression { public: TokenType op; - ExpressionNode* inner; + std::unique_ptr<Expression> inner; - UnaryExpression(TokenType op_, ExpressionNode* inner_) : op(op_), inner(inner_) {} - virtual ~UnaryExpression() { delete inner; } + UnaryExpression(TokenType op_, std::unique_ptr<Expression>&& inner_) + : op(op_), inner(std::move(inner_)) + { + } ControlState GetValue() const override { ControlState value = inner->GetValue(); @@ -338,9 +325,50 @@ public: } int CountNumControls() const override { return inner->CountNumControls(); } + void UpdateReferences(ControlFinder& finder) override { inner->UpdateReferences(finder); } operator std::string() const override { return OpName(op) + "(" + (std::string)(*inner) + ")"; } }; +// This class proxies all methods to its either left-hand child if it has bound controls, or its +// right-hand child. Its intended use is for supporting old-style barewords expressions. +class CoalesceExpression : public Expression +{ +public: + CoalesceExpression(std::unique_ptr<Expression>&& lhs, std::unique_ptr<Expression>&& rhs) + : m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) + { + } + + ControlState GetValue() const override { return GetActiveChild()->GetValue(); } + void SetValue(ControlState value) override + { + m_lhs->SetValue(GetActiveChild() == m_lhs ? value : 0.0); + m_rhs->SetValue(GetActiveChild() == m_rhs ? value : 0.0); + } + + int CountNumControls() const override { return GetActiveChild()->CountNumControls(); } + operator std::string() const override + { + return "Coalesce(" + static_cast<std::string>(*m_lhs) + ", " + + static_cast<std::string>(*m_rhs) + ')'; + } + + void UpdateReferences(ControlFinder& finder) override + { + m_lhs->UpdateReferences(finder); + m_rhs->UpdateReferences(finder); + } + +private: + const std::unique_ptr<Expression>& GetActiveChild() const + { + return m_lhs->CountNumControls() > 0 ? m_lhs : m_rhs; + } + + std::unique_ptr<Expression> m_lhs; + std::unique_ptr<Expression> m_rhs; +}; + std::shared_ptr<Device> ControlFinder::FindDevice(ControlQualifier qualifier) const { if (qualifier.has_device) @@ -361,29 +389,25 @@ Device::Control* ControlFinder::FindControl(ControlQualifier qualifier) const return device->FindOutput(qualifier.control_name); } -class Parser +struct ParseResult { -public: - Parser(std::vector<Token> tokens_, ControlFinder& finder_) : tokens(tokens_), finder(finder_) + ParseResult(ParseStatus status_, std::unique_ptr<Expression>&& expr_ = {}) + : status(status_), expr(std::move(expr_)) { - m_it = tokens.begin(); } - ParseStatus Parse(Expression** expr_out) - { - ExpressionNode* node; - ParseStatus status = Toplevel(&node); - if (status != ParseStatus::Successful) - return status; - - *expr_out = new Expression(node); - return ParseStatus::Successful; - } + ParseStatus status; + std::unique_ptr<Expression> expr; +}; +class Parser +{ +public: + explicit Parser(std::vector<Token> tokens_) : tokens(tokens_) { m_it = tokens.begin(); } + ParseResult Parse() { return Toplevel(); } private: std::vector<Token> tokens; std::vector<Token>::iterator m_it; - ControlFinder& finder; Token Chew() { return *m_it++; } Token Peek() { return *m_it; } @@ -393,28 +417,17 @@ private: return tok.type == type; } - ParseStatus Atom(ExpressionNode** expr_out) + ParseResult Atom() { Token tok = Chew(); switch (tok.type) { case TOK_CONTROL: - { - std::shared_ptr<Device> device = finder.FindDevice(tok.qualifier); - Device::Control* control = finder.FindControl(tok.qualifier); - if (control == nullptr) - { - *expr_out = new DummyExpression(tok.qualifier); - return ParseStatus::NoDevice; - } - - *expr_out = new ControlExpression(tok.qualifier, device, control); - return ParseStatus::Successful; - } + return {ParseStatus::Successful, std::make_unique<ControlExpression>(tok.qualifier)}; case TOK_LPAREN: - return Paren(expr_out); + return Paren(); default: - return ParseStatus::SyntaxError; + return {ParseStatus::SyntaxError}; } } @@ -429,20 +442,19 @@ private: } } - ParseStatus Unary(ExpressionNode** expr_out) + ParseResult Unary() { if (IsUnaryExpression(Peek().type)) { Token tok = Chew(); - ExpressionNode* atom_expr; - ParseStatus status = Atom(&atom_expr); - if (status == ParseStatus::SyntaxError) - return status; - *expr_out = new UnaryExpression(tok.type, atom_expr); - return ParseStatus::Successful; + ParseResult result = Atom(); + if (result.status == ParseStatus::SyntaxError) + return result; + return {ParseStatus::Successful, + std::make_unique<UnaryExpression>(tok.type, std::move(result.expr))}; } - return Atom(expr_out); + return Atom(); } bool IsBinaryToken(TokenType type) @@ -458,113 +470,83 @@ private: } } - ParseStatus Binary(ExpressionNode** expr_out) + ParseResult Binary() { - ParseStatus status = Unary(expr_out); - if (status == ParseStatus::SyntaxError) - return status; + ParseResult result = Unary(); + if (result.status == ParseStatus::SyntaxError) + return result; + std::unique_ptr<Expression> expr = std::move(result.expr); while (IsBinaryToken(Peek().type)) { Token tok = Chew(); - ExpressionNode* unary_expr; - status = Unary(&unary_expr); - if (status == ParseStatus::SyntaxError) + ParseResult unary_result = Unary(); + if (unary_result.status == ParseStatus::SyntaxError) { - delete *expr_out; - return status; + return unary_result; } - *expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr); + expr = std::make_unique<BinaryExpression>(tok.type, std::move(expr), + std::move(unary_result.expr)); } - return ParseStatus::Successful; + return {ParseStatus::Successful, std::move(expr)}; } - ParseStatus Paren(ExpressionNode** expr_out) + ParseResult Paren() { - ParseStatus status; - // lparen already chewed - if ((status = Toplevel(expr_out)) != ParseStatus::Successful) - return status; + ParseResult result = Toplevel(); + if (result.status != ParseStatus::Successful) + return result; if (!Expects(TOK_RPAREN)) { - delete *expr_out; - return ParseStatus::SyntaxError; + return {ParseStatus::SyntaxError}; } - return ParseStatus::Successful; + return result; } - ParseStatus Toplevel(ExpressionNode** expr_out) { return Binary(expr_out); } + ParseResult Toplevel() { return Binary(); } }; -ControlState Expression::GetValue() const -{ - return node->GetValue(); -} - -void Expression::SetValue(ControlState value) -{ - node->SetValue(value); -} - -Expression::Expression(ExpressionNode* node_) +static ParseResult ParseComplexExpression(const std::string& str) { - node = node_; - num_controls = node->CountNumControls(); -} - -Expression::~Expression() -{ - delete node; -} - -static ParseStatus ParseExpressionInner(const std::string& str, ControlFinder& finder, - Expression** expr_out) -{ - ParseStatus status; - Expression* expr; - *expr_out = nullptr; - - if (str == "") - return ParseStatus::Successful; - Lexer l(str); std::vector<Token> tokens; - status = l.Tokenize(tokens); - if (status != ParseStatus::Successful) - return status; + ParseStatus tokenize_status = l.Tokenize(tokens); + if (tokenize_status != ParseStatus::Successful) + return {tokenize_status}; - Parser p(tokens, finder); - status = p.Parse(&expr); - if (status != ParseStatus::Successful) - return status; - - *expr_out = expr; - return ParseStatus::Successful; + return Parser(std::move(tokens)).Parse(); } -ParseStatus ParseExpression(const std::string& str, ControlFinder& finder, Expression** expr_out) +static std::unique_ptr<Expression> ParseBarewordExpression(const std::string& str) { - // Add compatibility with old simple expressions, which are simple - // barewords control names. - ControlQualifier qualifier; qualifier.control_name = str; qualifier.has_device = false; - std::shared_ptr<Device> device = finder.FindDevice(qualifier); - Device::Control* control = finder.FindControl(qualifier); - if (control) + return std::make_unique<ControlExpression>(qualifier); +} + +std::pair<ParseStatus, std::unique_ptr<Expression>> ParseExpression(const std::string& str) +{ + if (StripSpaces(str).empty()) + return std::make_pair(ParseStatus::EmptyExpression, nullptr); + + auto bareword_expr = ParseBarewordExpression(str); + ParseResult complex_result = ParseComplexExpression(str); + + if (complex_result.status != ParseStatus::Successful) { - *expr_out = new Expression(new ControlExpression(qualifier, device, control)); - return ParseStatus::Successful; + return std::make_pair(complex_result.status, std::move(bareword_expr)); } - return ParseExpressionInner(str, finder, expr_out); + auto combined_expr = std::make_unique<CoalesceExpression>(std::move(bareword_expr), + std::move(complex_result.expr)); + return std::make_pair(complex_result.status, std::move(combined_expr)); } } } |
