Skip to content
Permalink
Browse files

ExpressionParser: Renamed ControlFinder to ControlEnvironment. Added …

…support for variables and assignment operator. ControlExpression objects now reference a matching input and output so the two can me mixed in any expression. (you can set rumble directly from inputs)
  • Loading branch information...
jordan-woyak committed Dec 30, 2018
1 parent 1efcf86 commit e896835f86e52051b1998a344549dfa8ba79847a
@@ -100,7 +100,7 @@ void MappingButton::Detect()
return;

m_reference->SetExpression(expression.toStdString());
m_parent->GetController()->UpdateReferences(g_controller_interface);
m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, m_reference);

ConfigChanged();
m_parent->SaveSettings();
@@ -111,7 +111,7 @@ void MappingButton::Clear()
m_reference->range = 100.0 / SLIDER_TICK_COUNT;

m_reference->SetExpression("");
m_parent->GetController()->UpdateReferences(g_controller_interface);
m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, m_reference);

m_parent->SaveSettings();
ConfigChanged();
@@ -25,12 +25,12 @@ bool ControlReference::InputGateOn()
// Updates a controlreference's binded devices/controls
// need to call this to re-bind a control reference after changing its expression
//
void ControlReference::UpdateReference(const ciface::Core::DeviceContainer& devices,
const ciface::Core::DeviceQualifier& default_device)
void ControlReference::UpdateReference(ciface::ExpressionParser::ControlEnvironment& env)
{
ControlFinder finder(devices, default_device, IsInput());
if (m_parsed_expression)
m_parsed_expression->UpdateReferences(finder);
{
m_parsed_expression->UpdateReferences(env);
}
}

int ControlReference::BoundCount() const
@@ -30,8 +30,7 @@ class ControlReference

int BoundCount() const;
ciface::ExpressionParser::ParseStatus GetParseStatus() const;
void UpdateReference(const ciface::Core::DeviceContainer& devices,
const ciface::Core::DeviceQualifier& default_device);
void UpdateReference(ciface::ExpressionParser::ControlEnvironment& env);
std::string GetExpression() const;
void SetExpression(std::string expr);

@@ -35,8 +35,10 @@ enum TokenType
TOK_MUL,
TOK_DIV,
TOK_MOD,
TOK_ASSIGN,
TOK_CONTROL,
TOK_LITERAL,
TOK_VARIABLE,
};

inline std::string OpName(TokenType op)
@@ -57,6 +59,10 @@ inline std::string OpName(TokenType op)
return "Div";
case TOK_MOD:
return "Mod";
case TOK_ASSIGN:
return "Assign";
case TOK_VARIABLE:
return "Var";
default:
assert(false);
return "";
@@ -97,10 +103,14 @@ class Token
return "/";
case TOK_MOD:
return "%";
case TOK_ASSIGN:
return "=";
case TOK_CONTROL:
return "Device(" + data + ")";
case TOK_LITERAL:
return '\'' + data + '\'';
case TOK_VARIABLE:
return '$' + data;
case TOK_INVALID:
break;
}
@@ -131,28 +141,32 @@ class Lexer
return false;
}

Token GetUnaryFunction()
std::string FetchWordChars()
{
std::string name;
std::string word;

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;
word += *it;
++it;
}

return Token(TOK_UNARY, name);
return word;
}

Token GetUnaryFunction() { return Token(TOK_UNARY, FetchWordChars()); }

Token GetLiteral()
{
std::string value;
FetchDelimString(value, '\'');
return Token(TOK_LITERAL, value);
}

Token GetVariable() { return Token(TOK_VARIABLE, FetchWordChars()); }

