program.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. use crate::parser;
  2. use crate::{Ix, IxArg, Program, State, StateInterface, StateIx};
  3. const STATE_STRUCT_ATTRIBUTE: &str = "state";
  4. pub fn parse(program_mod: syn::ItemMod) -> Program {
  5. let mod_ident = &program_mod.ident;
  6. let mod_content = &program_mod.content.as_ref().unwrap().1;
  7. // Parse program state.
  8. let state: Option<State> = {
  9. // Parse `struct` marked with the `#[state]` attribute.
  10. let strct: Option<&syn::ItemStruct> = mod_content
  11. .iter()
  12. .filter_map(|item| match item {
  13. syn::Item::Struct(item_strct) => {
  14. let attrs = &item_strct.attrs;
  15. if attrs.is_empty() {
  16. return None;
  17. }
  18. let attr_label = attrs[0].path.get_ident().map(|i| i.to_string());
  19. if attr_label != Some(STATE_STRUCT_ATTRIBUTE.to_string()) {
  20. return None;
  21. }
  22. Some(item_strct)
  23. }
  24. _ => None,
  25. })
  26. .next();
  27. // Parse `impl` block for the state struct.
  28. let impl_block: Option<syn::ItemImpl> = match strct {
  29. None => None,
  30. Some(strct) => mod_content
  31. .iter()
  32. .filter_map(|item| match item {
  33. syn::Item::Impl(item_impl) => {
  34. let impl_ty_str = parser::tts_to_string(&item_impl.self_ty);
  35. let strct_name = strct.ident.to_string();
  36. if item_impl.trait_.is_some() {
  37. return None;
  38. }
  39. if strct_name != impl_ty_str {
  40. return None;
  41. }
  42. Some(item_impl.clone())
  43. }
  44. _ => None,
  45. })
  46. .next(),
  47. };
  48. // Parse ctor and the generic type in `Context<MY-TYPE>`.
  49. let ctor_and_anchor = match &impl_block {
  50. None => None,
  51. Some(impl_block) => {
  52. impl_block
  53. .items
  54. .iter()
  55. .filter_map(|item: &syn::ImplItem| match item {
  56. syn::ImplItem::Method(m) => {
  57. if m.sig.ident.to_string() == "new" {
  58. let ctx_arg = m.sig.inputs.first().unwrap(); // todo: unwrap.
  59. match ctx_arg {
  60. syn::FnArg::Receiver(_) => panic!("invalid syntax"),
  61. syn::FnArg::Typed(arg) => {
  62. Some((m.clone(), extract_ident(&arg).clone()))
  63. }
  64. }
  65. } else {
  66. None
  67. }
  68. }
  69. _ => None,
  70. })
  71. .next()
  72. .clone()
  73. }
  74. };
  75. // Parse all methods in the above `impl` block.
  76. let methods: Option<Vec<StateIx>> = impl_block.as_ref().map(|impl_block| {
  77. impl_block
  78. .items
  79. .iter()
  80. .filter_map(|item: &syn::ImplItem| match item {
  81. syn::ImplItem::Method(m) => match m.sig.inputs.first() {
  82. None => None,
  83. Some(arg) => match arg {
  84. syn::FnArg::Typed(_) => None,
  85. syn::FnArg::Receiver(_) => {
  86. let mut args = m
  87. .sig
  88. .inputs
  89. .iter()
  90. .filter_map(|arg| match arg {
  91. syn::FnArg::Receiver(_) => None,
  92. syn::FnArg::Typed(arg) => Some(arg),
  93. })
  94. .map(|raw_arg| {
  95. let ident = match &*raw_arg.pat {
  96. syn::Pat::Ident(ident) => &ident.ident,
  97. _ => panic!("invalid syntax"),
  98. };
  99. IxArg {
  100. name: ident.clone(),
  101. raw_arg: raw_arg.clone(),
  102. }
  103. })
  104. .collect::<Vec<IxArg>>();
  105. // Remove the Anchor accounts argument
  106. let anchor = args.remove(0);
  107. let anchor_ident = extract_ident(&anchor.raw_arg).clone();
  108. Some(StateIx {
  109. raw_method: m.clone(),
  110. ident: m.sig.ident.clone(),
  111. args,
  112. anchor_ident,
  113. has_receiver: true,
  114. })
  115. }
  116. },
  117. },
  118. _ => None,
  119. })
  120. .collect()
  121. });
  122. // Parse all trait implementations for the above `#[state]` struct.
  123. let trait_impls: Option<Vec<StateInterface>> = strct.map(|_strct| {
  124. mod_content
  125. .iter()
  126. .filter_map(|item| match item {
  127. syn::Item::Impl(item_impl) => {
  128. let trait_name = match &item_impl.trait_ {
  129. None => return None,
  130. Some((_, path, _)) => path
  131. .segments
  132. .iter()
  133. .next()
  134. .expect("Must have one segment in a path")
  135. .ident
  136. .clone()
  137. .to_string(),
  138. };
  139. if item_impl.trait_.is_none() {
  140. return None;
  141. }
  142. let methods = item_impl
  143. .items
  144. .iter()
  145. .filter_map(|item: &syn::ImplItem| match item {
  146. syn::ImplItem::Method(m) => match m.sig.inputs.first() {
  147. None => None,
  148. Some(_arg) => {
  149. let mut has_receiver = false;
  150. let mut args = m
  151. .sig
  152. .inputs
  153. .iter()
  154. .filter_map(|arg| match arg {
  155. syn::FnArg::Receiver(_) => {
  156. has_receiver = true;
  157. None
  158. }
  159. syn::FnArg::Typed(arg) => Some(arg),
  160. })
  161. .map(|raw_arg| {
  162. let ident = match &*raw_arg.pat {
  163. syn::Pat::Ident(ident) => &ident.ident,
  164. _ => panic!("invalid syntax"),
  165. };
  166. IxArg {
  167. name: ident.clone(),
  168. raw_arg: raw_arg.clone(),
  169. }
  170. })
  171. .collect::<Vec<IxArg>>();
  172. // Remove the Anchor accounts argument
  173. let anchor = args.remove(0);
  174. let anchor_ident = extract_ident(&anchor.raw_arg).clone();
  175. Some(StateIx {
  176. raw_method: m.clone(),
  177. ident: m.sig.ident.clone(),
  178. args,
  179. anchor_ident,
  180. has_receiver,
  181. })
  182. }
  183. },
  184. _ => None,
  185. })
  186. .collect();
  187. Some(StateInterface {
  188. trait_name,
  189. methods,
  190. })
  191. }
  192. _ => None,
  193. })
  194. .collect::<Vec<StateInterface>>()
  195. });
  196. // Put it all together.
  197. strct.map(|strct| {
  198. // Chop off the `#[state]` attribute. It's just a marker.
  199. let mut strct = strct.clone();
  200. strct.attrs = vec![];
  201. State {
  202. name: strct.ident.to_string(),
  203. strct: strct.clone(),
  204. interfaces: trait_impls,
  205. impl_block_and_methods: impl_block
  206. .map(|impl_block| (impl_block.clone(), methods.unwrap())),
  207. ctor_and_anchor,
  208. }
  209. })
  210. };
  211. // Parse all non-state ix handlers.
  212. let ixs: Vec<Ix> = mod_content
  213. .iter()
  214. .filter_map(|item| match item {
  215. syn::Item::Fn(item_fn) => Some(item_fn),
  216. _ => None,
  217. })
  218. .map(|method: &syn::ItemFn| {
  219. let mut args: Vec<IxArg> = method
  220. .sig
  221. .inputs
  222. .iter()
  223. .map(|arg: &syn::FnArg| match arg {
  224. syn::FnArg::Typed(arg) => {
  225. let ident = match &*arg.pat {
  226. syn::Pat::Ident(ident) => &ident.ident,
  227. _ => panic!("invalid syntax"),
  228. };
  229. IxArg {
  230. name: ident.clone(),
  231. raw_arg: arg.clone(),
  232. }
  233. }
  234. _ => panic!("invalid syntax"),
  235. })
  236. .collect();
  237. // Remove the Context argument
  238. let anchor = args.remove(0);
  239. let anchor_ident = extract_ident(&anchor.raw_arg).clone();
  240. Ix {
  241. raw_method: method.clone(),
  242. ident: method.sig.ident.clone(),
  243. args,
  244. anchor_ident,
  245. }
  246. })
  247. .collect();
  248. Program {
  249. state,
  250. ixs,
  251. name: mod_ident.clone(),
  252. program_mod,
  253. }
  254. }
  255. fn extract_ident(path_ty: &syn::PatType) -> &proc_macro2::Ident {
  256. let p = match &*path_ty.ty {
  257. syn::Type::Path(p) => &p.path,
  258. _ => panic!("invalid syntax"),
  259. };
  260. let segment = p.segments.first().unwrap();
  261. let generic_args = match &segment.arguments {
  262. syn::PathArguments::AngleBracketed(args) => args,
  263. _ => panic!("invalid syntax"),
  264. };
  265. let generic_ty = generic_args
  266. .args
  267. .iter()
  268. .filter_map(|arg| match arg {
  269. syn::GenericArgument::Type(ty) => Some(ty),
  270. _ => None,
  271. })
  272. .next()
  273. .unwrap();
  274. let path = match generic_ty {
  275. syn::Type::Path(ty_path) => &ty_path.path,
  276. _ => panic!("invalid syntax"),
  277. };
  278. &path.segments[0].ident
  279. }