file.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. use crate::idl::*;
  2. use crate::parser::anchor;
  3. use crate::parser::program;
  4. use crate::AccountsStruct;
  5. use anyhow::Result;
  6. use quote::ToTokens;
  7. use std::collections::{HashMap, HashSet};
  8. use std::fs::File;
  9. use std::io::Read;
  10. static DERIVE_NAME: &'static str = "Accounts";
  11. // Parse an entire interface file.
  12. pub fn parse(filename: &str) -> Result<Idl> {
  13. let mut file = File::open(&filename)?;
  14. let mut src = String::new();
  15. file.read_to_string(&mut src).expect("Unable to read file");
  16. let f = syn::parse_file(&src).expect("Unable to parse file");
  17. let p = program::parse(parse_program_mod(&f));
  18. let accs = parse_accounts(&f);
  19. let acc_names = {
  20. let mut acc_names = HashSet::new();
  21. for accs_strct in accs.values() {
  22. for a in accs_strct.account_tys() {
  23. acc_names.insert(a);
  24. }
  25. }
  26. acc_names
  27. };
  28. let instructions = p
  29. .rpcs
  30. .iter()
  31. .map(|rpc| {
  32. let args = rpc
  33. .args
  34. .iter()
  35. .map(|arg| {
  36. let mut tts = proc_macro2::TokenStream::new();
  37. arg.raw_arg.ty.to_tokens(&mut tts);
  38. let ty = tts.to_string().parse().unwrap();
  39. IdlField {
  40. name: arg.name.to_string(),
  41. ty,
  42. }
  43. })
  44. .collect::<Vec<_>>();
  45. // todo: don't unwrap
  46. let accounts_strct = accs.get(&rpc.anchor_ident.to_string()).unwrap();
  47. let accounts = accounts_strct
  48. .fields
  49. .iter()
  50. .map(|acc| IdlAccount {
  51. name: acc.ident.to_string(),
  52. is_mut: acc.is_mut,
  53. is_signer: acc.is_signer,
  54. })
  55. .collect::<Vec<_>>();
  56. IdlInstruction {
  57. name: rpc.ident.to_string(),
  58. accounts,
  59. args,
  60. }
  61. })
  62. .collect::<Vec<_>>();
  63. // All user defined types.
  64. let mut accounts = vec![];
  65. let mut types = vec![];
  66. let ty_defs = parse_ty_defs(&f)?;
  67. for ty_def in ty_defs {
  68. if acc_names.contains(&ty_def.name) {
  69. accounts.push(ty_def);
  70. } else {
  71. types.push(ty_def);
  72. }
  73. }
  74. Ok(Idl {
  75. version: "0.0.0".to_string(),
  76. name: p.name.to_string(),
  77. instructions,
  78. types,
  79. accounts,
  80. })
  81. }
  82. // Parse the main program mod.
  83. fn parse_program_mod(f: &syn::File) -> syn::ItemMod {
  84. let mods = f
  85. .items
  86. .iter()
  87. .filter_map(|i| match i {
  88. syn::Item::Mod(item_mod) => {
  89. let mods = item_mod
  90. .attrs
  91. .iter()
  92. .filter_map(|attr| {
  93. let segment = attr.path.segments.last().unwrap();
  94. if segment.ident.to_string() == "program" {
  95. return Some(attr);
  96. }
  97. None
  98. })
  99. .collect::<Vec<_>>();
  100. if mods.len() != 1 {
  101. panic!("invalid program attribute");
  102. }
  103. Some(item_mod)
  104. }
  105. _ => None,
  106. })
  107. .collect::<Vec<_>>();
  108. assert!(mods.len() == 1);
  109. mods[0].clone()
  110. }
  111. // Parse all structs deriving the `Accounts` macro.
  112. fn parse_accounts(f: &syn::File) -> HashMap<String, AccountsStruct> {
  113. f.items
  114. .iter()
  115. .filter_map(|i| match i {
  116. syn::Item::Struct(i_strct) => {
  117. for attr in &i_strct.attrs {
  118. if attr.tokens.to_string().contains(DERIVE_NAME) {
  119. let strct = anchor::parse(i_strct);
  120. return Some((strct.ident.to_string(), strct));
  121. }
  122. }
  123. None
  124. }
  125. _ => None,
  126. })
  127. .collect()
  128. }
  129. // Parse all user defined types in the file.
  130. fn parse_ty_defs(f: &syn::File) -> Result<Vec<IdlTypeDef>> {
  131. f.items
  132. .iter()
  133. .filter_map(|i| match i {
  134. syn::Item::Struct(item_strct) => {
  135. for attr in &item_strct.attrs {
  136. if attr.tokens.to_string().contains(DERIVE_NAME) {
  137. return None;
  138. }
  139. }
  140. if let syn::Visibility::Public(_) = &item_strct.vis {
  141. let name = item_strct.ident.to_string();
  142. let fields = match &item_strct.fields {
  143. syn::Fields::Named(fields) => fields
  144. .named
  145. .iter()
  146. .map(|f| {
  147. let mut tts = proc_macro2::TokenStream::new();
  148. f.ty.to_tokens(&mut tts);
  149. Ok(IdlField {
  150. name: f.ident.as_ref().unwrap().to_string(),
  151. ty: tts.to_string().parse()?,
  152. })
  153. })
  154. .collect::<Result<Vec<IdlField>>>(),
  155. _ => panic!("Only named structs are allowed."),
  156. };
  157. return Some(fields.map(|fields| IdlTypeDef {
  158. name,
  159. ty: IdlTypeDefTy::Struct { fields },
  160. }));
  161. }
  162. None
  163. }
  164. _ => None,
  165. })
  166. .collect()
  167. }