ExpressionParser: add FallbackExpression node type

This commit is contained in:
Michael M 2017-06-07 18:29:02 -07:00
parent 7e74961eb1
commit ba87a50338
1 changed files with 55 additions and 16 deletions

View File

@ -322,6 +322,40 @@ public:
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) + ')';
}
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)
@ -474,41 +508,46 @@ private:
ParseResult Toplevel() { return Binary(); } ParseResult Toplevel() { return Binary(); }
}; };
static ParseResult ParseExpressionInner(const std::string& str, ControlFinder& finder) static ParseResult ParseComplexExpression(const std::string& str, ControlFinder& finder)
{ {
if (StripSpaces(str).empty())
return {ParseStatus::EmptyExpression};
Lexer l(str); Lexer l(str);
std::vector<Token> tokens; std::vector<Token> tokens;
ParseStatus tokenize_status = l.Tokenize(tokens); ParseStatus tokenize_status = l.Tokenize(tokens);
if (tokenize_status != ParseStatus::Successful) if (tokenize_status != ParseStatus::Successful)
return {tokenize_status}; return {tokenize_status};
ParseResult result = Parser(tokens, finder).Parse(); return Parser(tokens, finder).Parse();
return result;
} }
std::pair<ParseStatus, std::unique_ptr<Expression>> ParseExpression(const std::string& str, static std::unique_ptr<Expression> ParseBarewordExpression(const std::string& str,
ControlFinder& finder) ControlFinder& finder)
{ {
// 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); std::shared_ptr<Device> device = finder.FindDevice(qualifier);
Device::Control* control = finder.FindControl(qualifier); Device::Control* control = finder.FindControl(qualifier);
if (control) return std::make_unique<ControlExpression>(qualifier, std::move(device), control);
}
std::pair<ParseStatus, std::unique_ptr<Expression>> ParseExpression(const std::string& str,
ControlFinder& finder)
{
if (StripSpaces(str).empty())
return std::make_pair(ParseStatus::EmptyExpression, nullptr);
auto bareword_expr = ParseBarewordExpression(str, finder);
ParseResult complex_result = ParseComplexExpression(str, finder);
if (complex_result.status != ParseStatus::Successful)
{ {
return std::make_pair(ParseStatus::Successful, std::make_unique<ControlExpression>( return std::make_pair(complex_result.status, std::move(bareword_expr));
qualifier, std::move(device), control));
} }
ParseResult result = ParseExpressionInner(str, finder); auto combined_expr = std::make_unique<CoalesceExpression>(std::move(bareword_expr),
return std::make_pair(result.status, std::move(result.expr)); std::move(complex_result.expr));
return std::make_pair(complex_result.status, std::move(combined_expr));
} }
} }
} }