blob: 854d27d7ed323300ddc1f45059c231a64db06900 [file] [log] [blame] [edit]
use std::fmt::Debug;
use std::panic::catch_unwind;
use std::str::FromStr;
use proc_macro::*;
use self::Mode::*;
// FIXME: all cases should become `NormalOk` or `NormalErr`
#[derive(PartialEq, Clone, Copy)]
enum Mode {
NormalOk,
NormalErr,
OtherError,
OtherWithPanic,
}
fn parse<T>(s: &str, mode: Mode)
where
T: FromStr<Err = LexError> + Debug,
{
match mode {
NormalOk => {
let t = T::from_str(s);
println!("{:?}", t);
assert!(t.is_ok());
}
NormalErr => {
let t = T::from_str(s);
println!("{:?}", t);
assert!(t.is_err());
}
OtherError => {
println!("{:?}", T::from_str(s));
}
OtherWithPanic => {
if catch_unwind(|| println!("{:?}", T::from_str(s))).is_ok() {
eprintln!("{s} did not panic");
}
}
}
}
fn stream(s: &str, mode: Mode) {
parse::<TokenStream>(s, mode);
}
fn lit(s: &str, mode: Mode) {
parse::<Literal>(s, mode);
if mode == NormalOk {
let Ok(lit) = Literal::from_str(s) else {
panic!("literal was not ok");
};
let Ok(stream) = TokenStream::from_str(s) else {
panic!("tokenstream was not ok, but literal was");
};
let Some(tree) = stream.into_iter().next() else {
panic!("tokenstream should have a tokentree");
};
if let TokenTree::Literal(tokenstream_lit) = tree {
assert_eq!(lit.to_string(), tokenstream_lit.to_string());
}
}
}
pub fn run() {
// returns Ok(valid instance)
lit("123", NormalOk);
lit("\"ab\"", NormalOk);
lit("\'b\'", NormalOk);
lit("'b'", NormalOk);
lit("b\"b\"", NormalOk);
lit("c\"b\"", NormalOk);
lit("cr\"b\"", NormalOk);
lit("b'b'", NormalOk);
lit("256u8", NormalOk);
lit("-256u8", NormalOk);
stream("-256u8", NormalOk);
lit("0b11111000000001111i16", NormalOk);
lit("0xf32", NormalOk);
lit("0b0f32", NormalOk);
lit("2E4", NormalOk);
lit("2.2E-4f64", NormalOk);
lit("18u8E", NormalOk);
lit("18.0u8E", NormalOk);
lit("cr#\"// /* // \n */\"#", NormalOk);
lit("'\\''", NormalOk);
lit("'\\\''", NormalOk);
lit(&format!("r{0}\"a\"{0}", "#".repeat(255)), NormalOk);
stream("fn main() { println!(\"Hello, world!\") }", NormalOk);
stream("18.u8E", NormalOk);
stream("18.0f32", NormalOk);
stream("18.0f34", NormalOk);
stream("18.bu8", NormalOk);
stream("3//\n4", NormalOk);
stream(
"\'c\'/*\n
*/",
NormalOk,
);
stream("/*a*/ //", NormalOk);
println!("### ERRORS");
// returns Err(LexError)
lit("\'c\'/**/", NormalErr);
lit(" 0", NormalErr);
lit("0 ", NormalErr);
lit("0//", NormalErr);
lit("3//\n4", NormalErr);
lit("18.u8E", NormalErr);
lit("/*a*/ //", NormalErr);
// FIXME: all of the cases below should return an Err and emit no diagnostics, but don't yet.
// emits diagnostics and returns LexError
lit("r'r'", OtherError);
lit("c'r'", OtherError);
// emits diagnostic and returns a seemingly valid tokenstream
stream("r'r'", OtherError);
stream("c'r'", OtherError);
for parse in [stream as fn(&str, Mode), lit] {
// emits diagnostic(s), then panics
parse("1 ) 2", OtherWithPanic);
parse("( x [ ) ]", OtherWithPanic);
parse("r#", OtherWithPanic);
// emits diagnostic(s), then returns Ok(Literal { kind: ErrWithGuar, .. })
parse("0b2", OtherError);
parse("0bf32", OtherError);
parse("0b0.0f32", OtherError);
parse("'\''", OtherError);
parse(
"'
'", OtherError,
);
parse(&format!("r{0}\"a\"{0}", "#".repeat(256)), OtherWithPanic);
// emits diagnostic, then, when parsing as a lit, returns LexError, otherwise ErrWithGuar
parse("/*a*/ 0b2 //", OtherError);
}
}