mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-09 14:08:58 +01:00
ExpressionParser: Expand ! symbol to allow for named unary functions. Added !toggle function which toggles on/off with each activation of its inner expression.
This commit is contained in:
parent
bf63f85d73
commit
a8f3e9585f
@ -7,6 +7,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ enum TokenType
|
|||||||
TOK_RPAREN,
|
TOK_RPAREN,
|
||||||
TOK_AND,
|
TOK_AND,
|
||||||
TOK_OR,
|
TOK_OR,
|
||||||
TOK_NOT,
|
TOK_UNARY,
|
||||||
TOK_ADD,
|
TOK_ADD,
|
||||||
TOK_MUL,
|
TOK_MUL,
|
||||||
TOK_DIV,
|
TOK_DIV,
|
||||||
@ -42,8 +43,8 @@ inline std::string OpName(TokenType op)
|
|||||||
return "And";
|
return "And";
|
||||||
case TOK_OR:
|
case TOK_OR:
|
||||||
return "Or";
|
return "Or";
|
||||||
case TOK_NOT:
|
case TOK_UNARY:
|
||||||
return "Not";
|
return "Unary";
|
||||||
case TOK_ADD:
|
case TOK_ADD:
|
||||||
return "Add";
|
return "Add";
|
||||||
case TOK_MUL:
|
case TOK_MUL:
|
||||||
@ -80,8 +81,8 @@ public:
|
|||||||
return "&";
|
return "&";
|
||||||
case TOK_OR:
|
case TOK_OR:
|
||||||
return "|";
|
return "|";
|
||||||
case TOK_NOT:
|
case TOK_UNARY:
|
||||||
return "!";
|
return "!" + data;
|
||||||
case TOK_ADD:
|
case TOK_ADD:
|
||||||
return "+";
|
return "+";
|
||||||
case TOK_MUL:
|
case TOK_MUL:
|
||||||
@ -122,6 +123,21 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token GetUnaryFunction()
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
std::regex valid_name_char("[a-z0-9_]", std::regex_constants::icase);
|
||||||
|
|
||||||
|
while (it != expr.end() && std::regex_match(std::string(1, *it), valid_name_char))
|
||||||
|
{
|
||||||
|
name += *it;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Token(TOK_UNARY, name);
|
||||||
|
}
|
||||||
|
|
||||||
Token GetLiteral()
|
Token GetLiteral()
|
||||||
{
|
{
|
||||||
std::string value;
|
std::string value;
|
||||||
@ -177,7 +193,7 @@ public:
|
|||||||
case '|':
|
case '|':
|
||||||
return Token(TOK_OR);
|
return Token(TOK_OR);
|
||||||
case '!':
|
case '!':
|
||||||
return Token(TOK_NOT);
|
return GetUnaryFunction();
|
||||||
case '+':
|
case '+':
|
||||||
return Token(TOK_ADD);
|
return Token(TOK_ADD);
|
||||||
case '*':
|
case '*':
|
||||||
@ -322,44 +338,93 @@ public:
|
|||||||
class UnaryExpression : public Expression
|
class UnaryExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TokenType op;
|
UnaryExpression(std::unique_ptr<Expression>&& inner_) : inner(std::move(inner_)) {}
|
||||||
std::unique_ptr<Expression> inner;
|
|
||||||
|
|
||||||
UnaryExpression(TokenType op_, std::unique_ptr<Expression>&& inner_)
|
|
||||||
: op(op_), inner(std::move(inner_))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
ControlState GetValue() const override
|
|
||||||
{
|
|
||||||
ControlState value = inner->GetValue();
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case TOK_NOT:
|
|
||||||
return 1.0 - value;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetValue(ControlState value) override
|
|
||||||
{
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case TOK_NOT:
|
|
||||||
inner->SetValue(1.0 - value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CountNumControls() const override { return inner->CountNumControls(); }
|
int CountNumControls() const override { return inner->CountNumControls(); }
|
||||||
void UpdateReferences(ControlFinder& finder) override { inner->UpdateReferences(finder); }
|
void UpdateReferences(ControlFinder& finder) override { inner->UpdateReferences(finder); }
|
||||||
operator std::string() const override { return OpName(op) + "(" + (std::string)(*inner) + ")"; }
|
|
||||||
|
operator std::string() const override
|
||||||
|
{
|
||||||
|
return "!" + GetFuncName() + "(" + (std::string)(*inner) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual std::string GetFuncName() const = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<Expression> inner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Return an oscillating value to make it apparent something was spelled wrong?
|
||||||
|
class UnaryUnknownExpression : public UnaryExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnaryUnknownExpression(std::unique_ptr<Expression>&& inner_) : UnaryExpression(std::move(inner_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlState GetValue() const override { return 0.0; }
|
||||||
|
void SetValue(ControlState value) override {}
|
||||||
|
std::string GetFuncName() const override { return "Unknown"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnaryToggleExpression : public UnaryExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnaryToggleExpression(std::unique_ptr<Expression>&& inner_) : UnaryExpression(std::move(inner_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlState GetValue() const override
|
||||||
|
{
|
||||||
|
const ControlState inner_value = inner->GetValue();
|
||||||
|
|
||||||
|
if (inner_value < THRESHOLD)
|
||||||
|
{
|
||||||
|
m_released = true;
|
||||||
|
}
|
||||||
|
else if (m_released && inner_value > THRESHOLD)
|
||||||
|
{
|
||||||
|
m_released = false;
|
||||||
|
m_state ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValue(ControlState value) override {}
|
||||||
|
std::string GetFuncName() const override { return "Toggle"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr ControlState THRESHOLD = 0.5;
|
||||||
|
// eww:
|
||||||
|
mutable bool m_released{};
|
||||||
|
mutable bool m_state{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnaryNotExpression : public UnaryExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnaryNotExpression(std::unique_ptr<Expression>&& inner_) : UnaryExpression(std::move(inner_)) {}
|
||||||
|
|
||||||
|
ControlState GetValue() const override { return 1.0 - inner->GetValue(); }
|
||||||
|
void SetValue(ControlState value) override { inner->SetValue(1.0 - value); }
|
||||||
|
std::string GetFuncName() const override { return ""; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<UnaryExpression> MakeUnaryExpression(std::string name,
|
||||||
|
std::unique_ptr<Expression>&& inner_)
|
||||||
|
{
|
||||||
|
// Case insensitive matching.
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||||
|
|
||||||
|
if ("" == name)
|
||||||
|
return std::make_unique<UnaryNotExpression>(std::move(inner_));
|
||||||
|
else if ("toggle" == name)
|
||||||
|
return std::make_unique<UnaryToggleExpression>(std::move(inner_));
|
||||||
|
else
|
||||||
|
return std::make_unique<UnaryUnknownExpression>(std::move(inner_));
|
||||||
|
}
|
||||||
|
|
||||||
class LiteralExpression : public Expression
|
class LiteralExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -500,7 +565,7 @@ private:
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case TOK_NOT:
|
case TOK_UNARY:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -515,8 +580,7 @@ private:
|
|||||||
ParseResult result = Atom();
|
ParseResult result = Atom();
|
||||||
if (result.status == ParseStatus::SyntaxError)
|
if (result.status == ParseStatus::SyntaxError)
|
||||||
return result;
|
return result;
|
||||||
return {ParseStatus::Successful,
|
return {ParseStatus::Successful, MakeUnaryExpression(tok.data, std::move(result.expr))};
|
||||||
std::make_unique<UnaryExpression>(tok.type, std::move(result.expr))};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Atom();
|
return Atom();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user