Merge pull request #5577 from ligfx/separateexpressionparsingandbinding
ControlReference/ExpressionParser: separate parsing from binding
This commit is contained in:
commit
2b4bf8662a
|
@ -344,7 +344,7 @@ void HotkeyManager::LoadDefaults(const ControllerInterface& ciface)
|
||||||
auto set_key_expression = [this](int index, const std::string& expression) {
|
auto set_key_expression = [this](int index, const std::string& expression) {
|
||||||
m_keys[FindGroupByID(index)]
|
m_keys[FindGroupByID(index)]
|
||||||
->controls[GetIndexForGroup(FindGroupByID(index), index)]
|
->controls[GetIndexForGroup(FindGroupByID(index), index)]
|
||||||
->control_ref->expression = expression;
|
->control_ref->SetExpression(expression);
|
||||||
};
|
};
|
||||||
|
|
||||||
// General hotkeys
|
// General hotkeys
|
||||||
|
|
|
@ -110,7 +110,7 @@ void IOWindow::CreateMainLayout()
|
||||||
|
|
||||||
void IOWindow::Update()
|
void IOWindow::Update()
|
||||||
{
|
{
|
||||||
m_expression_text->setPlainText(QString::fromStdString(m_reference->expression));
|
m_expression_text->setPlainText(QString::fromStdString(m_reference->GetExpression()));
|
||||||
m_range_spinbox->setValue(m_reference->range * SLIDER_TICK_COUNT);
|
m_range_spinbox->setValue(m_reference->range * SLIDER_TICK_COUNT);
|
||||||
m_range_slider->setValue(m_reference->range * SLIDER_TICK_COUNT);
|
m_range_slider->setValue(m_reference->range * SLIDER_TICK_COUNT);
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ void IOWindow::OnDialogButtonPressed(QAbstractButton* button)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_reference->expression = m_expression_text->toPlainText().toStdString();
|
m_reference->SetExpression(m_expression_text->toPlainText().toStdString());
|
||||||
|
|
||||||
if (button != m_apply_button)
|
if (button != m_apply_button)
|
||||||
accept();
|
accept();
|
||||||
|
|
|
@ -27,7 +27,7 @@ static QString EscapeAmpersand(QString&& string)
|
||||||
}
|
}
|
||||||
|
|
||||||
MappingButton::MappingButton(MappingWidget* widget, ControlReference* ref)
|
MappingButton::MappingButton(MappingWidget* widget, ControlReference* ref)
|
||||||
: ElidedButton(EscapeAmpersand(QString::fromStdString(ref->expression))), m_parent(widget),
|
: ElidedButton(EscapeAmpersand(QString::fromStdString(ref->GetExpression()))), m_parent(widget),
|
||||||
m_reference(ref)
|
m_reference(ref)
|
||||||
{
|
{
|
||||||
Connect();
|
Connect();
|
||||||
|
@ -66,7 +66,7 @@ void MappingButton::OnButtonPressed()
|
||||||
|
|
||||||
if (!expr.isEmpty())
|
if (!expr.isEmpty())
|
||||||
{
|
{
|
||||||
m_reference->expression = expr.toStdString();
|
m_reference->SetExpression(expr.toStdString());
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -78,13 +78,13 @@ void MappingButton::OnButtonPressed()
|
||||||
|
|
||||||
void MappingButton::OnButtonTimeout()
|
void MappingButton::OnButtonTimeout()
|
||||||
{
|
{
|
||||||
setText(EscapeAmpersand(QString::fromStdString(m_reference->expression)));
|
setText(EscapeAmpersand(QString::fromStdString(m_reference->GetExpression())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingButton::Clear()
|
void MappingButton::Clear()
|
||||||
{
|
{
|
||||||
m_parent->Update();
|
m_parent->Update();
|
||||||
m_reference->expression.clear();
|
m_reference->SetExpression("");
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ void MappingButton::Update()
|
||||||
{
|
{
|
||||||
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
||||||
m_reference->UpdateReference(g_controller_interface, m_parent->GetParent()->GetDeviceQualifier());
|
m_reference->UpdateReference(g_controller_interface, m_parent->GetParent()->GetDeviceQualifier());
|
||||||
setText(EscapeAmpersand(QString::fromStdString(m_reference->expression)));
|
setText(EscapeAmpersand(QString::fromStdString(m_reference->GetExpression())));
|
||||||
m_parent->SaveSettings();
|
m_parent->SaveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
#include "InputCommon/ControllerInterface/Device.h"
|
#include "InputCommon/ControllerInterface/Device.h"
|
||||||
#include "InputCommon/InputConfig.h"
|
#include "InputCommon/InputConfig.h"
|
||||||
|
|
||||||
using namespace ciface::ExpressionParser;
|
using ciface::ExpressionParser::ParseStatus;
|
||||||
|
|
||||||
void InputConfigDialog::ConfigExtension(wxCommandEvent& event)
|
void InputConfigDialog::ConfigExtension(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
|
@ -243,7 +243,7 @@ ControlButton::ControlButton(wxWindow* const parent, ControlReference* const _re
|
||||||
m_configured_width(FromDIP(width))
|
m_configured_width(FromDIP(width))
|
||||||
{
|
{
|
||||||
if (label.empty())
|
if (label.empty())
|
||||||
SetLabelText(StrToWxStr(_ref->expression));
|
SetLabelText(StrToWxStr(_ref->GetExpression()));
|
||||||
else
|
else
|
||||||
SetLabel(StrToWxStr(label));
|
SetLabel(StrToWxStr(label));
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ void ControlDialog::SelectControl(const std::string& name)
|
||||||
void ControlDialog::UpdateGUI()
|
void ControlDialog::UpdateGUI()
|
||||||
{
|
{
|
||||||
// update textbox
|
// update textbox
|
||||||
textctrl->SetValue(StrToWxStr(control_reference->expression));
|
textctrl->SetValue(StrToWxStr(control_reference->GetExpression()));
|
||||||
|
|
||||||
// updates the "bound controls:" label
|
// updates the "bound controls:" label
|
||||||
m_bound_label->SetLabel(
|
m_bound_label->SetLabel(
|
||||||
|
@ -347,11 +347,12 @@ void ControlDialog::UpdateGUI()
|
||||||
case ParseStatus::SyntaxError:
|
case ParseStatus::SyntaxError:
|
||||||
m_error_label->SetLabel(_("Syntax error"));
|
m_error_label->SetLabel(_("Syntax error"));
|
||||||
break;
|
break;
|
||||||
case ParseStatus::NoDevice:
|
case ParseStatus::Successful:
|
||||||
m_error_label->SetLabel(_("Device not found"));
|
m_error_label->SetLabel(control_reference->BoundCount() > 0 ? "" : _("Device not found"));
|
||||||
break;
|
break;
|
||||||
default:
|
case ParseStatus::EmptyExpression:
|
||||||
m_error_label->SetLabel("");
|
m_error_label->SetLabel("");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -364,7 +365,7 @@ void InputConfigDialog::UpdateGUI()
|
||||||
{
|
{
|
||||||
for (ControlButton* button : cgBox->control_buttons)
|
for (ControlButton* button : cgBox->control_buttons)
|
||||||
{
|
{
|
||||||
button->SetLabelText(StrToWxStr(button->control_reference->expression));
|
button->SetLabelText(StrToWxStr(button->control_reference->GetExpression()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PadSetting* padSetting : cgBox->options)
|
for (PadSetting* padSetting : cgBox->options)
|
||||||
|
@ -399,7 +400,7 @@ void InputConfigDialog::LoadDefaults(wxCommandEvent&)
|
||||||
|
|
||||||
bool ControlDialog::Validate()
|
bool ControlDialog::Validate()
|
||||||
{
|
{
|
||||||
control_reference->expression = WxStrToStr(textctrl->GetValue());
|
control_reference->SetExpression(WxStrToStr(textctrl->GetValue()));
|
||||||
|
|
||||||
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
||||||
control_reference->UpdateReference(g_controller_interface,
|
control_reference->UpdateReference(g_controller_interface,
|
||||||
|
@ -408,7 +409,7 @@ bool ControlDialog::Validate()
|
||||||
UpdateGUI();
|
UpdateGUI();
|
||||||
|
|
||||||
const auto parse_status = control_reference->GetParseStatus();
|
const auto parse_status = control_reference->GetParseStatus();
|
||||||
return parse_status == ParseStatus::Successful || parse_status == ParseStatus::NoDevice;
|
return parse_status == ParseStatus::Successful || parse_status == ParseStatus::EmptyExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputConfigDialog::SetDevice(wxCommandEvent&)
|
void InputConfigDialog::SetDevice(wxCommandEvent&)
|
||||||
|
@ -438,7 +439,7 @@ void ControlDialog::SetDevice(wxCommandEvent&)
|
||||||
|
|
||||||
void ControlDialog::ClearControl(wxCommandEvent&)
|
void ControlDialog::ClearControl(wxCommandEvent&)
|
||||||
{
|
{
|
||||||
control_reference->expression.clear();
|
control_reference->SetExpression("");
|
||||||
|
|
||||||
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
||||||
control_reference->UpdateReference(g_controller_interface,
|
control_reference->UpdateReference(g_controller_interface,
|
||||||
|
@ -497,7 +498,7 @@ void ControlDialog::SetSelectedControl(wxCommandEvent&)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
textctrl->WriteText(expr);
|
textctrl->WriteText(expr);
|
||||||
control_reference->expression = textctrl->GetValue();
|
control_reference->SetExpression(WxStrToStr(textctrl->GetValue()));
|
||||||
|
|
||||||
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
||||||
control_reference->UpdateReference(g_controller_interface,
|
control_reference->UpdateReference(g_controller_interface,
|
||||||
|
@ -533,7 +534,7 @@ void ControlDialog::AppendControl(wxCommandEvent& event)
|
||||||
}
|
}
|
||||||
|
|
||||||
textctrl->WriteText(expr);
|
textctrl->WriteText(expr);
|
||||||
control_reference->expression = textctrl->GetValue();
|
control_reference->SetExpression(WxStrToStr(textctrl->GetValue()));
|
||||||
|
|
||||||
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
||||||
control_reference->UpdateReference(g_controller_interface,
|
control_reference->UpdateReference(g_controller_interface,
|
||||||
|
@ -637,7 +638,7 @@ void InputConfigDialog::ConfigControl(wxEvent& event)
|
||||||
void InputConfigDialog::ClearControl(wxEvent& event)
|
void InputConfigDialog::ClearControl(wxEvent& event)
|
||||||
{
|
{
|
||||||
ControlButton* const btn = (ControlButton*)event.GetEventObject();
|
ControlButton* const btn = (ControlButton*)event.GetEventObject();
|
||||||
btn->control_reference->expression.clear();
|
btn->control_reference->SetExpression("");
|
||||||
btn->control_reference->range = 1.0;
|
btn->control_reference->range = 1.0;
|
||||||
|
|
||||||
controller->UpdateReferences(g_controller_interface);
|
controller->UpdateReferences(g_controller_interface);
|
||||||
|
@ -716,7 +717,7 @@ bool InputConfigDialog::DetectButton(ControlButton* button)
|
||||||
wxString control_name = ctrl->GetName();
|
wxString control_name = ctrl->GetName();
|
||||||
wxString expr;
|
wxString expr;
|
||||||
GetExpressionForControl(expr, control_name);
|
GetExpressionForControl(expr, control_name);
|
||||||
button->control_reference->expression = expr;
|
button->control_reference->SetExpression(WxStrToStr(expr));
|
||||||
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
||||||
button->control_reference->UpdateReference(g_controller_interface,
|
button->control_reference->UpdateReference(g_controller_interface,
|
||||||
controller->default_device);
|
controller->default_device);
|
||||||
|
|
|
@ -25,21 +25,20 @@ bool ControlReference::InputGateOn()
|
||||||
// UpdateReference
|
// UpdateReference
|
||||||
//
|
//
|
||||||
// Updates a controlreference's binded devices/controls
|
// Updates a controlreference's binded devices/controls
|
||||||
// need to call this to re-parse a control reference's expression after changing it
|
// need to call this to re-bind a control reference after changing its expression
|
||||||
//
|
//
|
||||||
void ControlReference::UpdateReference(const ciface::Core::DeviceContainer& devices,
|
void ControlReference::UpdateReference(const ciface::Core::DeviceContainer& devices,
|
||||||
const ciface::Core::DeviceQualifier& default_device)
|
const ciface::Core::DeviceQualifier& default_device)
|
||||||
{
|
{
|
||||||
Expression* expr;
|
|
||||||
ControlFinder finder(devices, default_device, IsInput());
|
ControlFinder finder(devices, default_device, IsInput());
|
||||||
m_parse_status = ParseExpression(expression, finder, &expr);
|
if (m_parsed_expression)
|
||||||
m_parsed_expression.reset(expr);
|
m_parsed_expression->UpdateReferences(finder);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ControlReference::BoundCount() const
|
int ControlReference::BoundCount() const
|
||||||
{
|
{
|
||||||
if (m_parsed_expression)
|
if (m_parsed_expression)
|
||||||
return m_parsed_expression->num_controls;
|
return m_parsed_expression->CountNumControls();
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -49,6 +48,17 @@ ParseStatus ControlReference::GetParseStatus() const
|
||||||
return m_parse_status;
|
return m_parse_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ControlReference::GetExpression() const
|
||||||
|
{
|
||||||
|
return m_expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlReference::SetExpression(std::string expr)
|
||||||
|
{
|
||||||
|
m_expression = std::move(expr);
|
||||||
|
std::tie(m_parse_status, m_parsed_expression) = ParseExpression(m_expression);
|
||||||
|
}
|
||||||
|
|
||||||
ControlReference::ControlReference() : range(1), m_parsed_expression(nullptr)
|
ControlReference::ControlReference() : range(1), m_parsed_expression(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,14 @@ public:
|
||||||
ciface::ExpressionParser::ParseStatus GetParseStatus() const;
|
ciface::ExpressionParser::ParseStatus GetParseStatus() const;
|
||||||
void UpdateReference(const ciface::Core::DeviceContainer& devices,
|
void UpdateReference(const ciface::Core::DeviceContainer& devices,
|
||||||
const ciface::Core::DeviceQualifier& default_device);
|
const ciface::Core::DeviceQualifier& default_device);
|
||||||
|
std::string GetExpression() const;
|
||||||
|
void SetExpression(std::string expr);
|
||||||
|
|
||||||
ControlState range;
|
ControlState range;
|
||||||
std::string expression;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ControlReference();
|
ControlReference();
|
||||||
|
std::string m_expression;
|
||||||
std::unique_ptr<ciface::ExpressionParser::Expression> m_parsed_expression;
|
std::unique_ptr<ciface::ExpressionParser::Expression> m_parsed_expression;
|
||||||
ciface::ExpressionParser::ParseStatus m_parse_status;
|
ciface::ExpressionParser::ParseStatus m_parse_status;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
#include "InputCommon/ControlReference/ExpressionParser.h"
|
#include "InputCommon/ControlReference/ExpressionParser.h"
|
||||||
|
|
||||||
using namespace ciface::Core;
|
using namespace ciface::Core;
|
||||||
|
@ -207,64 +208,42 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExpressionNode
|
class ControlExpression : public Expression
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~ExpressionNode() {}
|
|
||||||
virtual ControlState GetValue() const { return 0; }
|
|
||||||
virtual void SetValue(ControlState state) {}
|
|
||||||
virtual int CountNumControls() const { return 0; }
|
|
||||||
virtual operator std::string() const { return ""; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class DummyExpression : public ExpressionNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string name;
|
|
||||||
|
|
||||||
DummyExpression(const std::string& name_) : name(name_) {}
|
|
||||||
ControlState GetValue() const override { return 0.0; }
|
|
||||||
void SetValue(ControlState value) override {}
|
|
||||||
int CountNumControls() const override { return 0; }
|
|
||||||
operator std::string() const override { return "`" + name + "`"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class ControlExpression : public ExpressionNode
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ControlQualifier qualifier;
|
ControlQualifier qualifier;
|
||||||
Device::Control* control;
|
Device::Control* control = nullptr;
|
||||||
|
// Keep a shared_ptr to the device so the control pointer doesn't become invalid
|
||||||
ControlExpression(ControlQualifier qualifier_, std::shared_ptr<Device> device,
|
|
||||||
Device::Control* control_)
|
|
||||||
: qualifier(qualifier_), control(control_), m_device(device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlState GetValue() const override { return control->ToInput()->GetState(); }
|
|
||||||
void SetValue(ControlState value) override { control->ToOutput()->SetState(value); }
|
|
||||||
int CountNumControls() const override { return 1; }
|
|
||||||
operator std::string() const override { return "`" + (std::string)qualifier + "`"; }
|
|
||||||
private:
|
|
||||||
std::shared_ptr<Device> m_device;
|
std::shared_ptr<Device> m_device;
|
||||||
|
|
||||||
|
explicit ControlExpression(ControlQualifier qualifier_) : qualifier(qualifier_) {}
|
||||||
|
ControlState GetValue() const override { return control ? control->ToInput()->GetState() : 0.0; }
|
||||||
|
void SetValue(ControlState value) override
|
||||||
|
{
|
||||||
|
if (control)
|
||||||
|
control->ToOutput()->SetState(value);
|
||||||
|
}
|
||||||
|
int CountNumControls() const override { return control ? 1 : 0; }
|
||||||
|
void UpdateReferences(ControlFinder& finder) override
|
||||||
|
{
|
||||||
|
m_device = finder.FindDevice(qualifier);
|
||||||
|
control = finder.FindControl(qualifier);
|
||||||
|
}
|
||||||
|
operator std::string() const override { return "`" + static_cast<std::string>(qualifier) + "`"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class BinaryExpression : public ExpressionNode
|
class BinaryExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TokenType op;
|
TokenType op;
|
||||||
ExpressionNode* lhs;
|
std::unique_ptr<Expression> lhs;
|
||||||
ExpressionNode* rhs;
|
std::unique_ptr<Expression> rhs;
|
||||||
|
|
||||||
BinaryExpression(TokenType op_, ExpressionNode* lhs_, ExpressionNode* rhs_)
|
BinaryExpression(TokenType op_, std::unique_ptr<Expression>&& lhs_,
|
||||||
: op(op_), lhs(lhs_), rhs(rhs_)
|
std::unique_ptr<Expression>&& rhs_)
|
||||||
|
: op(op_), lhs(std::move(lhs_)), rhs(std::move(rhs_))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
virtual ~BinaryExpression()
|
|
||||||
{
|
|
||||||
delete lhs;
|
|
||||||
delete rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlState GetValue() const override
|
ControlState GetValue() const override
|
||||||
{
|
{
|
||||||
|
@ -297,20 +276,28 @@ public:
|
||||||
return lhs->CountNumControls() + rhs->CountNumControls();
|
return lhs->CountNumControls() + rhs->CountNumControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateReferences(ControlFinder& finder) override
|
||||||
|
{
|
||||||
|
lhs->UpdateReferences(finder);
|
||||||
|
rhs->UpdateReferences(finder);
|
||||||
|
}
|
||||||
|
|
||||||
operator std::string() const override
|
operator std::string() const override
|
||||||
{
|
{
|
||||||
return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")";
|
return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnaryExpression : public ExpressionNode
|
class UnaryExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TokenType op;
|
TokenType op;
|
||||||
ExpressionNode* inner;
|
std::unique_ptr<Expression> inner;
|
||||||
|
|
||||||
UnaryExpression(TokenType op_, ExpressionNode* inner_) : op(op_), inner(inner_) {}
|
UnaryExpression(TokenType op_, std::unique_ptr<Expression>&& inner_)
|
||||||
virtual ~UnaryExpression() { delete inner; }
|
: op(op_), inner(std::move(inner_))
|
||||||
|
{
|
||||||
|
}
|
||||||
ControlState GetValue() const override
|
ControlState GetValue() const override
|
||||||
{
|
{
|
||||||
ControlState value = inner->GetValue();
|
ControlState value = inner->GetValue();
|
||||||
|
@ -338,9 +325,50 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
int CountNumControls() const override { return inner->CountNumControls(); }
|
int CountNumControls() const override { return inner->CountNumControls(); }
|
||||||
|
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 OpName(op) + "(" + (std::string)(*inner) + ")"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
class CoalesceExpression : public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CoalesceExpression(std::unique_ptr<Expression>&& lhs, std::unique_ptr<Expression>&& rhs)
|
||||||
|
: m_lhs(std::move(lhs)), m_rhs(std::move(rhs))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlState GetValue() const override { return GetActiveChild()->GetValue(); }
|
||||||
|
void SetValue(ControlState value) override
|
||||||
|
{
|
||||||
|
m_lhs->SetValue(GetActiveChild() == m_lhs ? value : 0.0);
|
||||||
|
m_rhs->SetValue(GetActiveChild() == m_rhs ? value : 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CountNumControls() const override { return GetActiveChild()->CountNumControls(); }
|
||||||
|
operator std::string() const override
|
||||||
|
{
|
||||||
|
return "Coalesce(" + static_cast<std::string>(*m_lhs) + ", " +
|
||||||
|
static_cast<std::string>(*m_rhs) + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateReferences(ControlFinder& finder) override
|
||||||
|
{
|
||||||
|
m_lhs->UpdateReferences(finder);
|
||||||
|
m_rhs->UpdateReferences(finder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::unique_ptr<Expression>& GetActiveChild() const
|
||||||
|
{
|
||||||
|
return m_lhs->CountNumControls() > 0 ? m_lhs : m_rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Expression> m_lhs;
|
||||||
|
std::unique_ptr<Expression> m_rhs;
|
||||||
|
};
|
||||||
|
|
||||||
std::shared_ptr<Device> ControlFinder::FindDevice(ControlQualifier qualifier) const
|
std::shared_ptr<Device> ControlFinder::FindDevice(ControlQualifier qualifier) const
|
||||||
{
|
{
|
||||||
if (qualifier.has_device)
|
if (qualifier.has_device)
|
||||||
|
@ -361,29 +389,25 @@ Device::Control* ControlFinder::FindControl(ControlQualifier qualifier) const
|
||||||
return device->FindOutput(qualifier.control_name);
|
return device->FindOutput(qualifier.control_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ParseResult
|
||||||
|
{
|
||||||
|
ParseResult(ParseStatus status_, std::unique_ptr<Expression>&& expr_ = {})
|
||||||
|
: status(status_), expr(std::move(expr_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseStatus status;
|
||||||
|
std::unique_ptr<Expression> expr;
|
||||||
|
};
|
||||||
|
|
||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Parser(std::vector<Token> tokens_, ControlFinder& finder_) : tokens(tokens_), finder(finder_)
|
explicit Parser(std::vector<Token> tokens_) : tokens(tokens_) { m_it = tokens.begin(); }
|
||||||
{
|
ParseResult Parse() { return Toplevel(); }
|
||||||
m_it = tokens.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseStatus Parse(Expression** expr_out)
|
|
||||||
{
|
|
||||||
ExpressionNode* node;
|
|
||||||
ParseStatus status = Toplevel(&node);
|
|
||||||
if (status != ParseStatus::Successful)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
*expr_out = new Expression(node);
|
|
||||||
return ParseStatus::Successful;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
std::vector<Token>::iterator m_it;
|
std::vector<Token>::iterator m_it;
|
||||||
ControlFinder& finder;
|
|
||||||
|
|
||||||
Token Chew() { return *m_it++; }
|
Token Chew() { return *m_it++; }
|
||||||
Token Peek() { return *m_it; }
|
Token Peek() { return *m_it; }
|
||||||
|
@ -393,28 +417,17 @@ private:
|
||||||
return tok.type == type;
|
return tok.type == type;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus Atom(ExpressionNode** expr_out)
|
ParseResult Atom()
|
||||||
{
|
{
|
||||||
Token tok = Chew();
|
Token tok = Chew();
|
||||||
switch (tok.type)
|
switch (tok.type)
|
||||||
{
|
{
|
||||||
case TOK_CONTROL:
|
case TOK_CONTROL:
|
||||||
{
|
return {ParseStatus::Successful, std::make_unique<ControlExpression>(tok.qualifier)};
|
||||||
std::shared_ptr<Device> device = finder.FindDevice(tok.qualifier);
|
|
||||||
Device::Control* control = finder.FindControl(tok.qualifier);
|
|
||||||
if (control == nullptr)
|
|
||||||
{
|
|
||||||
*expr_out = new DummyExpression(tok.qualifier);
|
|
||||||
return ParseStatus::NoDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
*expr_out = new ControlExpression(tok.qualifier, device, control);
|
|
||||||
return ParseStatus::Successful;
|
|
||||||
}
|
|
||||||
case TOK_LPAREN:
|
case TOK_LPAREN:
|
||||||
return Paren(expr_out);
|
return Paren();
|
||||||
default:
|
default:
|
||||||
return ParseStatus::SyntaxError;
|
return {ParseStatus::SyntaxError};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,20 +442,19 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus Unary(ExpressionNode** expr_out)
|
ParseResult Unary()
|
||||||
{
|
{
|
||||||
if (IsUnaryExpression(Peek().type))
|
if (IsUnaryExpression(Peek().type))
|
||||||
{
|
{
|
||||||
Token tok = Chew();
|
Token tok = Chew();
|
||||||
ExpressionNode* atom_expr;
|
ParseResult result = Atom();
|
||||||
ParseStatus status = Atom(&atom_expr);
|
if (result.status == ParseStatus::SyntaxError)
|
||||||
if (status == ParseStatus::SyntaxError)
|
return result;
|
||||||
return status;
|
return {ParseStatus::Successful,
|
||||||
*expr_out = new UnaryExpression(tok.type, atom_expr);
|
std::make_unique<UnaryExpression>(tok.type, std::move(result.expr))};
|
||||||
return ParseStatus::Successful;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Atom(expr_out);
|
return Atom();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBinaryToken(TokenType type)
|
bool IsBinaryToken(TokenType type)
|
||||||
|
@ -458,113 +470,83 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus Binary(ExpressionNode** expr_out)
|
ParseResult Binary()
|
||||||
{
|
{
|
||||||
ParseStatus status = Unary(expr_out);
|
ParseResult result = Unary();
|
||||||
if (status == ParseStatus::SyntaxError)
|
if (result.status == ParseStatus::SyntaxError)
|
||||||
return status;
|
return result;
|
||||||
|
|
||||||
|
std::unique_ptr<Expression> expr = std::move(result.expr);
|
||||||
while (IsBinaryToken(Peek().type))
|
while (IsBinaryToken(Peek().type))
|
||||||
{
|
{
|
||||||
Token tok = Chew();
|
Token tok = Chew();
|
||||||
ExpressionNode* unary_expr;
|
ParseResult unary_result = Unary();
|
||||||
status = Unary(&unary_expr);
|
if (unary_result.status == ParseStatus::SyntaxError)
|
||||||
if (status == ParseStatus::SyntaxError)
|
|
||||||
{
|
{
|
||||||
delete *expr_out;
|
return unary_result;
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr);
|
expr = std::make_unique<BinaryExpression>(tok.type, std::move(expr),
|
||||||
|
std::move(unary_result.expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseStatus::Successful;
|
return {ParseStatus::Successful, std::move(expr)};
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus Paren(ExpressionNode** expr_out)
|
ParseResult Paren()
|
||||||
{
|
{
|
||||||
ParseStatus status;
|
|
||||||
|
|
||||||
// lparen already chewed
|
// lparen already chewed
|
||||||
if ((status = Toplevel(expr_out)) != ParseStatus::Successful)
|
ParseResult result = Toplevel();
|
||||||
return status;
|
if (result.status != ParseStatus::Successful)
|
||||||
|
return result;
|
||||||
|
|
||||||
if (!Expects(TOK_RPAREN))
|
if (!Expects(TOK_RPAREN))
|
||||||
{
|
{
|
||||||
delete *expr_out;
|
return {ParseStatus::SyntaxError};
|
||||||
return ParseStatus::SyntaxError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseStatus::Successful;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus Toplevel(ExpressionNode** expr_out) { return Binary(expr_out); }
|
ParseResult Toplevel() { return Binary(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
ControlState Expression::GetValue() const
|
static ParseResult ParseComplexExpression(const std::string& str)
|
||||||
{
|
{
|
||||||
return node->GetValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Expression::SetValue(ControlState value)
|
|
||||||
{
|
|
||||||
node->SetValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression::Expression(ExpressionNode* node_)
|
|
||||||
{
|
|
||||||
node = node_;
|
|
||||||
num_controls = node->CountNumControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression::~Expression()
|
|
||||||
{
|
|
||||||
delete node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParseStatus ParseExpressionInner(const std::string& str, ControlFinder& finder,
|
|
||||||
Expression** expr_out)
|
|
||||||
{
|
|
||||||
ParseStatus status;
|
|
||||||
Expression* expr;
|
|
||||||
*expr_out = nullptr;
|
|
||||||
|
|
||||||
if (str == "")
|
|
||||||
return ParseStatus::Successful;
|
|
||||||
|
|
||||||
Lexer l(str);
|
Lexer l(str);
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
status = l.Tokenize(tokens);
|
ParseStatus tokenize_status = l.Tokenize(tokens);
|
||||||
if (status != ParseStatus::Successful)
|
if (tokenize_status != ParseStatus::Successful)
|
||||||
return status;
|
return {tokenize_status};
|
||||||
|
|
||||||
Parser p(tokens, finder);
|
return Parser(std::move(tokens)).Parse();
|
||||||
status = p.Parse(&expr);
|
|
||||||
if (status != ParseStatus::Successful)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
*expr_out = expr;
|
|
||||||
return ParseStatus::Successful;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseStatus ParseExpression(const std::string& str, ControlFinder& finder, Expression** expr_out)
|
static std::unique_ptr<Expression> ParseBarewordExpression(const std::string& str)
|
||||||
{
|
{
|
||||||
// Add compatibility with old simple expressions, which are simple
|
|
||||||
// barewords control names.
|
|
||||||
|
|
||||||
ControlQualifier qualifier;
|
ControlQualifier qualifier;
|
||||||
qualifier.control_name = str;
|
qualifier.control_name = str;
|
||||||
qualifier.has_device = false;
|
qualifier.has_device = false;
|
||||||
|
|
||||||
std::shared_ptr<Device> device = finder.FindDevice(qualifier);
|
return std::make_unique<ControlExpression>(qualifier);
|
||||||
Device::Control* control = finder.FindControl(qualifier);
|
}
|
||||||
if (control)
|
|
||||||
|
std::pair<ParseStatus, std::unique_ptr<Expression>> ParseExpression(const std::string& str)
|
||||||
|
{
|
||||||
|
if (StripSpaces(str).empty())
|
||||||
|
return std::make_pair(ParseStatus::EmptyExpression, nullptr);
|
||||||
|
|
||||||
|
auto bareword_expr = ParseBarewordExpression(str);
|
||||||
|
ParseResult complex_result = ParseComplexExpression(str);
|
||||||
|
|
||||||
|
if (complex_result.status != ParseStatus::Successful)
|
||||||
{
|
{
|
||||||
*expr_out = new Expression(new ControlExpression(qualifier, device, control));
|
return std::make_pair(complex_result.status, std::move(bareword_expr));
|
||||||
return ParseStatus::Successful;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseExpressionInner(str, finder, expr_out);
|
auto combined_expr = std::make_unique<CoalesceExpression>(std::move(bareword_expr),
|
||||||
|
std::move(complex_result.expr));
|
||||||
|
return std::make_pair(complex_result.status, std::move(combined_expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include "InputCommon/ControllerInterface/Device.h"
|
#include "InputCommon/ControllerInterface/Device.h"
|
||||||
|
|
||||||
namespace ciface
|
namespace ciface
|
||||||
|
@ -46,26 +47,24 @@ private:
|
||||||
bool is_input;
|
bool is_input;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExpressionNode;
|
|
||||||
class Expression
|
class Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Expression() : node(nullptr) {}
|
virtual ~Expression() = default;
|
||||||
Expression(ExpressionNode* node);
|
virtual ControlState GetValue() const = 0;
|
||||||
~Expression();
|
virtual void SetValue(ControlState state) = 0;
|
||||||
ControlState GetValue() const;
|
virtual int CountNumControls() const = 0;
|
||||||
void SetValue(ControlState state);
|
virtual void UpdateReferences(ControlFinder& finder) = 0;
|
||||||
int num_controls;
|
virtual operator std::string() const = 0;
|
||||||
ExpressionNode* node;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ParseStatus
|
enum class ParseStatus
|
||||||
{
|
{
|
||||||
Successful,
|
Successful,
|
||||||
SyntaxError,
|
SyntaxError,
|
||||||
NoDevice,
|
EmptyExpression,
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseStatus ParseExpression(const std::string& expr, ControlFinder& finder, Expression** expr_out);
|
std::pair<ParseStatus, std::unique_ptr<Expression>> ParseExpression(const std::string& expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,12 @@ void ControlGroup::LoadConfig(IniFile::Section* sec, const std::string& defdev,
|
||||||
|
|
||||||
for (auto& c : controls)
|
for (auto& c : controls)
|
||||||
{
|
{
|
||||||
// control expression
|
{
|
||||||
sec->Get(group + c->name, &c->control_ref->expression, "");
|
// control expression
|
||||||
|
std::string expression;
|
||||||
|
sec->Get(group + c->name, &expression, "");
|
||||||
|
c->control_ref->SetExpression(std::move(expression));
|
||||||
|
}
|
||||||
|
|
||||||
// range
|
// range
|
||||||
sec->Get(group + c->name + "/Range", &c->control_ref->range, 100.0);
|
sec->Get(group + c->name + "/Range", &c->control_ref->range, 100.0);
|
||||||
|
@ -109,7 +113,7 @@ void ControlGroup::SaveConfig(IniFile::Section* sec, const std::string& defdev,
|
||||||
for (auto& c : controls)
|
for (auto& c : controls)
|
||||||
{
|
{
|
||||||
// control expression
|
// control expression
|
||||||
sec->Set(group + c->name, c->control_ref->expression, "");
|
sec->Set(group + c->name, c->control_ref->GetExpression(), "");
|
||||||
|
|
||||||
// range
|
// range
|
||||||
sec->Set(group + c->name + "/Range", c->control_ref->range * 100.0, 100.0);
|
sec->Set(group + c->name + "/Range", c->control_ref->range * 100.0, 100.0);
|
||||||
|
@ -128,6 +132,6 @@ void ControlGroup::SaveConfig(IniFile::Section* sec, const std::string& defdev,
|
||||||
|
|
||||||
void ControlGroup::SetControlExpression(int index, const std::string& expression)
|
void ControlGroup::SetControlExpression(int index, const std::string& expression)
|
||||||
{
|
{
|
||||||
controls.at(index)->control_ref->expression = expression;
|
controls.at(index)->control_ref->SetExpression(expression);
|
||||||
}
|
}
|
||||||
} // namespace ControllerEmu
|
} // namespace ControllerEmu
|
||||||
|
|
Loading…
Reference in New Issue