boolean expressions
parent
aaf29c5fe7
commit
54ac0acd55
|
@ -19,6 +19,9 @@ namespace cs
|
||||||
public:
|
public:
|
||||||
LexerSyntaxError(): std::runtime_error("Invalid template syntax. EOF occurred before template was fully processed!")
|
LexerSyntaxError(): std::runtime_error("Invalid template syntax. EOF occurred before template was fully processed!")
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
explicit LexerSyntaxError(const std::string& err): std::runtime_error(err)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LexerSearchFailure : public std::runtime_error
|
class LexerSearchFailure : public std::runtime_error
|
||||||
|
|
|
@ -107,38 +107,135 @@ namespace cs
|
||||||
class LogicalEval
|
class LogicalEval
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
// stmt -> (stmt) | expr | (expr)
|
||||||
|
// expr -> ident && ident | ident || ident
|
||||||
|
// ident -> lit | !lit
|
||||||
enum class TokenType
|
enum class TokenType
|
||||||
{
|
{
|
||||||
AND, // &&
|
AND, // &&
|
||||||
OR, // ||
|
OR, // ||
|
||||||
NOT, // !
|
NOT, // !
|
||||||
|
IDENT, // literal
|
||||||
OPEN, // (
|
OPEN, // (
|
||||||
CLOSE // )
|
CLOSE // )
|
||||||
};
|
};
|
||||||
struct Token {
|
struct Token
|
||||||
|
{
|
||||||
TokenType type;
|
TokenType type;
|
||||||
std::optional<std::string> value;
|
std::optional<std::string> value;
|
||||||
};
|
};
|
||||||
std::vector<Token> tokens;
|
|
||||||
size_t m_index = 0;
|
static inline bool isSpecial(char c)
|
||||||
public:
|
|
||||||
void processString(const std::string& str)
|
|
||||||
{
|
{
|
||||||
size_t index = 0;
|
return c == '&' || c == '|' || c == '!' || c == '(' || c == ')' || std::isspace(c);
|
||||||
while (index < str.size())
|
}
|
||||||
|
|
||||||
|
std::vector<Token> tokens;
|
||||||
|
size_t t_index = 0;
|
||||||
|
size_t s_index = 0;
|
||||||
|
std::string str;
|
||||||
|
|
||||||
|
inline bool hasNextToken()
|
||||||
|
{
|
||||||
|
return t_index < tokens.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Token& peekToken()
|
||||||
|
{
|
||||||
|
return tokens[t_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Token& consumeToken()
|
||||||
|
{
|
||||||
|
return tokens[t_index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool hasNext()
|
||||||
|
{
|
||||||
|
return s_index < str.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char peek()
|
||||||
|
{
|
||||||
|
return str[s_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char consume()
|
||||||
|
{
|
||||||
|
return str[s_index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LogicalEval(std::string str): str(std::move(str))
|
||||||
|
{
|
||||||
|
processString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void processString()
|
||||||
|
{
|
||||||
|
while (hasNext())
|
||||||
{
|
{
|
||||||
char c = str[index++];
|
char c = consume();
|
||||||
if (c == '&' || c == '|'){
|
// ignore whitespace
|
||||||
|
if (isspace(c))
|
||||||
} else if (c == '!') {
|
continue;
|
||||||
|
switch (c)
|
||||||
} else if (c == '(') {
|
{
|
||||||
tokens.emplace_back(TokenType::OPEN);
|
case '&':
|
||||||
} else if (c == ')') {
|
if (consume() != '&')
|
||||||
tokens.emplace_back(TokenType::CLOSE);
|
throw LexerSyntaxError("Unable to parse logical expression. Found single '&' missing second '&'");
|
||||||
|
tokens.emplace_back(TokenType::AND);
|
||||||
|
break;
|
||||||
|
case '|':
|
||||||
|
if (consume() != '|')
|
||||||
|
throw LexerSyntaxError("Unable to parse logical expression. Found single '|' missing second '|'");
|
||||||
|
tokens.emplace_back(TokenType::OR);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
tokens.emplace_back(TokenType::NOT);
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
tokens.emplace_back(TokenType::OPEN);
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
tokens.emplace_back(TokenType::CLOSE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::string token;
|
||||||
|
while (hasNext() && !isSpecial(peek()))
|
||||||
|
token += consume();
|
||||||
|
tokens.emplace_back(TokenType::IDENT, token);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isEmpty(const std::string& token, const RuntimeContext& context)
|
||||||
|
{
|
||||||
|
return !context.contains(token) || context.at(token).empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool factor(const RuntimeContext& context)
|
||||||
|
{
|
||||||
|
if (!hasNextToken())
|
||||||
|
throw LexerSyntaxError("Processing boolean factor but no token was found!");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool term(const RuntimeContext& context)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool expr(const RuntimeContext& context)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eval(const RuntimeContext& context)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in New Issue