Skip to content

Commit

Permalink
libnixf: parse pipe operator (#595)
Browse files Browse the repository at this point in the history
Implements: NixOS/rfcs#148
Closes: #554
  • Loading branch information
inclyc authored Sep 18, 2024
1 parent f9d141f commit e2f0d90
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 10 deletions.
4 changes: 4 additions & 0 deletions libnixf/include/nixf/Basic/TokenKinds.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions libnixf/src/Parse/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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("!=")) {
Expand All @@ -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;
Expand Down
25 changes: 15 additions & 10 deletions libnixf/src/Parse/ParseOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace {

/// Binary operators:
///
/// %left |> | %right <|
/// %right ->
/// %left ||
/// %left &&
Expand All @@ -31,31 +32,35 @@ namespace {
/// %nonassoc NEGATE
std::pair<unsigned, unsigned> 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();
Expand Down
72 changes: 72 additions & 0 deletions libnixf/test/Parse/ParseOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,76 @@ 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<Diagnostic> 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<Diagnostic> Diags;
Parser P(Src, Diags);
auto AST = P.parseExpr();

ASSERT_TRUE(AST);

ASSERT_EQ(AST->kind(), Node::NK_ExprBinOp);

const auto &BinOp = static_cast<const ExprBinOp &>(*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<Diagnostic> 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<Diagnostic> Diags;
Parser P(Src, Diags);
auto AST = P.parseExpr();

ASSERT_TRUE(AST);

ASSERT_EQ(AST->kind(), Node::NK_ExprBinOp);

const auto &BinOp = static_cast<const ExprBinOp &>(*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<Diagnostic> 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

0 comments on commit e2f0d90

Please sign in to comment.