extern crate env_logger; extern crate regex; extern crate clap; extern crate kailua_test; extern crate kailua_env; extern crate kailua_diag; extern crate kailua_syntax; use std::cell::RefCell; use std::rc::Rc; use std::collections::HashMap; use clap::{App, Arg, ArgMatches}; use kailua_env::{Source, Span}; use kailua_diag::{Report, Reporter, TrackMaxKind}; use kailua_syntax::{Lexer, Nest, NestedToken, Parser, Chunk}; use kailua_syntax::ast::TokenAux; fn lex_and_parse_chunk(source: &Source, span: Span, report: &Report) -> kailua_diag::Result<(Vec<NestedToken>, Chunk)> { if let Some(mut iter) = source.iter_from_span(span) { let mut lexer = Lexer::new(&mut iter, &report); let tokens: Vec<_> = Nest::new(&mut lexer).collect(); let chunk = { let mut tokens_iter = tokens.iter().cloned(); let parser = Parser::new(&mut tokens_iter, &report); parser.into_chunk()? }; Ok((tokens, chunk)) } else { panic!("couldn't lex and parse chunk"); } } struct Testing { span_pattern: regex::Regex, scoped_id_pattern: regex::Regex, note_scopes: bool, note_token_aux: bool, } impl Testing { fn new() -> Testing { let span_pattern = regex::Regex::new(r"@(?:_|\d+(?:/\d+(?:-\d+)?)?)").unwrap(); assert_eq!(span_pattern.replace_all("[X@1, Y@3/40-978]@_", ""), "[X, Y]"); let scoped_id_pattern = regex::Regex::new(r"<(\d+)>").unwrap(); Testing { span_pattern: span_pattern, scoped_id_pattern: scoped_id_pattern, note_scopes: false, note_token_aux: false, } } } impl kailua_test::Testing for Testing { fn augment_args<'a, 'b: 'a>(&self, app: App<'a, 'b>) -> App<'a, 'b> { app.arg( Arg::with_name("note_scopes") .short("s") .long("note-scopes") .help("Displays a list of scopes and associated names as reports.\n\ Only useful when used with `--exact-diags`.") ).arg( Arg::with_name("note_token_aux") .short("x") .long("note-token-aux") .help("Displays auxiliary informations generated for each token after parsing.\n\ Only useful when used with `--exact-diags`.") ) } fn collect_args<'a>(&mut self, matches: &ArgMatches<'a>) { self.note_scopes = matches.is_present("note_scopes"); self.note_token_aux = matches.is_present("note_token_aux"); } fn run(&self, source: Rc<RefCell<Source>>, span: Span, _filespans: &HashMap<String, Span>, report: Rc<Report>) -> String { let report = TrackMaxKind::new(&*report); if let Ok((tokens, chunk)) = lex_and_parse_chunk(&source.borrow(), span, &report) { assert_eq!(tokens.len(), chunk.token_aux.len()); let s = format!("{:?}", chunk.block); if self.note_scopes { for scope in chunk.map.all_scopes() { let mut msg = format!("scope {:?}", scope.base); if let Some(parent) = chunk.map.parent_scope(scope.base) { msg.push_str(&format!(" <- {:?}", parent)); } msg.push_str(&format!(": {:?}", chunk.map.names(scope.base).collect::<Vec<_>>())); report.info(scope.span, msg).done().unwrap(); } } if self.note_token_aux { for (tok, aux) in tokens.iter().zip(chunk.token_aux.iter()) { match *aux { TokenAux::None => {} TokenAux::LocalVarName(ref id) => { let def = chunk.local_names.get(id).expect("unregistered scoped id"); let msg = format!("LocalVarName #{} ({:?})", id.to_usize(), def.kind); report.info(tok.tok.span, msg).done().unwrap(); } TokenAux::GlobalVarName => { report.info(tok.tok.span, "GlobalVarName").done().unwrap(); } } } } let s = self.span_pattern.replace_all(&s, ""); let s = self.scoped_id_pattern.replace_all(&s, |caps: ®ex::Captures| { let id = caps[1].parse().unwrap(); if let Some((name, scope)) = chunk.map.find_id_with_index(id) { format!("{:?}{:?}", name, scope) } else { caps[0].to_owned() } }); return s.into_owned(); } String::from("error") } } fn main() { env_logger::init().unwrap(); kailua_test::Tester::new("kailua-parse-test", Testing::new()).scan("src/tests").done(); }