Skip to content

Commit 4e780d3

Browse files
committed
Add line/column numbers to LALR parser errors
1 parent 87d3439 commit 4e780d3

File tree

1 file changed

+33
-2
lines changed

1 file changed

+33
-2
lines changed

src/lang/dynamic_lola/lalr_parser.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::BTreeMap;
2+
use std::fmt;
23

34
use anyhow::{Error, anyhow};
45
use ecow::EcoVec;
@@ -79,17 +80,47 @@ pub fn create_lola_spec(stmts: &EcoVec<STopDecl>) -> LOLASpecification {
7980
LOLASpecification::new(inputs, outputs, assignments, type_annotations, aux_info)
8081
}
8182

83+
struct LineCol {
84+
line: usize,
85+
col: usize,
86+
}
87+
88+
impl fmt::Display for LineCol {
89+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90+
write!(f, "line {}, column {}", self.line, self.col)
91+
}
92+
}
93+
94+
// Converts a byte offset into a line and a column
95+
fn line_col(input: &str, byte: usize) -> LineCol {
96+
let byte = byte.min(input.len());
97+
let mut line = 1usize;
98+
let mut col = 1usize;
99+
100+
for ch in input[..byte].chars() {
101+
if ch == '\n' {
102+
line += 1;
103+
col = 1;
104+
} else {
105+
col += 1;
106+
}
107+
}
108+
LineCol { line, col }
109+
}
110+
82111
pub fn parse_str<'input>(input: &'input str) -> anyhow::Result<LOLASpecification> {
83112
let stmts = TopDeclsParser::new().parse(&input).map_err(|e| {
84-
anyhow::anyhow!(e.to_string()).context(format!("Failed to parse input {}", input))
113+
let err_fixed = e.map_location(|byte| line_col(&input, byte));
114+
anyhow::anyhow!(err_fixed.to_string()).context(format!("Failed to parse input {}", input))
85115
})?;
86116
Ok(create_lola_spec(&stmts))
87117
}
88118

89119
pub async fn parse_file<'file>(file: &'file str) -> anyhow::Result<LOLASpecification> {
90120
let contents = smol::fs::read_to_string(file).await?;
91121
let stmts = TopDeclsParser::new().parse(&contents).map_err(|e| {
92-
anyhow::anyhow!(e.to_string()).context(format!("Failed to parse file {}", file))
122+
let err_fixed = e.map_location(|byte| line_col(&contents, byte));
123+
anyhow::anyhow!(err_fixed.to_string()).context(format!("Failed to parse file {}", file))
93124
})?;
94125
Ok(create_lola_spec(&stmts))
95126
}

0 commit comments

Comments
 (0)