lust/ast/
expr.rs

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