Quick start on ANTLR4 in Rust - part2

This is my note in adopting and learning ANTLR4Rust

Series


In the previous article, we built the minimal working example walking a parse tree using a listener. In this article, we are going to store a parsed CSV structure into a variable to use in the future.

Define a CSV structure:

1
2
3
4
5
type Row = Vec<String>;#[derive(Debug)]
struct CSV {
header: Row,
rows: Vec<Row>,
}

Add fields to a listener:

1
2
3
4
5
struct Listener {
csv: Box<CSV>,
add_to_header: bool,
row_to_add: Vec<String>,
}

csv will be a resultant CSV structure. add_to_header and row_to_add are internal state variables to generate a CSV structure.

Implement a listener:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
impl CSVListener for Listener {
fn enter_csvFile(&mut self, _ctx: &CsvFileContext) {}
fn exit_csvFile(&mut self, _ctx: &CsvFileContext) {}
fn enter_hdr(&mut self, _ctx: &HdrContext) {
self.add_to_header = true;
}
fn exit_hdr(&mut self, _ctx: &HdrContext) {
self.csv.header = self.row_to_add.to_vec();
self.row_to_add.clear();
self.add_to_header = false;
}
fn enter_row(&mut self, _ctx: &RowContext) {}
fn exit_row(&mut self, _ctx: &RowContext) {
if self.add_to_header {
return;
}
self.csv.rows.push(self.row_to_add.to_vec());
self.row_to_add.clear();
}
fn enter_field(&mut self, _ctx: &FieldContext) {}
fn exit_field(&mut self, _ctx: &FieldContext) {
self.row_to_add.push(_ctx.get_text());
}
}

Feed an input to a parse and extract the result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn main() {
let input = String::from(
"This, is, a, header
This, is, a, row
",
);
let lexer = CSVLexer::new(Box::new(InputStream::new(input)));
let token_source = CommonTokenStream::new(lexer);
let mut parser = CSVParser::new(Box::new(token_source));
let listener_id = parser.add_parse_listener(Box::new(Listener {
csv: Box::new(CSV {
header: Row::new(),
rows: Vec::new(),
}),
add_to_header: false,
row_to_add: Row::new(),
}));
let result = parser.csvFile();
assert!(result.is_ok());
let listener = parser.remove_parse_listener(listener_id);
let csv = listener.csv;
println!("{:#?}", csv);
}

A tricky part is that we have to extract csv from listener. And to this end, we have to extract listener with listener_id.

The minimal working example can be found here.