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