summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControlReference/ExpressionParser.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/InputCommon/ControlReference/ExpressionParser.h')
-rw-r--r--Source/Core/InputCommon/ControlReference/ExpressionParser.h154
1 files changed, 140 insertions, 14 deletions
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.h b/Source/Core/InputCommon/ControlReference/ExpressionParser.h
index 56c0340f49..cab6096c0e 100644
--- a/Source/Core/InputCommon/ControlReference/ExpressionParser.h
+++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.h
@@ -4,13 +4,102 @@
#pragma once
+#include <map>
#include <memory>
+#include <optional>
#include <string>
-#include <utility>
+
#include "InputCommon/ControllerInterface/Device.h"
namespace ciface::ExpressionParser
{
+enum TokenType
+{
+ TOK_WHITESPACE,
+ TOK_INVALID,
+ TOK_EOF,
+ TOK_LPAREN,
+ TOK_RPAREN,
+ TOK_NOT,
+ TOK_CONTROL,
+ TOK_LITERAL,
+ TOK_VARIABLE,
+ TOK_BAREWORD,
+ TOK_COMMENT,
+ // Binary Ops:
+ TOK_BINARY_OPS_BEGIN,
+ TOK_AND = TOK_BINARY_OPS_BEGIN,
+ TOK_OR,
+ TOK_ADD,
+ TOK_SUB,
+ TOK_MUL,
+ TOK_DIV,
+ TOK_MOD,
+ TOK_ASSIGN,
+ TOK_LTHAN,
+ TOK_GTHAN,
+ TOK_COMMA,
+ TOK_BINARY_OPS_END,
+};
+
+class Token
+{
+public:
+ TokenType type;
+ std::string data;
+
+ // Position in the input string:
+ std::size_t string_position = 0;
+ std::size_t string_length = 0;
+
+ explicit Token(TokenType type_);
+ Token(TokenType type_, std::string data_);
+
+ bool IsBinaryOperator() const;
+};
+
+enum class ParseStatus
+{
+ Successful,
+ SyntaxError,
+ EmptyExpression,
+};
+
+class Lexer
+{
+public:
+ std::string expr;
+ std::string::iterator it;
+
+ explicit Lexer(std::string expr_);
+
+ ParseStatus Tokenize(std::vector<Token>& tokens);
+
+private:
+ template <typename F>
+ std::string FetchCharsWhile(F&& func)
+ {
+ std::string value;
+ while (it != expr.end() && func(*it))
+ {
+ value += *it;
+ ++it;
+ }
+ return value;
+ }
+
+ std::string FetchDelimString(char delim);
+ std::string FetchWordChars();
+ Token GetDelimitedLiteral();
+ Token GetVariable();
+ Token GetFullyQualifiedControl();
+ Token GetBareword(char c);
+ Token GetRealLiteral(char c);
+
+ Token PeekToken();
+ Token NextToken();
+};
+
class ControlQualifier
{
public:
@@ -19,6 +108,7 @@ public:
std::string control_name;
ControlQualifier() : has_device(false) {}
+
operator std::string() const
{
if (has_device)
@@ -26,23 +116,45 @@ public:
else
return control_name;
}
+
+ void FromString(const std::string& str)
+ {
+ const auto col_pos = str.find_last_of(':');
+
+ has_device = (str.npos != col_pos);
+ if (has_device)
+ {
+ device_qualifier.FromString(str.substr(0, col_pos));
+ control_name = str.substr(col_pos + 1);
+ }
+ else
+ {
+ device_qualifier.FromString("");
+ control_name = str;
+ }
+ }
};
-class ControlFinder
+class ControlEnvironment
{
public:
- ControlFinder(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_,
- const bool is_input_)
- : container(container_), default_device(default_), is_input(is_input_)
+ using VariableContainer = std::map<std::string, ControlState>;
+
+ ControlEnvironment(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_,
+ VariableContainer& vars)
+ : m_variables(vars), container(container_), default_device(default_)
{
}
+
std::shared_ptr<Core::Device> FindDevice(ControlQualifier qualifier) const;
- Core::Device::Control* FindControl(ControlQualifier qualifier) const;
+ Core::Device::Input* FindInput(ControlQualifier qualifier) const;
+ Core::Device::Output* FindOutput(ControlQualifier qualifier) const;
+ ControlState* GetVariablePtr(const std::string& name);
private:
+ VariableContainer& m_variables;
const Core::DeviceContainer& container;
const Core::DeviceQualifier& default_device;
- bool is_input;
};
class Expression
@@ -52,16 +164,30 @@ public:
virtual ControlState GetValue() const = 0;
virtual void SetValue(ControlState state) = 0;
virtual int CountNumControls() const = 0;
- virtual void UpdateReferences(ControlFinder& finder) = 0;
- virtual operator std::string() const = 0;
+ virtual void UpdateReferences(ControlEnvironment& finder) = 0;
};
-enum class ParseStatus
+class ParseResult
{
- Successful,
- SyntaxError,
- EmptyExpression,
+public:
+ static ParseResult MakeEmptyResult();
+ static ParseResult MakeSuccessfulResult(std::unique_ptr<Expression>&& expr);
+ static ParseResult MakeErrorResult(Token token, std::string description);
+
+ ParseStatus status;
+ std::unique_ptr<Expression> expr;
+
+ // Used for parse errors:
+ // TODO: This should probably be moved elsewhere:
+ std::optional<Token> token;
+ std::optional<std::string> description;
+
+private:
+ ParseResult() = default;
};
-std::pair<ParseStatus, std::unique_ptr<Expression>> ParseExpression(const std::string& expr);
+ParseResult ParseExpression(const std::string& expr);
+ParseResult ParseTokens(const std::vector<Token>& tokens);
+void RemoveInertTokens(std::vector<Token>* tokens);
+
} // namespace ciface::ExpressionParser