diff --git a/impl-generator/src/main.rs b/impl-generator/src/main.rs index fb19f09..14d4dd6 100644 --- a/impl-generator/src/main.rs +++ b/impl-generator/src/main.rs @@ -7,21 +7,25 @@ use std::process; use std::string::ToString; +/// The string pattern that every incoming string should match against. pub static REGEX: &'static str = r##"(?x) - ^ impl - (?: < .+ >)? \s+ + # example: - ([A-Za-z0-9_:]+) - (< .+ >)? \s+ + ^ impl # impl + (?: < .+ >)? \s+ # <'a> - for \s+ + ([ A-Z a-z 0-9 _ : ]+) # ops::Add + (< .+ >)? \s+ # > - ([A-Za-z0-9_:]+) - (< .+ >)? \s* + for \s+ # for + + ([ A-Z a-z 0-9 _ : ]+) # MyOtherValue + (< .+ >)? \s* # <'a> \{? $ "##; + fn main() { let regex = Regex::new(REGEX).unwrap(); @@ -35,8 +39,11 @@ fn main() { let type_args = caps.at(4).unwrap_or(""); if let Some(components) = get_components(trait_name) { + + // Print the first line... println!("impl{} {}{} for {}{} {{", type_args, trait_name,trait_args, type_name,type_args); + // Then print all the components, with a blank line between each one: let mut printed_anything = false; for component in components.iter() { if printed_anything == false { @@ -48,10 +55,20 @@ fn main() { let text = component.to_string(); + // There are three patterns that get replaced before a template is + // printed out: + // + // - SELF, which gets replaced with the name of the type the trait + // is being implemented for; + // - PARAM, which gets replaced with the *parameter* of the trait; + // - RHS, which gets replaced with the parameter if one exists, + // and the name of the type (like SELF) otherwise. + if text.contains("PARAM") && trait_args.is_empty() { fail(&*format!("Trait {} needs a generic argument", trait_name)); } + // Remove the < and > from the trait's parameter if one exists. let rhs = if trait_args.is_empty() { type_name } else { &trait_args[1 .. trait_args.len() - 1] }; let text = text.replace("SELF", &*format!("{}{}", type_name, type_args)) @@ -61,6 +78,7 @@ fn main() { println!("{}", text); } + // And finally the last line. println!("}}"); } else { @@ -68,10 +86,15 @@ fn main() { } } + +/// A **component** forms part of the resulting template. #[derive(Copy, Clone)] enum Component<'a> { + + /// An associated type that has to be specified for this implementation. AssocType(&'a str), + /// A function definition that must be specified for this trait. Function { name: &'a str, input: &'a str, @@ -105,6 +128,9 @@ impl<'a> fmt::Display for Component<'a> { } } + +/// Return a vector of components for a trait if the trait exists; returns +/// `None` otherwise. fn get_components(trait_name: &str) -> Option>> { use self::Component::*; @@ -368,6 +394,9 @@ fn get_components(trait_name: &str) -> Option>> { Some(bits) } + +/// Return the components for a mathematical operator, all of which follow the +/// same pattern. fn maths(name: &'static str) -> Vec> { vec![ Component::AssocType("Output"), @@ -380,6 +409,9 @@ fn maths(name: &'static str) -> Vec> { ] } + +/// Return the components for a formatting trait, which all look exactly the +/// same. fn format() -> Vec> { vec![ Component::Function { @@ -391,6 +423,8 @@ fn format() -> Vec> { ] } + +/// Print the given message, and exit the program, returning failure. fn fail(message: &str) -> ! { println!("{}", message); process::exit(1);