ExpressionParser: Add Hotkey syntax.

This commit is contained in:
Jordan Woyak 2019-10-22 19:12:55 -05:00
parent 57f14b260b
commit 52547379c9
2 changed files with 98 additions and 0 deletions

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
@ -112,6 +113,8 @@ Token Lexer::NextToken()
return Token(TOK_LPAREN); return Token(TOK_LPAREN);
case ')': case ')':
return Token(TOK_RPAREN); return Token(TOK_RPAREN);
case '@':
return Token(TOK_HOTKEY);
case '&': case '&':
return Token(TOK_AND); return Token(TOK_AND);
case '|': case '|':
@ -374,6 +377,63 @@ protected:
ControlState* m_value_ptr{}; ControlState* m_value_ptr{};
}; };
class HotkeyExpression : public Expression
{
public:
HotkeyExpression(std::vector<std::unique_ptr<ControlExpression>> inputs)
: m_inputs(std::move(inputs))
{
}
ControlState GetValue() const override
{
if (m_inputs.empty())
return 0;
const bool modifiers_pressed = std::all_of(m_inputs.begin(), std::prev(m_inputs.end()),
[](const std::unique_ptr<ControlExpression>& input) {
// TODO: kill magic number.
return input->GetValue() > 0.5;
});
if (modifiers_pressed)
{
// TODO: kill magic number.
const bool final_input_pressed = (**m_inputs.rbegin()).GetValue() > 0.5;
if (m_is_ready)
return final_input_pressed;
if (!final_input_pressed)
m_is_ready = true;
}
else
m_is_ready = false;
return 0;
}
void SetValue(ControlState) override {}
int CountNumControls() const override
{
int result = 0;
for (auto& input : m_inputs)
result += input->CountNumControls();
return result;
}
void UpdateReferences(ControlEnvironment& env) override
{
for (auto& input : m_inputs)
input->UpdateReferences(env);
}
private:
std::vector<std::unique_ptr<ControlExpression>> m_inputs;
mutable bool m_is_ready = false;
};
// 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
@ -600,6 +660,10 @@ private:
{ {
return ParseParens(); return ParseParens();
} }
case TOK_HOTKEY:
{
return ParseHotkeys();
}
case TOK_SUB: case TOK_SUB:
{ {
// An atom was expected but we got a subtraction symbol. // An atom was expected but we got a subtraction symbol.
@ -684,6 +748,39 @@ private:
return result; return result;
} }
ParseResult ParseHotkeys()
{
Token tok = Chew();
if (tok.type != TOK_LPAREN)
return ParseResult::MakeErrorResult(tok, _trans("Expected opening paren."));
std::vector<std::unique_ptr<ControlExpression>> inputs;
while (true)
{
tok = Chew();
if (tok.type != TOK_CONTROL && tok.type != TOK_BAREWORD)
return ParseResult::MakeErrorResult(tok, _trans("Expected name of input."));
ControlQualifier cq;
cq.FromString(tok.data);
inputs.emplace_back(std::make_unique<ControlExpression>(std::move(cq)));
tok = Chew();
if (tok.type == TOK_ADD)
continue;
if (tok.type == TOK_RPAREN)
break;
return ParseResult::MakeErrorResult(tok, _trans("Expected + or closing paren."));
}
return ParseResult::MakeSuccessfulResult(std::make_unique<HotkeyExpression>(std::move(inputs)));
}
ParseResult ParseToplevel() { return ParseBinary(); } ParseResult ParseToplevel() { return ParseBinary(); }
}; // namespace ExpressionParser }; // namespace ExpressionParser

View File

@ -26,6 +26,7 @@ enum TokenType
TOK_VARIABLE, TOK_VARIABLE,
TOK_BAREWORD, TOK_BAREWORD,
TOK_COMMENT, TOK_COMMENT,
TOK_HOTKEY,
// Binary Ops: // Binary Ops:
TOK_BINARY_OPS_BEGIN, TOK_BINARY_OPS_BEGIN,
TOK_AND = TOK_BINARY_OPS_BEGIN, TOK_AND = TOK_BINARY_OPS_BEGIN,