Skip to content

Commit eccd706

Browse files
Parsing Error Handling (#31)
* Allow only one struct * All next() calls now handle errors with diagnostic * Factor out diagnostic handling with expect_rule * formatting * Roll back requirement of a single struct per file
1 parent fcf9cdb commit eccd706

File tree

2 files changed

+146
-55
lines changed

2 files changed

+146
-55
lines changed

src/diagnostic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ impl DiagnosticHandler {
146146
&mut self,
147147
message: &str,
148148
fileid: usize,
149-
pair: Pair<'_, Rule>,
149+
pair: &Pair<'_, Rule>,
150150
level: Level,
151151
) {
152152
let start = pair.as_span().start();

src/parser.rs

Lines changed: 145 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
// Copyright 2024 Cornell University
2-
// released under MIT License
3-
// author: Nikil Shyamunder <nikil.shyamsunder@gmail.com>
4-
// author: Kevin Laeufer <laeufer@cornell.edu>
5-
61
use baa::BitVecValue;
72
use pest::error::InputLocation;
83
use pest::iterators::Pairs;
@@ -39,6 +34,36 @@ pub struct ParserContext<'a> {
3934
}
4035

4136
impl<'a> ParserContext<'a> {
37+
// Helper method for expected rule errors
38+
fn expect_rule<T>(
39+
&mut self,
40+
option: Option<T>,
41+
context_pair: &pest::iterators::Pair<Rule>,
42+
message: &str,
43+
) -> Result<T, String> {
44+
option.ok_or_else(|| {
45+
let msg = message.to_string();
46+
self.handler
47+
.emit_diagnostic_parsing(&msg, self.fileid, context_pair, Level::Error);
48+
msg
49+
})
50+
}
51+
52+
// Helper for getting symbol id from name with error handling
53+
fn get_symbol_id(
54+
&mut self,
55+
name: &str,
56+
context_pair: &pest::iterators::Pair<Rule>,
57+
message: &str,
58+
) -> Result<SymbolId, String> {
59+
self.st.symbol_id_from_name(name).ok_or_else(|| {
60+
let msg = format!("{}: {}", message, name);
61+
self.handler
62+
.emit_diagnostic_parsing(&msg, self.fileid, context_pair, Level::Error);
63+
msg
64+
})
65+
}
66+
4267
pub fn parse_boxed_expr(&mut self, pairs: Pairs<Rule>) -> Result<BoxedExpr, String> {
4368
PRATT_PARSER
4469
.map_primary(|primary| {
@@ -62,7 +87,7 @@ impl<'a> ParserContext<'a> {
6287
self.handler.emit_diagnostic_parsing(
6388
&msg,
6489
self.fileid,
65-
primary,
90+
&primary,
6691
Level::Error,
6792
);
6893
Err(msg)
@@ -71,8 +96,12 @@ impl<'a> ParserContext<'a> {
7196
}
7297
Rule::dont_care => Ok(BoxedExpr::DontCare(start, end)),
7398
Rule::slice => {
74-
let mut inner_rules = primary.into_inner();
75-
let path_rule = inner_rules.next().unwrap();
99+
let mut inner_rules = primary.clone().into_inner();
100+
let path_rule = self.expect_rule(
101+
inner_rules.next(),
102+
&primary,
103+
"Expected path rule in slice expression",
104+
)?;
76105
let path_id = self.parse_boxed_expr(Pairs::single(path_rule))?;
77106
let idx1_rule = inner_rules.next().unwrap();
78107
let idx1 = idx1_rule.as_str().parse::<u32>().unwrap();
@@ -159,18 +188,22 @@ impl<'a> ParserContext<'a> {
159188
}
160189

161190
fn parse_struct(&mut self, pair: pest::iterators::Pair<Rule>) -> Result<StructId, String> {
162-
let mut inner_rules = pair.into_inner();
163-
let struct_name = inner_rules.next().unwrap().as_str();
164-
let (pins, _symbols) = self.parse_fields(inner_rules.next().unwrap())?;
191+
let mut inner_rules = pair.clone().into_inner();
192+
let struct_name = self
193+
.expect_rule(inner_rules.next(), &pair, "Expected struct name")?
194+
.as_str();
195+
let next_rule = self.expect_rule(inner_rules.next(), &pair, "Expected fields in struct")?;
196+
let (pins, _symbols) = self.parse_fields(next_rule)?;
165197
let struct_id = self.st.add_struct(struct_name.to_string(), pins);
166198
Ok(struct_id)
167199
}
168200

169201
fn parse_transaction(&mut self, pair: pest::iterators::Pair<Rule>) -> Result<(), String> {
170202
match pair.as_rule() {
171203
Rule::fun => {
172-
let mut inner_rules = pair.into_inner();
173-
let id_pair = inner_rules.next().unwrap();
204+
let mut inner_rules = pair.clone().into_inner();
205+
let id_pair =
206+
self.expect_rule(inner_rules.next(), &pair, "Expected function identifier")?;
174207
let id = id_pair.as_str();
175208
self.tr.name = id.to_string();
176209

@@ -202,7 +235,7 @@ impl<'a> ParserContext<'a> {
202235
self.handler.emit_diagnostic_parsing(
203236
&msg,
204237
self.fileid,
205-
inner_pair,
238+
&inner_pair,
206239
Level::Error,
207240
);
208241
return Err(msg);
@@ -212,7 +245,12 @@ impl<'a> ParserContext<'a> {
212245

213246
if let Some(arglist_pair) = inner_rules.peek() {
214247
if arglist_pair.as_rule() == Rule::arglist {
215-
self.tr.args = self.parse_arglist(inner_rules.next().unwrap())?;
248+
let arg_rules = self.expect_rule(
249+
inner_rules.next(),
250+
&arglist_pair,
251+
"Expected argument list",
252+
)?;
253+
self.tr.args = self.parse_arglist(arg_rules)?;
216254
} else {
217255
self.tr.args = Vec::new();
218256
}
@@ -229,7 +267,7 @@ impl<'a> ParserContext<'a> {
229267
pair.as_rule()
230268
);
231269
self.handler
232-
.emit_diagnostic_parsing(&msg, self.fileid, pair, Level::Error);
270+
.emit_diagnostic_parsing(&msg, self.fileid, &pair, Level::Error);
233271
Err(msg)
234272
}
235273
}
@@ -260,7 +298,7 @@ impl<'a> ParserContext<'a> {
260298
self.handler.emit_diagnostic_parsing(
261299
&msg,
262300
self.fileid,
263-
inner_pair,
301+
&inner_pair,
264302
Level::Error,
265303
);
266304
return Err(msg);
@@ -274,30 +312,38 @@ impl<'a> ParserContext<'a> {
274312
}
275313

276314
fn parse_assign(&mut self, pair: pest::iterators::Pair<Rule>) -> Result<Stmt, String> {
277-
let mut inner_rules = pair.into_inner();
278-
let path_id_rule = inner_rules.next().unwrap();
279-
let expr_rule = inner_rules.next().unwrap();
315+
let mut inner_rules = pair.clone().into_inner();
316+
let path_id_rule = self.expect_rule(
317+
inner_rules.next(),
318+
&pair,
319+
"Expected path identifier in assignment",
320+
)?;
321+
let expr_rule = self.expect_rule(
322+
inner_rules.next(),
323+
&pair,
324+
"Expected expression in assignment",
325+
)?;
326+
280327
let path_id: &str = path_id_rule.as_str();
281-
let symbol_id = self.st.symbol_id_from_name(path_id).ok_or_else(|| {
282-
let msg = format!("Assigning to undeclared symbol: {}", path_id);
283-
self.handler
284-
.emit_diagnostic_parsing(&msg, self.fileid, path_id_rule, Level::Error);
285-
msg
286-
})?;
328+
let symbol_id =
329+
self.get_symbol_id(path_id, &path_id_rule, "Assigning to undeclared symbol")?;
287330
let expr_id = self.parse_expr(expr_rule.into_inner())?;
331+
288332
Ok(Stmt::Assign(symbol_id, expr_id))
289333
}
290334

291335
fn parse_cmd(&mut self, pair: pest::iterators::Pair<Rule>) -> Result<Stmt, String> {
292-
let mut inner_rules = pair.into_inner();
293-
let cmd_rule = inner_rules.next().unwrap();
336+
let mut inner_rules = pair.clone().into_inner();
337+
let cmd_rule = self.expect_rule(inner_rules.next(), &pair, "Expected command")?;
294338
let cmd = cmd_rule.as_str();
339+
295340
let arg = if let Some(expr_rule) = inner_rules.next() {
296341
let expr_id = self.parse_expr(expr_rule.into_inner())?;
297342
Some(expr_id)
298343
} else {
299344
None
300345
};
346+
301347
match cmd {
302348
"step" => match arg {
303349
Some(expr_id) => Ok(Stmt::Step(expr_id)),
@@ -309,46 +355,66 @@ impl<'a> ParserContext<'a> {
309355
"fork" => {
310356
if arg.is_some() {
311357
let msg = "Fork command should have no arguments.".to_string();
312-
self.handler
313-
.emit_diagnostic_parsing(&msg, self.fileid, cmd_rule, Level::Error);
358+
self.handler.emit_diagnostic_parsing(
359+
&msg,
360+
self.fileid,
361+
&cmd_rule,
362+
Level::Error,
363+
);
314364
return Err(msg);
315365
}
316366
Ok(Stmt::Fork)
317367
}
318368
_ => {
319369
let msg = format!("Unexpected command: {:?}", cmd);
320370
self.handler
321-
.emit_diagnostic_parsing(&msg, self.fileid, cmd_rule, Level::Error);
371+
.emit_diagnostic_parsing(&msg, self.fileid, &cmd_rule, Level::Error);
322372
Err(msg)
323373
}
324374
}
325375
}
326376

327377
fn parse_while(&mut self, pair: pest::iterators::Pair<Rule>) -> Result<Stmt, String> {
328-
let mut inner_rules = pair.into_inner();
329-
let expr_rule = inner_rules.next().unwrap();
378+
let mut inner_rules = pair.clone().into_inner();
379+
let expr_rule = self.expect_rule(
380+
inner_rules.next(),
381+
&pair,
382+
"Expected expression in while loop",
383+
)?;
330384
let guard = self.parse_expr(expr_rule.into_inner())?;
331385
let body = self.parse_stmt_block(inner_rules)?;
332386
Ok(Stmt::While(guard, body))
333387
}
334388

335389
fn parse_assert_eq(&mut self, pair: pest::iterators::Pair<Rule>) -> Result<Stmt, String> {
336-
let mut inner_rules = pair.into_inner();
337-
let lhs_rule = inner_rules.next().unwrap();
338-
let rhs_rule = inner_rules.next().unwrap();
390+
let mut inner_rules = pair.clone().into_inner();
391+
let lhs_rule = self.expect_rule(
392+
inner_rules.next(),
393+
&pair,
394+
"Expected left-hand side expression in assert_eq",
395+
)?;
396+
let rhs_rule = self.expect_rule(
397+
inner_rules.next(),
398+
&pair,
399+
"Expected right-hand side expression in assert_eq",
400+
)?;
339401
let lhs_id = self.parse_expr(lhs_rule.into_inner())?;
340402
let rhs_id = self.parse_expr(rhs_rule.into_inner())?;
341403
Ok(Stmt::AssertEq(lhs_id, rhs_id))
342404
}
343405

344406
fn parse_cond(&mut self, pair: pest::iterators::Pair<Rule>) -> Result<Stmt, String> {
345-
let mut inner_rules = pair.into_inner();
346-
let if_rule = inner_rules.next().unwrap();
407+
let mut inner_rules = pair.clone().into_inner();
408+
let if_rule = self.expect_rule(inner_rules.next(), &pair, "Expected if condition")?;
347409
let mut inner_if = if_rule.into_inner();
348-
let expr_rule = inner_if.next().unwrap();
410+
let expr_rule = self.expect_rule(
411+
inner_if.next(),
412+
&pair,
413+
"Expected expression in if condition",
414+
)?;
349415
let expr_id = self.parse_expr(expr_rule.into_inner())?;
350416
let if_block = self.parse_stmt_block(inner_if)?;
351-
let else_rule = inner_rules.next().unwrap();
417+
let else_rule = self.expect_rule(inner_rules.next(), &pair, "Expected else block")?;
352418
let inner_else = else_rule.into_inner();
353419
let else_block = self.parse_stmt_block(inner_else)?;
354420
Ok(Stmt::IfElse(expr_id, if_block, else_block))
@@ -359,10 +425,22 @@ impl<'a> ParserContext<'a> {
359425
for inner_pair in pair.into_inner() {
360426
match inner_pair.as_rule() {
361427
Rule::arg => {
362-
let mut arg_inner = inner_pair.into_inner();
363-
let dir_pair = arg_inner.next().unwrap();
364-
let id_pair = arg_inner.next().unwrap();
365-
let tpe_pair = arg_inner.next().unwrap();
428+
let mut arg_inner = inner_pair.clone().into_inner();
429+
let dir_pair = self.expect_rule(
430+
arg_inner.next(),
431+
&inner_pair,
432+
"Expected direction in argument",
433+
)?;
434+
let id_pair = self.expect_rule(
435+
arg_inner.next(),
436+
&inner_pair,
437+
"Expected identifier in argument",
438+
)?;
439+
let tpe_pair = self.expect_rule(
440+
arg_inner.next(),
441+
&inner_pair,
442+
"Expected type in argument",
443+
)?;
366444
let dir = self.parse_dir(dir_pair)?;
367445
let id = id_pair.as_str();
368446
let tpe = self.parse_type(tpe_pair)?;
@@ -382,7 +460,7 @@ impl<'a> ParserContext<'a> {
382460
self.handler.emit_diagnostic_parsing(
383461
&msg,
384462
self.fileid,
385-
inner_pair,
463+
&inner_pair,
386464
Level::Error,
387465
);
388466
return Err(msg);
@@ -401,10 +479,19 @@ impl<'a> ParserContext<'a> {
401479
for inner_pair in pair.into_inner() {
402480
match inner_pair.as_rule() {
403481
Rule::arg => {
404-
let mut arg_inner = inner_pair.into_inner();
405-
let dir_pair = arg_inner.next().unwrap();
406-
let id_pair = arg_inner.next().unwrap();
407-
let tpe_pair = arg_inner.next().unwrap();
482+
let mut arg_inner = inner_pair.clone().into_inner();
483+
let dir_pair = self.expect_rule(
484+
arg_inner.next(),
485+
&inner_pair,
486+
"Expected direction in field",
487+
)?;
488+
let id_pair = self.expect_rule(
489+
arg_inner.next(),
490+
&inner_pair,
491+
"Expected identifier in field",
492+
)?;
493+
let tpe_pair =
494+
self.expect_rule(arg_inner.next(), &inner_pair, "Expected type in field")?;
408495
let dir = self.parse_dir(dir_pair)?;
409496
let id = id_pair.as_str();
410497
let tpe = self.parse_type(tpe_pair)?;
@@ -425,7 +512,7 @@ impl<'a> ParserContext<'a> {
425512
self.handler.emit_diagnostic_parsing(
426513
&msg,
427514
self.fileid,
428-
inner_pair,
515+
&inner_pair,
429516
Level::Error,
430517
);
431518
return Err(msg);
@@ -444,8 +531,12 @@ impl<'a> ParserContext<'a> {
444531
"out" => Ok(Dir::Out),
445532
_ => {
446533
let msg = format!("Unexpected direction string: {:?}", dir_str);
447-
self.handler
448-
.emit_diagnostic_parsing(&msg, self.fileid, pair, Level::Error);
534+
self.handler.emit_diagnostic_parsing(
535+
&msg,
536+
self.fileid,
537+
&pair,
538+
Level::Error,
539+
);
449540
Err(msg)
450541
}
451542
}
@@ -456,7 +547,7 @@ impl<'a> ParserContext<'a> {
456547
pair.as_rule()
457548
);
458549
self.handler
459-
.emit_diagnostic_parsing(&msg, self.fileid, pair, Level::Error);
550+
.emit_diagnostic_parsing(&msg, self.fileid, &pair, Level::Error);
460551
Err(msg)
461552
}
462553
}
@@ -473,7 +564,7 @@ impl<'a> ParserContext<'a> {
473564
_ => {
474565
let msg = format!("Unexpected rule while parsing type: {:?}", pair.as_rule());
475566
self.handler
476-
.emit_diagnostic_parsing(&msg, self.fileid, pair, Level::Error);
567+
.emit_diagnostic_parsing(&msg, self.fileid, &pair, Level::Error);
477568
Err(msg)
478569
}
479570
}

0 commit comments

Comments
 (0)