use super::{
AssignOp, Attribute, BinOp, Block, Ident, Mutability, NodeId, Path, Pattern, Type, UnaryOp,
};
use crate::lexer::Span;
#[derive(Debug, Clone, PartialEq)]
pub struct Expr {
pub kind: ExprKind,
pub span: Span,
pub id: NodeId,
pub attrs: Vec<Attribute>,
}
impl Expr {
pub fn new(kind: ExprKind, span: Span) -> Self {
Self {
kind,
span,
id: NodeId::DUMMY,
attrs: Vec::new(),
}
}
pub fn with_attrs(kind: ExprKind, span: Span, attrs: Vec<Attribute>) -> Self {
Self {
kind,
span,
id: NodeId::DUMMY,
attrs,
}
}
pub fn is_place(&self) -> bool {
matches!(
self.kind,
ExprKind::Ident(_)
| ExprKind::Field { .. }
| ExprKind::TupleField { .. }
| ExprKind::Index { .. }
| ExprKind::Deref(_)
| ExprKind::Path(_)
)
}
pub fn requires_semi(&self) -> bool {
!matches!(
self.kind,
ExprKind::If { .. }
| ExprKind::Match { .. }
| ExprKind::Loop { .. }
| ExprKind::While { .. }
| ExprKind::For { .. }
| ExprKind::Block(_)
| ExprKind::Unsafe(_)
| ExprKind::Async { .. }
| ExprKind::Handle { .. }
)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExprKind {
Literal(Literal),
Ident(Ident),
Path(Path),
Array(Vec<Expr>),
ArrayRepeat {
element: Box<Expr>,
count: Box<Expr>,
},
Tuple(Vec<Expr>),
Struct {
path: Path,
fields: Vec<FieldExpr>,
rest: Option<Box<Expr>>,
},
Unary { op: UnaryOp, expr: Box<Expr> },
Binary {
op: BinOp,
left: Box<Expr>,
right: Box<Expr>,
},
Assign {
op: AssignOp,
target: Box<Expr>,
value: Box<Expr>,
},
Field { expr: Box<Expr>, field: Ident },
TupleField {
expr: Box<Expr>,
index: u32,
span: Span,
},
Index { expr: Box<Expr>, index: Box<Expr> },
Deref(Box<Expr>),
Ref {
mutability: Mutability,
expr: Box<Expr>,
},
Call { func: Box<Expr>, args: Vec<Expr> },
MethodCall {
receiver: Box<Expr>,
method: Ident,
generics: Vec<super::GenericArg>,
args: Vec<Expr>,
},
If {
condition: Box<Expr>,
then_branch: Box<Block>,
else_branch: Option<Box<Expr>>,
},
IfLet {
pattern: Box<Pattern>,
expr: Box<Expr>,
then_branch: Box<Block>,
else_branch: Option<Box<Expr>>,
},
Match {
scrutinee: Box<Expr>,
arms: Vec<MatchArm>,
},
Loop {
body: Box<Block>,
label: Option<Ident>,
},
While {
condition: Box<Expr>,
body: Box<Block>,
label: Option<Ident>,
},
WhileLet {
pattern: Box<Pattern>,
expr: Box<Expr>,
body: Box<Block>,
label: Option<Ident>,
},
For {
pattern: Box<Pattern>,
iter: Box<Expr>,
body: Box<Block>,
label: Option<Ident>,
},
Return(Option<Box<Expr>>),
Break {
label: Option<Ident>,
value: Option<Box<Expr>>,
},
Continue { label: Option<Ident> },
Closure {
is_move: bool,
is_async: bool,
params: Vec<ClosureParam>,
return_type: Option<Box<Type>>,
body: Box<Expr>,
},
Block(Box<Block>),
Unsafe(Box<Block>),
Async { is_move: bool, body: Box<Block> },
Cast { expr: Box<Expr>, ty: Box<Type> },
TypeAscription { expr: Box<Expr>, ty: Box<Type> },
Try(Box<Expr>),
Await(Box<Expr>),
Range {
start: Option<Box<Expr>>,
end: Option<Box<Expr>>,
inclusive: bool,
},
Macro {
path: Path,
delimiter: crate::lexer::Delimiter,
tokens: Vec<super::TokenTree>,
},
AIQuery {
prompt: Box<Expr>,
options: Vec<(Ident, Expr)>,
},
AIInfer { expr: Box<Expr>, ty: Box<Type> },
Handle {
effect: Path,
handlers: Vec<EffectHandler>,
body: Box<Block>,
},
Resume(Option<Box<Expr>>),
Perform {
effect: Ident,
operation: Ident,
args: Vec<Expr>,
},
Paren(Box<Expr>),
Error,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
Int {
value: u128,
suffix: Option<IntSuffix>,
base: super::super::lexer::IntBase,
},
Float {
value: f64,
suffix: Option<FloatSuffix>,
},
Str { value: String, is_raw: bool },
ByteStr { value: Vec<u8>, is_raw: bool },
Char(char),
Byte(u8),
Bool(bool),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntSuffix {
I8,
I16,
I32,
I64,
I128,
Isize,
U8,
U16,
U32,
U64,
U128,
Usize,
}
impl IntSuffix {
pub fn from_str(s: &str) -> Option<Self> {
match s {
"i8" => Some(IntSuffix::I8),
"i16" => Some(IntSuffix::I16),
"i32" => Some(IntSuffix::I32),
"i64" => Some(IntSuffix::I64),
"i128" => Some(IntSuffix::I128),
"isize" => Some(IntSuffix::Isize),
"u8" => Some(IntSuffix::U8),
"u16" => Some(IntSuffix::U16),
"u32" => Some(IntSuffix::U32),
"u64" => Some(IntSuffix::U64),
"u128" => Some(IntSuffix::U128),
"usize" => Some(IntSuffix::Usize),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FloatSuffix {
F16,
F32,
F64,
}
impl FloatSuffix {
pub fn from_str(s: &str) -> Option<Self> {
match s {
"f16" => Some(FloatSuffix::F16),
"f32" => Some(FloatSuffix::F32),
"f64" => Some(FloatSuffix::F64),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FieldExpr {
pub name: Ident,
pub value: Option<Box<Expr>>,
pub attrs: Vec<Attribute>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MatchArm {
pub attrs: Vec<Attribute>,
pub pattern: Pattern,
pub guard: Option<Box<Expr>>,
pub body: Box<Expr>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ClosureParam {
pub pattern: Pattern,
pub ty: Option<Box<Type>>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EffectHandler {
pub operation: Ident,
pub params: Vec<ClosureParam>,
pub body: Box<Expr>,
pub span: Span,
}
impl Expr {
pub fn precedence(&self) -> u8 {
match &self.kind {
ExprKind::Closure { .. } => 0,
ExprKind::Assign { .. } => 1,
ExprKind::Range { .. } => 2,
ExprKind::Binary { op, .. } => op.precedence(),
ExprKind::Unary { .. } => 25,
ExprKind::Cast { .. } | ExprKind::TypeAscription { .. } => 26,
ExprKind::Call { .. }
| ExprKind::MethodCall { .. }
| ExprKind::Field { .. }
| ExprKind::TupleField { .. }
| ExprKind::Index { .. }
| ExprKind::Try(_)
| ExprKind::Await(_) => 27,
_ => 28, }
}
}