nixd
Loading...
Searching...
No Matches
ParseOp.cpp
Go to the documentation of this file.
1/// \file
2/// \brief This file implements parsing of operators.
3
4#include "Parser.h"
5
8
9#include <cassert>
10
11using namespace nixf::tok;
12using namespace nixf::detail;
13using namespace nixf;
14
15/// Operators.
16namespace {
17
18/// Binary operators:
19///
20/// %left |> | %right <|
21/// %right ->
22/// %left ||
23/// %left &&
24/// %nonassoc == !=
25/// %nonassoc < > <= >=
26/// %right //
27/// %left NOT
28/// %left + -
29/// %left * /
30/// %right ++
31/// %nonassoc '?'
32/// %nonassoc NEGATE
33std::pair<unsigned, unsigned> getBP(TokenKind Kind) {
34 switch (Kind) {
35 case tok_op_pipe_from:
36 return {1, 2};
37 case tok_op_pipe_into:
38 return {2, 1};
39 case tok_op_impl: // %right ->
40 return {4, 3};
41 case tok_op_or: // %left ||
42 return {5, 6};
43 case tok_op_and: // %left &&
44 return {7, 8};
45 case tok_op_eq: // %nonassoc == !=
46 case tok_op_neq:
47 return {9, 9};
48 case tok_op_lt: // %nonassoc < > <= >=
49 case tok_op_le:
50 case tok_op_ge:
51 case tok_op_gt:
52 return {10, 10};
53 case tok_op_update: // %right //
54 return {12, 11};
55 // %left NOT - 13
56 case tok_op_add: // %left + -
57 case tok_op_negate:
58 return {14, 15};
59 case tok_op_mul: // %left * /
60 return {16, 17};
61 case tok_op_div:
62 case tok_op_concat: // %right ++
63 return {19, 18};
64 // % op_negate
65 default:
66 __builtin_unreachable();
67 }
68}
69
70unsigned getUnaryBP(TokenKind Kind) {
71 switch (Kind) {
72 case tok_op_not:
73 return 11;
74 case tok_op_negate:
75 return 100;
76 default:
77 __builtin_unreachable();
78 }
79}
80
81} // namespace
82
83std::shared_ptr<Expr> Parser::parseExprOpBP(unsigned LeftRBP) {
84 std::shared_ptr<Expr> Prefix;
85 LexerCursor LCur = lCur();
86 switch (Token Tok = peek(); Tok.kind()) {
87 case tok_op_not:
88 case tok_op_negate: {
89 consume();
90 assert(LastToken && "consume() should have set LastToken");
91 auto O = std::make_shared<Op>(Tok.range(), Tok.kind());
92 auto Expr = parseExprOpBP(getUnaryBP(Tok.kind()));
93 if (!Expr)
94 diagNullExpr(Diags, LastToken->rCur(),
95 "unary operator " + std::string(tok::spelling(Tok.kind())));
96 Prefix =
97 std::make_shared<ExprUnaryOp>(LexerCursorRange{LCur, LastToken->rCur()},
98 std::move(O), std::move(Expr));
99 break;
100 }
101 default:
102 Prefix = parseExprApp();
103 }
104
105 if (!Prefix)
106 return nullptr;
107
108 for (;;) {
109 switch (Token Tok = peek(); Tok.kind()) {
110#define TOK_BIN_OP(NAME) case tok_op_##NAME:
112#undef TOK_BIN_OP
113 {
114 // For all binary ops:
115 //
116 // expr_op OP expr_op OP expr_op
117 // ^LeftRBP ^ LBP
118 // |
119 // | we are here
120 auto [LBP, RBP] = getBP(Tok.kind());
121 if (LeftRBP > LBP)
122 return Prefix;
123 if (LeftRBP == LBP) {
124 // Report error, operator OP and expr_op is not associative.
125 Diags.emplace_back(Diagnostic::DK_OperatorNotAssociative,
126 Tok.range());
127 }
128 consume();
129 assert(LastToken && "consume() should have set LastToken");
130 auto O = std::make_shared<Op>(Tok.range(), Tok.kind());
131 auto RHS = parseExprOpBP(RBP);
132 if (!RHS) {
133 diagNullExpr(Diags, LastToken->rCur(), "binary op RHS");
134 continue;
135 }
136 LexerCursorRange Range{Prefix->lCur(), RHS->rCur()};
137 Prefix = std::make_shared<ExprBinOp>(Range, std::move(O),
138 std::move(Prefix), std::move(RHS));
139 break;
140 }
141 case tok_question: {
142 // expr_op '?' attrpath
143 consume();
144 assert(LastToken && "consume() should have set LastToken");
145 auto O = std::make_shared<Op>(Tok.range(), Tok.kind());
146
147 std::shared_ptr<AttrPath> Path = parseAttrPath();
148 LexerCursorRange Range{Prefix->lCur(), LastToken->rCur()};
149 Prefix = std::make_shared<ExprOpHasAttr>(
150 Range, std::move(O), std::move(Prefix), std::move(Path));
151 break;
152 }
153 default:
154 return Prefix;
155 }
156 }
157}
LexerCursor lCur() const
Definition Range.h:116
A point in the source file.
Definition Range.h:57
std::shared_ptr< Expr > parseExprApp(int Limit=INT_MAX)
Definition ParseExpr.cpp:52
std::shared_ptr< AttrPath > parseAttrPath()
A token. With it's kind, and the range in source code.
Definition Token.h:55
tok::TokenKind kind() const
Definition Token.h:65
std::string Path
Definition Path.h:24
Diagnostic & diagNullExpr(std::vector< Diagnostic > &Diags, LexerCursor Loc, std::string As)
constexpr std::string_view spelling(TokenKind Kind)
Definition Token.h:13
Parser for the Nix expression language.