Token GetFullyQualifiedControl()
{
std::string value;
@@ -210,8 +224,12 @@ class Lexer
return Token(TOK_DIV);
case '%':
return Token(TOK_MOD);
case '=':
return Token(TOK_ASSIGN);
case '\'':
return GetLiteral();
case '$':
return GetVariable();
case '`':
return GetFullyQualifiedControl();
default:
@@ -249,15 +267,14 @@ class Lexer
class ControlExpression : public Expression
{
public:
ControlQualifier qualifier;
Device::Control* control = nullptr;
// Keep a shared_ptr to the device so the control pointer doesn't become invalid
// TODO: This is causing devices to be destructed after backends are shutdown:
std::shared_ptr<Device> m_device;

explicit ControlExpression(ControlQualifier qualifier_) : qualifier(qualifier_) {}
ControlState GetValue() const override
{
if (!control)
if (!input)
return 0.0;

// Note: Inputs may return negative values in situations where opposing directions are
@@ -266,20 +283,26 @@ class ControlExpression : public Expression
// FYI: Clamping values greater than 1.0 is purposely not done to support unbounded values in
// the future. (e.g. raw accelerometer/gyro data)

return std::max(0.0, control->ToInput()->GetState());
return std::max(0.0, input->GetState());
}
void SetValue(ControlState value) override
{
if (control)
control->ToOutput()->SetState(value);
if (output)
output->SetState(value);
}
int CountNumControls() const override { return control ? 1 : 0; }
void UpdateReferences(ControlFinder& finder) override
int CountNumControls() const override { return (input || output) ? 1 : 0; }
void UpdateReferences(ControlEnvironment& env) override
{
m_device = finder.FindDevice(qualifier);
control = finder.FindControl(qualifier);
m_device = env.FindDevice(qualifier);
input = env.FindInput(qualifier);
output = env.FindOutput(qualifier);
}
operator std::string() const override { return "`" + static_cast<std::string>(qualifier) + "`"; }

private:
ControlQualifier qualifier;
Device::Input* input = nullptr;
Device::Output* output = nullptr;
};

class BinaryExpression : public Expression
@@ -319,6 +342,12 @@ class BinaryExpression : public Expression
const ControlState result = std::fmod(lhsValue, rhsValue);
return std::isnan(result) ? 0.0 : result;
}
case TOK_ASSIGN:
{
lhs->SetValue(rhsValue);
// TODO: Should this instead GetValue(lhs) ?
return rhsValue;
}
default:
assert(false);
return 0;
@@ -338,10 +367,10 @@ class BinaryExpression : public Expression
return lhs->CountNumControls() + rhs->CountNumControls();
}

void UpdateReferences(ControlFinder& finder) override
void UpdateReferences(ControlEnvironment& env) override
{
lhs->UpdateReferences(finder);
rhs->UpdateReferences(finder);
lhs->UpdateReferences(env);
rhs->UpdateReferences(env);
}

operator std::string() const override
@@ -356,7 +385,7 @@ class UnaryExpression : public Expression
UnaryExpression(std::unique_ptr<Expression>&& inner_) : inner(std::move(inner_)) {}

int CountNumControls() const override { return inner->CountNumControls(); }
void UpdateReferences(ControlFinder& finder) override { inner->UpdateReferences(finder); }
void UpdateReferences(ControlEnvironment& env) override { inner->UpdateReferences(env); }

operator std::string() const override
{
@@ -462,7 +491,7 @@ class LiteralExpression : public Expression

int CountNumControls() const override { return 1; }

void UpdateReferences(ControlFinder&) override
void UpdateReferences(ControlEnvironment&) override
{
// Nothing needed.
}
@@ -523,6 +552,29 @@ std::unique_ptr<LiteralExpression> MakeLiteralExpression(std::string name)
}
}

class VariableExpression : public Expression
{
public:
VariableExpression(std::string name) : m_name(name) {}

ControlState GetValue() const override { return *m_value_ptr; }

void SetValue(ControlState value) override { *m_value_ptr = value; }

int CountNumControls() const override { return 1; }

void UpdateReferences(ControlEnvironment& env) override
{
m_value_ptr = env.GetVariablePtr(m_name);
}

operator std::string() const override { return '$' + m_name; }

protected:
const std::string m_name;
ControlState* m_value_ptr{};
};

