Skip to main content

lust/ast/
expr.rs

1use super::{Span, Type};
2use crate::number::{LustFloat, LustInt};
3use alloc::{
4    boxed::Box,
5    format,
6    string::{String, ToString},
7    vec::Vec,
8};
9use core::fmt;
10#[derive(Debug, Clone, PartialEq)]
11pub struct Expr {
12    pub kind: ExprKind,
13    pub span: Span,
14}
15
16impl Expr {
17    pub fn new(kind: ExprKind, span: Span) -> Self {
18        Self { kind, span }
19    }
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub enum ExprKind {
24    Literal(Literal),
25    Identifier(String),
26    Binary {
27        left: Box<Expr>,
28        op: BinaryOp,
29        right: Box<Expr>,
30    },
31    Unary {
32        op: UnaryOp,
33        operand: Box<Expr>,
34    },
35    Call {
36        callee: Box<Expr>,
37        args: Vec<Expr>,
38    },
39    MethodCall {
40        receiver: Box<Expr>,
41        method: String,
42        type_args: Option<Vec<Type>>,
43        args: Vec<Expr>,
44    },
45    FieldAccess {
46        object: Box<Expr>,
47        field: String,
48    },
49    Index {
50        object: Box<Expr>,
51        index: Box<Expr>,
52    },
53    Array(Vec<Expr>),
54    Map(Vec<(Expr, Expr)>),
55    Tuple(Vec<Expr>),
56    StructLiteral {
57        name: String,
58        fields: Vec<StructLiteralField>,
59    },
60    EnumConstructor {
61        enum_name: String,
62        variant: String,
63        args: Vec<Expr>,
64    },
65    Lambda {
66        params: Vec<(String, Option<Type>)>,
67        return_type: Option<Type>,
68        body: Box<Expr>,
69    },
70    Paren(Box<Expr>),
71    Cast {
72        expr: Box<Expr>,
73        target_type: Type,
74    },
75    TypeCheck {
76        expr: Box<Expr>,
77        check_type: Type,
78    },
79    IsPattern {
80        expr: Box<Expr>,
81        pattern: Pattern,
82    },
83    If {
84        condition: Box<Expr>,
85        then_branch: Box<Expr>,
86        else_branch: Option<Box<Expr>>,
87    },
88    Block(Vec<super::stmt::Stmt>),
89    Return(Vec<Expr>),
90    Range {
91        start: Box<Expr>,
92        end: Box<Expr>,
93        inclusive: bool,
94    },
95}
96
97#[derive(Debug, Clone, PartialEq)]
98pub struct StructLiteralField {
99    pub name: String,
100    pub value: Expr,
101    pub span: Span,
102}
103
104#[derive(Debug, Clone, PartialEq)]
105pub enum Pattern {
106    Wildcard,
107    Literal(Literal),
108    Identifier(String),
109    Enum {
110        enum_name: String,
111        variant: String,
112        bindings: Vec<Pattern>,
113    },
114    Struct {
115        name: String,
116        fields: Vec<(String, Pattern)>,
117    },
118    TypeCheck(Type),
119}
120
121#[derive(Debug, Clone, PartialEq)]
122pub enum Literal {
123    Integer(LustInt),
124    Float(LustFloat),
125    String(String),
126    Bool(bool),
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum BinaryOp {
131    Add,
132    Sub,
133    Mul,
134    Div,
135    Mod,
136    Pow,
137    Eq,
138    Ne,
139    Lt,
140    Le,
141    Gt,
142    Ge,
143    And,
144    Or,
145    Concat,
146    Range,
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub enum UnaryOp {
151    Neg,
152    Not,
153}
154
155impl fmt::Display for BinaryOp {
156    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        let symbol = match self {
158            BinaryOp::Add => "+",
159            BinaryOp::Sub => "-",
160            BinaryOp::Mul => "*",
161            BinaryOp::Div => "/",
162            BinaryOp::Mod => "%",
163            BinaryOp::Pow => "^",
164            BinaryOp::Eq => "==",
165            BinaryOp::Ne => "!=",
166            BinaryOp::Lt => "<",
167            BinaryOp::Le => "<=",
168            BinaryOp::Gt => ">",
169            BinaryOp::Ge => ">=",
170            BinaryOp::And => "and",
171            BinaryOp::Or => "or",
172            BinaryOp::Concat => "..",
173            BinaryOp::Range => "..",
174        };
175        write!(f, "{symbol}")
176    }
177}
178
179impl fmt::Display for UnaryOp {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        match self {
182            UnaryOp::Neg => write!(f, "-"),
183            UnaryOp::Not => write!(f, "not"),
184        }
185    }
186}
187
188impl fmt::Display for Literal {
189    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190        match self {
191            Literal::Integer(value) => write!(f, "{value}"),
192            Literal::Float(value) => write!(f, "{value}"),
193            Literal::String(value) => write!(f, "\"{}\"", value.escape_default()),
194            Literal::Bool(value) => write!(f, "{value}"),
195        }
196    }
197}
198
199impl fmt::Display for Pattern {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        match self {
202            Pattern::Wildcard => write!(f, "_"),
203            Pattern::Literal(lit) => write!(f, "{lit}"),
204            Pattern::Identifier(name) => write!(f, "{name}"),
205            Pattern::Enum {
206                enum_name,
207                variant,
208                bindings,
209            } => {
210                let qualified = if enum_name.is_empty() {
211                    variant.clone()
212                } else {
213                    format!("{enum_name}.{variant}")
214                };
215                if bindings.is_empty() {
216                    write!(f, "{qualified}")
217                } else {
218                    let binding_str = bindings
219                        .iter()
220                        .map(|p| p.to_string())
221                        .collect::<Vec<_>>()
222                        .join(", ");
223                    write!(f, "{qualified}({binding_str})")
224                }
225            }
226
227            Pattern::Struct { name, fields } => {
228                let field_str = fields
229                    .iter()
230                    .map(|(field_name, pattern)| match pattern {
231                        Pattern::Identifier(id) if id == field_name => field_name.clone(),
232                        _ => format!("{field_name} = {pattern}"),
233                    })
234                    .collect::<Vec<_>>()
235                    .join(", ");
236                write!(f, "{name} {{ {field_str} }}")
237            }
238
239            Pattern::TypeCheck(ty) => write!(f, "as {ty}"),
240        }
241    }
242}