From 36e841d1d60eea10745f0d4db11f5d41646c4844 Mon Sep 17 00:00:00 2001 From: Yingchi Long Date: Wed, 18 Sep 2024 11:30:48 +0800 Subject: [PATCH] libnixf: parse pipe operator Implements: https://github.com/NixOS/rfcs/pull/148 Closes: https://github.com/nix-community/nixd/issues/554 --- libnixf/include/nixf/Basic/TokenKinds.inc | 4 ++ libnixf/src/Parse/Lexer.cpp | 4 ++ libnixf/src/Parse/ParseOp.cpp | 25 +++++--- libnixf/test/Parse/ParseOp.cpp | 74 +++++++++++++++++++++++ 4 files changed, 97 insertions(+), 10 deletions(-) diff --git a/libnixf/include/nixf/Basic/TokenKinds.inc b/libnixf/include/nixf/Basic/TokenKinds.inc index 035cc2c64..b04fc57d6 100644 --- a/libnixf/include/nixf/Basic/TokenKinds.inc +++ b/libnixf/include/nixf/Basic/TokenKinds.inc @@ -93,4 +93,8 @@ TOK_BIN_OP(mul) // * TOK_BIN_OP(div) // / TOK_BIN_OP(concat) // ++ +// [RFC 0418 Pipe operator](https://github.com/NixOS/rfcs/pull/148) +TOK_BIN_OP(pipe_into) // |> +TOK_BIN_OP(pipe_from) // <| + #endif // TOK_BIN_OP diff --git a/libnixf/src/Parse/Lexer.cpp b/libnixf/src/Parse/Lexer.cpp index 9042c440b..971377bbd 100644 --- a/libnixf/src/Parse/Lexer.cpp +++ b/libnixf/src/Parse/Lexer.cpp @@ -526,6 +526,8 @@ Token Lexer::lex() { case '|': if (consumePrefix("||")) Tok = tok_op_or; + if (consumePrefix("|>")) + Tok = tok_op_pipe_into; break; case '!': if (consumePrefix("!=")) { @@ -538,6 +540,8 @@ Token Lexer::lex() { case '<': if (consumePrefix("<=")) { Tok = tok_op_le; + } else if (consumePrefix("<|")) { + Tok = tok_op_pipe_from; } else { consume(); Tok = tok_op_lt; diff --git a/libnixf/src/Parse/ParseOp.cpp b/libnixf/src/Parse/ParseOp.cpp index 0e842bb32..772a6cf7e 100644 --- a/libnixf/src/Parse/ParseOp.cpp +++ b/libnixf/src/Parse/ParseOp.cpp @@ -17,6 +17,7 @@ namespace { /// Binary operators: /// +/// %left |> | %right <| /// %right -> /// %left || /// %left && @@ -31,31 +32,35 @@ namespace { /// %nonassoc NEGATE std::pair getBP(TokenKind Kind) { switch (Kind) { - case tok_op_impl: // %right -> + case tok_op_pipe_from: + return {1, 2}; + case tok_op_pipe_into: return {2, 1}; + case tok_op_impl: // %right -> + return {4, 3}; case tok_op_or: // %left || - return {3, 4}; - case tok_op_and: // %left && return {5, 6}; + case tok_op_and: // %left && + return {7, 8}; case tok_op_eq: // %nonassoc == != case tok_op_neq: - return {7, 7}; + return {9, 9}; case tok_op_lt: // %nonassoc < > <= >= case tok_op_le: case tok_op_ge: case tok_op_gt: - return {8, 8}; + return {10, 10}; case tok_op_update: // %right // - return {10, 9}; - // %left NOT - 11 + return {12, 11}; + // %left NOT - 13 case tok_op_add: // %left + - case tok_op_negate: - return {12, 13}; - case tok_op_mul: // %left * / return {14, 15}; + case tok_op_mul: // %left * / + return {16, 17}; case tok_op_div: case tok_op_concat: // %right ++ - return {17, 16}; + return {19, 18}; // % op_negate default: __builtin_unreachable(); diff --git a/libnixf/test/Parse/ParseOp.cpp b/libnixf/test/Parse/ParseOp.cpp index 444b37643..fec2826de 100644 --- a/libnixf/test/Parse/ParseOp.cpp +++ b/libnixf/test/Parse/ParseOp.cpp @@ -84,4 +84,78 @@ TEST(Parser, Op_NonAssociative) { ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_OperatorNotAssociative); } +TEST(Parser, Op_PipeOperator_Forward) { + auto Src = R"(a |> b)"sv; + + std::vector Diags; + Parser P(Src, Diags); + auto AST = P.parseExpr(); + + + ASSERT_EQ(AST->kind(), Node::NK_ExprBinOp); + ASSERT_EQ(Diags.size(), 0); +} + + +TEST(Parser, Op_PipeOperator_Forward_LeftAssosiative) { + auto Src = R"(a |> b |> c)"sv; + + std::vector Diags; + Parser P(Src, Diags); + auto AST = P.parseExpr(); + + ASSERT_TRUE(AST); + + ASSERT_EQ(AST->kind(), Node::NK_ExprBinOp); + + const auto &BinOp = static_cast(*AST); + ASSERT_EQ(BinOp.lhs()->kind(), Node::NK_ExprVar); + ASSERT_EQ(Diags.size(), 0); +} + +TEST(Parser, Op_PipeOperator_Backward) { + auto Src = R"(a <| b)"sv; + + std::vector Diags; + Parser P(Src, Diags); + auto AST = P.parseExpr(); + + ASSERT_TRUE(AST); + + ASSERT_EQ(AST->kind(), Node::NK_ExprBinOp); + ASSERT_EQ(Diags.size(), 0); +} + +TEST(Parser, Op_PipeOperator_Forward_RightAssosiative) { + auto Src = R"(a <| b <| c)"sv; + + std::vector Diags; + Parser P(Src, Diags); + auto AST = P.parseExpr(); + + ASSERT_TRUE(AST); + + ASSERT_EQ(AST->kind(), Node::NK_ExprBinOp); + + const auto &BinOp = static_cast(*AST); + ASSERT_EQ(BinOp.lhs()->kind(), Node::NK_ExprBinOp); + ASSERT_EQ(BinOp.rhs()->kind(), Node::NK_ExprVar); + ASSERT_EQ(Diags.size(), 0); +} + +TEST(Parser, Op_PipeOperator_NonAssociative) { + auto Src = R"(a <| b |> c)"sv; + + std::vector Diags; + Parser P(Src, Diags); + auto AST = P.parseExpr(); + + ASSERT_TRUE(AST); + + ASSERT_EQ(AST->kind(), Node::NK_ExprBinOp); + + ASSERT_EQ(Diags.size(), 1); + ASSERT_EQ(Diags[0].kind(), nixf::Diagnostic::DK_OperatorNotAssociative); +} + } // namespace