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}