// 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
@@ -543,10 +595,10 @@ class CoalesceExpression : public Expression
static_cast<std::string>(*m_rhs) + ')';
}

void UpdateReferences(ControlFinder& finder) override
void UpdateReferences(ControlEnvironment& env) override
{
m_lhs->UpdateReferences(finder);
m_rhs->UpdateReferences(finder);
m_lhs->UpdateReferences(env);
m_rhs->UpdateReferences(env);
}

private:
@@ -559,24 +611,35 @@ class CoalesceExpression : public Expression
std::unique_ptr<Expression> m_rhs;
};

std::shared_ptr<Device> ControlFinder::FindDevice(ControlQualifier qualifier) const
std::shared_ptr<Device> ControlEnvironment::FindDevice(ControlQualifier qualifier) const
{
if (qualifier.has_device)
return container.FindDevice(qualifier.device_qualifier);
else
return container.FindDevice(default_device);
}

Device::Control* ControlFinder::FindControl(ControlQualifier qualifier) const
Device::Input* ControlEnvironment::FindInput(ControlQualifier qualifier) const
{
const std::shared_ptr<Device> device = FindDevice(qualifier);
if (!device)
return nullptr;

if (is_input)
return device->FindInput(qualifier.control_name);
else
return device->FindOutput(qualifier.control_name);
return device->FindInput(qualifier.control_name);
}

Device::Output* ControlEnvironment::FindOutput(ControlQualifier qualifier) const
{
const std::shared_ptr<Device> device = FindDevice(qualifier);
if (!device)
return nullptr;

return device->FindOutput(qualifier.control_name);
}

ControlState* ControlEnvironment::GetVariablePtr(const std::string& name)
{
return &m_variables[name];
}

struct ParseResult
@@ -623,6 +686,10 @@ class Parser
{
return {ParseStatus::Successful, MakeLiteralExpression(tok.data)};
}
case TOK_VARIABLE:
{
return {ParseStatus::Successful, std::make_unique<VariableExpression>(tok.data)};
}
case TOK_LPAREN:
return Paren();
default:
@@ -665,6 +732,7 @@ class Parser
case TOK_MUL:
case TOK_DIV:
case TOK_MOD:
case TOK_ASSIGN:
return true;
default:
return false;
@@ -4,6 +4,7 @@

#pragma once

#include <map>
#include <memory>
#include <string>
#include <utility>
@@ -46,21 +47,26 @@ class ControlQualifier
}
};

class ControlFinder
class ControlEnvironment
{
public:
ControlFinder(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_,
const bool is_input_)
: container(container_), default_device(default_), is_input(is_input_)
using VariableContainer = std::map<std::string, ControlState>;

ControlEnvironment(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_,
VariableContainer& vars)
: m_variables(vars), container(container_), default_device(default_)
{
}

std::shared_ptr<Core::Device> FindDevice(ControlQualifier qualifier) const;
Core::Device::Control* FindControl(ControlQualifier qualifier) const;
Core::Device::Input* FindInput(ControlQualifier qualifier) const;
Core::Device::Output* FindOutput(ControlQualifier qualifier) const;
ControlState* GetVariablePtr(const std::string& name);

private:
VariableContainer& m_variables;
const Core::DeviceContainer& container;
const Core::DeviceQualifier& default_device;
bool is_input;
};

class Expression
@@ -70,7 +76,7 @@ class Expression
virtual ControlState GetValue() const = 0;
virtual void SetValue(ControlState state) = 0;
virtual int CountNumControls() const = 0;
virtual void UpdateReferences(ControlFinder& finder) = 0;
virtual void UpdateReferences(ControlEnvironment& finder) = 0;
virtual operator std::string() const = 0;
};

0 comments on commit e896835

Please sign in to comment.
You can’t perform that action at this time.