use proc_macro2::TokenStream;
use super::{
super::generate::Feature,
builtin::{
prelude::MethodType,
pyth::{ExprContext, ExprContextStack},
},
check::Ty,
};
use crate::core::Tree;
use std::collections::{BTreeMap, BTreeSet};
#[derive(Clone, Debug)]
pub struct Artifact {
pub features: BTreeSet<Feature>,
pub uses: Vec<Use>,
pub directives: Vec<Directive>,
pub constants: Vec<Constant>,
pub type_defs: Vec<TypeDef>,
pub functions: Vec<Function>,
}
#[derive(Clone, Debug)]
pub struct Use {
pub rooted: bool,
pub tree: Tree<Option<String>>,
}
#[derive(Clone, Debug)]
pub enum Directive {
DeclareId(String),
}
#[derive(Clone, Debug)]
pub struct Constant {
pub name: String,
pub value: TypedExpression,
}
#[derive(Clone, Debug)]
pub enum TypeDef {
Struct(Struct),
Account(Account),
Enum(Enum),
}
#[derive(Clone, Debug)]
pub struct Struct {
pub name: String,
pub fields: Vec<(String, TyExpr, Ty)>,
pub methods: Vec<(MethodType, Function)>,
pub constructor: Option<Function>,
pub is_event: bool,
pub is_dataclass: bool,
}
#[derive(Clone, Debug)]
pub struct Account {
pub name: String,
pub fields: Vec<(String, TyExpr, Ty)>,
pub methods: Vec<(MethodType, Function)>,
}
#[derive(Clone, Debug)]
pub struct Enum {
pub name: String,
pub variants: Vec<(String, Option<TyExpr>)>,
}
#[derive(Clone, Debug)]
pub enum TyExpr {
Generic {
mutability: Mutability,
name: Vec<String>,
params: Vec<TyExpr>,
is_loadable: bool,
},
Array {
element: Box<TyExpr>,
size: Box<TyExpr>,
},
Tuple(Vec<TyExpr>),
Account(Vec<String>), Const(usize),
InfoLifetime,
AnonLifetime,
}
#[derive(Clone, Debug)]
pub enum Mutability {
Mutable,
Immutable,
}
impl TyExpr {
pub fn new_specific(name: Vec<&str>, mutability: Mutability) -> Self {
Self::Generic {
mutability,
name: name.into_iter().map(|part| part.to_string()).collect(),
params: vec![],
is_loadable: false,
}
}
pub fn has_info_lifetime(&self) -> bool {
match self {
Self::Generic { params, .. } => params.iter().any(|param| param.has_info_lifetime()),
Self::Array { element, .. } => element.has_info_lifetime(),
Self::Tuple(tuple) => tuple.iter().any(|part| part.has_info_lifetime()),
Self::InfoLifetime { .. } => true,
Self::Account(..) => true,
_ => false,
}
}
}
#[derive(Clone, Debug)]
pub struct Function {
pub ix_context: Option<InstructionContext>,
pub name: String,
pub info_lifetime: bool,
pub params: Vec<(String, TyExpr)>,
pub returns: TyExpr,
pub body: Block,
}
#[derive(Clone, Debug)]
pub struct InstructionContext {
pub name: String,
pub params: Vec<(String, TyExpr)>,
pub accounts: Vec<(String, ContextAccount)>,
pub inferred_accounts: BTreeMap<String, ContextAccount>,
}
#[derive(Clone, Debug)]
pub struct ContextAccount {
pub account_ty: AccountTyExpr,
pub annotation: Option<AccountAnnotation>,
pub ty: Option<TyExpr>,
}
#[derive(Clone, Debug)]
pub enum AccountTyExpr {
Empty(Box<AccountTyExpr>),
Defined(Vec<String>),
Signer,
TokenMint,
TokenAccount,
UncheckedAccount,
SystemProgram,
TokenProgram,
AssociatedTokenProgram,
RentSysvar,
ClockSysvar,
}
impl AccountTyExpr {
pub fn is_program(&self) -> bool {
match self {
Self::SystemProgram | Self::TokenProgram | Self::AssociatedTokenProgram => true,
_ => false,
}
}
}
#[derive(Clone, Debug)]
pub struct AccountAnnotation {
pub is_mut: bool,
pub is_associated: bool,
pub init: bool,
pub payer: Option<TypedExpression>,
pub seeds: Option<Vec<TypedExpression>>,
pub mint_decimals: Option<TypedExpression>,
pub mint_authority: Option<TypedExpression>,
pub token_mint: Option<TypedExpression>,
pub token_authority: Option<TypedExpression>,
pub space: Option<TypedExpression>,
pub padding: Option<TypedExpression>,
}
impl AccountAnnotation {
pub fn new() -> Self {
Self {
is_mut: true,
is_associated: false,
init: false,
payer: None,
seeds: None,
mint_decimals: None,
mint_authority: None,
token_mint: None,
token_authority: None,
space: None,
padding: None,
}
}
}
#[derive(Clone, Debug)]
pub struct Block {
pub body: Vec<Statement>,
pub implicit_return: Option<Box<TypedExpression>>,
}
#[derive(Clone, Debug)]
pub enum Statement {
Let {
undeclared: Vec<String>,
target: LetTarget,
value: TypedExpression,
},
Assign {
receiver: TypedExpression,
value: TypedExpression,
},
Expression(TypedExpression),
Return(Option<TypedExpression>),
Break,
Continue,
Noop,
AnchorRequire {
cond: TypedExpression,
msg: TypedExpression,
},
If {
cond: TypedExpression,
body: Block,
orelse: Option<Block>,
},
While {
cond: TypedExpression,
body: Block,
},
Loop {
label: Option<String>,
body: Block,
},
For {
target: LetTarget,
iter: TypedExpression,
body: Block,
},
}
#[derive(Clone, Debug)]
pub enum LetTarget {
Var { name: String, is_mut: bool },
Tuple(Vec<LetTarget>),
}
impl LetTarget {
pub fn as_immut(&self) -> Self {
match self {
Self::Var { name, .. } => Self::Var {
name: name.clone(),
is_mut: false,
},
Self::Tuple(tuple) => Self::Tuple(tuple.iter().map(|part| part.as_immut()).collect()),
}
}
}
#[derive(Clone, Debug)]
pub struct TypedExpression {
pub ty: Ty,
pub obj: ExpressionObj,
}
impl TypedExpression {
pub fn optional(self) -> Option<Self> {
match &self.obj {
ExpressionObj::Placeholder => None,
_ => Some(self),
}
}
pub fn moved(mut self, context_stack: &ExprContextStack) -> Self {
if !context_stack.has_any(&[ExprContext::Directive, ExprContext::Seed]) {
self.obj = ExpressionObj::Move(self.obj.into());
}
return self;
}
pub fn without_borrows(mut self) -> Self {
self.obj = self.obj.without_borrows();
return self;
}
}
impl From<ExpressionObj> for TypedExpression {
fn from(obj: ExpressionObj) -> Self {
Self { ty: Ty::Never, obj }
}
}
impl From<ExpressionObj> for Box<TypedExpression> {
fn from(obj: ExpressionObj) -> Self {
TypedExpression { ty: Ty::Never, obj }.into()
}
}
#[derive(Clone, Debug)]
pub enum ExpressionObj {
BinOp {
left: Box<TypedExpression>,
op: Operator,
right: Box<TypedExpression>,
},
Index {
value: Box<TypedExpression>,
index: Box<TypedExpression>,
},
TupleIndex {
tuple: Box<TypedExpression>,
index: usize,
},
UnOp {
op: UnaryOperator,
value: Box<TypedExpression>,
},
Attribute {
value: Box<TypedExpression>,
name: String,
},
StaticAttribute {
value: Box<TypedExpression>,
name: String,
},
Call {
function: Box<TypedExpression>,
args: Vec<TypedExpression>,
},
Ternary {
cond: Box<TypedExpression>,
body: Box<TypedExpression>,
orelse: Box<TypedExpression>,
},
As {
value: Box<TypedExpression>,
ty: TyExpr,
},
Vec(Vec<TypedExpression>),
Array(Vec<TypedExpression>),
Tuple(Vec<TypedExpression>),
Id(String),
Literal(Literal),
Block(Block),
Ref(Box<TypedExpression>),
Move(Box<TypedExpression>),
BorrowMut(Box<TypedExpression>),
BorrowImmut(Box<TypedExpression>),
Mutable(Box<TypedExpression>),
Rendered(TokenStream),
Placeholder,
}
impl ExpressionObj {
pub fn with_call(self, name: &str, args: Vec<TypedExpression>) -> Self {
ExpressionObj::Call {
function: ExpressionObj::Attribute {
value: self.into(),
name: name.into(),
}
.into(),
args,
}
}
pub fn is_owned(&self) -> bool {
match self {
Self::Attribute { .. }
| Self::Id(..)
| Self::Index { .. }
| Self::TupleIndex { .. } => true,
_ => false,
}
}
pub fn without_borrows(self) -> Self {
match self {
Self::BinOp { left, op, right } => Self::BinOp {
left: left.without_borrows().into(),
op,
right: right.without_borrows().into(),
},
Self::Index { value, index } => Self::Index {
value: value.without_borrows().into(),
index: index.without_borrows().into(),
},
Self::TupleIndex { tuple, index } => Self::TupleIndex {
tuple: tuple.without_borrows().into(),
index,
},
Self::UnOp { op, value } => Self::UnOp {
op,
value: value.without_borrows().into(),
},
Self::Attribute { value, name } => Self::Attribute {
value: value.without_borrows().into(),
name,
},
Self::StaticAttribute { value, name } => Self::StaticAttribute {
value: value.without_borrows().into(),
name,
},
Self::Call { function, args } => Self::Call {
function: function.without_borrows().into(),
args: args.into_iter().map(|arg| arg.without_borrows()).collect(),
},
Self::Ternary { cond, body, orelse } => Self::Ternary {
cond: cond.without_borrows().into(),
body: body.without_borrows().into(),
orelse: orelse.without_borrows().into(),
},
Self::As { value, ty } => Self::As {
value: value.without_borrows().into(),
ty,
},
Self::Vec(elements) => Self::Vec(
elements
.into_iter()
.map(|element| element.without_borrows())
.collect(),
),
Self::Array(elements) => Self::Array(
elements
.into_iter()
.map(|element| element.without_borrows())
.collect(),
),
Self::Tuple(elements) => Self::Tuple(
elements
.into_iter()
.map(|element| element.without_borrows())
.collect(),
),
Self::Ref(value) => Self::Ref(value.without_borrows().into()),
Self::Move(value) => Self::Move(value.without_borrows().into()),
Self::BorrowMut(value) | Self::BorrowImmut(value) => value.without_borrows().obj,
Self::Mutable(value) => Self::Mutable(value.without_borrows().into()),
obj => obj,
}
}
}
#[derive(Clone, Debug)]
pub enum Literal {
Int(i128),
Float(f64),
Str(String),
Bool(bool),
Unit,
}
#[derive(Clone, Debug)]
pub enum Operator {
Add,
Sub,
Mul,
Div,
Mod,
LShift,
RShift,
BitOr,
BitXor,
BitAnd,
And,
Or,
Eq,
NotEq,
Lt,
Lte,
Gt,
Gte,
}
#[derive(Clone, Debug)]
pub enum UnaryOperator {
Pos,
Neg,
Not,
Inv,
}