extern crate goscript_parser as fe; extern crate goscript_types as types; use regex::Regex; use std::collections::HashMap; use std::fs; use std::fs::File; use std::io::{self, BufRead}; use std::path::Path; #[derive(Debug)] struct ErrInfo { text: String, regex: Regex, checked: bool, line: usize, } impl ErrInfo { fn new(txt: String, line: usize) -> ErrInfo { let txt = txt.trim().trim_matches('"').to_string(); let regex = Regex::new(&txt).unwrap(); ErrInfo { text: txt, regex: regex, checked: false, line: line, } } } fn read_lines

(filename: P) -> io::Result>> where P: AsRef, { let file = File::open(filename)?; Ok(io::BufReader::new(file).lines()) } fn parse_error(s: &str, line: usize) -> io::Result> { let mut texts = vec![]; let mut cursor = 0; loop { if let Some(index) = s[cursor..].find("/* ERROR ") { if let Some(end) = s[cursor + index..].find(" */") { let txt = s[cursor + index + "/* ERROR ".len()..cursor + index + end].to_string(); texts.push(ErrInfo::new(txt, line)); cursor = cursor + index + end } else { return Err(io::Error::new(io::ErrorKind::Other, "invalid comment")); } } else if let Some(index) = s[cursor..].find("// ERROR ") { let txt = s[cursor + index + "// ERROR ".len()..].to_string(); texts.push(ErrInfo::new(txt, line)); break; } else { break; } } Ok(texts) } fn test_file(path: &str, trace: bool) { dbg!(path); let pkgs = &mut HashMap::new(); let config = types::Config { work_dir: Some("./".to_string()), base_path: None, trace_parser: trace, trace_checker: trace, }; let fs = &mut fe::FileSet::new(); let asto = &mut fe::objects::Objects::new(); let el = &mut fe::errors::ErrorList::new(); let tco = &mut types::TCObjects::new(); let results = &mut HashMap::new(); let importer = &mut types::Importer::new(&config, fs, pkgs, results, asto, tco, el, 0); let key = types::ImportKey::new(path, "./"); let _ = importer.import(&key); if trace { el.sort(); print!("{}", el); //dbg!(results); } let mut expected_errs = parse_comment_errors(path).unwrap(); for e in el.borrow().iter() { if e.msg.starts_with('\t') || e.by_parser { continue; } if let Some(errs) = expected_errs.get_mut(&e.pos.line) { let mut found = false; for info in errs.iter_mut() { if !info.checked { if info.text == e.msg || info.regex.is_match(&e.msg) { info.checked = true; found = true; break; } } } if !found { panic!("unexpected error(1): {}", e); } } else { panic!("unexpected error(2): {}", e); } } for (_, errs) in expected_errs.iter() { for info in errs.iter() { if !info.checked { panic!( "expected error at line {} not reported: {}", info.line, info.text ); } } } } fn parse_comment_errors

(path: P) -> io::Result>> where P: AsRef, { let mut result = HashMap::new(); let mut parse_file = |lines: io::Lines>| -> io::Result<()> { for (i, x) in lines.enumerate() { let t = x?; let mut errors = parse_error(&t, i + 1)?; if !errors.is_empty() { let entry = result.entry(i + 1).or_insert(vec![]); entry.append(&mut errors); } } Ok(()) }; if path.as_ref().is_file() { let lines = read_lines(path)?; parse_file(lines)?; } else if path.as_ref().is_dir() { for entry in fs::read_dir(path)? { let entry = entry?; let path = entry.path(); if !path.is_dir() { let lines = read_lines(path)?; parse_file(lines)?; } } } Ok(result) } #[test] fn test_auto() { let trace = false; test_file("./tests/data/builtins.gos", trace); test_file("./tests/data/const0.gos", trace); test_file("./tests/data/const1.gos", trace); test_file("./tests/data/constdecl.gos", trace); test_file("./tests/data/conversions.gos", trace); test_file("./tests/data/conversions2.gos", trace); test_file("./tests/data/cycles.gos", trace); test_file("./tests/data/cycles1.gos", trace); test_file("./tests/data/cycles2.gos", trace); test_file("./tests/data/cycles3.gos", trace); test_file("./tests/data/cycles4.gos", trace); test_file("./tests/data/cycles5.gos", trace); test_file("./tests/data/decls0.src", trace); test_file("./tests/data/decls1.src", trace); test_file("./tests/data/decls2", trace); test_file("./tests/data/decls3.src", trace); test_file("./tests/data/decls4.src", trace); test_file("./tests/data/decls5.src", trace); test_file("./tests/data/errors.src", trace); test_file("./tests/data/expr0.src", trace); test_file("./tests/data/expr2.src", trace); test_file("./tests/data/expr3.src", trace); test_file("./tests/data/gotos.src", trace); test_file("./tests/data/importdecl0", trace); test_file("./tests/data/importdecl1", trace); test_file("./tests/data/init0.src", trace); test_file("./tests/data/init1.src", trace); test_file("./tests/data/init2.src", trace); test_file("./tests/data/issues.src", trace); test_file("./tests/data/labels.src", trace); test_file("./tests/data/methodsets.src", trace); test_file("./tests/data/shifts.src", trace); test_file("./tests/data/stmt0.src", trace); test_file("./tests/data/stmt1.src", trace); test_file("./tests/data/vardecl.src", trace); } #[test] fn test_temp() { test_file("./tests/data/temp.gos", true); }