mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-27 23:08:47 +00:00
ExpressionParser: Add mod operator, sin function, and timer "constant" which can be used for auto-fire and oscillators.
This commit is contained in:
parent
a8f3e9585f
commit
1efcf861ea
1 changed files with 81 additions and 11 deletions
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -11,6 +13,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/MathUtil.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "InputCommon/ControlReference/ExpressionParser.h"
|
#include "InputCommon/ControlReference/ExpressionParser.h"
|
||||||
|
|
||||||
|
@ -31,6 +34,7 @@ enum TokenType
|
||||||
TOK_ADD,
|
TOK_ADD,
|
||||||
TOK_MUL,
|
TOK_MUL,
|
||||||
TOK_DIV,
|
TOK_DIV,
|
||||||
|
TOK_MOD,
|
||||||
TOK_CONTROL,
|
TOK_CONTROL,
|
||||||
TOK_LITERAL,
|
TOK_LITERAL,
|
||||||
};
|
};
|
||||||
|
@ -51,6 +55,8 @@ inline std::string OpName(TokenType op)
|
||||||
return "Mul";
|
return "Mul";
|
||||||
case TOK_DIV:
|
case TOK_DIV:
|
||||||
return "Div";
|
return "Div";
|
||||||
|
case TOK_MOD:
|
||||||
|
return "Mod";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
return "";
|
return "";
|
||||||
|
@ -89,6 +95,8 @@ public:
|
||||||
return "*";
|
return "*";
|
||||||
case TOK_DIV:
|
case TOK_DIV:
|
||||||
return "/";
|
return "/";
|
||||||
|
case TOK_MOD:
|
||||||
|
return "%";
|
||||||
case TOK_CONTROL:
|
case TOK_CONTROL:
|
||||||
return "Device(" + data + ")";
|
return "Device(" + data + ")";
|
||||||
case TOK_LITERAL:
|
case TOK_LITERAL:
|
||||||
|
@ -200,6 +208,8 @@ public:
|
||||||
return Token(TOK_MUL);
|
return Token(TOK_MUL);
|
||||||
case '/':
|
case '/':
|
||||||
return Token(TOK_DIV);
|
return Token(TOK_DIV);
|
||||||
|
case '%':
|
||||||
|
return Token(TOK_MOD);
|
||||||
case '\'':
|
case '\'':
|
||||||
return GetLiteral();
|
return GetLiteral();
|
||||||
case '`':
|
case '`':
|
||||||
|
@ -304,6 +314,11 @@ public:
|
||||||
const ControlState result = lhsValue / rhsValue;
|
const ControlState result = lhsValue / rhsValue;
|
||||||
return std::isinf(result) ? 0.0 : result;
|
return std::isinf(result) ? 0.0 : result;
|
||||||
}
|
}
|
||||||
|
case TOK_MOD:
|
||||||
|
{
|
||||||
|
const ControlState result = std::fmod(lhsValue, rhsValue);
|
||||||
|
return std::isnan(result) ? 0.0 : result;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -411,6 +426,16 @@ public:
|
||||||
std::string GetFuncName() const override { return ""; }
|
std::string GetFuncName() const override { return ""; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UnarySinExpression : public UnaryExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnarySinExpression(std::unique_ptr<Expression>&& inner_) : UnaryExpression(std::move(inner_)) {}
|
||||||
|
|
||||||
|
ControlState GetValue() const override { return std::cos(inner->GetValue()); }
|
||||||
|
void SetValue(ControlState value) override {}
|
||||||
|
std::string GetFuncName() const override { return "Sin"; }
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<UnaryExpression> MakeUnaryExpression(std::string name,
|
std::unique_ptr<UnaryExpression> MakeUnaryExpression(std::string name,
|
||||||
std::unique_ptr<Expression>&& inner_)
|
std::unique_ptr<Expression>&& inner_)
|
||||||
{
|
{
|
||||||
|
@ -421,6 +446,8 @@ std::unique_ptr<UnaryExpression> MakeUnaryExpression(std::string name,
|
||||||
return std::make_unique<UnaryNotExpression>(std::move(inner_));
|
return std::make_unique<UnaryNotExpression>(std::move(inner_));
|
||||||
else if ("toggle" == name)
|
else if ("toggle" == name)
|
||||||
return std::make_unique<UnaryToggleExpression>(std::move(inner_));
|
return std::make_unique<UnaryToggleExpression>(std::move(inner_));
|
||||||
|
else if ("sin" == name)
|
||||||
|
return std::make_unique<UnarySinExpression>(std::move(inner_));
|
||||||
else
|
else
|
||||||
return std::make_unique<UnaryUnknownExpression>(std::move(inner_));
|
return std::make_unique<UnaryUnknownExpression>(std::move(inner_));
|
||||||
}
|
}
|
||||||
|
@ -428,14 +455,6 @@ std::unique_ptr<UnaryExpression> MakeUnaryExpression(std::string name,
|
||||||
class LiteralExpression : public Expression
|
class LiteralExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit LiteralExpression(const std::string& str)
|
|
||||||
{
|
|
||||||
// If it fails to parse it will just be the default: 0.0
|
|
||||||
TryParse(str, &m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlState GetValue() const override { return m_value; }
|
|
||||||
|
|
||||||
void SetValue(ControlState value) override
|
void SetValue(ControlState value) override
|
||||||
{
|
{
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
|
@ -448,12 +467,62 @@ public:
|
||||||
// Nothing needed.
|
// Nothing needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
operator std::string() const override { return '\'' + ValueToString(m_value) + '\''; }
|
operator std::string() const override { return '\'' + GetName() + '\''; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual std::string GetName() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LiteralReal : public LiteralExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LiteralReal(ControlState value) : m_value(value) {}
|
||||||
|
|
||||||
|
ControlState GetValue() const override { return m_value; }
|
||||||
|
|
||||||
|
std::string GetName() const override { return ValueToString(m_value); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ControlState m_value{};
|
const ControlState m_value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A +1.0 per second incrementing timer:
|
||||||
|
class LiteralTimer : public LiteralExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ControlState GetValue() const override
|
||||||
|
{
|
||||||
|
const auto ms =
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now().time_since_epoch());
|
||||||
|
// TODO: Will this roll over nicely?
|
||||||
|
return ms.count() / 1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetName() const override { return "Timer"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Clock = std::chrono::steady_clock;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<LiteralExpression> MakeLiteralExpression(std::string name)
|
||||||
|
{
|
||||||
|
// Case insensitive matching.
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||||
|
|
||||||
|
// Check for named literals:
|
||||||
|
if ("timer" == name)
|
||||||
|
{
|
||||||
|
return std::make_unique<LiteralTimer>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Assume it's a Real. If TryParse fails we'll just get a Zero.
|
||||||
|
ControlState val{};
|
||||||
|
TryParse(name, &val);
|
||||||
|
return std::make_unique<LiteralReal>(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This class proxies all methods to its either left-hand child if it has bound controls, or its
|
// 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.
|
// right-hand child. Its intended use is for supporting old-style barewords expressions.
|
||||||
class CoalesceExpression : public Expression
|
class CoalesceExpression : public Expression
|
||||||
|
@ -552,7 +621,7 @@ private:
|
||||||
}
|
}
|
||||||
case TOK_LITERAL:
|
case TOK_LITERAL:
|
||||||
{
|
{
|
||||||
return {ParseStatus::Successful, std::make_unique<LiteralExpression>(tok.data)};
|
return {ParseStatus::Successful, MakeLiteralExpression(tok.data)};
|
||||||
}
|
}
|
||||||
case TOK_LPAREN:
|
case TOK_LPAREN:
|
||||||
return Paren();
|
return Paren();
|
||||||
|
@ -595,6 +664,7 @@ private:
|
||||||
case TOK_ADD:
|
case TOK_ADD:
|
||||||
case TOK_MUL:
|
case TOK_MUL:
|
||||||
case TOK_DIV:
|
case TOK_DIV:
|
||||||
|
case TOK_MOD:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue