Guest User

Untitled

a guest
Jun 23rd, 2018
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.55 KB | None | 0 0
  1. extern crate syn;
  2. #[macro_use]
  3. extern crate quote;
  4. extern crate proc_macro2;
  5.  
  6. use quote::ToTokens;
  7. use proc_macro2::{Ident, Span};
  8.  
  9. /**
  10. * Generate a boilerplate for a plural rule function.
  11. */
  12. fn create_boilerplate_from_quote() -> syn::File {
  13. let locale = "en";
  14. let plural_type = "cardinal";
  15. // let fn_name = format!("pr_{}_{}", locale, plural_type);
  16. let fnname = "pr_en";
  17. let boilerplate_tokens = quote! {
  18. fn pr_en (po: PluralOperands) -> PluralCategory {}
  19. };
  20. syn::parse2(boilerplate_tokens).expect("Unable to parse boilerplate")
  21. }
  22.  
  23. // This is a bit too high level since this one creates a full clause for `one` for
  24. // english, cardinal. But for now, it gives us a good starting point to get
  25. // an AST for the en, cardinal `one` rule.
  26. fn create_en_one_clause() -> syn::Expr {
  27. let one_clause_tokens = quote! {
  28. if po.i == 1 { return PluralCategory::ONE }
  29. };
  30. syn::parse2(one_clause_tokens).expect("Unable to parse tokens")
  31. }
  32.  
  33. // This is just a generic return clause for `other`.
  34. fn create_en_other_clause() -> syn::Expr {
  35. let s = "PluralCategory::OTHER";
  36. let result = syn::parse_str(s).expect("Unable to parse boilerplate");
  37. return result;
  38. }
  39.  
  40. /**
  41. * This function takes the file AST and adds an expression as a block
  42. * to its first function's body.
  43. *
  44. * This is what we'll use to inject blocks into the body.
  45. */
  46. fn add_block(f: &mut syn::File, b: syn::Expr) {
  47. let func = &mut f.items[0];
  48. match func {
  49. syn::Item::Fn(ref mut f) => {
  50. let block = &mut f.block;
  51. let stmts = &mut block.stmts;
  52. stmts.push(syn::Stmt::Expr(b));
  53. },
  54. _ => panic!("Unknown boilerplate")
  55. };
  56. }
  57.  
  58. fn main() {
  59. // 1. Get the boilerplate AST
  60. let mut result = create_boilerplate_from_quote();
  61.  
  62. // 2. Get the `one` block
  63. let one = create_en_one_clause();
  64. // 3. Get the `other` block
  65. let other = create_en_other_clause();
  66.  
  67. // 4. Insert them in order
  68. add_block(&mut result, one);
  69. add_block(&mut result, other);
  70.  
  71. // Print the result function.
  72. println!("{}", result.into_token_stream().to_string());
  73. }
  74.  
  75.  
  76. /**
  77. * This is just an insight into how the AST look. We're actually *not*
  78. * going to use this function at all :)
  79. */
  80. fn _create_boilerplate() -> syn::File {
  81. let mut segments: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2> = syn::punctuated::Punctuated::new();
  82. segments.push(syn::PathSegment {
  83. ident: Ident::new("PluralOperands", Span::call_site()),
  84. arguments: syn::PathArguments::None
  85. });
  86.  
  87. let mut pc_segments: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2> = syn::punctuated::Punctuated::new();
  88. pc_segments.push(syn::PathSegment {
  89. ident: Ident::new("PluralCategory", Span::call_site()),
  90. arguments: syn::PathArguments::None
  91. });
  92.  
  93. let mut inputs: syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma> = syn::punctuated::Punctuated::new();
  94. inputs.push_value(
  95. syn::FnArg::Captured(
  96. syn::ArgCaptured {
  97. pat: syn::Pat::Ident(
  98. syn::PatIdent {
  99. by_ref: None,
  100. mutability: None,
  101. ident: Ident::new("po", Span::call_site()),
  102. subpat: None,
  103. }
  104. ),
  105. colon_token: syn::token::Colon::new(Span::call_site()),
  106. ty: syn::Type::Path(
  107. syn::TypePath {
  108. qself: None,
  109. path: syn::Path {
  110. leading_colon: None,
  111. segments
  112. }
  113. }
  114. ),
  115. }
  116. ));
  117.  
  118. let syntax2 = syn::File {
  119. shebang: None,
  120. attrs: vec![],
  121. items: vec![
  122. syn::Item::Fn(
  123. syn::ItemFn {
  124. attrs: vec![],
  125. vis: syn::Visibility::Inherited,
  126. constness: None,
  127. unsafety: None,
  128. abi: None,
  129. ident: Ident::new("en_cardinal", Span::call_site()),
  130. decl: Box::new(syn::FnDecl {
  131. fn_token: syn::token::Fn(Span::call_site()),
  132. generics: syn::Generics {
  133. lt_token: None,
  134. params: syn::punctuated::Punctuated::new(),
  135. gt_token: None,
  136. where_clause: None,
  137. },
  138. paren_token: syn::token::Paren(Span::call_site()),
  139. inputs,
  140. variadic: None,
  141. output: syn::ReturnType::Type(
  142. syn::token::RArrow::new(Span::call_site()),
  143. Box::new(syn::Type::Path(syn::TypePath {
  144. qself: None,
  145. path: syn::Path {
  146. leading_colon: None,
  147. segments: pc_segments
  148. }
  149. }))
  150. ),
  151. }),
  152. block: Box::new(syn::Block {
  153. brace_token: syn::token::Brace(Span::call_site()),
  154. stmts: vec![]
  155. })
  156. }
  157. )
  158. ]
  159. };
  160. return syntax2;
  161. }
Add Comment
Please, Sign In to add comment