diff --git a/src/interpreter.cc b/src/interpreter.cc index 98b0705..e7008f4 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -492,6 +492,19 @@ Result Interpreter::eval(Ast &&ast) std::vector 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()) { diff --git a/src/lexer.cc b/src/lexer.cc index 5582596..2c80972 100644 --- a/src/lexer.cc +++ b/src/lexer.cc @@ -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> 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; } diff --git a/src/musique.hh b/src/musique.hh index 609bdf8..ab64760 100644 --- a/src/musique.hh +++ b/src/musique.hh @@ -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 diff --git a/src/parser.cc b/src/parser.cc index 3d2c459..e45fd87 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -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 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));