1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
//! Code generation for expressions/statements/patterns
use super::SwcGenerator;
use crate::parser::*;
use crate::codegen::decorated_ast::*;
use crate::codegen::type_context::{TypeContext, TypeEnvironment};
use crate::mapping::{get_node_mapping, get_swc_variant_in_context, get_field_mapping};
impl SwcGenerator {
pub(super) fn gen_decorated_pattern(&mut self, pattern: &DecoratedPattern) {
// Use metadata.swc_pattern directly - no inference needed!
self.emit(&pattern.metadata.swc_pattern);
// Handle inner patterns recursively
match &pattern.kind {
DecoratedPatternKind::Variant { inner: Some(inner_pat), .. } => {
self.emit("(");
self.gen_decorated_pattern(inner_pat);
self.emit(")");
}
DecoratedPatternKind::Tuple(patterns) => {
self.emit("(");
for (i, p) in patterns.iter().enumerate() {
if i > 0 { self.emit(", "); }
self.gen_decorated_pattern(p);
}
self.emit(")");
}
DecoratedPatternKind::Struct { fields, .. } => {
self.emit(" { ");
for (i, (name, p)) in fields.iter().enumerate() {
if i > 0 { self.emit(", "); }
self.emit(name);
self.emit(": ");
self.gen_decorated_pattern(p);
}
self.emit(" }");
}
_ => {
// Other pattern kinds don't need special handling
}
}
}
/// Generate expression from decorated AST (uses metadata)
pub(super) fn gen_pattern(&mut self, pattern: &Pattern) {
match pattern {
Pattern::Literal(lit) => self.gen_literal(lit),
Pattern::Ident(name) => self.emit(name),
Pattern::Wildcard => self.emit("_"),
Pattern::Tuple(patterns) => {
self.emit("(");
for (i, pat) in patterns.iter().enumerate() {
if i > 0 {
self.emit(", ");
}
self.gen_pattern(pat);
}
self.emit(")");
}
Pattern::Array(patterns) => {
self.emit("[");
for (i, pat) in patterns.iter().enumerate() {
if i > 0 {
self.emit(", ");
}
self.gen_pattern(pat);
}
self.emit("]");
}
Pattern::Object(_) => {
// Rust doesn't have object destructuring, use wildcard
self.emit("_");
}
Pattern::Rest(_) => {
// Rest patterns in Rust use ..
self.emit("..");
}
Pattern::Struct { name, fields } => {
self.emit(name);
self.emit(" { ");
for (i, (fname, fpat)) in fields.iter().enumerate() {
if i > 0 {
self.emit(", ");
}
self.emit(fname);
self.emit(": ");
self.gen_pattern(fpat);
}
self.emit(" }");
}
Pattern::Variant { name, inner } => {
// Map ReluxScript type names to SWC types (e.g., Expression::Identifier -> Expr::Ident)
let swc_name = if name.contains("::") {
let parts: Vec<&str> = name.split("::").collect();
if parts.len() == 2 {
let enum_name = self.reluxscript_to_swc_type(parts[0]);
let variant_name = self.reluxscript_to_swc_type(parts[1]);
format!("{}::{}", enum_name, variant_name)
} else {
name.clone()
}
} else {
// Handle standalone variant names (Some, None, Ok, Err)
name.clone()
};
self.emit(&swc_name);
if let Some(inner_pat) = inner {
self.emit("(");
self.gen_pattern(inner_pat);
self.emit(")");
}
}
Pattern::Or(patterns) => {
for (i, p) in patterns.iter().enumerate() {
if i > 0 {
self.emit(" | ");
}
self.gen_pattern(p);
}
}
Pattern::Ref { pattern: inner, .. } => {
// Preserve ref in Rust
self.emit("ref ");
self.gen_pattern(inner);
}
}
}
pub(super) fn gen_swc_pattern_check(&mut self, scrutinee: &Expr, pattern: &Expr, depth: usize) {
match pattern {
Expr::StructInit(init) => {
// Check if this is a wildcard pattern TypeName(_)
if init.fields.len() == 1 && init.fields[0].0 == "_wildcard" {
// Wildcard pattern - just check the type
self.emit("matches!(");
self.gen_expr(scrutinee);
self.emit(", ");
// Use mapping module for SWC enum variants
if let Some(mapping) = get_node_mapping(&init.name) {
// Extract the enum variant pattern (e.g., "Expr::Call(_)")
let pattern_parts: Vec<&str> = mapping.swc_pattern.split('(').collect();
if let Some(variant) = pattern_parts.get(0) {
self.emit(&format!("{}(_)", variant));
} else {
self.emit(&format!("{}(_)", mapping.swc_pattern));
}
} else {
// Fallback for unknown types
self.emit(&format!("{}(_)", init.name));
}
self.emit(")");
return;
}
let swc_type = self.reluxscript_to_swc_type(&init.name.to_lowercase());
// For nested patterns, we need to check the type and fields
// Generate: matches!(scrutinee, SomeType { .. }) && field checks
self.emit("matches!(");
self.gen_expr(scrutinee);
self.emit(", ");
// Use mapping module for SWC enum variants
if let Some(mapping) = get_node_mapping(&init.name) {
// Use the swc_pattern from mapping (e.g., "Expr::Ident(ident)")
// but we need just the pattern without binding
let pattern = mapping.swc_pattern.replace(|c: char| c.is_lowercase() || c == '_', "");
let pattern = if pattern.ends_with("()") {
pattern.replace("()", "(_)")
} else {
format!("{}(_)", mapping.swc_pattern.split('(').next().unwrap_or(&mapping.swc_pattern))
};
self.emit(&pattern);
} else if init.name == "StringLiteral" {
self.emit("Expr::Lit(Lit::Str(_))");
} else {
self.emit(&format!("{}{{ .. }}", swc_type));
}
self.emit(")");
// Generate field checks with && chains
for (field_name, field_pattern) in &init.fields {
self.emit(" && ");
// Generate field access - need to unwrap the enum first
let unwrap_prefix = if let Some(mapping) = get_node_mapping(&init.name) {
// Generate: if let Pattern = &expr { ... }
format!("if let {} = &", mapping.swc_pattern)
} else {
String::new()
};
if !unwrap_prefix.is_empty() {
self.emit("{ ");
self.emit(&unwrap_prefix);
self.gen_expr(scrutinee);
self.emit(" { ");
}
let field_var = format!("__f{}", depth);
match field_pattern {
Expr::Literal(Literal::String(s)) => {
// String equality check on field
// Use field mapping to get correct SWC field name
let swc_field = get_field_mapping(&init.name, field_name)
.map(|m| m.swc)
.unwrap_or(field_name.as_str());
// Get the variable name from the pattern binding
let var_name = get_node_mapping(&init.name)
.map(|m| {
// Extract binding name from pattern like "Expr::Ident(ident)" -> "ident"
m.swc_pattern
.split('(')
.nth(1)
.and_then(|s| s.strip_suffix(')'))
.unwrap_or("n")
})
.unwrap_or("n");
self.emit(&format!("&*{}.{} == \"{}\"", var_name, swc_field, s));
}
Expr::StructInit(nested) => {
// Nested pattern - recursive check
// Get the variable name from the pattern binding
let obj_var = get_node_mapping(&init.name)
.map(|m| {
m.swc_pattern
.split('(')
.nth(1)
.and_then(|s| s.strip_suffix(')'))
.unwrap_or("n")
})
.unwrap_or("n");
// Use field mapping for the field name
let swc_field = get_field_mapping(&init.name, field_name)
.map(|m| m.swc)
.unwrap_or(field_name.as_str());
// Handle MemberProp specially - it's not an Expr
if init.name == "MemberExpression" && field_name == "property" {
// MemberProp needs special handling
if nested.name == "Identifier" {
// MemberProp::Ident
self.emit(&format!("matches!({}.prop, MemberProp::Ident(_))", obj_var));
// Check name if specified
for (nested_field, nested_val) in &nested.fields {
if nested_field == "name" {
if let Expr::Literal(Literal::String(s)) = nested_val {
self.emit(&format!(" && {{ if let MemberProp::Ident(id) = &{}.prop {{ &*id.sym == \"{}\" }} else {{ false }} }}", obj_var, s));
}
}
}
} else {
self.emit("true /* unsupported MemberProp pattern */");
}
} else {
// Create a synthetic expression for the field access
let field_access = Expr::Ident(IdentExpr {
name: format!("(*{}.{})", obj_var, swc_field),
span: crate::lexer::Span::new(0, 0, 0, 0),
});
self.gen_swc_pattern_check(&field_access, &Expr::StructInit(nested.clone()), depth + 1);
}
}
_ => {
self.emit("true");
}
}
if !unwrap_prefix.is_empty() {
self.emit(" } else { false } }");
}
}
}
Expr::Ident(ident) => {
// Type check for a simple type name (e.g., MemberExpression)
let type_name = &ident.name;
// Use mapping to get the correct SWC pattern
if let Some(mapping) = get_node_mapping(type_name) {
// Generate: matches!(scrutinee, Expr::Member(_))
self.emit("matches!(");
self.gen_expr(scrutinee);
self.emit(", ");
// Extract just the pattern part (e.g., "Expr::Member(_)")
let pattern_str = mapping.swc_pattern;
// Replace any binding variable with _
let pattern = if pattern_str.contains('(') {
let parts: Vec<&str> = pattern_str.split('(').collect();
format!("{}(_)", parts[0])
} else {
format!("{}{{ .. }}", pattern_str)
};
self.emit(&pattern);
self.emit(")");
} else {
// Fallback: try common mappings
let swc_pattern = match type_name.as_str() {
"MemberExpression" => "Expr::Member(_)",
"CallExpression" => "Expr::Call(_)",
"Identifier" => "Expr::Ident(_)",
"FunctionDeclaration" => "Decl::Fn(_)",
"VariableDeclaration" => "Decl::Var(_)",
"ReturnStatement" => "Stmt::Return(_)",
"IfStatement" => "Stmt::If(_)",
"BlockStatement" => "Stmt::Block(_)",
_ => {
// Generate a placeholder
self.gen_expr(scrutinee);
self.emit(&format!(".is_{}()", type_name.to_lowercase()));
return;
}
};
self.emit(&format!("matches!("));
self.gen_expr(scrutinee);
self.emit(&format!(", {})", swc_pattern));
}
}
_ => {
// Literal or other pattern - generate equality check
self.gen_expr(scrutinee);
self.emit(" == ");
self.gen_expr(pattern);
}
}
}
}
impl Default for SwcGenerator {
}