@@ -110,6 +110,12 @@ class Parser {
110
110
{
111
111
}
112
112
113
+ void error_expected (const std::string& msg) const
114
+ {
115
+ std::cerr << " [Parse Error] Expected " << msg << " on line " << peek (-1 ).value ().line << std::endl;
116
+ exit (EXIT_FAILURE);
117
+ }
118
+
113
119
std::optional<NodeTerm*> parse_term () // NOLINT(*-no-recursion)
114
120
{
115
121
if (auto int_lit = try_consume (TokenType::int_lit)) {
@@ -122,13 +128,12 @@ class Parser {
122
128
auto term = m_allocator.emplace <NodeTerm>(expr_ident);
123
129
return term;
124
130
}
125
- if (auto open_paren = try_consume (TokenType::open_paren)) {
131
+ if (const auto open_paren = try_consume (TokenType::open_paren)) {
126
132
auto expr = parse_expr ();
127
133
if (!expr.has_value ()) {
128
- std::cerr << " Expected expression" << std::endl;
129
- exit (EXIT_FAILURE);
134
+ error_expected (" expression" );
130
135
}
131
- try_consume (TokenType::close_paren, " Expected `)` " );
136
+ try_consume_err (TokenType::close_paren);
132
137
auto term_paren = m_allocator.emplace <NodeTermParen>(expr.value ());
133
138
auto term = m_allocator.emplace <NodeTerm>(term_paren);
134
139
return term;
@@ -156,12 +161,11 @@ class Parser {
156
161
else {
157
162
break ;
158
163
}
159
- const auto [type, value] = consume ();
164
+ const auto [type, line, value] = consume ();
160
165
const int next_min_prec = prec.value () + 1 ;
161
166
auto expr_rhs = parse_expr (next_min_prec);
162
167
if (!expr_rhs.has_value ()) {
163
- std::cerr << " Unable to parse expression" << std::endl;
164
- exit (EXIT_FAILURE);
168
+ error_expected (" expression" );
165
169
}
166
170
auto expr = m_allocator.emplace <NodeBinExpr>();
167
171
auto expr_lhs2 = m_allocator.emplace <NodeExpr>();
@@ -202,29 +206,27 @@ class Parser {
202
206
while (auto stmt = parse_stmt ()) {
203
207
scope->stmts .push_back (stmt.value ());
204
208
}
205
- try_consume (TokenType::close_curly, " Expected `}` " );
209
+ try_consume_err (TokenType::close_curly);
206
210
return scope;
207
211
}
208
212
209
213
std::optional<NodeIfPred*> parse_if_pred () // NOLINT(*-no-recursion)
210
214
{
211
215
if (try_consume (TokenType::elif)) {
212
- try_consume (TokenType::open_paren, " Expected `(` " );
216
+ try_consume_err (TokenType::open_paren);
213
217
const auto elif = m_allocator.alloc <NodeIfPredElif>();
214
218
if (const auto expr = parse_expr ()) {
215
219
elif->expr = expr.value ();
216
220
}
217
221
else {
218
- std::cerr << " Expected expression" << std::endl;
219
- exit (EXIT_FAILURE);
222
+ error_expected (" expression" );
220
223
}
221
- try_consume (TokenType::close_paren, " Expected `)` " );
224
+ try_consume_err (TokenType::close_paren);
222
225
if (const auto scope = parse_scope ()) {
223
226
elif->scope = scope.value ();
224
227
}
225
228
else {
226
- std::cerr << " Expected scope" << std::endl;
227
- exit (EXIT_FAILURE);
229
+ error_expected (" scope" );
228
230
}
229
231
elif->pred = parse_if_pred ();
230
232
auto pred = m_allocator.emplace <NodeIfPred>(elif);
@@ -236,8 +238,7 @@ class Parser {
236
238
else_->scope = scope.value ();
237
239
}
238
240
else {
239
- std::cerr << " Expected scope" << std::endl;
240
- exit (EXIT_FAILURE);
241
+ error_expected (" scope" );
241
242
}
242
243
auto pred = m_allocator.emplace <NodeIfPred>(else_);
243
244
return pred;
@@ -247,7 +248,7 @@ class Parser {
247
248
248
249
std::optional<NodeStmt*> parse_stmt () // NOLINT(*-no-recursion)
249
250
{
250
- if (peek ().value ().type == TokenType::exit && peek (1 ).has_value ()
251
+ if (peek ().has_value () && peek (). value ().type == TokenType::exit && peek (1 ).has_value ()
251
252
&& peek (1 ).value ().type == TokenType::open_paren) {
252
253
consume ();
253
254
consume ();
@@ -256,11 +257,10 @@ class Parser {
256
257
stmt_exit->expr = node_expr.value ();
257
258
}
258
259
else {
259
- std::cerr << " Invalid expression" << std::endl;
260
- exit (EXIT_FAILURE);
260
+ error_expected (" expression" );
261
261
}
262
- try_consume (TokenType::close_paren, " Expected `)` " );
263
- try_consume (TokenType::semi, " Expected `;` " );
262
+ try_consume_err (TokenType::close_paren);
263
+ try_consume_err (TokenType::semi);
264
264
auto stmt = m_allocator.emplace <NodeStmt>();
265
265
stmt->var = stmt_exit;
266
266
return stmt;
@@ -276,10 +276,9 @@ class Parser {
276
276
stmt_let->expr = expr.value ();
277
277
}
278
278
else {
279
- std::cerr << " Invalid expression" << std::endl;
280
- exit (EXIT_FAILURE);
279
+ error_expected (" expression" );
281
280
}
282
- try_consume (TokenType::semi, " Expected `;` " );
281
+ try_consume_err (TokenType::semi);
283
282
auto stmt = m_allocator.emplace <NodeStmt>();
284
283
stmt->var = stmt_let;
285
284
return stmt;
@@ -293,10 +292,9 @@ class Parser {
293
292
assign->expr = expr.value ();
294
293
}
295
294
else {
296
- std::cerr << " Expected expression" << std::endl;
297
- exit (EXIT_FAILURE);
295
+ error_expected (" expression" );
298
296
}
299
- try_consume (TokenType::semi, " Expected `;` " );
297
+ try_consume_err (TokenType::semi);
300
298
auto stmt = m_allocator.emplace <NodeStmt>(assign);
301
299
return stmt;
302
300
}
@@ -305,26 +303,23 @@ class Parser {
305
303
auto stmt = m_allocator.emplace <NodeStmt>(scope.value ());
306
304
return stmt;
307
305
}
308
- std::cerr << " Invalid scope" << std::endl;
309
- exit (EXIT_FAILURE);
306
+ error_expected (" scope" );
310
307
}
311
308
if (auto if_ = try_consume (TokenType::if_)) {
312
- try_consume (TokenType::open_paren, " Expected `(` " );
309
+ try_consume_err (TokenType::open_paren);
313
310
auto stmt_if = m_allocator.emplace <NodeStmtIf>();
314
311
if (const auto expr = parse_expr ()) {
315
312
stmt_if->expr = expr.value ();
316
313
}
317
314
else {
318
- std::cerr << " Invalid expression" << std::endl;
319
- exit (EXIT_FAILURE);
315
+ error_expected (" expression" );
320
316
}
321
- try_consume (TokenType::close_paren, " Expected `)` " );
317
+ try_consume_err (TokenType::close_paren);
322
318
if (const auto scope = parse_scope ()) {
323
319
stmt_if->scope = scope.value ();
324
320
}
325
321
else {
326
- std::cerr << " Invalid scope" << std::endl;
327
- exit (EXIT_FAILURE);
322
+ error_expected (" scope" );
328
323
}
329
324
stmt_if->pred = parse_if_pred ();
330
325
auto stmt = m_allocator.emplace <NodeStmt>(stmt_if);
@@ -341,15 +336,14 @@ class Parser {
341
336
prog.stmts .push_back (stmt.value ());
342
337
}
343
338
else {
344
- std::cerr << " Invalid statement" << std::endl;
345
- exit (EXIT_FAILURE);
339
+ error_expected (" statement" );
346
340
}
347
341
}
348
342
return prog;
349
343
}
350
344
351
345
private:
352
- [[nodiscard]] std::optional<Token> peek (const size_t offset = 0 ) const
346
+ [[nodiscard]] std::optional<Token> peek (const int offset = 0 ) const
353
347
{
354
348
if (m_index + offset >= m_tokens.size ()) {
355
349
return {};
@@ -362,13 +356,13 @@ class Parser {
362
356
return m_tokens.at (m_index++);
363
357
}
364
358
365
- Token try_consume (const TokenType type, const std::string& err_msg )
359
+ Token try_consume_err (const TokenType type)
366
360
{
367
361
if (peek ().has_value () && peek ().value ().type == type) {
368
362
return consume ();
369
363
}
370
- std::cerr << err_msg << std::endl ;
371
- exit (EXIT_FAILURE) ;
364
+ error_expected ( to_string (type)) ;
365
+ return {} ;
372
366
}
373
367
374
368
std::optional<Token> try_consume (const TokenType type)
0 commit comments