From aa04ee834cad6ab2855d36e900ba6bd19cc420bc 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 | 59 +++++++++++++++++++++++ 4 files changed, 82 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 45e7f0b77..14d5f92cd 100644 --- a/libnixf/src/Parse/ParseOp.cpp +++ b/libnixf/src/Parse/ParseOp.cpp @@ -16,6 +16,7 @@ namespace { /// Binary operators: /// +/// %left |> | %right <| /// %right -> /// %left || /// %left && @@ -30,31 +31,35 @@ namespace { /// %nonassoc NEGATE std::pair getBP(TokenKind Kind) { switch (Kind) { + case tok_op_pipe_from: + return {0, 1}; + case tok_op_pipe_into: + return {1, 0}; case tok_op_impl: // %right -> - return {2, 1}; + return {3, 2}; case tok_op_or: // %left || - return {3, 4}; + return {4, 5}; case tok_op_and: // %left && - return {5, 6}; + return {6, 7}; case tok_op_eq: // %nonassoc == != case tok_op_neq: - return {7, 7}; + return {8, 8}; case tok_op_lt: // %nonassoc < > <= >= case tok_op_le: case tok_op_ge: case tok_op_gt: - return {8, 8}; + return {9, 9}; case tok_op_update: // %right // - return {10, 9}; - // %left NOT - 11 + return {11, 10}; + // %left NOT - 12 case tok_op_add: // %left + - case tok_op_negate: - return {12, 13}; + return {13, 14}; case tok_op_mul: // %left * / - return {14, 15}; + return {15, 16}; case tok_op_div: case tok_op_concat: // %right ++ - return {17, 16}; + return {18, 17}; // % op_negate default: __builtin_unreachable(); diff --git a/libnixf/test/Parse/ParseOp.cpp b/libnixf/test/Parse/ParseOp.cpp index 840f7fb91..53f021191 100644 --- a/libnixf/test/Parse/ParseOp.cpp +++ b/libnixf/test/Parse/ParseOp.cpp @@ -71,4 +71,63 @@ TEST(Parser, OpHasAttr_empty) { ASSERT_EQ(Diags.size(), 0); } +TEST(Parser, Op_PipeOperator_Forward) { + 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_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); +} + } // namespace