anchor/lang/syn/src/lib.rs

368 lines
9.5 KiB
Rust
Raw Normal View History

2020-12-31 15:48:06 -08:00
//! DSL syntax tokens.
2021-01-14 22:35:50 -08:00
#[cfg(feature = "idl")]
2021-01-20 17:13:02 -08:00
use crate::idl::{IdlAccount, IdlAccountItem, IdlAccounts};
2021-01-14 22:35:50 -08:00
use anyhow::Result;
#[cfg(feature = "idl")]
use heck::MixedCase;
use quote::quote;
use std::collections::HashMap;
2020-12-31 15:48:06 -08:00
pub mod codegen;
2021-02-05 03:17:40 -08:00
#[cfg(feature = "hash")]
pub mod hash;
#[cfg(not(feature = "hash"))]
pub(crate) mod hash;
2021-01-01 19:07:26 -08:00
#[cfg(feature = "idl")]
2020-12-31 15:48:06 -08:00
pub mod idl;
pub mod parser;
#[derive(Debug)]
pub struct Program {
pub state: Option<State>,
2021-02-10 22:35:23 -08:00
pub ixs: Vec<Ix>,
2020-12-31 15:48:06 -08:00
pub name: syn::Ident,
pub program_mod: syn::ItemMod,
}
// State struct singleton.
#[derive(Debug)]
pub struct State {
pub name: String,
pub strct: syn::ItemStruct,
pub ctor_and_anchor: Option<(syn::ImplItemMethod, syn::Ident)>,
2021-02-10 22:35:23 -08:00
pub impl_block_and_methods: Option<(syn::ItemImpl, Vec<StateIx>)>,
pub interfaces: Option<Vec<StateInterface>>,
2021-01-23 00:18:50 -08:00
}
#[derive(Debug)]
2021-02-10 22:35:23 -08:00
pub struct StateIx {
2021-01-23 00:18:50 -08:00
pub raw_method: syn::ImplItemMethod,
pub ident: syn::Ident,
2021-02-10 22:35:23 -08:00
pub args: Vec<IxArg>,
2021-01-23 00:18:50 -08:00
pub anchor_ident: syn::Ident,
2021-02-07 07:45:10 -08:00
// True if there exists a &self on the method.
pub has_receiver: bool,
}
#[derive(Debug)]
pub struct StateInterface {
pub trait_name: String,
2021-02-10 22:35:23 -08:00
pub methods: Vec<StateIx>,
}
2020-12-31 15:48:06 -08:00
#[derive(Debug)]
2021-02-10 22:35:23 -08:00
pub struct Ix {
2020-12-31 15:48:06 -08:00
pub raw_method: syn::ItemFn,
pub ident: syn::Ident,
2021-02-10 22:35:23 -08:00
pub args: Vec<IxArg>,
2021-01-14 15:16:27 -08:00
// The ident for the struct deriving Accounts.
2020-12-31 15:48:06 -08:00
pub anchor_ident: syn::Ident,
}
#[derive(Debug)]
2021-02-10 22:35:23 -08:00
pub struct IxArg {
2020-12-31 15:48:06 -08:00
pub name: proc_macro2::Ident,
pub raw_arg: syn::PatType,
}
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
2020-12-31 15:48:06 -08:00
pub struct AccountsStruct {
// Name of the accounts struct.
pub ident: syn::Ident,
// Generics + lifetimes on the accounts struct.
pub generics: syn::Generics,
// Fields on the accounts struct.
2021-01-14 22:35:50 -08:00
pub fields: Vec<AccountField>,
2020-12-31 15:48:06 -08:00
}
impl AccountsStruct {
2021-01-14 22:35:50 -08:00
pub fn new(strct: syn::ItemStruct, fields: Vec<AccountField>) -> Self {
2020-12-31 15:48:06 -08:00
let ident = strct.ident.clone();
2021-02-15 21:52:54 -08:00
let generics = strct.generics;
2020-12-31 15:48:06 -08:00
Self {
ident,
generics,
fields,
}
}
2021-01-14 15:16:27 -08:00
// Returns all program owned accounts in the Accounts struct.
2021-01-14 22:35:50 -08:00
//
// `global_accs` is given to "link" account types that are embedded
// in each other.
pub fn account_tys(
&self,
global_accs: &HashMap<String, AccountsStruct>,
) -> Result<Vec<String>> {
let mut tys = vec![];
for f in &self.fields {
match f {
AccountField::Field(f) => {
if let Ty::ProgramAccount(pty) = &f.ty {
tys.push(pty.account_ident.to_string());
}
}
AccountField::AccountsStruct(comp_f) => {
2021-02-15 21:52:54 -08:00
let accs = global_accs.get(&comp_f.symbol).ok_or_else(|| {
anyhow::format_err!("Invalid account type: {}", comp_f.symbol)
})?;
2021-01-14 22:35:50 -08:00
tys.extend(accs.account_tys(global_accs)?);
}
}
}
Ok(tys)
}
#[cfg(feature = "idl")]
2021-01-20 17:13:02 -08:00
pub fn idl_accounts(
&self,
global_accs: &HashMap<String, AccountsStruct>,
) -> Vec<IdlAccountItem> {
2020-12-31 15:48:06 -08:00
self.fields
.iter()
2021-01-20 17:13:02 -08:00
.map(|acc: &AccountField| match acc {
2021-01-14 22:35:50 -08:00
AccountField::AccountsStruct(comp_f) => {
let accs_strct = global_accs
.get(&comp_f.symbol)
.expect("Could not reslve Accounts symbol");
2021-01-20 17:13:02 -08:00
let accounts = accs_strct.idl_accounts(global_accs);
IdlAccountItem::IdlAccounts(IdlAccounts {
name: comp_f.ident.to_string().to_mixed_case(),
accounts,
})
2021-01-14 22:35:50 -08:00
}
2021-01-20 17:13:02 -08:00
AccountField::Field(acc) => IdlAccountItem::IdlAccount(IdlAccount {
2021-01-14 22:35:50 -08:00
name: acc.ident.to_string().to_mixed_case(),
is_mut: acc.is_mut,
is_signer: acc.is_signer,
2021-01-20 17:13:02 -08:00
}),
2020-12-31 15:48:06 -08:00
})
.collect::<Vec<_>>()
}
}
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
pub enum AccountField {
// Use a `String` instead of the `AccountsStruct` because all
// accounts structs aren't visible to a single derive macro.
//
// When we need the global context, we fill in the String with the
// appropriate values. See, `account_tys` as an example.
AccountsStruct(CompositeField), // Composite
Field(Field), // Primitive
}
#[derive(Debug)]
pub struct CompositeField {
pub ident: syn::Ident,
pub symbol: String,
2021-01-20 17:13:02 -08:00
pub constraints: Vec<Constraint>,
pub raw_field: syn::Field,
2021-01-14 22:35:50 -08:00
}
2020-12-31 15:48:06 -08:00
// An account in the accounts struct.
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
2020-12-31 15:48:06 -08:00
pub struct Field {
pub ident: syn::Ident,
pub ty: Ty,
pub constraints: Vec<Constraint>,
pub is_mut: bool,
pub is_signer: bool,
2021-01-09 22:03:14 -08:00
pub is_init: bool,
// TODO: move associated out of the constraints and put into tis own
// field + struct.
// Used by the associated attribute only.
pub payer: Option<syn::Ident>,
// Used by the associated attribute only.
pub space: Option<proc_macro2::TokenStream>,
// Used by the associated attribute only.
pub associated_seeds: Vec<syn::Ident>,
2020-12-31 15:48:06 -08:00
}
2021-01-14 22:35:50 -08:00
impl Field {
pub fn typed_ident(&self) -> proc_macro2::TokenStream {
let name = &self.ident;
let ty = match &self.ty {
Ty::AccountInfo => quote! { AccountInfo },
Ty::ProgramState(ty) => {
let account = &ty.account_ident;
quote! {
ProgramState<#account>
}
}
2021-04-11 17:23:43 -07:00
Ty::CpiState(ty) => {
let account = &ty.account_ident;
quote! {
CpiState<#account>
}
}
2021-01-14 22:35:50 -08:00
Ty::ProgramAccount(ty) => {
let account = &ty.account_ident;
quote! {
ProgramAccount<#account>
}
}
2021-04-17 12:07:48 -07:00
Ty::Loader(ty) => {
let account = &ty.account_ident;
quote! {
Loader<#account>
}
}
2021-01-14 22:35:50 -08:00
Ty::CpiAccount(ty) => {
let account = &ty.account_ident;
quote! {
CpiAccount<#account>
}
}
Ty::Sysvar(ty) => {
let account = match ty {
SysvarTy::Clock => quote! {Clock},
SysvarTy::Rent => quote! {Rent},
SysvarTy::EpochSchedule => quote! {EpochSchedule},
SysvarTy::Fees => quote! {Fees},
SysvarTy::RecentBlockHashes => quote! {RecentBlockHashes},
SysvarTy::SlotHashes => quote! {SlotHashes},
SysvarTy::SlotHistory => quote! {SlotHistory},
SysvarTy::StakeHistory => quote! {StakeHistory},
SysvarTy::Instructions => quote! {Instructions},
SysvarTy::Rewards => quote! {Rewards},
};
quote! {
Sysvar<#account>
}
}
};
quote! {
#name: #ty
}
}
}
2020-12-31 15:48:06 -08:00
// A type of an account field.
2021-01-14 22:35:50 -08:00
#[derive(Debug, PartialEq)]
2020-12-31 15:48:06 -08:00
pub enum Ty {
AccountInfo,
ProgramState(ProgramStateTy),
2021-04-11 17:23:43 -07:00
CpiState(CpiStateTy),
2020-12-31 15:48:06 -08:00
ProgramAccount(ProgramAccountTy),
2021-04-17 12:07:48 -07:00
Loader(LoaderTy),
2021-01-14 15:16:27 -08:00
CpiAccount(CpiAccountTy),
2021-01-14 22:35:50 -08:00
Sysvar(SysvarTy),
2021-01-11 09:22:25 -08:00
}
2021-01-14 22:35:50 -08:00
#[derive(Debug, PartialEq)]
2021-01-11 09:22:25 -08:00
pub enum SysvarTy {
Clock,
Rent,
EpochSchedule,
Fees,
RecentBlockHashes,
SlotHashes,
SlotHistory,
StakeHistory,
Instructions,
Rewards,
2020-12-31 15:48:06 -08:00
}
#[derive(Debug, PartialEq)]
pub struct ProgramStateTy {
pub account_ident: syn::Ident,
}
2021-04-11 17:23:43 -07:00
#[derive(Debug, PartialEq)]
pub struct CpiStateTy {
pub account_ident: syn::Ident,
}
2021-01-14 22:35:50 -08:00
#[derive(Debug, PartialEq)]
2020-12-31 15:48:06 -08:00
pub struct ProgramAccountTy {
// The struct type of the account.
pub account_ident: syn::Ident,
}
2021-01-14 22:35:50 -08:00
#[derive(Debug, PartialEq)]
2021-01-14 15:16:27 -08:00
pub struct CpiAccountTy {
// The struct type of the account.
pub account_ident: syn::Ident,
}
2021-04-17 12:07:48 -07:00
#[derive(Debug, PartialEq)]
pub struct LoaderTy {
// The struct type of the account.
pub account_ident: syn::Ident,
}
2020-12-31 15:48:06 -08:00
// An access control constraint for an account.
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
2020-12-31 15:48:06 -08:00
pub enum Constraint {
Signer(ConstraintSigner),
BelongsTo(ConstraintBelongsTo),
Literal(ConstraintLiteral),
Owner(ConstraintOwner),
RentExempt(ConstraintRentExempt),
2021-01-20 17:13:02 -08:00
Seeds(ConstraintSeeds),
Executable(ConstraintExecutable),
2021-04-11 17:23:43 -07:00
State(ConstraintState),
Associated(ConstraintAssociated),
2020-12-31 15:48:06 -08:00
}
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
2020-12-31 15:48:06 -08:00
pub struct ConstraintBelongsTo {
pub join_target: proc_macro2::Ident,
}
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
2020-12-31 15:48:06 -08:00
pub struct ConstraintSigner {}
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
2020-12-31 15:48:06 -08:00
pub struct ConstraintLiteral {
pub tokens: proc_macro2::TokenStream,
}
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
2021-04-11 21:54:35 -07:00
pub struct ConstraintOwner {
pub owner_target: proc_macro2::Ident,
2020-12-31 15:48:06 -08:00
}
2021-01-14 22:35:50 -08:00
#[derive(Debug)]
pub enum ConstraintRentExempt {
Enforce,
Skip,
}
2021-01-15 23:05:26 -08:00
2021-01-20 17:13:02 -08:00
#[derive(Debug)]
pub struct ConstraintSeeds {
pub seeds: proc_macro2::Group,
}
#[derive(Debug)]
pub struct ConstraintExecutable {}
2021-04-11 17:23:43 -07:00
#[derive(Debug)]
pub struct ConstraintState {
pub program_target: proc_macro2::Ident,
}
#[derive(Debug)]
pub struct ConstraintAssociated {
pub associated_target: proc_macro2::Ident,
}
2021-01-15 23:05:26 -08:00
#[derive(Debug)]
pub struct Error {
2021-01-20 17:13:02 -08:00
pub name: String,
2021-01-15 23:05:26 -08:00
pub raw_enum: syn::ItemEnum,
pub ident: syn::Ident,
pub codes: Vec<ErrorCode>,
}
#[derive(Debug)]
pub struct ErrorCode {
pub id: u32,
pub ident: syn::Ident,
pub msg: Option<String>,
}