Skip to content

Commit b95668e

Browse files
authored
Merge pull request #625 from ratmice/issue_623
Add span information for action code, improve errors.
2 parents 0ebc37c + ceb7b83 commit b95668e

4 files changed

Lines changed: 43 additions & 14 deletions

File tree

cfgrammar/src/lib/yacc/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pub struct Rule {
190190
pub struct Production {
191191
pub symbols: Vec<Symbol>,
192192
pub precedence: Option<String>,
193-
pub action: Option<String>,
193+
pub action: Option<(String, Span)>,
194194
pub prod_span: Span,
195195
}
196196

@@ -271,7 +271,7 @@ impl GrammarAST {
271271
rule_name: String,
272272
symbols: Vec<Symbol>,
273273
precedence: Option<String>,
274-
action: Option<String>,
274+
action: Option<(String, Span)>,
275275
prod_span: Span,
276276
) {
277277
self.rules[&rule_name].pidxs.push(self.prods.len());

cfgrammar/src/lib/yacc/grammar.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ pub struct YaccGrammar<StorageT = u32> {
8181
implicit_rule: Option<RIdx<StorageT>>,
8282
/// User defined Rust programs which can be called within actions
8383
actions: Box<[Option<String>]>,
84+
/// Spans for each action.
85+
action_spans: Box<[Option<Span>]>,
8486
/// A `(name, type)` pair defining an extra parameter to pass to action functions.
8587
parse_param: Option<(String, String)>,
8688
/// Generic parameters (types and lifetimes) to pass to action functions.
@@ -131,6 +133,7 @@ where
131133
prod_precs: Decode::decode(decoder)?,
132134
implicit_rule: Decode::decode(decoder)?,
133135
actions: Decode::decode(decoder)?,
136+
action_spans: Decode::decode(decoder)?,
134137
parse_param: Decode::decode(decoder)?,
135138
parse_generics: Decode::decode(decoder)?,
136139
programs: Decode::decode(decoder)?,
@@ -170,6 +173,7 @@ where
170173
prod_precs: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
171174
implicit_rule: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
172175
actions: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
176+
action_spans: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
173177
parse_param: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
174178
parse_generics: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
175179
programs: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
@@ -328,6 +332,7 @@ where
328332
let mut prod_precs: Vec<Option<Option<Precedence>>> = vec![None; ast.prods.len()];
329333
let mut prods_rules = vec![None; ast.prods.len()];
330334
let mut actions = vec![None; ast.prods.len()];
335+
let mut action_spans = vec![None; ast.prods.len()];
331336
let mut actiontypes = vec![None; rule_names.len()];
332337
let (start_name, _) = ast.start.as_ref().unwrap();
333338
for (astrulename, _) in &rule_names {
@@ -419,8 +424,9 @@ where
419424
prods[pidx] = Some(prod);
420425
prod_precs[pidx] = Some(prec.map(|(prec, _)| prec));
421426
prods_rules[pidx] = Some(ridx);
422-
if let Some(ref s) = astprod.action {
427+
if let Some((s, span)) = &astprod.action {
423428
actions[pidx] = Some(s.clone());
429+
action_spans[pidx] = Some(*span);
424430
}
425431
}
426432
}
@@ -459,6 +465,7 @@ where
459465
prod_precs: prod_precs.into_iter().map(Option::unwrap).collect(),
460466
implicit_rule: implicit_rule.map(|x| rule_map[&x]),
461467
actions: actions.into_boxed_slice(),
468+
action_spans: action_spans.into_boxed_slice(),
462469
parse_param: ast.parse_param.clone(),
463470
parse_generics: ast.parse_generics.clone(),
464471
programs: ast.programs.clone(),
@@ -625,6 +632,10 @@ where
625632
&self.actions[usize::from(pidx)]
626633
}
627634

635+
pub fn action_span(&self, pidx: PIdx<StorageT>) -> Option<Span> {
636+
self.action_spans[usize::from(pidx)]
637+
}
638+
628639
pub fn actiontype(&self, ridx: RIdx<StorageT>) -> &Option<String> {
629640
&self.actiontypes[usize::from(ridx)]
630641
}

cfgrammar/src/lib/yacc/parser.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,13 @@ impl YaccParser<'_> {
734734
pos_prod_end = Some(k);
735735
i = k;
736736
} else if self.lookahead_is("{", i).is_some() {
737+
let pos_action_start = i + 1;
737738
pos_prod_end = Some(i);
739+
// With j the location of the right brace, i the location of the left brace.
738740
let (j, a) = self.parse_action(i)?;
739741
i = self.parse_ws(j, true)?;
740-
action = Some(a);
742+
let action_span = Span::new(pos_action_start, pos_action_start + a.len());
743+
action = Some((a, action_span));
741744

742745
if !(self.lookahead_is("|", i).is_some() || self.lookahead_is(";", i).is_some()) {
743746
return Err(self.mk_error(YaccGrammarErrorKind::ProductionNotTerminated, i));
@@ -2284,13 +2287,15 @@ x"
22842287
",
22852288
)
22862289
.unwrap();
2290+
let action_str = "println!(\"test\");".to_string();
22872291
assert_eq!(
22882292
grm.prods[grm.rules["A"].pidxs[0]].action,
2289-
Some("println!(\"test\");".to_string())
2293+
Some((action_str.clone(), Span::new(34, 34 + action_str.len())))
22902294
);
2295+
let action_str = "add($1, $2);".to_string();
22912296
assert_eq!(
22922297
grm.prods[grm.rules["B"].pidxs[0]].action,
2293-
Some("add($1, $2);".to_string())
2298+
Some((action_str.clone(), Span::new(90, 90 + action_str.len())))
22942299
);
22952300
assert_eq!(grm.prods[grm.rules["B"].pidxs[1]].action, None);
22962301
}
@@ -2302,9 +2307,10 @@ x"
23022307
"%%A: '_' {(); // 🦀};",
23032308
)
23042309
.unwrap();
2310+
let action_str = "(); // 🦀".to_string();
23052311
assert_eq!(
23062312
grm.prods[grm.rules["A"].pidxs[0]].action,
2307-
Some("(); // 🦀".to_string())
2313+
Some((action_str.clone(), Span::new(10, 10 + action_str.len())))
23082314
);
23092315
}
23102316

