1 // Copyright 2013 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <map>
8 #include <memory>
9 #include <optional>
10 #include <string>
11 
12 #include "InputCommon/ControllerInterface/Device.h"
13 
14 namespace ciface::ExpressionParser
15 {
16 enum TokenType
17 {
18   TOK_WHITESPACE,
19   TOK_INVALID,
20   TOK_EOF,
21   TOK_LPAREN,
22   TOK_RPAREN,
23   TOK_NOT,
24   TOK_CONTROL,
25   TOK_LITERAL,
26   TOK_VARIABLE,
27   TOK_BAREWORD,
28   TOK_COMMENT,
29   TOK_HOTKEY,
30   // Binary Ops:
31   TOK_BINARY_OPS_BEGIN,
32   TOK_AND = TOK_BINARY_OPS_BEGIN,
33   TOK_OR,
34   TOK_ADD,
35   TOK_SUB,
36   TOK_MUL,
37   TOK_DIV,
38   TOK_MOD,
39   TOK_ASSIGN,
40   TOK_LTHAN,
41   TOK_GTHAN,
42   TOK_COMMA,
43   TOK_XOR,
44   TOK_BINARY_OPS_END,
45 };
46 
47 class Token
48 {
49 public:
50   TokenType type;
51   std::string data;
52 
53   // Position in the input string:
54   std::size_t string_position = 0;
55   std::size_t string_length = 0;
56 
57   explicit Token(TokenType type_);
58   Token(TokenType type_, std::string data_);
59 
60   bool IsBinaryOperator() const;
61 };
62 
63 enum class ParseStatus
64 {
65   Successful,
66   SyntaxError,
67   EmptyExpression,
68 };
69 
70 class Lexer
71 {
72 public:
73   std::string expr;
74   std::string::iterator it;
75 
76   explicit Lexer(std::string expr_);
77 
78   ParseStatus Tokenize(std::vector<Token>& tokens);
79 
80 private:
81   template <typename F>
FetchCharsWhile(F && func)82   std::string FetchCharsWhile(F&& func)
83   {
84     std::string value;
85     while (it != expr.end() && func(*it))
86     {
87       value += *it;
88       ++it;
89     }
90     return value;
91   }
92 
93   std::string FetchDelimString(char delim);
94   std::string FetchWordChars();
95   Token GetDelimitedLiteral();
96   Token GetVariable();
97   Token GetFullyQualifiedControl();
98   Token GetBareword(char c);
99   Token GetRealLiteral(char c);
100 
101   Token PeekToken();
102   Token NextToken();
103 };
104 
105 class ControlQualifier
106 {
107 public:
108   bool has_device;
109   Core::DeviceQualifier device_qualifier;
110   std::string control_name;
111 
ControlQualifier()112   ControlQualifier() : has_device(false) {}
113 
string()114   operator std::string() const
115   {
116     if (has_device)
117       return device_qualifier.ToString() + ":" + control_name;
118     else
119       return control_name;
120   }
121 
FromString(const std::string & str)122   void FromString(const std::string& str)
123   {
124     const auto col_pos = str.find_last_of(':');
125 
126     has_device = (str.npos != col_pos);
127     if (has_device)
128     {
129       device_qualifier.FromString(str.substr(0, col_pos));
130       control_name = str.substr(col_pos + 1);
131     }
132     else
133     {
134       device_qualifier.FromString("");
135       control_name = str;
136     }
137   }
138 };
139 
140 class ControlEnvironment
141 {
142 public:
143   using VariableContainer = std::map<std::string, ControlState>;
144 
ControlEnvironment(const Core::DeviceContainer & container_,const Core::DeviceQualifier & default_,VariableContainer & vars)145   ControlEnvironment(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_,
146                      VariableContainer& vars)
147       : m_variables(vars), container(container_), default_device(default_)
148   {
149   }
150 
151   std::shared_ptr<Core::Device> FindDevice(ControlQualifier qualifier) const;
152   Core::Device::Input* FindInput(ControlQualifier qualifier) const;
153   Core::Device::Output* FindOutput(ControlQualifier qualifier) const;
154   ControlState* GetVariablePtr(const std::string& name);
155 
156 private:
157   VariableContainer& m_variables;
158   const Core::DeviceContainer& container;
159   const Core::DeviceQualifier& default_device;
160 };
161 
162 class Expression
163 {
164 public:
165   virtual ~Expression() = default;
166   virtual ControlState GetValue() const = 0;
167   virtual void SetValue(ControlState state) = 0;
168   virtual int CountNumControls() const = 0;
169   virtual void UpdateReferences(ControlEnvironment& finder) = 0;
170 };
171 
172 class ParseResult
173 {
174 public:
175   static ParseResult MakeEmptyResult();
176   static ParseResult MakeSuccessfulResult(std::unique_ptr<Expression>&& expr);
177   static ParseResult MakeErrorResult(Token token, std::string description);
178 
179   ParseStatus status;
180   std::unique_ptr<Expression> expr;
181 
182   // Used for parse errors:
183   // TODO: This should probably be moved elsewhere:
184   std::optional<Token> token;
185   std::optional<std::string> description;
186 
187 private:
188   ParseResult() = default;
189 };
190 
191 ParseResult ParseExpression(const std::string& expr);
192 ParseResult ParseTokens(const std::vector<Token>& tokens);
193 void RemoveInertTokens(std::vector<Token>* tokens);
194 
195 }  // namespace ciface::ExpressionParser
196