boolean expressions

main
Brett 2023-08-21 19:09:23 -04:00
parent aaf29c5fe7
commit 54ac0acd55
2 changed files with 116 additions and 16 deletions

View File

@ -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

View File

@ -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;
}; };
static inline bool isSpecial(char c)
{
return c == '&' || c == '|' || c == '!' || c == '(' || c == ')' || std::isspace(c);
}
std::vector<Token> tokens; std::vector<Token> tokens;
size_t m_index = 0; 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: public:
void processString(const std::string& str) explicit LogicalEval(std::string str): str(std::move(str))
{ {
size_t index = 0; processString();
while (index < str.size()) }
void processString()
{ {
char c = str[index++]; while (hasNext())
if (c == '&' || c == '|'){ {
char c = consume();
} else if (c == '!') { // ignore whitespace
if (isspace(c))
} else if (c == '(') { continue;
switch (c)
{
case '&':
if (consume() != '&')
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); tokens.emplace_back(TokenType::OPEN);
} else if (c == ')') { break;
case ')':
tokens.emplace_back(TokenType::CLOSE); 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: