ExpressionParser: Add support for literals.

This commit is contained in:
Jordan Woyak 2018-12-30 10:37:23 -06:00
parent 5be061e27f
commit f3192ca06d
2 changed files with 76 additions and 21 deletions

View File

@ -29,6 +29,7 @@ enum TokenType
TOK_NOT, TOK_NOT,
TOK_ADD, TOK_ADD,
TOK_CONTROL, TOK_CONTROL,
TOK_LITERAL,
}; };
inline std::string OpName(TokenType op) inline std::string OpName(TokenType op)
@ -53,10 +54,10 @@ class Token
{ {
public: public:
TokenType type; TokenType type;
ControlQualifier qualifier; std::string data;
Token(TokenType type_) : type(type_) {} Token(TokenType type_) : type(type_) {}
Token(TokenType type_, ControlQualifier qualifier_) : type(type_), qualifier(qualifier_) {} Token(TokenType type_, std::string data_) : type(type_), data(std::move(data_)) {}
operator std::string() const operator std::string() const
{ {
switch (type) switch (type)
@ -78,7 +79,9 @@ public:
case TOK_ADD: case TOK_ADD:
return "+"; return "+";
case TOK_CONTROL: case TOK_CONTROL:
return "Device(" + (std::string)qualifier + ")"; return "Device(" + data + ")";
case TOK_LITERAL:
return '\'' + data + '\'';
case TOK_INVALID: case TOK_INVALID:
break; break;
} }
@ -94,38 +97,33 @@ public:
std::string::iterator it; std::string::iterator it;
Lexer(const std::string& expr_) : expr(expr_) { it = expr.begin(); } Lexer(const std::string& expr_) : expr(expr_) { it = expr.begin(); }
bool FetchBacktickString(std::string& value, char otherDelim = 0)
bool FetchDelimString(std::string& value, char delim)
{ {
value = ""; value = "";
while (it != expr.end()) while (it != expr.end())
{ {
char c = *it; char c = *it;
++it; ++it;
if (c == '`') if (c == delim)
return false;
if (c > 0 && c == otherDelim)
return true; return true;
value += c; value += c;
} }
return false; return false;
} }
Token GetLiteral()
{
std::string value;
FetchDelimString(value, '\'');
return Token(TOK_LITERAL, value);
}
Token GetFullyQualifiedControl() Token GetFullyQualifiedControl()
{ {
ControlQualifier qualifier;
std::string value; std::string value;
FetchDelimString(value, '`');
if (FetchBacktickString(value, ':')) return Token(TOK_CONTROL, value);
{
// Found colon, this is the device name
qualifier.has_device = true;
qualifier.device_qualifier.FromString(value);
FetchBacktickString(value);
}
qualifier.control_name = value;
return Token(TOK_CONTROL, qualifier);
} }
Token GetBarewordsControl(char c) Token GetBarewordsControl(char c)
@ -172,6 +170,8 @@ public:
return Token(TOK_NOT); return Token(TOK_NOT);
case '+': case '+':
return Token(TOK_ADD); return Token(TOK_ADD);
case '\'':
return GetLiteral();
case '`': case '`':
return GetFullyQualifiedControl(); return GetFullyQualifiedControl();
default: default:
@ -339,6 +339,35 @@ public:
operator std::string() const override { return OpName(op) + "(" + (std::string)(*inner) + ")"; } operator std::string() const override { return OpName(op) + "(" + (std::string)(*inner) + ")"; }
}; };
class LiteralExpression : public Expression
{
public:
explicit LiteralExpression(const std::string& str)
{
// If it fails to parse it will just be the default: 0.0
TryParse(str, &m_value);
}
ControlState GetValue() const override { return m_value; }
void SetValue(ControlState value) override
{
// Do nothing.
}
int CountNumControls() const override { return 1; }
void UpdateReferences(ControlFinder&) override
{
// Nothing needed.
}
operator std::string() const override { return '\'' + ValueToString(m_value) + '\''; }
private:
ControlState m_value{};
};
// 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
@ -430,7 +459,15 @@ private:
switch (tok.type) switch (tok.type)
{ {
case TOK_CONTROL: case TOK_CONTROL:
return {ParseStatus::Successful, std::make_unique<ControlExpression>(tok.qualifier)}; {
ControlQualifier cq;
cq.FromString(tok.data);
return {ParseStatus::Successful, std::make_unique<ControlExpression>(cq)};
}
case TOK_LITERAL:
{
return {ParseStatus::Successful, std::make_unique<LiteralExpression>(tok.data)};
}
case TOK_LPAREN: case TOK_LPAREN:
return Paren(); return Paren();
default: default:

View File

@ -19,6 +19,7 @@ public:
std::string control_name; std::string control_name;
ControlQualifier() : has_device(false) {} ControlQualifier() : has_device(false) {}
operator std::string() const operator std::string() const
{ {
if (has_device) if (has_device)
@ -26,6 +27,23 @@ public:
else else
return control_name; return control_name;
} }
void FromString(const std::string& str)
{
const auto col_pos = str.find_last_of(':');
has_device = (str.npos != col_pos);
if (has_device)
{
device_qualifier.FromString(str.substr(0, col_pos));
control_name = str.substr(col_pos + 1);
}
else
{
device_qualifier.FromString("");
control_name = str;
}
}
}; };
class ControlFinder class ControlFinder