Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion lrlex/src/lib/ctbuilder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,15 @@ where
format!("{}_l", stem)
}
};
let mod_name = format_ident!("{}", mod_name);
let mod_name =
match syn::parse_str::<proc_macro2::Ident>(&mod_name) {
Ok(s) => s,
Err(e) => return Err(format!(
"CTLexerBuilder::mod_name(\"{}\") is not a valid rust identifier due to '{}'",
mod_name, e
)
.into()),
};
let mut lexerdef_func_impl = {
let LexFlags {
allow_wholeline_comments,
Expand Down Expand Up @@ -1488,4 +1496,34 @@ mod test {
.unwrap();
}
}

#[test]
/// Tests a yacc .y filename containing a dash character leading to an invalid rust identifier
/// when that dash is subsequently used as the default `CTParserBuilder::mod_name`.
fn test_invalid_identifier_in_derived_mod_name() {
let mut lex_path = std::path::PathBuf::from(env!("OUT_DIR"));
lex_path.push("contains-a-dash.l");
let mut f = File::create(&lex_path).unwrap();
let _ = f.write_all(
r#"
%%
A "A"
"#
.as_bytes(),
);
match CTLexerBuilder::new()
.output_path(format!("{}.rs", lex_path.display()))
.lexer_path(lex_path.clone())
.build()
{
Ok(_) => panic!("Expected error"),
Err(e) => {
let err_string = e.to_string();
assert_eq!(
err_string,
"CTLexerBuilder::mod_name(\"contains-a-dash_l\") is not a valid rust identifier due to 'unexpected token'"
);
}
}
}
}
41 changes: 40 additions & 1 deletion lrpar/src/lib/ctbuilder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,15 @@ where
None
};

let mod_name = format_ident!("{}", mod_name);
let mod_name =
match syn::parse_str::<proc_macro2::Ident>(mod_name) {
Ok(s) => s,
Err(e) => return Err(format!(
"CTParserBuilder::mod_name(\"{}\") is not a valid rust identifier due to '{}'",
mod_name, e
)
.into()),
};
let out_tokens = quote! {
#visibility mod #mod_name {
// At the top so that `user_actions` may contain #![inner_attribute]
Expand Down Expand Up @@ -1801,6 +1809,37 @@ C : 'a';"
}
}

#[test]
/// Tests a yacc .y filename containing a dash character leading to an invalid rust identifier
/// when that dash is subsequently used as the default `CTParserBuilder::mod_name`.
fn test_invalid_identifier_in_derived_mod_name() {
let temp = TempDir::new().unwrap();
let mut file_path = PathBuf::from(temp.as_ref());
file_path.push("contains-a-dash.y");
let mut f = File::create(&file_path).unwrap();
let _ = f.write_all(
"%start A
%%
A : 'a';"
.as_bytes(),
);
match CTParserBuilder::<TestLexerTypes>::new()
.yacckind(YaccKind::Original(YaccOriginalActionKind::GenericParseTree))
.grammar_path(file_path.to_str().unwrap())
.output_path(file_path.with_extension("ignored"))
.build()
{
Ok(_) => panic!("Expected error"),
Err(e) => {
let err_string = e.to_string();
assert_eq!(
err_string,
"CTParserBuilder::mod_name(\"contains-a-dash_y\") is not a valid rust identifier due to 'unexpected token'"
);
}
}
}

#[cfg(test)]
#[test]
fn test_recoverer_header() -> Result<(), Box<dyn std::error::Error>> {
Expand Down