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 .