Logical short-circuting operators

This commit is contained in:
Robert Bendun 2022-06-03 00:52:55 +02:00
parent 946d4b96b1
commit 4d88ca7e40
4 changed files with 30 additions and 4 deletions

View File

@ -492,6 +492,19 @@ Result<Value> Interpreter::eval(Ast &&ast)
std::vector<Value> values;
values.reserve(ast.arguments.size());
if (ast.token.source == "and" || ast.token.source == "or") {
assert(ast.arguments.size() == 2, "Expected arguments of binary operation to be 2 long");
auto lhs = std::move(ast.arguments.front());
auto rhs = std::move(ast.arguments.back());
auto result = Try(eval(std::move(lhs)));
if (ast.token.source == "or" ? result.truthy() : result.falsy()) {
return result;
} else {
return eval(std::move(rhs));
}
}
auto op = operators.find(std::string(ast.token.source));
if (op == operators.end()) {

View File

@ -14,9 +14,13 @@ constexpr auto Keywords = std::array {
"false"sv,
"nil"sv,
"true"sv,
"var"sv
"var"sv,
"and"sv,
"or"sv
};
static_assert(Keywords.size() == Keywords_Count, "Table above should contain all the tokens for lexing");
void Lexer::skip_whitespace_and_comments()
{
for (;;) {
@ -124,8 +128,6 @@ auto Lexer::next_token() -> Result<std::variant<Token, End_Of_File>>
Token t = { Token::Type::Symbol, finish(), token_location };
if (std::find(Keywords.begin(), Keywords.end(), t.source) != Keywords.end()) {
t.type = Token::Type::Keyword;
} else if (t.source == "v") {
t.type = Token::Type::Operator;
}
return t;
}

View File

@ -382,6 +382,8 @@ struct Token
Location location;
};
static constexpr auto Keywords_Count = 6;
std::string_view type_name(Token::Type type);
/// Token debug printing

View File

@ -21,6 +21,15 @@ constexpr auto Literal_Keywords = std::array {
"true"sv,
};
static_assert(Keywords_Count == Literal_Keywords.size() + 3, "Ensure that all literal keywords are listed");
constexpr auto Operator_Keywords = std::array {
"and"sv,
"or"sv
};
static_assert(Keywords_Count == Operator_Keywords.size() + 4, "Ensure that all keywords that are operators are listed here");
enum class At_Least : bool
{
Zero,
@ -113,7 +122,7 @@ Result<Ast> Parser::parse_infix_expression()
auto atomics = Try(parse_many(*this, &Parser::parse_atomic_expression, std::nullopt, At_Least::One));
auto lhs = wrap_if_several(std::move(atomics), Ast::call);
if (expect(Token::Type::Operator)) {
if (expect(Token::Type::Operator) || expect(Token::Type::Keyword, "and") || expect(Token::Type::Keyword, "or")) {
auto op = consume();
return parse_expression().map([&](Ast rhs) {
return Ast::binary(std::move(op), std::move(lhs), std::move(rhs));