1use super::type_system::TypeExpr;
2pub use crate::rt::Span;
3use smol_strc::SmolStr;
4use smol_strc::ToSmolStr;
5use std::{hint::unreachable_unchecked, rc::Rc};
6
7pub const METHOD_SEP: char = '#';
16
17#[must_use]
23pub fn mangle_method(type_name: &str, method_name: &str) -> SmolStr {
24 format_args!("{type_name}{METHOD_SEP}{method_name}").to_smolstr()
25}
26
27#[derive(Debug, Clone, PartialEq)]
28pub enum Expr {
29 Float(f64),
30 Int(i32),
31 Bool(bool),
32 Null,
33 String(SmolStr),
34 Var(SmolStr, Span),
35 Array(Box<[Self]>, Box<[Span]>),
37 Map(Box<[(Self, Span, Self, Span)]>, Span),
39 Struct(Box<[SmolStr]>, Box<[(SmolStr, Self, Span, Span)]>, Span),
41 StructDeclare(SmolStr, Box<[(SmolStr, TypeExpr, Span)]>, Span),
43 EnumDeclare(SmolStr, Box<[(SmolStr, Box<[TypeExpr]>, Span)]>, Span),
45 NamespacedRef(Box<[SmolStr]>, Span),
51 Match(
58 Box<Self>,
59 Box<[(Self, Box<[Self]>)]>,
60 Option<Box<[Self]>>,
61 Span,
62 ),
63 GetStructField(Box<Self>, SmolStr, Span, Span),
65 SetStructField(Box<Self>, SmolStr, Box<Self>, Span, Span, Span),
67 VarDeclare(SmolStr, Box<Self>),
69 VarAssign(SmolStr, Box<Self>, Span),
71 Condition(Box<Self>, Box<[Self]>, Span),
73 InlineCondition(Box<Self>, Box<[Self]>, Span),
75 ElseIfBlock(Box<Self>, Box<[Self]>),
76 ElseBlock(Box<[Self]>),
77
78 AnonymousFunction(Box<[SmolStr]>, Box<[Self]>, Span),
80 WhileBlock(Box<Self>, Box<[Self]>),
82 FunctionCall(Box<[Self]>, Box<[SmolStr]>, Span, Box<[Span]>),
84 ObjFunctionCall(
86 Box<Self>,
88 Box<[Self]>,
89 Box<[SmolStr]>,
90 Span,
92 Span,
94 Box<[Span]>,
95 ),
96 FunctionDecl(
102 SmolStr,
103 Box<[(SmolStr, Option<TypeExpr>)]>,
104 Rc<[Self]>,
105 Span,
106 Option<(TypeExpr, Span)>,
107 ),
108
109 ReturnVal(Box<Option<Self>>),
110
111 ArrayGetIndex(Box<Self>, Box<Self>, Span),
112 ArrayGetSlice(Box<Self>, Box<Self>, Box<Self>, Span),
114 ArrayModify(Box<Self>, Box<Self>, Box<Self>, Span, Span),
115
116 ForLoop(SmolStr, Box<Self>, Box<[Self]>, Span),
118 IntForLoop(SmolStr, Box<Self>, Box<Self>, Box<[Self]>, Span, Span),
120 ImportDylib(
122 SmolStr,
123 Box<[(SmolStr, Box<[TypeExpr]>, TypeExpr, Span)]>,
124 Span,
125 ),
126
127 HostBlock(
133 SmolStr,
134 Box<[(SmolStr, Box<[TypeExpr]>, TypeExpr, Span)]>,
135 Span,
136 ),
137
138 ImportFile(SmolStr, Option<SmolStr>, bool, Span),
148
149 Break,
150 Continue,
151
152 EvalBlock(Box<[Self]>),
153 LoopBlock(Box<[Self]>),
154
155 TryCatchBlock(Box<[Self]>, SmolStr, Box<[Self]>),
157
158 Mul(Box<Self>, Box<Self>, Span, Span),
159 Div(Box<Self>, Box<Self>, Span, Span),
160 Add(Box<Self>, Box<Self>, Span, Span),
161 Sub(Box<Self>, Box<Self>, Span, Span),
162 Mod(Box<Self>, Box<Self>, Span, Span),
163 Pow(Box<Self>, Box<Self>, Span, Span),
164 Eq(Box<Self>, Box<Self>),
165 NotEq(Box<Self>, Box<Self>),
166 Sup(Box<Self>, Box<Self>, Span, Span),
167 SupEq(Box<Self>, Box<Self>, Span, Span),
168 Inf(Box<Self>, Box<Self>, Span, Span),
169 InfEq(Box<Self>, Box<Self>, Span, Span),
170 BoolAnd(Box<Self>, Box<Self>, Span, Span),
171 BoolOr(Box<Self>, Box<Self>, Span, Span),
172 BoolNeg(Box<Self>, Span, Span),
173 Neg(Box<Self>, Span, Span),
174}
175
176#[cold]
177#[inline(never)]
178#[must_use]
179pub const fn symbol_of_expr(expr: &Expr) -> &'static str {
180 match expr {
181 Expr::Mul(_, _, _, _) => "*",
182 Expr::Div(_, _, _, _) => "/",
183 Expr::Add(_, _, _, _) => "+",
184 Expr::Sub(_, _, _, _) | Expr::Neg(_, _, _) => "-",
185 Expr::Mod(_, _, _, _) => "%",
186 Expr::Pow(_, _, _, _) => "^",
187 Expr::Eq(_, _) => "==",
188 Expr::NotEq(_, _) => "!=",
189 Expr::Sup(_, _, _, _) => ">",
190 Expr::SupEq(_, _, _, _) => ">=",
191 Expr::Inf(_, _, _, _) => "<",
192 Expr::InfEq(_, _, _, _) => "<=",
193 Expr::BoolAnd(_, _, _, _) => "&&",
194 Expr::BoolOr(_, _, _, _) => "||",
195 _ => unsafe { unreachable_unchecked() },
196 }
197}
198
199#[must_use]
200pub fn code_modifies_variable(var_name: &SmolStr, code: &[Expr]) -> bool {
201 code.iter().any(|expr| match expr {
202 Expr::VarAssign(n, _, _) => n == var_name,
203 Expr::Condition(_, body, _)
204 | Expr::WhileBlock(_, body)
205 | Expr::EvalBlock(body)
206 | Expr::LoopBlock(body)
207 | Expr::InlineCondition(_, body, _)
208 | Expr::ElseIfBlock(_, body)
209 | Expr::ElseBlock(body)
210 | Expr::ForLoop(_, _, body, _)
211 | Expr::IntForLoop(_, _, _, body, _, _) => code_modifies_variable(var_name, body),
212 Expr::Match(_, arms, wildcard, _) => {
213 arms.iter()
214 .any(|(_, body)| code_modifies_variable(var_name, body))
215 || wildcard
216 .as_ref()
217 .is_some_and(|body| code_modifies_variable(var_name, body))
218 }
219 _ => false,
220 })
221}
222
223#[must_use]
224pub fn var_assign(target: Expr, value: Expr, expr_span: Span, value_span: Span) -> Expr {
225 if let Expr::Var(n, s) = target {
226 Expr::VarAssign(n, Box::from(value), s)
227 } else if let Expr::ArrayGetIndex(base, idx, _) = target {
228 Expr::ArrayModify(base, idx, Box::from(value), expr_span, value_span)
229 } else if let Expr::GetStructField(obj, field, obj_span, field_span) = target {
230 Expr::SetStructField(
231 obj,
232 field,
233 Box::from(value),
234 obj_span,
235 field_span,
236 value_span,
237 )
238 } else {
239 unsafe { unreachable_unchecked() }
240 }
241}