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;
|
2021-02-06 00:28:33 -08:00
|
|
|
#[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 {
|
2021-01-22 03:35:57 -08:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
2021-01-22 03:35:57 -08:00
|
|
|
// State struct singleton.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct State {
|
|
|
|
pub name: String,
|
|
|
|
pub strct: syn::ItemStruct,
|
2021-02-09 06:25:23 -08:00
|
|
|
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>)>,
|
2021-02-09 06:25:23 -08:00
|
|
|
pub interfaces: Option<Vec<StateInterface>>,
|
2021-04-18 09:54:18 -07:00
|
|
|
pub is_zero_copy: bool,
|
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>,
|
2021-01-22 03:35:57 -08:00
|
|
|
}
|
|
|
|
|
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,
|
2021-04-13 11:47:54 -07:00
|
|
|
// 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.
|
2021-04-14 17:29:52 -07:00
|
|
|
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 },
|
2021-01-22 03:35:57 -08:00
|
|
|
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,
|
2021-01-22 03:35:57 -08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-01-22 03:35:57 -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),
|
2021-01-11 12:00:18 -08:00
|
|
|
RentExempt(ConstraintRentExempt),
|
2021-01-20 17:13:02 -08:00
|
|
|
Seeds(ConstraintSeeds),
|
2021-04-03 15:13:12 -07:00
|
|
|
Executable(ConstraintExecutable),
|
2021-04-11 17:23:43 -07:00
|
|
|
State(ConstraintState),
|
2021-04-13 11:47:54 -07:00
|
|
|
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-11 12:00:18 -08:00
|
|
|
|
2021-01-14 22:35:50 -08:00
|
|
|
#[derive(Debug)]
|
2021-01-11 12:00:18 -08:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
2021-04-03 15:13:12 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ConstraintExecutable {}
|
|
|
|
|
2021-04-11 17:23:43 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ConstraintState {
|
|
|
|
pub program_target: proc_macro2::Ident,
|
|
|
|
}
|
|
|
|
|
2021-04-13 11:47:54 -07:00
|
|
|
#[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>,
|
|
|
|
}
|