lrpar/src/lib/ctbuilder.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::unstable_api::UnstableApi;
2424

2525
use bincode::{Decode, Encode, decode_from_slice, encode_to_vec};
2626
use cfgrammar::{
27-
Location, RIdx, Symbol,
27+
Location, RIdx, Span, Symbol,
2828
header::{GrmtoolsSectionParser, Header, HeaderValue, Value},
2929
markmap::{Entry, MergeBehavior},
3030
yacc::{YaccGrammar, YaccKind, YaccOriginalActionKind, ast::ASTWithValidityInfo},
@@ -810,6 +810,7 @@ where
810810
&derived_mod_name,
811811
outp,
812812
&format!("/* CACHE INFORMATION {} */\n", cache),
813+
&yacc_diag,
813814
)?;
814815
let conflicts = if stable.conflicts().is_some() {
815816
Some((sgraph, stable))
@@ -937,13 +938,14 @@ where
937938
mod_name: &str,
938939
outp_rs: P,
939940
cache: &str,
941+
diag: &SpannedDiagnosticFormatter,
940942
) -> Result<(), Box<dyn Error>> {
941943
let visibility = self.visibility.clone();
942944
let user_actions = if let Some(
943945
YaccKind::Original(YaccOriginalActionKind::UserAction) | YaccKind::Grmtools,
944946
) = self.yacckind
945947
{
946-
Some(self.gen_user_actions(grm)?)
948+
Some(self.gen_user_actions(grm, diag)?)
947949
} else {
948950
None
949951
};
@@ -1419,7 +1421,11 @@ where
14191421
}
14201422

14211423
/// Generate the user action functions (if any).
1422-
fn gen_user_actions(&self, grm: &YaccGrammar<StorageT>) -> Result<TokenStream, Box<dyn Error>> {
1424+
fn gen_user_actions(
1425+
&self,
1426+
grm: &YaccGrammar<StorageT>,
1427+
diag: &SpannedDiagnosticFormatter,
1428+
) -> Result<TokenStream, Box<dyn Error>> {
14231429
let programs = grm
14241430
.programs()
14251431
.as_ref()
@@ -1520,10 +1526,16 @@ where
15201526
write!(outs, "{prefix}arg_", prefix = ACTION_PREFIX).ok();
15211527
last = last + off + "$".len();
15221528
} else {
1523-
panic!(
1524-
"Unknown text following '$' operator: {}",
1525-
&pre_action[last + off..]
1526-
);
1529+
let span = grm.action_span(pidx).unwrap();
1530+
let inner_span =
1531+
Span::new(span.start() + last + off + "$".len(), span.end());
1532+
let mut s = String::from("\n");
1533+
s.push_str(&diag.underline_span_with_text(
1534+
inner_span,
1535+
"Unknown text following '$'".to_string(),
1536+
'^',
1537+
));
1538+
return Err(ErrorString(s).into());
15271539
}
15281540
}
15291541
None => {

0 commit comments

Comments
 (0)