From 258832b1e89b62d582e42d23099570f03c407885 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 8 Jan 2019 18:26:36 -0600 Subject: [PATCH] ExpressionParser: Change function argument syntax to something more c++-like. --- .../ControlReference/ExpressionParser.cpp | 135 ++++++++++++++---- 1 file changed, 106 insertions(+), 29 deletions(-) diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp index 85e19da972..3838a6a7e9 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp @@ -449,14 +449,19 @@ public: return result; } - void AppendArg(std::unique_ptr arg) { m_args.emplace_back(std::move(arg)); } + bool SetArguments(std::vector>&& args) + { + m_args = std::move(args); - Expression& GetArg(u32 number) { return *m_args[number]; } - const Expression& GetArg(u32 number) const { return *m_args[number]; } - virtual int GetArity() const = 0; + return ValidateArguments(m_args); + } protected: virtual std::string GetFuncName() const = 0; + virtual bool ValidateArguments(const std::vector>& args) = 0; + + Expression& GetArg(u32 number) { return *m_args[number]; } + const Expression& GetArg(u32 number) const { return *m_args[number]; } private: std::vector> m_args; @@ -465,16 +470,24 @@ private: // TODO: Return an oscillating value to make it apparent something was spelled wrong? class UnknownFunctionExpression : public FunctionExpression { -public: +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return false; + } ControlState GetValue() const override { return 0.0; } void SetValue(ControlState value) override {} std::string GetFuncName() const override { return "Unknown"; } - int GetArity() const override { return 0; } }; class ToggleExpression : public FunctionExpression { -public: +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + ControlState GetValue() const override { const ControlState inner_value = GetArg(0).GetValue(); @@ -494,34 +507,45 @@ public: void SetValue(ControlState value) override {} std::string GetFuncName() const override { return "Toggle"; } - int GetArity() const override { return 1; } -private: mutable bool m_released{}; mutable bool m_state{}; }; class NotExpression : public FunctionExpression { -public: +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + ControlState GetValue() const override { return 1.0 - GetArg(0).GetValue(); } void SetValue(ControlState value) override { GetArg(0).SetValue(1.0 - value); } std::string GetFuncName() const override { return ""; } - int GetArity() const override { return 1; } }; class SinExpression : public FunctionExpression { -public: +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + ControlState GetValue() const override { return std::sin(GetArg(0).GetValue()); } void SetValue(ControlState value) override {} std::string GetFuncName() const override { return "Sin"; } - int GetArity() const override { return 1; } }; class TimerExpression : public FunctionExpression { -public: +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + ControlState GetValue() const override { const auto now = Clock::now(); @@ -551,7 +575,6 @@ public: } void SetValue(ControlState value) override {} std::string GetFuncName() const override { return "Timer"; } - int GetArity() const override { return 1; } private: using Clock = std::chrono::steady_clock; @@ -560,7 +583,12 @@ private: class IfExpression : public FunctionExpression { -public: +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 3 == args.size(); + } + ControlState GetValue() const override { return (GetArg(0).GetValue() > CONDITION_THRESHOLD) ? GetArg(1).GetValue() : @@ -569,12 +597,16 @@ public: void SetValue(ControlState value) override {} std::string GetFuncName() const override { return "If"; } - int GetArity() const override { return 3; } }; class UnaryMinusExpression : public FunctionExpression { -public: +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + ControlState GetValue() const override { // Subtraction for clarity: @@ -583,12 +615,15 @@ public: void SetValue(ControlState value) override {} std::string GetFuncName() const override { return "Minus"; } - int GetArity() const override { return 1; } }; class WhileExpression : public FunctionExpression { -public: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 2 == args.size(); + } + ControlState GetValue() const override { // Returns 1.0 on successful loop, 0.0 on reps exceeded. Sensible? @@ -610,7 +645,6 @@ public: void SetValue(ControlState value) override {} std::string GetFuncName() const override { return "While"; } - int GetArity() const override { return 2; } }; std::unique_ptr MakeFunctionExpression(std::string name) @@ -787,17 +821,61 @@ public: ParseResult Parse() { return Toplevel(); } private: + struct FunctionArguments + { + FunctionArguments(ParseStatus status_, std::vector>&& args_ = {}) + : status(status_), args(std::move(args_)) + { + } + + ParseStatus status; + std::vector> args; + }; + std::vector tokens; std::vector::iterator m_it; Token Chew() { return *m_it++; } Token Peek() { return *m_it; } + bool Expects(TokenType type) { Token tok = Chew(); return tok.type == type; } + FunctionArguments ParseFunctionArguments() + { + if (!Expects(TOK_LPAREN)) + return {ParseStatus::SyntaxError}; + + // Check for empty argument list: + if (TOK_RPAREN == Peek().type) + return {ParseStatus::Successful}; + + std::vector> args; + + while (true) + { + // Read one argument. + // Grab an expression, but stop at comma. + auto arg = Binary(BinaryOperatorPrecedence(TOK_COMMA)); + if (ParseStatus::Successful != arg.status) + return {ParseStatus::SyntaxError}; + + args.emplace_back(std::move(arg.expr)); + + // Right paren is the end of our arguments. + const Token tok = Chew(); + if (TOK_RPAREN == tok.type) + return {ParseStatus::Successful, std::move(args)}; + + // Comma before the next argument. + if (TOK_COMMA != tok.type) + return {ParseStatus::SyntaxError}; + } + } + ParseResult Atom(const Token& tok) { switch (tok.type) @@ -805,15 +883,14 @@ private: case TOK_FUNCTION: { auto func = MakeFunctionExpression(tok.data); - int arity = func->GetArity(); - while (arity--) - { - auto arg = Atom(Chew()); - if (arg.status == ParseStatus::SyntaxError) - return arg; + auto args = ParseFunctionArguments(); + + if (ParseStatus::Successful != args.status) + return {ParseStatus::SyntaxError}; + + if (!func->SetArguments(std::move(args.args))) + return {ParseStatus::SyntaxError}; - func->AppendArg(std::move(arg.expr)); - } return {ParseStatus::Successful, std::move(func)}; } case TOK_CONTROL: