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#[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
33fn ident<S: ToString>(name: &S) -> Ident {
35 format_ident!("{}", name.to_string())
36}
37
38struct 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 use crate::{id, seahorse_util::*};
66 use std::{rc::Rc, cell::RefCell};
67 use anchor_lang::{prelude::*, solana_program};
68 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 TyExpr::Generic { name, params, .. } if name == &["Vec"] => {
161 let inner = loaded_field(quote! { element }, ¶ms[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 }, ¶ms[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 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 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 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
593pub struct LoadedTyExpr<'a>(pub &'a TyExpr);
598impl<'a> ToTokens for LoadedTyExpr<'a> {
599 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
658struct StoredTyExpr<'a>(&'a TyExpr);
660impl<'a> ToTokens for StoredTyExpr<'a> {
661 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
742struct 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 ..
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
880struct 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 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!(), };
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 #[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 #(#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 Self::Let {
1020 undeclared,
1021 target,
1022 value,
1023 } => {
1024 let value = Grouped(value);
1025
1026 match target {
1027 LetTarget::Var { .. } => {
1028 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 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 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 }
1143}
1144
1145struct 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 !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::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 } }
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 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 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 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 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 pub mod seahorse_util {
1502 use super::*;
1503 use std::{collections::HashMap, fmt::Debug, ops::{Deref, Index, IndexMut}};
1504 #maybe_pyth_import
1505
1506 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 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 #[derive(Clone)]
1606 pub struct Empty<T: Clone> {
1607 pub account: T,
1608 pub bump: Option<u8>
1609 }
1610
1611 #[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 #[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 pub type SeahorseAccount<'info, 'entrypoint, A> = WithPrograms<'info, 'entrypoint, Box<Account<'info, A>>>;
1642 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 #[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 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 #[macro_export]
1712 macro_rules! assign {
1713 ($lval:expr, $rval:expr) => {
1714 {
1715 let temp = $rval;
1716 $lval = temp;
1717 }
1718 }
1719 }
1720
1721 #[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
1752fn 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#[cfg(not(target_arch = "wasm32"))]
1774fn beautify_impl(tokens: TokenStream) -> CResult<String> {
1776 let config = Config {
1777 ..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 let re = Regex::new(r"([};])\n(\s*[^\s}])").unwrap();
1803 source = re.replace_all(&source, "$1\n\n$2").to_string();
1804
1805 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 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 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}