summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
diff options
context:
space:
mode:
authorLeo Lam <leolino.lam@gmail.com>2017-09-15 19:11:57 +0200
committerGitHub <noreply@github.com>2017-09-15 19:11:57 +0200
commit2b4bf8662a18b8b3a49e67133f3e2e2fa45322b6 (patch)
treef7c161353249490421b2f0239d5d78ede901fc6b /Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
parent0d078219358b04266206ea1e2622396db7724136 (diff)
parent294b1895ef2963cfc6fda1818d9a9f3b8b0af48f (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.cpp294
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));
}
}
}