From ec63f8f438b261ec130eb03c43e7a6b574173f01 Mon Sep 17 00:00:00 2001 From: Monnoroch Date: Wed, 11 Jul 2018 23:00:53 +0100 Subject: [PATCH] Parse class definitions and generate empty structs. Related to #76. --- generator/src/lib.rs | 285 ++++++++++++++++++++++++++++++++++++++-- generator/tests/test.rs | 6 +- 2 files changed, 279 insertions(+), 12 deletions(-) diff --git a/generator/src/lib.rs b/generator/src/lib.rs index cfc3558..e77cdcd 100644 --- a/generator/src/lib.rs +++ b/generator/src/lib.rs @@ -21,10 +21,53 @@ fn java_generate_impl(input: TokenStream) -> TokenStream { } #[derive(Debug, PartialEq, Eq, Clone)] -struct JavaDefinitions {} +struct JavaDefinition { + class: Ident, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct JavaDefinitions { + definitions: Vec, +} -fn parse_java_definition(_input: TokenStream) -> JavaDefinitions { - JavaDefinitions {} +fn parse_java_definition(input: TokenStream) -> JavaDefinitions { + let definitions = input.clone().into_iter().collect::>(); + let definitions = definitions + .split(is_definition) + .filter(|tokens| !tokens.is_empty()) + .map(|header| { + if header.len() < 2 { + panic!("Expected a class definition, got {:?}.", header); + } + + let (token, header) = header.split_first().unwrap(); + if !is_identifier(&token, "class") { + panic!("Expected \"class\", got {:?}.", token); + } + + let (class, _) = header.split_first().unwrap(); + let class = match class.clone() { + TokenTree::Ident(identifier) => identifier, + token => panic!("Expected an identifier, got {:?}.", token), + }; + JavaDefinition { class } + }) + .collect(); + JavaDefinitions { definitions } +} + +fn is_identifier(token: &TokenTree, name: &str) -> bool { + match token { + TokenTree::Ident(identifier) => identifier == name, + _ => false, + } +} + +fn is_definition(token: &TokenTree) -> bool { + match token { + TokenTree::Group(group) => group.delimiter() == Delimiter::Brace, + _ => false, + } } #[cfg(test)] @@ -34,15 +77,100 @@ mod parse_tests { #[test] fn empty() { let input = quote!{}; - assert_eq!(parse_java_definition(input), JavaDefinitions {}); + assert_eq!( + parse_java_definition(input), + JavaDefinitions { + definitions: vec![], + } + ); + } + + #[test] + fn one() { + let input = quote!{ + class TestClass1 {} + }; + assert_eq!( + parse_java_definition(input), + JavaDefinitions { + definitions: vec![JavaDefinition { + class: Ident::new("TestClass1", Span::call_site()), + }], + } + ); } + + #[test] + fn multiple() { + let input = quote!{ + class TestClass1 {} + class TestClass2 {} + }; + assert_eq!( + parse_java_definition(input), + JavaDefinitions { + definitions: vec![ + JavaDefinition { + class: Ident::new("TestClass1", Span::call_site()), + }, + JavaDefinition { + class: Ident::new("TestClass2", Span::call_site()), + }, + ], + } + ); + } + + #[test] + #[should_panic(expected = "Expected \"class\"")] + fn invalid_definition_kind() { + let input = quote!{ + class test {} + invalid 1 + }; + parse_java_definition(input); + } + + #[test] + #[should_panic(expected = "Expected a class definition")] + fn too_few_tokens() { + let input = quote!{ + class test {} + invalid + }; + parse_java_definition(input); + } + + #[test] + #[should_panic(expected = "Expected an identifier")] + fn definition_name_not_identifier() { + let input = quote!{ + class 1 {} + }; + parse_java_definition(input); + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct GeneratorDefinition { + class: Ident, } #[derive(Debug, PartialEq, Eq, Clone)] -struct GeneratorData {} +struct GeneratorData { + definitions: Vec, +} -fn to_generator_data(_definitions: JavaDefinitions) -> GeneratorData { - GeneratorData {} +fn to_generator_data(definitions: JavaDefinitions) -> GeneratorData { + GeneratorData { + definitions: definitions + .definitions + .into_iter() + .map(|definition| GeneratorDefinition { + class: definition.class, + }) + .collect(), + } } #[cfg(test)] @@ -51,12 +179,74 @@ mod to_generator_data_tests { #[test] fn empty() { - assert_eq!(to_generator_data(JavaDefinitions {}), GeneratorData {}); + assert_eq!( + to_generator_data(JavaDefinitions { + definitions: vec![], + }), + GeneratorData { + definitions: vec![], + } + ); + } + + #[test] + fn one() { + assert_eq!( + to_generator_data(JavaDefinitions { + definitions: vec![JavaDefinition { + class: Ident::new("test1", Span::call_site()), + }], + }), + GeneratorData { + definitions: vec![GeneratorDefinition { + class: Ident::new("test1", Span::call_site()), + }], + } + ); + } + + #[test] + fn multiple() { + assert_eq!( + to_generator_data(JavaDefinitions { + definitions: vec![ + JavaDefinition { + class: Ident::new("test1", Span::call_site()), + }, + JavaDefinition { + class: Ident::new("test2", Span::call_site()), + }, + ], + }), + GeneratorData { + definitions: vec![ + GeneratorDefinition { + class: Ident::new("test1", Span::call_site()), + }, + GeneratorDefinition { + class: Ident::new("test2", Span::call_site()), + }, + ], + } + ); } } -fn generate(_data: GeneratorData) -> TokenStream { - TokenStream::new() +fn generate(data: GeneratorData) -> TokenStream { + let mut tokens = TokenStream::new(); + for definition in data.definitions { + tokens.extend(generate_definition(definition)); + } + tokens +} + +fn generate_definition(definition: GeneratorDefinition) -> TokenStream { + let GeneratorDefinition { class, .. } = definition; + quote! { + #[derive(Debug)] + pub struct #class { + } + } } #[cfg(test)] @@ -65,8 +255,50 @@ mod generate_tests { #[test] fn empty() { + let input = GeneratorData { + definitions: vec![], + }; let expected = quote!{}; - assert_tokens_equals(generate(GeneratorData {}), expected); + assert_tokens_equals(generate(input), expected); + } + + #[test] + fn one() { + let input = GeneratorData { + definitions: vec![GeneratorDefinition { + class: Ident::new("test1", Span::call_site()), + }], + }; + let expected = quote!{ + #[derive(Debug)] + pub struct test1 { + } + }; + assert_tokens_equals(generate(input), expected); + } + + #[test] + fn multiple() { + let input = GeneratorData { + definitions: vec![ + GeneratorDefinition { + class: Ident::new("test1", Span::call_site()), + }, + GeneratorDefinition { + class: Ident::new("test2", Span::call_site()), + }, + ], + }; + let expected = quote!{ + #[derive(Debug)] + pub struct test1 { + } + + #[derive(Debug)] + pub struct test2 { + } + }; + assert_tokens_equals(generate(input), expected); } } @@ -80,6 +312,37 @@ mod java_generate_tests { let expected = quote!{}; assert_tokens_equals(java_generate_impl(input), expected); } + + #[test] + fn one() { + let input = quote!{ + class TestClass1 {} + }; + let expected = quote!{ + #[derive(Debug)] + pub struct TestClass1 { + } + }; + assert_tokens_equals(java_generate_impl(input), expected); + } + + #[test] + fn multiple() { + let input = quote!{ + class TestClass1 {} + class TestClass2 {} + }; + let expected = quote!{ + #[derive(Debug)] + pub struct TestClass1 { + } + + #[derive(Debug)] + pub struct TestClass2 { + } + }; + assert_tokens_equals(java_generate_impl(input), expected); + } } #[cfg(test)] diff --git a/generator/tests/test.rs b/generator/tests/test.rs index fc5ddbe..49ed2ce 100644 --- a/generator/tests/test.rs +++ b/generator/tests/test.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] extern crate rust_jni_generator; #[cfg(test)] @@ -5,7 +6,10 @@ mod tests { #[allow(unused_imports)] use rust_jni_generator::*; - java_generate!{} + java_generate!{ + class TestClass1 {} + class TestClass2 {} + } #[test] fn test() {}