nixd
Loading...
Searching...
No Matches
ParseSimple.cpp
Go to the documentation of this file.
1#include "Parser.h"
2
5
6#include <charconv>
7
8using namespace nixf;
9using namespace nixf::detail;
10
11namespace {
12
13/// \brief Whether the node could be produced by non-term \p expr_simple
14bool mayProducedBySimple(Node::NodeKind NK) {
15 switch (NK) {
16 case Node::NK_ExprVar:
17 case Node::NK_ExprInt:
18 case Node::NK_ExprFloat:
19 case Node::NK_ExprSPath:
20 case Node::NK_ExprString:
21 case Node::NK_ExprPath:
22 case Node::NK_ExprParen:
23 case Node::NK_ExprAttrs:
24 case Node::NK_ExprList:
25 return true;
26 default:
27 break;
28 }
29 return false;
30}
31
32bool mayProducedBySimple(const Expr *E) {
33 if (!E)
34 return false;
35 return mayProducedBySimple(E->kind());
36}
37
38} // namespace
39
40std::shared_ptr<ExprParen> Parser::parseExprParen() {
41 Token L = peek();
42 auto LParen = std::make_shared<Misc>(L.range());
43 assert(L.kind() == tok_l_paren);
44 consume(); // (
45 auto Sync = withSync(tok_r_paren);
46 assert(LastToken && "LastToken should be set after consume()");
47 auto Expr = parseExpr();
48 if (!Expr)
49 diagNullExpr(Diags, LastToken->rCur(), "parenthesized");
50 if (ExpectResult ER = expect(tok_r_paren); ER.ok()) {
51 consume(); // )
52 auto RParen = std::make_shared<Misc>(ER.tok().range());
53 if (mayProducedBySimple(Expr.get())) {
54 Diagnostic &D =
55 Diags.emplace_back(Diagnostic::DK_RedundantParen, LParen->range());
57 Fix &F = D.fix("remove ( and )");
58 F.edit(TextEdit::mkRemoval(LParen->range()));
59 F.edit(TextEdit::mkRemoval(RParen->range()));
60 }
61 return std::make_shared<ExprParen>(
62 LexerCursorRange{L.lCur(), ER.tok().rCur()}, std::move(Expr),
63 std::move(LParen), std::move(RParen));
64 } else { // NOLINT(readability-else-after-return)
65 ER.diag().note(Note::NK_ToMachThis, L.range())
66 << std::string(tok::spelling(tok_l_paren));
67 if (mayProducedBySimple(Expr.get())) {
68 Diagnostic &D =
69 Diags.emplace_back(Diagnostic::DK_RedundantParen, LParen->range());
71 Fix &F = D.fix("remove (");
72 F.edit(TextEdit::mkRemoval(LParen->range()));
73 }
74 return std::make_shared<ExprParen>(
75 LexerCursorRange{L.lCur(), LastToken->rCur()}, std::move(Expr),
76 std::move(LParen),
77 /*RParen=*/nullptr);
78 }
79}
80
81std::shared_ptr<ExprList> Parser::parseExprList() {
82 Token Tok = peek();
83 if (Tok.kind() != tok_l_bracket)
84 return nullptr;
85 consume(); // [
86 auto Sync = withSync(tok_r_bracket);
87 assert(LastToken && "LastToken should be set after consume()");
88 LexerCursor Begin = Tok.lCur();
89 std::vector<std::shared_ptr<Expr>> Exprs;
90 while (true) {
91 if (Token Tok = peek(); Tok.kind() == tok_r_bracket)
92 break;
93 std::shared_ptr<Expr> Expr = parseExprSelect();
94 if (!Expr)
95 break;
96 Exprs.emplace_back(std::move(Expr));
97 }
98 if (ExpectResult ER = expect(tok_r_bracket); ER.ok())
99 consume();
100 else
101 ER.diag().note(Note::NK_ToMachThis, Tok.range())
102 << std::string(tok::spelling(tok_l_bracket));
103 return std::make_shared<ExprList>(LexerCursorRange{Begin, LastToken->rCur()},
104 std::move(Exprs));
105}
106
107std::shared_ptr<Expr> Parser::parseExprSimple() {
108 Token Tok = peek();
109 switch (Tok.kind()) {
110 case tok_uri: {
111 // URI is desugared into string
112 consume();
113 auto Literal = std::string(Tok.view());
114 // Create the string used for this URI
115 auto Parts = std::make_shared<InterpolatedParts>(
116 Tok.range(), std::vector<InterpolablePart>{
117 InterpolablePart{std::move(Literal)},
118 });
119 auto Str = std::make_shared<ExprString>(Tok.range(), std::move(Parts));
120 // Report warning about URL deprecation.
121 Diagnostic &D =
122 Diags.emplace_back(Diagnostic::DK_DeprecatedURL, Tok.range());
123 Fix &F = D.fix("convert it to string");
124 // Insert a pair of quotes
125 F.edit(TextEdit::mkInsertion(Tok.lCur(), "\""));
126 F.edit(TextEdit::mkInsertion(Tok.rCur(), "\""));
127 return Str;
128 }
129 case tok_id: {
130 consume();
131 auto ID =
132 std::make_shared<Identifier>(Tok.range(), std::string(Tok.view()));
133 return std::make_shared<ExprVar>(Tok.range(), std::move(ID));
134 }
135 case tok_int: {
136 consume();
137 NixInt N = 0;
138 auto [Ptr, Errc] = std::from_chars(Tok.view().begin(), Tok.view().end(), N);
139 if (Errc != std::errc()) {
140 // Cannot decode int from tok_int.
141 assert(Errc == std::errc::result_out_of_range);
142 // emit a diagnostic saying we cannot decode integer to NixInt.
143 Diags.emplace_back(Diagnostic::DK_IntTooBig, Tok.range());
144 }
145 return std::make_shared<ExprInt>(Tok.range(), N);
146 }
147 case tok_float: {
148 consume();
149 // libc++ doesn't support std::from_chars for floating point numbers.
150 NixFloat N = std::strtof(std::string(Tok.view()).c_str(), nullptr);
151 return std::make_shared<ExprFloat>(Tok.range(), N);
152 }
153 case tok_spath: {
154 consume();
155 return std::make_shared<ExprSPath>(
156 Tok.range(), std::string(Tok.view().substr(1, Tok.view().size() - 2)));
157 }
158 case tok_dquote: // " - normal strings
159 return parseString(/*IsIndented=*/false);
160 case tok_quote2: // '' - indented strings
161 return parseString(/*IsIndented=*/true);
162 case tok_path_fragment:
163 return parseExprPath();
164 case tok_l_paren:
165 return parseExprParen();
166 case tok_kw_rec:
167 case tok_l_curly:
168 return parseExprAttrs();
169 case tok_l_bracket:
170 return parseExprList();
171 default:
172 return nullptr;
173 }
174}
Fix & fix(std::string Message)
Definition Diagnostic.h:203
Fix & edit(TextEdit Edit)
Definition Diagnostic.h:65
A point in the source file.
Definition Range.h:57
NodeKind kind() const
Definition Basic.h:34
NoteKind
Internal kind.
Definition Diagnostic.h:117
std::shared_ptr< ExprParen > parseExprParen()
std::shared_ptr< Expr > parseExpr()
Definition ParseExpr.cpp:73
std::shared_ptr< ExprString > parseString(bool IsIndented)
std::shared_ptr< Expr > parseExprSelect()
Definition ParseExpr.cpp:6
std::shared_ptr< Expr > parseExprPath()
Parse paths.
std::shared_ptr< Expr > parseExprSimple()
std::shared_ptr< ExprList > parseExprList()
std::shared_ptr< ExprAttrs > parseExprAttrs()
void tag(DiagnosticTag Tag)
Definition Diagnostic.h:96
static TextEdit mkRemoval(LexerCursorRange RemovingRange)
Definition Diagnostic.h:39
static TextEdit mkInsertion(LexerCursor P, std::string NewText)
Definition Diagnostic.h:35
A token. With it's kind, and the range in source code.
Definition Token.h:55
LexerCursor lCur() const
Definition Token.h:63
tok::TokenKind kind() const
Definition Token.h:65
LexerCursorRange range() const
Definition Token.h:66
LexerCursor rCur() const
Definition Token.h:64
std::string_view view() const
Definition Token.h:67
Diagnostic & diagNullExpr(std::vector< Diagnostic > &Diags, LexerCursor Loc, std::string As)
constexpr std::string_view spelling(TokenKind Kind)
Definition Token.h:13
int64_t NixInt
Definition Simple.h:12
double NixFloat
Definition Simple.h:13
Parser for the Nix expression language.