Skip to main content

seahorse_dev/core/generate/
mod.rs

1use crate::{
2    core::{compile::ast::*, compile::build::BuildOutput, util::*, CoreError},
3    match1,
4};
5use proc_macro2::{Ident, Literal as PM2Literal, TokenStream};
6use quote::{format_ident, quote, ToTokens};
7use regex::Regex;
8#[cfg(not(target_arch = "wasm32"))]
9use rustfmt_wrapper::{config::*, rustfmt_config, Error as RustfmtError};
10use std::{cell::RefCell, collections::BTreeSet, rc::Rc};
11
12use super::compile::builtin::prelude::MethodType;
13
14pub struct GenerateOutput {
15    pub tree: Tree<String>,
16    pub features: BTreeSet<Feature>,
17}
18
19/// A set of features that need to be turned on in order to compile an artifact.
20#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
21pub enum Feature {
22    Pyth,
23}
24
25impl Feature {
26    pub fn name(&self) -> &'static str {
27        match self {
28            Self::Pyth => "pyth-sdk-solana",
29        }
30    }
31}
32
33/// Convenience function for turning strings into Idents
34fn ident<S: ToString>(name: &S) -> Ident {
35    format_ident!("{}", name.to_string())
36}
37
38/// Newtype for a `::`-separated path.
39struct StaticPath<'a>(&'a Vec<String>);
40impl ToTokens for StaticPath<'_> {
41    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
42        let Self(path) = self;
43        let path = path.iter().map(|part| ident(part));
44
45        tokens.extend(quote! { #(#path)::* });
46    }
47}
48
49impl ToTokens for Artifact {
50    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
51        let Self {
52            constants,
53            uses,
54            type_defs,
55            functions,
56            ..
57        } = self;
58
59        tokens.extend(quote! {
60            #![allow(unused_imports)]
61            #![allow(unused_variables)]
62            #![allow(unused_mut)]
63
64            // Default imports
65            use crate::{id, seahorse_util::*};
66            use std::{rc::Rc, cell::RefCell};
67            use anchor_lang::{prelude::*, solana_program};
68            // TODO might not need these, contexts are defined in lib.rs now
69            use anchor_spl::token::{self, Token, Mint, TokenAccount};
70
71            #(#uses)*
72            #(#constants)*
73            #(#type_defs)*
74            #(#functions)*
75        });
76    }
77}
78
79impl ToTokens for Use {
80    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
81        let Use { rooted, tree } = self;
82
83        if !tree.is_dead() {
84            tokens.extend(if *rooted {
85                quote! { use crate::#tree; }
86            } else {
87                quote! { use #tree; }
88            });
89        }
90    }
91}
92
93impl ToTokens for Tree<Option<String>> {
94    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
95        tokens.extend(match self {
96            Self::Leaf(None) => quote! {},
97            Self::Leaf(Some(alias)) => {
98                let alias = ident(alias);
99
100                quote! { as #alias }
101            }
102            Self::Node(node) => {
103                let node = node
104                    .iter()
105                    .filter_map(|(name, tree)| {
106                        if tree.is_dead() {
107                            return None;
108                        }
109
110                        let name = ident(name);
111
112                        match tree {
113                            Tree::Leaf(None) => Some(quote! { #name }),
114                            Tree::Leaf(Some(alias)) => {
115                                let alias = ident(alias);
116
117                                Some(quote! { #name as #alias })
118                            }
119                            tree @ Tree::Node(..) => Some(quote! { #name::#tree }),
120                        }
121                    })
122                    .collect::<Vec<_>>();
123
124                if node.len() == 1 {
125                    quote! { #(#node)* }
126                } else {
127                    quote! { {#(#node),*} }
128                }
129            }
130        })
131    }
132}
133
134impl ToTokens for Constant {
135    fn to_tokens(&self, tokens: &mut TokenStream) {
136        let Self { name, value } = self;
137        let name = ident(name);
138
139        tokens.extend(quote! {
140            seahorse_const! { #name, #value }
141        });
142    }
143}
144
145impl ToTokens for TypeDef {
146    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
147        tokens.extend(match self {
148            Self::Struct(type_def) => quote! { #type_def },
149            Self::Account(type_def) => quote! { #type_def },
150            Self::Enum(type_def) => quote! { #type_def },
151        });
152    }
153}
154
155fn loaded_field(expr: TokenStream, ty: &TyExpr) -> TokenStream {
156    let ty_expr = StoredTyExpr(ty);
157
158    match ty {
159        // Vec<T> special case, works a bit like Array
160        TyExpr::Generic { name, params, .. } if name == &["Vec"] => {
161            let inner = loaded_field(quote! { element }, &params[0]);
162
163            quote! {
164                Mutable::new(#expr.into_iter().map(|element| #inner).collect())
165            }
166        }
167        TyExpr::Generic {
168            is_loadable,
169            mutability,
170            ..
171        } => {
172            let inner = match is_loadable {
173                false => quote! { #expr },
174                true => quote! { #ty_expr::load(#expr) },
175            };
176
177            match mutability {
178                Mutability::Immutable => inner,
179                Mutability::Mutable => quote! { Mutable::new(#inner) },
180            }
181        }
182        TyExpr::Array { element, .. } => {
183            let inner = loaded_field(quote! { element }, &**element);
184
185            quote! { Mutable::new(#expr.map(|element| #inner)) }
186        }
187        TyExpr::Tuple(tuple) => {
188            let inner = tuple
189                .iter()
190                .enumerate()
191                .map(|(index, ty)| loaded_field(quote! { tuple.#index }, ty));
192
193            quote! {
194                {
195                    let tuple = #expr;
196                    (#(#inner),*)
197                }
198            }
199        }
200        _ => todo!(),
201    }
202}
203
204fn stored_field(expr: TokenStream, ty: &TyExpr) -> TokenStream {
205    let ty_expr = StoredTyExpr(ty);
206
207    match ty {
208        TyExpr::Generic { name, params, .. } if name == &["Vec"] => {
209            let inner = stored_field(quote! { element }, &params[0]);
210
211            quote! {
212                #expr.borrow().clone().into_iter().map(|element| #inner).collect()
213            }
214        }
215        TyExpr::Generic {
216            is_loadable,
217            mutability,
218            ..
219        } => {
220            let inner = match mutability {
221                Mutability::Immutable => expr,
222                Mutability::Mutable => quote! { #expr.borrow().clone() },
223            };
224
225            match is_loadable {
226                false => inner,
227                true => quote! { #ty_expr::store(#inner) },
228            }
229        }
230        TyExpr::Array { element, .. } => {
231            let inner = stored_field(quote! { element }, &**element);
232
233            quote! {
234                #expr.borrow().clone().map(|element| #inner)
235            }
236        }
237        TyExpr::Tuple(tuple) => {
238            let inner = tuple
239                .iter()
240                .enumerate()
241                .map(|(index, ty)| stored_field(quote! { tuple.#index }, ty));
242
243            quote! {
244                {
245                    let tuple = #expr;
246                    (#(#inner),*)
247                }
248            }
249        }
250        _ => todo!(),
251    }
252}
253
254impl ToTokens for Struct {
255    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
256        let Self {
257            name,
258            fields,
259            methods,
260            constructor,
261            is_event,
262            is_dataclass,
263        } = self;
264        let stored_name = ident(name);
265        let name = ident(&format!("Loaded{}", name));
266
267        let mut instance_methods = vec![];
268        let mut static_methods = vec![];
269
270        if let Some(func) = constructor {
271            // This might look esoteric but it's actually pretty much exactly how Python uses
272            // constructors under the hood - a __new__ method calls the user-defined __init__ to
273            // perform the heavy lifting of the constructor.
274            let ext_params = func.params.iter().map(|(name, ty)| {
275                let name = ident(name);
276                let ty = LoadedTyExpr(ty);
277
278                quote! { #name: #ty }
279            });
280
281            let ext_param_names = func.params.iter().map(|(name, _)| {
282                let name = ident(name);
283
284                quote! { #name }
285            });
286
287            let func = InstanceMethod(func);
288
289            instance_methods.push(quote! { #func });
290
291            static_methods.push(quote! {
292                pub fn __new__(#(#ext_params),*) -> Mutable<Self> {
293                    let obj = Mutable::new(#name::default());
294                    obj.__init__(#(#ext_param_names),*);
295                    return obj;
296                }
297            });
298        } else if *is_dataclass {
299            let ctor_params = fields.iter().map(|(name, ty_expr, _)| {
300                let name = ident(name);
301                let ty_expr = LoadedTyExpr(ty_expr);
302
303                quote! { #name: #ty_expr }
304            });
305
306            let ctor_param_names = fields.iter().map(|(name, _, _)| {
307                let name = ident(name);
308
309                quote! { #name }
310            });
311
312            static_methods.push(quote! {
313                pub fn __new__(#(#ctor_params), *) -> Mutable<Self> {
314                    let obj = #name { #(#ctor_param_names),* };
315                    return Mutable::new(obj);
316                }
317            });
318        }
319
320        for (method_type, func) in methods.iter() {
321            match method_type {
322                MethodType::Instance => {
323                    let method = InstanceMethod(func);
324
325                    instance_methods.push(quote! { #method });
326                }
327                MethodType::Static => {
328                    static_methods.push(quote! { #func });
329                }
330            }
331        }
332
333        // Split up the instance methods and static methods: each instance method of a class will
334        // belong to an `impl Mutable<Class>` block, and the static methods will belong to an
335        // `impl Class` block.
336
337        let event_emit_fn = if *is_event {
338            let fs = fields.iter().map(|(name, ty, original_ty)| {
339                let name = ident(name);
340
341                let needs_clone = !original_ty.is_copy();
342                let field = if needs_clone {
343                    quote! { e.#name.clone() }
344                } else {
345                    quote! { e.#name }
346                };
347
348                let field = stored_field(quote! { #field }, ty);
349
350                quote! { #name: #field }
351            });
352
353            Some(quote! {
354                fn __emit__(&self) {
355                    let e = self.borrow();
356                    emit!(#stored_name { #(#fs),* })
357                }
358            })
359        } else {
360            None
361        };
362
363        let instance_impl = if instance_methods.len() > 0 || event_emit_fn.is_some() {
364            Some(quote! { impl Mutable<#name> {
365                #(#instance_methods)*
366
367                #event_emit_fn
368            }})
369        } else {
370            None
371        };
372
373        let static_impl = if static_methods.len() > 0 {
374            Some(quote! { impl #name { #(#static_methods)* } })
375        } else {
376            None
377        };
378
379        let stored_macros = if *is_event {
380            quote! { #[event] }
381        } else {
382            quote! { #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] }
383        };
384
385        let macros = quote! { #[derive(Clone, Debug, Default)] };
386
387        let stored_fields = fields.iter().map(|(name, ty, _)| {
388            let name = ident(name);
389            let ty = StoredTyExpr(ty);
390
391            quote! { pub #name: #ty }
392        });
393
394        let load_fields = fields.iter().map(|(name, ty, _)| {
395            let name = ident(name);
396            let field = loaded_field(quote! { stored.#name }, ty);
397
398            quote! { #name: #field }
399        });
400
401        let store_fields = fields.iter().map(|(name, ty, orig_ty)| {
402            let name = ident(name);
403            let field = if orig_ty.is_copy() {
404                quote! { loaded.#name }
405            } else {
406                quote! { loaded.#name.clone() }
407            };
408            let field = stored_field(field, ty);
409
410            quote! { #name: #field }
411        });
412
413        let fields = fields.iter().map(|(name, ty, _)| {
414            let name = ident(name);
415            let ty = LoadedTyExpr(ty);
416
417            quote! { pub #name: #ty }
418        });
419
420        tokens.extend(quote! {
421            #stored_macros
422            pub struct #stored_name { #(#stored_fields),* }
423
424            #macros
425            pub struct #name { #(#fields),* }
426
427            #instance_impl
428
429            #static_impl
430
431            impl Loadable for #stored_name {
432                type Loaded = #name;
433
434                fn load(stored: Self) -> Self::Loaded {
435                    Self::Loaded { #(#load_fields),* }
436                }
437
438                fn store(loaded: Self::Loaded) -> Self {
439                    Self { #(#store_fields),* }
440                }
441            }
442        });
443    }
444}
445
446impl ToTokens for Account {
447    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
448        let Self {
449            name,
450            fields,
451            methods,
452        } = self;
453
454        let account_name = ident(name);
455        let loaded_name = ident(&format!("Loaded{}", name));
456
457        let account_fields = fields.iter().map(|(name, ty, _)| {
458            let name = ident(name);
459            let ty = StoredTyExpr(ty);
460
461            quote! { pub #name: #ty }
462        });
463
464        let loaded_fields = fields.iter().map(|(name, ty_expr, _)| {
465            let name = ident(name);
466            let ty_expr = LoadedTyExpr(ty_expr);
467
468            quote! { pub #name: #ty_expr }
469        });
470
471        let loads = fields.iter().map(|(name, ty, orig_ty)| {
472            let name = ident(name);
473            let field = if orig_ty.is_copy() {
474                quote! { account.#name }
475            } else {
476                quote! { account.#name.clone() }
477            };
478            let field = loaded_field(field, ty);
479
480            quote! { let #name = #field; }
481        });
482
483        let field_names = fields.iter().map(|(name, ..)| {
484            let name = ident(name);
485
486            quote! { #name }
487        });
488
489        let store_fields = fields.iter().map(|(name, ty, orig_ty)| {
490            let name = ident(name);
491            let field = if orig_ty.is_copy() {
492                quote! { loaded.#name }
493            } else {
494                quote! { loaded.#name.clone() }
495            };
496            let field = stored_field(field, ty);
497
498            quote! {
499                let #name = #field;
500                loaded.__account__.#name = #name;
501            }
502        });
503
504        let mut instance_methods = vec![];
505        let mut static_methods = vec![];
506
507        for (method_type, func) in methods.iter() {
508            match method_type {
509                MethodType::Instance => {
510                    let method = InstanceMethod(func);
511
512                    instance_methods.push(quote! { #method });
513                }
514                MethodType::Static => {
515                    static_methods.push(quote! { #func });
516                }
517            }
518        }
519
520        // Like regular structs, split up the instance methods and static methods: each instance
521        // method of an account will belong to an `impl Mutable<LoadedAccount<'_, '_>>` block, and
522        // the static methods will belong to the original `impl Account` block.
523
524        let instance_impl = if instance_methods.len() > 0 {
525            Some(quote! { impl Mutable<#loaded_name<'_, '_>> { #(#instance_methods)* } })
526        } else {
527            None
528        };
529
530        tokens.extend(quote! {
531            #[account]
532            #[derive(Debug)]
533            pub struct #account_name { #(#account_fields),* }
534
535            impl<'info, 'entrypoint> #account_name {
536                pub fn load(account: &'entrypoint mut Box<Account<'info, Self>>, programs_map: &'entrypoint ProgramsMap<'info>) -> Mutable<#loaded_name<'info, 'entrypoint>> {
537                    #(#loads)*
538                    Mutable::new(#loaded_name {
539                        __account__: account,
540                        __programs__: programs_map,
541                        #(#field_names),*
542                    })
543                }
544
545                pub fn store(loaded: Mutable<#loaded_name>) {
546                    let mut loaded = loaded.borrow_mut();
547                    #(#store_fields)*
548                }
549
550                #(#static_methods)*
551            }
552
553            #[derive(Debug)]
554            pub struct #loaded_name<'info, 'entrypoint> {
555                pub __account__: &'entrypoint mut Box<Account<'info, #account_name>>,
556                pub __programs__: &'entrypoint ProgramsMap<'info>,
557                #(#loaded_fields),*
558            }
559
560            #instance_impl
561        });
562    }
563}
564
565impl ToTokens for Enum {
566    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
567        let Self { name, variants } = self;
568        let name = ident(name);
569        let variants_tokens = variants.iter().map(|(name, _)| {
570            let name = ident(name);
571
572            quote! { #name }
573        });
574
575        let (first_variant, _) = &variants[0];
576        let first_variant = ident(first_variant);
577
578        tokens.extend(quote! {
579            #[derive(Clone, Debug, PartialEq, AnchorSerialize, AnchorDeserialize, Copy)]
580            pub enum #name {
581                #(#variants_tokens),*
582            }
583
584            impl Default for #name {
585                fn default() -> Self {
586                    #name::#first_variant
587                }
588            }
589        });
590    }
591}
592
593/// Newtype to display the "loaded" (used at runtime) type of a type expression.
594///
595/// Note that there isn't a `ToTokens` implementation for `TyExpr` itself - you
596/// need to choose either `LoadedTyExpr` or `StoredTyExpr` for context.
597pub struct LoadedTyExpr<'a>(pub &'a TyExpr);
598impl<'a> ToTokens for LoadedTyExpr<'a> {
599    // Mutability is relevant in this context and defined types need to be their Loaded- counterpart
600    fn to_tokens(&self, tokens: &mut TokenStream) {
601        tokens.extend(match self.0 {
602            TyExpr::Generic {
603                name,
604                params,
605                mutability,
606                is_loadable,
607            } => {
608                let path = StaticPath(name);
609                let params = match params.len() {
610                    0 => quote! {},
611                    _ => {
612                        let params = params.iter().map(|param| LoadedTyExpr(param));
613
614                        quote! { <#(#params),*> }
615                    }
616                };
617
618                let inner = if *is_loadable {
619                    quote! { Loaded!(#path #params) }
620                } else {
621                    quote! { #path #params }
622                };
623
624                match mutability {
625                    Mutability::Immutable => inner,
626                    Mutability::Mutable => quote! { Mutable<#inner> },
627                }
628            }
629            TyExpr::Array { element, size } => {
630                let element = LoadedTyExpr(element.as_ref());
631                let size = LoadedTyExpr(size.as_ref());
632
633                quote! { Mutable<[#element; #size]> }
634            }
635            TyExpr::Tuple(tuple) => {
636                let tuple = tuple.iter().map(|element| LoadedTyExpr(element));
637
638                quote! { (#(#tuple),*) }
639            }
640            TyExpr::Account(path) => {
641                let mut path = path.clone();
642                *path.last_mut().unwrap() = format!("Loaded{}", path.last().unwrap());
643                let path = StaticPath(&path);
644
645                quote! { Mutable<#path<'info, '_>> }
646            }
647            TyExpr::Const(size) => {
648                let size = PM2Literal::usize_unsuffixed(*size);
649
650                quote! { #size }
651            }
652            TyExpr::InfoLifetime => quote! { 'info },
653            TyExpr::AnonLifetime => quote! { '_ },
654        })
655    }
656}
657
658/// Newtype to display the "stored" (used in on-chain interface) type of a type expression.
659struct StoredTyExpr<'a>(&'a TyExpr);
660impl<'a> ToTokens for StoredTyExpr<'a> {
661    // Mutability is irrelevant in this context
662    fn to_tokens(&self, tokens: &mut TokenStream) {
663        tokens.extend(match self.0 {
664            TyExpr::Generic { name, params, .. } => {
665                let path = StaticPath(name);
666                let params = match params.len() {
667                    0 => quote! {},
668                    _ => {
669                        let params = params.iter().map(|param| StoredTyExpr(param));
670
671                        quote! { <#(#params),*> }
672                    }
673                };
674
675                quote! { #path #params }
676            }
677            TyExpr::Array { element, size } => {
678                let element = StoredTyExpr(element.as_ref());
679                let size = StoredTyExpr(size.as_ref());
680
681                quote! { [#element; #size] }
682            }
683            TyExpr::Tuple(tuple) => {
684                let tuple = tuple.iter().map(|element| LoadedTyExpr(element));
685
686                quote! { (#(#tuple),*) }
687            }
688            TyExpr::Account(path) => {
689                let path = StaticPath(&path);
690
691                quote! { #path<'info, '_> }
692            }
693            TyExpr::Const(size) => {
694                let size = PM2Literal::usize_unsuffixed(*size);
695
696                quote! { #size }
697            }
698            TyExpr::InfoLifetime => quote! { 'info },
699            TyExpr::AnonLifetime => quote! { '_ },
700        })
701    }
702}
703
704impl ToTokens for Function {
705    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
706        let Self {
707            ix_context,
708            name,
709            info_lifetime,
710            params,
711            returns,
712            body,
713        } = self;
714
715        let name = if ix_context.is_some() {
716            ident(&format!("{}_handler", name))
717        } else {
718            ident(name)
719        };
720
721        let info_lifetime = if *info_lifetime {
722            Some(quote! { <'info> })
723        } else {
724            None
725        };
726
727        let params = params.iter().map(|(name, ty)| {
728            let name = ident(name);
729            let ty = LoadedTyExpr(ty);
730
731            quote! { mut #name: #ty }
732        });
733
734        let returns = LoadedTyExpr(returns);
735
736        tokens.extend(quote! {
737            pub fn #name #info_lifetime(#(#params),*) -> #returns #body
738        });
739    }
740}
741
742/// Newtype for an instance method of a mutable type.
743struct InstanceMethod<'a>(&'a Function);
744
745impl<'a> ToTokens for InstanceMethod<'a> {
746    fn to_tokens(&self, tokens: &mut TokenStream) {
747        let Function {
748            ix_context,
749            name,
750            info_lifetime,
751            params,
752            returns,
753            body,
754        } = self.0;
755
756        let name = if ix_context.is_some() {
757            ident(&format!("{}_handler", name))
758        } else {
759            ident(name)
760        };
761
762        let info_lifetime = if *info_lifetime {
763            Some(quote! { <'info> })
764        } else {
765            None
766        };
767
768        let params = [quote! { &self }]
769            .into_iter()
770            .chain(params.iter().map(|(name, ty)| {
771                let name = ident(name);
772                let ty = LoadedTyExpr(ty);
773
774                quote! { mut #name: #ty }
775            }));
776
777        let returns = LoadedTyExpr(returns);
778
779        tokens.extend(quote! {
780            pub fn #name #info_lifetime(#(#params),*) -> #returns #body
781        });
782    }
783}
784
785impl ToTokens for InstructionContext {
786    fn to_tokens(&self, tokens: &mut TokenStream) {
787        let Self {
788            name,
789            params,
790            accounts,
791            inferred_accounts,
792        } = self;
793
794        let name = ident(name);
795
796        let params = match params.len() {
797            0 => quote! {},
798            _ => {
799                let params = params.iter().map(|(name, ty_expr)| {
800                    let name = ident(name);
801                    let ty_expr = StoredTyExpr(ty_expr);
802
803                    quote! { #name: #ty_expr }
804                });
805
806                quote! {
807                    #[instruction(#(#params),*)]
808                }
809            }
810        };
811
812        let accounts =
813            accounts
814                .iter()
815                .map(
816                    |(
817                        name,
818                        ContextAccount {
819                            annotation,
820                            account_ty,
821                            // ty,
822                            ..
823                        },
824                    )| {
825                        let name = ident(name);
826                        let annotation = annotation
827                            .as_ref()
828                            .map(|annotation| AccountAnnotationWithTyExpr(annotation, account_ty));
829
830                        quote! {
831                            #annotation
832                            pub #name: #account_ty
833                        }
834                    },
835                )
836                .chain(inferred_accounts.iter().map(
837                    |(name, ContextAccount { account_ty, .. })| {
838                        let name = ident(name);
839
840                        quote! {
841                            pub #name: #account_ty
842                        }
843                    },
844                ));
845
846        tokens.extend(quote! {
847            #[derive(Accounts)]
848            #params
849            pub struct #name<'info> { #(#accounts),* }
850        })
851    }
852}
853
854impl ToTokens for AccountTyExpr {
855    fn to_tokens(&self, tokens: &mut TokenStream) {
856        tokens.extend(match self {
857            Self::Empty(ty_expr) => {
858                quote! { #ty_expr }
859            }
860            Self::Defined(ty_expr) => {
861                let ty_expr = StaticPath(ty_expr);
862
863                quote! { Box<Account<'info, #ty_expr>> }
864            }
865            Self::Signer => quote! { Signer<'info> },
866            Self::TokenMint => quote! { Box<Account<'info, Mint>> },
867            Self::TokenAccount => quote! { Box<Account<'info, TokenAccount>> },
868            Self::UncheckedAccount => quote! {
869                UncheckedAccount<'info>
870            },
871            Self::SystemProgram => quote! { Program<'info, System> },
872            Self::TokenProgram => quote! { Program<'info, Token> },
873            Self::AssociatedTokenProgram => quote! { Program<'info, AssociatedToken> },
874            Self::RentSysvar => quote! { Sysvar<'info, Rent> },
875            Self::ClockSysvar => quote! { Sysvar<'info, Clock> },
876        });
877    }
878}
879
880/// The `space` parameter requires some extra info not present in the original annotation, so here's
881/// my ugly solution.
882struct AccountAnnotationWithTyExpr<'a>(&'a AccountAnnotation, &'a AccountTyExpr);
883impl<'a> ToTokens for AccountAnnotationWithTyExpr<'a> {
884    fn to_tokens(&self, tokens: &mut TokenStream) {
885        let AccountAnnotationWithTyExpr(
886            AccountAnnotation {
887                is_mut,
888                is_associated,
889                init,
890                payer,
891                seeds,
892                token_mint,
893                token_authority,
894                mint_decimals,
895                mint_authority,
896                space,
897                padding,
898            },
899            ty_expr,
900        ) = self;
901
902        // Build a filter-map of all the possible account attributes that Seahorse supports
903        let mut params = vec![];
904
905        if *is_mut {
906            params.push(Some(quote! { mut }));
907        }
908        if *init {
909            let ty_expr = match1!(ty_expr, AccountTyExpr::Empty(ty_expr) => ty_expr);
910            if let AccountTyExpr::Defined(name) = &**ty_expr {
911                let ty_expr = StaticPath(name);
912
913                let space = match (space, padding) {
914                    (None, None) => quote! { std::mem::size_of::<#ty_expr>() + 8 },
915                    (Some(s), None) => quote! { #s as usize },
916                    (None, Some(p)) => {
917                        quote! { std::mem::size_of::<#ty_expr>() + 8 + (#p as usize) }
918                    }
919                    (Some(_), Some(_)) => panic!(), // we protect against this in prelude.rs
920                };
921
922                params.push(Some(quote! { init, space = #space }));
923            } else {
924                params.push(Some(quote! { init }));
925            }
926        }
927
928        params.push(payer.as_ref().map(|payer| quote! { payer = #payer }));
929        params.push(
930            seeds
931                .as_ref()
932                .map(|seeds| quote! { seeds = [#(#seeds),*], bump }),
933        );
934        params.push(
935            mint_decimals
936                .as_ref()
937                .map(|decimals| quote! { mint::decimals = #decimals }),
938        );
939        params.push(
940            mint_authority
941                .as_ref()
942                .map(|authority| quote! { mint::authority = #authority }),
943        );
944        params.push(token_mint.as_ref().map(|mint| {
945            if !*is_associated {
946                quote! { token::mint = #mint }
947            } else {
948                quote! { associated_token::mint = #mint }
949            }
950        }));
951        params.push(token_authority.as_ref().map(|authority| {
952            if !*is_associated {
953                quote! { token::authority = #authority }
954            } else {
955                quote! { associated_token::authority = #authority }
956            }
957        }));
958
959        let params = params.into_iter().filter_map(|param| param);
960
961        let unchecked = if let &&AccountTyExpr::UncheckedAccount = ty_expr {
962            Some(quote! {
963                #[doc="CHECK: This account is unchecked."]
964            })
965        } else {
966            None
967        };
968
969        tokens.extend(quote! {
970            // dummy: __SEAHORSE_ACCOUNT_ANNOTATION_FORMATTER__![[[ #(#params),* ]]],
971            #[account(#(#params),*)]
972            #unchecked
973        });
974    }
975}
976
977impl ToTokens for Block {
978    fn to_tokens(&self, tokens: &mut TokenStream) {
979        let Self {
980            body,
981            implicit_return,
982        } = self;
983
984        tokens.extend(quote! {{
985            // Statements own their semicolons
986            #(#body)*
987            #implicit_return
988        }});
989    }
990}
991
992impl ToTokens for Statement {
993    fn to_tokens(&self, tokens: &mut TokenStream) {
994        tokens.extend(match self {
995            // Tuple declaration in regular assignment statements gets converted to (maybe multiple)
996            // `let mut <var>;` statements followed by a non-let assignment of the tuple, instead of just
997            // doing a let-assignment of the tuple. This is to prevent variables from accidentally
998            // shadowing each other. For illustration, we might have a scenario like this:
999            //
1000            // x = 1
1001            // if cond:
1002            //     (x, y) = (2, 3)
1003            //
1004            // Translating this to Rust could cause problems if done naively:
1005            //
1006            // let mut x = 1;
1007            // if cond {
1008            //     // `x` just got shadowed, not mutated!
1009            //     let (x, y) = (2, 3)
1010            // }
1011            //
1012            // So instead:
1013            //
1014            // let mut x = 1;
1015            // if cond {
1016            //     let mut y;
1017            //     (x, y) = (2, 3)
1018            // }
1019            Self::Let {
1020                undeclared,
1021                target,
1022                value,
1023            } => {
1024                let value = Grouped(value);
1025
1026                match target {
1027                    LetTarget::Var { .. } => {
1028                        // No undeclared variables means that this statement is just an assignment
1029                        if undeclared.len() == 0 {
1030                            let target = target.as_immut();
1031                            quote! { #target = #value; }
1032                        } else {
1033                            quote! { let #target = #value; }
1034                        }
1035                    }
1036                    LetTarget::Tuple(..) => {
1037                        let target = target.as_immut();
1038
1039                        if undeclared.len() == 0 {
1040                            quote! { #target = #value; }
1041                        } else {
1042                            let undeclared = undeclared.iter().map(|var| {
1043                                let var = ident(var);
1044
1045                                quote! { mut #var }
1046                            });
1047
1048                            quote! {
1049                                let (#(#undeclared),*);
1050                                #target = #value;
1051                            }
1052                        }
1053                    }
1054                }
1055            }
1056            Self::Assign { receiver, value } => {
1057                let value = Grouped(value);
1058
1059                // TODO maybe can do a normal = assignment if there are no `borrow`s in the rval?
1060                quote! {
1061                    assign!(#receiver, #value);
1062                }
1063            }
1064            Self::Expression(expression) => {
1065                let expression = Grouped(expression);
1066
1067                quote! { #expression; }
1068            }
1069            Self::Return(value) => {
1070                let value = value.as_ref().map(|value| Grouped(value));
1071
1072                quote! { return #value; }
1073            }
1074            Self::Break => quote! { break; },
1075            Self::Continue => quote! { continue; },
1076            Self::Noop => quote! {},
1077            Self::AnchorRequire { cond, msg } => {
1078                let msg = Grouped(msg);
1079
1080                quote! {
1081                    if ! #cond {
1082                        panic!(#msg);
1083                    }
1084                }
1085            }
1086            Self::If { cond, body, orelse } => {
1087                let cond = Grouped(cond);
1088
1089                match orelse {
1090                    // TODO if the `orelse` block just contains a single if statement, can turn this into an `else if`
1091                    Some(orelse) => quote! { if #cond #body else #orelse },
1092                    None => quote! { if #cond #body },
1093                }
1094            }
1095            Self::While { cond, body } => {
1096                let cond = Grouped(cond);
1097
1098                quote! { while #cond #body }
1099            }
1100            Self::Loop { label, body } => {
1101                let label = match label {
1102                    Some(label) => Some(ident(label)),
1103                    None => None,
1104                };
1105
1106                quote! { #label loop #body }
1107            }
1108            Self::For { target, iter, body } => {
1109                let iter = Grouped(iter);
1110
1111                quote! { for #target in #iter #body }
1112            }
1113        });
1114    }
1115}
1116
1117impl ToTokens for LetTarget {
1118    fn to_tokens(&self, tokens: &mut TokenStream) {
1119        tokens.extend(match self {
1120            Self::Var { name, is_mut } => {
1121                let name = ident(name);
1122
1123                match is_mut {
1124                    true => quote! { mut #name },
1125                    false => quote! { #name },
1126                }
1127            }
1128            Self::Tuple(targets) => quote! { (#(#targets),*) },
1129        });
1130    }
1131}
1132
1133impl ToTokens for TypedExpression {
1134    fn to_tokens(&self, tokens: &mut TokenStream) {
1135        let Self { obj, .. } = self;
1136
1137        tokens.extend(quote! { #obj });
1138
1139        // let Self { ty, obj } = self;
1140        // let ty_str = format!("{}", ty);
1141        // tokens.extend(quote! { ty!(#ty_str, #obj) });
1142    }
1143}
1144
1145/// Newtype for an expression that doesn't need extra parentheses to group it.
1146struct Grouped<'a>(&'a TypedExpression);
1147impl<'a> ToTokens for Grouped<'a> {
1148    fn to_tokens(&self, tokens: &mut TokenStream) {
1149        tokens.extend(match &self.0.obj {
1150            ExpressionObj::BinOp { left, op, right } => quote! { #left #op #right },
1151            ExpressionObj::UnOp { op, value } => quote! { #op #value },
1152            ExpressionObj::As { value, ty } => {
1153                let ty = LoadedTyExpr(ty);
1154
1155                quote! { #value as #ty }
1156            }
1157            obj => quote! { #obj },
1158        });
1159    }
1160}
1161
1162impl ToTokens for ExpressionObj {
1163    fn to_tokens(&self, tokens: &mut TokenStream) {
1164        tokens.extend(match self {
1165            Self::BinOp { left, op, right } => quote! { (#left #op #right) },
1166            Self::Index { value, index } => {
1167                let value = Grouped(&**value);
1168                let index = Grouped(&**index);
1169
1170                quote! { #value[#index] }
1171            }
1172            Self::TupleIndex { tuple, index } => {
1173                let index = PM2Literal::usize_unsuffixed(*index);
1174
1175                quote! { #tuple . #index }
1176            }
1177            Self::UnOp { op, value } => quote! { (#op #value) },
1178            Self::Attribute { value, name } => {
1179                let name = ident(name);
1180
1181                quote! { #value . #name }
1182            }
1183            Self::StaticAttribute { value, name } => {
1184                let name = ident(name);
1185
1186                quote! { #value :: #name }
1187            }
1188            Self::Call { function, args } => {
1189                let args = args.iter().map(|arg| Grouped(arg));
1190
1191                quote! { #function(#(#args),*) }
1192            }
1193            Self::Ternary { cond, body, orelse } => {
1194                let cond = Grouped(&**cond);
1195
1196                quote! {
1197                    if #cond { #body } else { #orelse }
1198                }
1199            }
1200            Self::As { value, ty } => {
1201                let ty = LoadedTyExpr(ty);
1202
1203                quote! { (#value as #ty) }
1204            }
1205            Self::Vec(elements) => {
1206                let elements = elements.iter().map(|element| Grouped(element));
1207
1208                quote! { vec![#(#elements),*] }
1209            }
1210            Self::Array(elements) => {
1211                let elements = elements.iter().map(|element| Grouped(element));
1212
1213                quote! { [#(#elements),*] }
1214            }
1215            Self::Tuple(tuple) => {
1216                let tuple = tuple.iter().map(|part| Grouped(part));
1217
1218                quote! { (#(#tuple),*) }
1219            }
1220            Self::Id(name) => {
1221                let name = ident(name);
1222
1223                quote! { #name }
1224            }
1225            Self::Literal(literal) => quote! { #literal },
1226            Self::Block(block) => quote! { #block },
1227            Self::Ref(value) => quote! { (& #value) },
1228            Self::Move(value) => {
1229                // If we're trying to move some data, we need to explicitly
1230                // clone it if the type is not `Copy` and the data is owned
1231                if !value.ty.is_copy() && value.obj.is_owned() {
1232                    quote! { #value . clone() }
1233                } else {
1234                    quote! { #value }
1235                }
1236            }
1237            Self::BorrowMut(value) => quote! { #value . borrow_mut() },
1238            Self::BorrowImmut(value) => quote! { #value . borrow() },
1239            Self::Mutable(value) => {
1240                let value = Grouped(&**value);
1241
1242                quote! { Mutable::new(#value) }
1243            }
1244            Self::Rendered(tokens) => tokens.clone(),
1245            Self::Placeholder => panic!("Attempted to convert an explicit placeholder to tokens"),
1246        });
1247    }
1248}
1249
1250impl ToTokens for Literal {
1251    fn to_tokens(&self, tokens: &mut TokenStream) {
1252        tokens.extend(match self {
1253            Self::Int(n) => {
1254                let n = PM2Literal::i128_unsuffixed(*n);
1255
1256                quote! { #n }
1257            }
1258            Self::Float(n) => quote! { #n },
1259            Self::Str(s) => quote! { #s },
1260            Self::Bool(p) => quote! { #p },
1261            Self::Unit => quote! { () },
1262        });
1263    }
1264}
1265
1266impl ToTokens for Operator {
1267    fn to_tokens(&self, tokens: &mut TokenStream) {
1268        tokens.extend(match self {
1269            Self::Add => quote! { + },
1270            Self::Sub => quote! { - },
1271            Self::Mul => quote! { * },
1272            Self::Div => quote! { / },
1273            Self::Mod => quote! { % },
1274            // Self::Pow => quote! { + },
1275            Self::LShift => quote! { << },
1276            Self::RShift => quote! { >> },
1277            Self::BitOr => quote! { | },
1278            Self::BitXor => quote! { ^ },
1279            Self::BitAnd => quote! { & },
1280            Self::And => quote! { && },
1281            Self::Or => quote! { || },
1282            Self::Eq => quote! { == },
1283            Self::NotEq => quote! { != },
1284            Self::Lt => quote! { < },
1285            Self::Lte => quote! { <= },
1286            Self::Gt => quote! { > },
1287            Self::Gte => quote! { >= },
1288        })
1289    }
1290}
1291
1292impl ToTokens for UnaryOperator {
1293    fn to_tokens(&self, tokens: &mut TokenStream) {
1294        tokens.extend(match self {
1295            Self::Pos => quote! { + },
1296            Self::Neg => quote! { - },
1297            Self::Not => quote! { ! },
1298            Self::Inv => quote! { ! },
1299        })
1300    }
1301}
1302
1303fn make_lib(
1304    origin: &Artifact,
1305    path: &Vec<String>,
1306    program_name: &String,
1307    features: &BTreeSet<Feature>,
1308) -> CResult<String> {
1309    let program_name = ident(program_name);
1310
1311    let mut id = None;
1312    for directive in origin.directives.iter() {
1313        match directive {
1314            Directive::DeclareId(id_str) => {
1315                id = Some(id_str.clone());
1316            } // _ => {}
1317        }
1318    }
1319
1320    if id.is_none() {
1321        return Err(CoreError::make_raw(
1322            "declare_id not found",
1323            "Help: Anchor should generate your program's ID, check the IDL for this program in target/idl/<program name>.json, and add it to your program:\n\n    declare_id(\"id from the .json file\")"
1324        ));
1325    }
1326
1327    let instructions = origin.functions.iter().filter_map(
1328        |Function {
1329             name,
1330             ix_context,
1331             params,
1332             ..
1333         }| {
1334            let ix_context = match ix_context {
1335                Some(ix_context) => ix_context,
1336                None => {
1337                    return None;
1338                }
1339            };
1340
1341            let name = ident(name);
1342            let handler_name = ident(&format!("{}_handler", name));
1343            let context_name = ident(&ix_context.name);
1344
1345            let insert_programs = ix_context.inferred_accounts.iter().filter_map(
1346                |(name, ContextAccount { account_ty, .. })| {
1347                    if account_ty.is_program() {
1348                        let name_id = ident(&String::from(name));
1349
1350                        Some(quote! {
1351                            programs.insert(#name, ctx.accounts.#name_id.to_account_info());
1352                        })
1353                    } else {
1354                        None
1355                    }
1356                },
1357            );
1358
1359            let load_accounts = ix_context.accounts.iter().filter_map(
1360                |(name, ContextAccount { account_ty, ty, .. })| {
1361                    let name = ident(name);
1362
1363                    // Deconstruct `Empty` accounts
1364                    let (is_empty, account_ty) = match account_ty {
1365                        AccountTyExpr::Empty(empty) => (true, &**empty),
1366                        ty => (false, ty),
1367                    };
1368
1369                    let loaded = match account_ty {
1370                        AccountTyExpr::Defined(path) => {
1371                            let path = StaticPath(path);
1372
1373                            quote! { #path::load(&mut ctx.accounts.#name, &programs_map) }
1374                        }
1375                        AccountTyExpr::Signer => quote! {
1376                            SeahorseSigner {
1377                                account: &ctx.accounts.#name,
1378                                programs: &programs_map
1379                            }
1380                        },
1381                        AccountTyExpr::TokenMint | AccountTyExpr::TokenAccount => quote! {
1382                            SeahorseAccount {
1383                                account: &ctx.accounts.#name,
1384                                programs: &programs_map
1385                            }
1386                        },
1387                        AccountTyExpr::UncheckedAccount => quote! {
1388                            &ctx.accounts.#name.clone()
1389                        },
1390                        AccountTyExpr::ClockSysvar => quote! {
1391                            &ctx.accounts.#name.clone()
1392                        },
1393                        _ => {
1394                            return None;
1395                        }
1396                    };
1397
1398                    Some(if is_empty {
1399                        quote! {
1400                            let #name = Empty {
1401                                account: #loaded,
1402                                bump: Some(ctx.bumps.#name)
1403                            };
1404                        }
1405                    } else {
1406                        quote! {
1407                            let #name = #loaded;
1408                        }
1409                    })
1410                },
1411            );
1412
1413            let ix_params = params.iter().filter_map(|(name, ty)| {
1414                if !ix_context.params.iter().any(|(name_, _)| name == name_) {
1415                    return None;
1416                }
1417
1418                let name = ident(name);
1419                let ty = StoredTyExpr(ty);
1420
1421                Some(quote! { #name: #ty })
1422            });
1423
1424            let params = params.iter().map(|(name, _)| {
1425                let name = ident(name);
1426
1427                // TODO don't need to clone all accounts
1428                if ix_context.params.iter().any(|(name_, _)| name == name_) {
1429                    quote! { #name }
1430                } else {
1431                    quote! { #name.clone() }
1432                }
1433            });
1434
1435            let store_accounts = ix_context.accounts.iter().filter_map(
1436                |(name, ContextAccount { account_ty, .. })| {
1437                    // Deconstruct `Empty` accounts
1438                    let (is_empty, account_ty) = match account_ty {
1439                        AccountTyExpr::Empty(empty) => (true, &**empty),
1440                        ty => (false, ty),
1441                    };
1442
1443                    match account_ty {
1444                        AccountTyExpr::Defined(path) => {
1445                            let name = ident(name);
1446                            let path = StaticPath(path);
1447
1448                            if is_empty {
1449                                Some(quote! { #path::store(#name.account); })
1450                            } else {
1451                                Some(quote! { #path::store(#name); })
1452                            }
1453                        }
1454                        _ => None,
1455                    }
1456                },
1457            );
1458
1459            Some(quote! {
1460                #ix_context
1461
1462                pub fn #name(ctx: Context<#context_name>, #(#ix_params),*) -> Result<()> {
1463                    let mut programs = HashMap::new();
1464                    #(#insert_programs)*
1465                    let programs_map = ProgramsMap(programs);
1466
1467                    #(#load_accounts)*
1468                    #handler_name(#(#params),*);
1469                    #(#store_accounts)*
1470
1471                    return Ok(());
1472                }
1473            })
1474        },
1475    );
1476
1477    let path = StaticPath(path);
1478
1479    let maybe_pyth_import = if (features.contains(&Feature::Pyth)) {
1480        Some(quote! {
1481            // Re-export for ease of access
1482            pub use pyth_sdk_solana::{load_price_feed_from_account_info, PriceFeed};
1483        })
1484    } else {
1485        None
1486    };
1487
1488    let text = beautify(quote! {
1489        use std::{cell::RefCell, rc::Rc};
1490        use anchor_lang::prelude::*;
1491        use anchor_spl::{
1492            token::{self, Mint, Token, TokenAccount},
1493            associated_token::{self, AssociatedToken}
1494        };
1495        use #path::*;
1496
1497        declare_id!(#id);
1498
1499        // TODO maybe hide the names better? wouldn't want any namespace collisions
1500        // Utility structs, functions, and macros to beautify the generated code a little.
1501        pub mod seahorse_util {
1502            use super::*;
1503            use std::{collections::HashMap, fmt::Debug, ops::{Deref, Index, IndexMut}};
1504            #maybe_pyth_import
1505
1506            // A "Python mutable" object.
1507            pub struct Mutable<T>(Rc<RefCell<T>>);
1508
1509            impl<T> Mutable<T> {
1510                pub fn new(obj: T) -> Self {
1511                    Self(Rc::new(RefCell::new(obj)))
1512                }
1513            }
1514
1515            impl <T> Clone for Mutable<T> {
1516                fn clone(&self) -> Self {
1517                    Self(self.0.clone())
1518                }
1519            }
1520
1521            impl<T> Deref for Mutable<T> {
1522                type Target = Rc<RefCell<T>>;
1523
1524                fn deref(&self) -> &Self::Target {
1525                    &self.0
1526                }
1527            }
1528
1529            impl<T: Debug> Debug for Mutable<T> {
1530                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1531                    write!(f, "{:?}", self.0)
1532                }
1533            }
1534
1535            impl <T: Default> Default for Mutable<T> {
1536                fn default() -> Self {
1537                    Self::new(T::default())
1538                }
1539            }
1540
1541            // Pythonic indexing for vec/array types (Seahorse List, Array types)
1542            pub trait IndexWrapped {
1543                type Output;
1544
1545                fn index_wrapped(&self, index: i128) -> &Self::Output;
1546            }
1547
1548            pub trait IndexWrappedMut: IndexWrapped {
1549                fn index_wrapped_mut(&mut self, index: i128) -> &mut <Self as IndexWrapped>::Output;
1550            }
1551
1552            impl<T> IndexWrapped for Vec<T> {
1553                type Output = T;
1554
1555                fn index_wrapped(&self, mut index: i128) -> &Self::Output {
1556                    if index < 0 {
1557                        index += self.len() as i128;
1558                    }
1559
1560                    let index: usize = index.try_into().unwrap();
1561
1562                    self.index(index)
1563                }
1564            }
1565
1566            impl<T> IndexWrappedMut for Vec<T> {
1567                fn index_wrapped_mut(&mut self, mut index: i128) -> &mut <Self as IndexWrapped>::Output {
1568                    if index < 0 {
1569                        index += self.len() as i128;
1570                    }
1571
1572                    let index: usize = index.try_into().unwrap();
1573
1574                    self.index_mut(index)
1575                }
1576            }
1577
1578            impl<T, const N: usize> IndexWrapped for [T; N] {
1579                type Output = T;
1580
1581                fn index_wrapped(&self, mut index: i128) -> &Self::Output {
1582                    if index < 0 {
1583                        index += N as i128;
1584                    }
1585
1586                    let index: usize = index.try_into().unwrap();
1587
1588                    self.index(index)
1589                }
1590            }
1591
1592            impl<T, const N: usize> IndexWrappedMut for [T; N] {
1593                fn index_wrapped_mut(&mut self, mut index: i128) -> &mut <Self as IndexWrapped>::Output {
1594                    if index < 0 {
1595                        index += N as i128;
1596                    }
1597
1598                    let index: usize = index.try_into().unwrap();
1599
1600                    self.index_mut(index)
1601                }
1602            }
1603
1604            // An initialized account with a bump seed.
1605            #[derive(Clone)]
1606            pub struct Empty<T: Clone> {
1607                pub account: T,
1608                pub bump: Option<u8>
1609            }
1610
1611            // A struct to contain programs that need to be used for CPIs, inferred by Seahorse.
1612            #[derive(Clone, Debug)]
1613            pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>);
1614
1615            impl<'info> ProgramsMap<'info> {
1616                pub fn get(&self, name: &'static str) -> AccountInfo<'info> {
1617                    self.0.get(name).unwrap().clone()
1618                }
1619            }
1620
1621            // A generic container for an account and programs.
1622            //
1623            // The 'info lifetime designates the lifetime of the data in the Anchor `Context` struct,
1624            // and the 'entrypoint lifetime designates the lifetime of the data in the instruction's
1625            // entrypoint function.
1626            #[derive(Clone, Debug)]
1627            pub struct WithPrograms<'info, 'entrypoint, A> {
1628                pub account: &'entrypoint A,
1629                pub programs: &'entrypoint ProgramsMap<'info>,
1630            }
1631
1632            impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> {
1633                type Target = A;
1634
1635                fn deref(&self) -> &Self::Target {
1636                    &self.account
1637                }
1638            }
1639
1640            // Boxed account with programs
1641            pub type SeahorseAccount<'info, 'entrypoint, A> = WithPrograms<'info, 'entrypoint, Box<Account<'info, A>>>;
1642            // Signer with programs
1643            pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>;
1644
1645            #[derive(Clone, Debug)]
1646            pub struct CpiAccount<'info> {
1647                #[doc="CHECK: CpiAccounts temporarily store AccountInfos."]
1648                pub account_info: AccountInfo<'info>,
1649                pub is_writable: bool,
1650                pub is_signer: bool,
1651                pub seeds: Option<Vec<Vec<u8>>>
1652            }
1653
1654            // This macro just expands to another macro, which is how constants are defined.
1655            // The `pub(crate) use ...` lets us treat the macro exactly like any other crate-
1656            // exported item.
1657            #[macro_export]
1658            macro_rules! seahorse_const {
1659                ($name:ident, $value:expr) => {
1660                    macro_rules! $name {
1661                        () => { $value }
1662                    }
1663                    pub(crate) use $name;
1664                }
1665            }
1666
1667            // Trait that allows us to easily define Loaded- (runtime) types for stored data.
1668            //
1669            // I tried, but this trait can't be used for accounts due to how lifetimes need to be
1670            // used in the program vs. how Rust allows us to use them for trait impls.
1671            pub trait Loadable {
1672                type Loaded;
1673
1674                fn load(stored: Self) -> Self::Loaded;
1675
1676                fn store(loaded: Self::Loaded) -> Self;
1677            }
1678
1679            macro_rules! Loaded {
1680                ($name:ty) => {
1681                    <$name as Loadable>::Loaded
1682                }
1683            }
1684
1685            pub(crate) use Loaded;
1686
1687            // Because of how `RefCell::borrow_mut()/borrow()` works, if we try to borrow from the
1688            // same value we're assigning to it will cause an error at runtime, for example:
1689            //
1690            // obj.borrow_mut().x = obj.borrow().y + 1;
1691            //
1692            // ...will always error, because we can't `borrow_mut` `obj` while it's already being
1693            // `borrow`'d. The simple solution is to decompose the assignment into its lval and rval
1694            // and assign them in two statements:
1695            //
1696            // let temp = obj.borrow().y + 1;
1697            // obj.borrow_mut().x = temp;
1698            //
1699            // This isn't always needed, of course, but it's difficult to figure out exactly when we
1700            // need to use this approach at compile time. For example:
1701            //
1702            // let mut original: Mutable<X> = ... ;
1703            // let mut maybe_copy: Mutable<X> = ... ;
1704            //
1705            // if condition { maybe_copy = original.clone(); }
1706            //
1707            // maybe_copy.borrow_mut().x = original.borrow().y + 1;
1708            //
1709            // Here, an error will only be thrown if `condition` was true, since we'll still be
1710            // borrowing the same object twice.
1711            #[macro_export]
1712            macro_rules! assign {
1713                ($lval:expr, $rval:expr) => {
1714                    {
1715                        let temp = $rval;
1716                        $lval = temp;
1717                    }
1718                }
1719            }
1720
1721            // Same problem from above applies, but in a more complex way because indices are
1722            // involved. To support Python's "negative index wraparound" syntax, we'll need to find
1723            // the absolute index of a list based on the length of the list itself. This involves a
1724            // borrow, so we need to separate the index from the lval as well.
1725            #[macro_export]
1726            macro_rules! index_assign {
1727                ($lval:expr, $idx:expr, $rval:expr) => {
1728                    let temp_rval = $rval;
1729                    let temp_idx = $idx;
1730                    $lval[temp_idx] = temp_rval;
1731                }
1732            }
1733
1734            pub(crate) use seahorse_const;
1735            pub(crate) use assign;
1736            pub(crate) use index_assign;
1737        }
1738
1739        #[program]
1740        mod #program_name {
1741            use super::*;
1742            use seahorse_util::*;
1743            use std::collections::HashMap;
1744
1745            #(#instructions)*
1746        }
1747    })?;
1748
1749    return Ok(text);
1750}
1751
1752/// Add mod.rs content.
1753fn add_mods(tree: &mut Tree<String>) {
1754    match tree {
1755        Tree::Node(node) => {
1756            let mods = node.keys().map(|key| {
1757                let key = ident(key);
1758
1759                quote! { pub mod #key; }
1760            });
1761            let text = beautify(quote! { #(#mods)* }).unwrap();
1762            node.insert("mod".to_string(), Tree::Leaf(text));
1763
1764            for (_, tree) in node.iter_mut() {
1765                add_mods(tree);
1766            }
1767        }
1768        _ => {}
1769    }
1770}
1771
1772// Rustfmt isn't supported for wasm
1773#[cfg(not(target_arch = "wasm32"))]
1774/// Make a `TokenStream` look nice.
1775fn beautify_impl(tokens: TokenStream) -> CResult<String> {
1776    let config = Config {
1777        // Maybe there will be something here one day
1778        ..Config::default()
1779    };
1780
1781    let mut source = rustfmt_config(config, tokens).map_err(|err| match err {
1782        RustfmtError::NoRustfmt => CoreError::make_raw(
1783            "rustfmt not installed",
1784            "Help: Seahorse depends on rustfmt, which is part of the Rust toolchain. To install:\n\n    rustup components add rustfmt"
1785        ),
1786        RustfmtError::Rustfmt(message) => CoreError::make_raw(
1787            "rustfmt error",
1788            format!("{}This is most likely an error in Seahorse.", message)
1789        ),
1790        _ => CoreError::make_raw("unknown rustfmt error", ""),
1791    })?;
1792
1793    // Perform some simple regex-based transformations
1794    // NOTE makes some bold assumptions about the spacing in rustfmt's output. Likely won't cause
1795    // any major problems, at worst has the potential to corrupt very weird strings
1796
1797    // let re = Regex::new(r"(?s)dummy: __SEAHORSE_ACCOUNT_ANNOTATION_FORMATTER__\s*!\s*\[\[\[(.*?)\]\]\],").unwrap();
1798    // source = re.replace_all(&source, "#[account($1)]").to_string();
1799
1800    // Add a blank line after the end of statements or blocks (semicolon or right curly at line
1801    // end), but not before the end of a block
1802    let re = Regex::new(r"([};])\n(\s*[^\s}])").unwrap();
1803    source = re.replace_all(&source, "$1\n\n$2").to_string();
1804
1805    // Remove blank lines between blocks of (single-line) "use ...;"
1806    // Regex::replace_all only catches non-overlapping occurrences of the pattern, so we have to
1807    // run this twice to get everything
1808    let re = Regex::new(r"(use .*?;)\n\n(\s*use )").unwrap();
1809    source = re.replace_all(&source, "$1\n$2").to_string();
1810    let re = Regex::new(r"(use .*?;)\n\n(\s*use )").unwrap();
1811    source = re.replace_all(&source, "$1\n$2").to_string();
1812
1813    // Remove blank lines between blocks of (single-line) "let ...;"
1814    // ^ ditto with use statements, run this twice to catch everything
1815    let re = Regex::new(r"(let .*?;)\n\n(\s*let )").unwrap();
1816    source = re.replace_all(&source, "$1\n$2").to_string();
1817    let re = Regex::new(r"(let .*?;)\n\n(\s*let )").unwrap();
1818    source = re.replace_all(&source, "$1\n$2").to_string();
1819
1820    // Collapse any accidental doubled blank lines
1821    let re = Regex::new(r"\n\n\n+").unwrap();
1822    source = re.replace_all(&source, "\n\n").to_string();
1823
1824    return Ok(source);
1825}
1826
1827fn beautify(tokens: TokenStream) -> CResult<String> {
1828    #[cfg(not(target_arch = "wasm32"))]
1829    {
1830        return beautify_impl(tokens);
1831    }
1832    #[cfg(target_arch = "wasm32")]
1833    {
1834        return Ok(tokens.to_string());
1835    }
1836}
1837
1838impl TryFrom<(BuildOutput, String)> for GenerateOutput {
1839    type Error = CoreError;
1840
1841    fn try_from((build_output, program_name): (BuildOutput, String)) -> CResult<Self> {
1842        let tree = build_output.tree.clone();
1843        let origin = tree.get_leaf(&build_output.origin).unwrap();
1844
1845        let features = Rc::new(RefCell::new(BTreeSet::new()));
1846
1847        let mut tree = build_output
1848            .tree
1849            .map(|artifact| {
1850                let text = beautify(quote! { #artifact })?;
1851
1852                features.borrow_mut().extend(artifact.features.into_iter());
1853
1854                Ok(text)
1855            })
1856            .transpose()?;
1857
1858        let features = features.take();
1859        let lib = make_lib(origin, &build_output.origin, &program_name, &features)?;
1860
1861        add_mods(&mut tree);
1862
1863        if let Tree::Node(node) = &mut tree {
1864            let allows = concat!(
1865                "#![allow(unused_imports)]\n",
1866                "#![allow(unused_variables)]\n",
1867                "#![allow(unused_mut)]\n"
1868            );
1869
1870            let mod_text = match node.remove("mod") {
1871                Some(Tree::Leaf(text)) => text,
1872                _ => panic!(),
1873            };
1874
1875            node.insert(
1876                "lib".to_string(),
1877                Tree::Leaf(format!("{}\n{}\n{}", allows, mod_text, lib)),
1878            );
1879        }
1880
1881        return Ok(GenerateOutput { tree, features });
1882    }
1883}
1884
1885pub fn generate(build_output: BuildOutput, program_name: String) -> CResult<GenerateOutput> {
1886    (build_output, program_name).try_into()
1887}