Skip to main content

zapcode_core/parser/
mod.rs

1pub mod ir;
2
3use ir::*;
4use oxc_allocator::Allocator;
5use oxc_ast::ast;
6use oxc_parser::Parser;
7use oxc_span::SourceType;
8
9use crate::error::{Result, ZapcodeError};
10
11pub fn parse(source: &str) -> Result<Program> {
12    let allocator = Allocator::default();
13    let source_type = SourceType::tsx();
14    let ret = Parser::new(&allocator, source, source_type).parse();
15
16    if !ret.errors.is_empty() {
17        let msgs: Vec<String> = ret.errors.iter().map(|e| e.to_string()).collect();
18        return Err(ZapcodeError::ParseError(msgs.join("\n")));
19    }
20
21    let mut lowerer = AstLowerer::new(source);
22    lowerer.lower_program(&ret.program)?;
23
24    Ok(Program {
25        body: lowerer.body,
26        functions: lowerer.functions,
27    })
28}
29
30struct AstLowerer<'a> {
31    #[allow(dead_code)]
32    source: &'a str,
33    body: Vec<Statement>,
34    functions: Vec<FunctionDef>,
35}
36
37impl<'a> AstLowerer<'a> {
38    fn new(source: &'a str) -> Self {
39        Self {
40            source,
41            body: Vec::new(),
42            functions: Vec::new(),
43        }
44    }
45
46    fn span(&self, s: oxc_span::Span) -> Span {
47        s.into()
48    }
49
50    fn unsupported(&self, span: oxc_span::Span, desc: &str) -> ZapcodeError {
51        ZapcodeError::UnsupportedSyntax {
52            span: format!("{}..{}", span.start, span.end),
53            description: desc.to_string(),
54        }
55    }
56
57    fn lower_program(&mut self, program: &ast::Program<'_>) -> Result<()> {
58        // Handle directives (e.g., "use strict", but also bare string literals)
59        for directive in &program.directives {
60            let span = self.span(directive.span);
61            let expr = Expr::StringLit(directive.directive.to_string());
62            self.body.push(Statement::Expression { expr, span });
63        }
64        for stmt in &program.body {
65            let s = self.lower_statement(stmt)?;
66            self.body.push(s);
67        }
68        Ok(())
69    }
70
71    fn lower_statement(&mut self, stmt: &ast::Statement<'_>) -> Result<Statement> {
72        match stmt {
73            ast::Statement::VariableDeclaration(decl) => self.lower_var_decl(decl),
74            ast::Statement::ExpressionStatement(expr_stmt) => {
75                let span = self.span(expr_stmt.span);
76                let expr = self.lower_expr(&expr_stmt.expression)?;
77                Ok(Statement::Expression { expr, span })
78            }
79            ast::Statement::ReturnStatement(ret) => {
80                let span = self.span(ret.span);
81                let value = match &ret.argument {
82                    Some(arg) => Some(self.lower_expr(arg)?),
83                    None => None,
84                };
85                Ok(Statement::Return { value, span })
86            }
87            ast::Statement::IfStatement(if_stmt) => self.lower_if(if_stmt),
88            ast::Statement::WhileStatement(while_stmt) => {
89                let span = self.span(while_stmt.span);
90                let test = self.lower_expr(&while_stmt.test)?;
91                let body = self.lower_statement_as_block(&while_stmt.body)?;
92                Ok(Statement::While { test, body, span })
93            }
94            ast::Statement::DoWhileStatement(do_while) => {
95                let span = self.span(do_while.span);
96                let body = self.lower_statement_as_block(&do_while.body)?;
97                let test = self.lower_expr(&do_while.test)?;
98                Ok(Statement::DoWhile { body, test, span })
99            }
100            ast::Statement::ForStatement(for_stmt) => self.lower_for(for_stmt),
101            ast::Statement::ForInStatement(s) => {
102                Err(self.unsupported(s.span, "for...in loops are not supported, use for...of"))
103            }
104            ast::Statement::ForOfStatement(for_of) => self.lower_for_of(for_of),
105            ast::Statement::BlockStatement(block) => {
106                let span = self.span(block.span);
107                let body = self.lower_statements(&block.body)?;
108                Ok(Statement::Block { body, span })
109            }
110            ast::Statement::ThrowStatement(throw) => {
111                let span = self.span(throw.span);
112                let value = self.lower_expr(&throw.argument)?;
113                Ok(Statement::Throw { value, span })
114            }
115            ast::Statement::TryStatement(try_stmt) => self.lower_try(try_stmt),
116            ast::Statement::BreakStatement(s) => Ok(Statement::Break {
117                span: self.span(s.span),
118            }),
119            ast::Statement::ContinueStatement(s) => Ok(Statement::Continue {
120                span: self.span(s.span),
121            }),
122            ast::Statement::FunctionDeclaration(func) => self.lower_func_decl(func),
123            ast::Statement::ClassDeclaration(class) => self.lower_class_decl(class),
124            ast::Statement::SwitchStatement(switch) => self.lower_switch(switch),
125            ast::Statement::EmptyStatement(_) => Ok(Statement::Expression {
126                expr: Expr::UndefinedLit,
127                span: Span { start: 0, end: 0 },
128            }),
129            ast::Statement::LabeledStatement(labeled) => self.lower_statement(&labeled.body),
130            ast::Statement::TSTypeAliasDeclaration(s) => Ok(Statement::Expression {
131                expr: Expr::UndefinedLit,
132                span: self.span(s.span),
133            }),
134            ast::Statement::TSInterfaceDeclaration(s) => Ok(Statement::Expression {
135                expr: Expr::UndefinedLit,
136                span: self.span(s.span),
137            }),
138            ast::Statement::TSEnumDeclaration(s) => {
139                Err(self.unsupported(s.span, "TypeScript enums are not supported"))
140            }
141            ast::Statement::ImportDeclaration(s) => Err(ZapcodeError::SandboxViolation(format!(
142                "import declarations are forbidden in the sandbox (at {}..{})",
143                s.span.start, s.span.end
144            ))),
145            ast::Statement::ExportDefaultDeclaration(s) => {
146                Err(ZapcodeError::SandboxViolation(format!(
147                    "export declarations are forbidden in the sandbox (at {}..{})",
148                    s.span.start, s.span.end
149                )))
150            }
151            ast::Statement::ExportNamedDeclaration(s) => {
152                Err(ZapcodeError::SandboxViolation(format!(
153                    "export declarations are forbidden in the sandbox (at {}..{})",
154                    s.span.start, s.span.end
155                )))
156            }
157            ast::Statement::ExportAllDeclaration(s) => {
158                Err(ZapcodeError::SandboxViolation(format!(
159                    "export declarations are forbidden in the sandbox (at {}..{})",
160                    s.span.start, s.span.end
161                )))
162            }
163            _ => Err(ZapcodeError::UnsupportedSyntax {
164                span: "unknown".to_string(),
165                description: "unsupported statement type".to_string(),
166            }),
167        }
168    }
169
170    fn lower_statements(&mut self, stmts: &[ast::Statement<'_>]) -> Result<Vec<Statement>> {
171        stmts.iter().map(|s| self.lower_statement(s)).collect()
172    }
173
174    fn lower_statement_as_block(&mut self, stmt: &ast::Statement<'_>) -> Result<Vec<Statement>> {
175        match stmt {
176            ast::Statement::BlockStatement(block) => self.lower_statements(&block.body),
177            other => Ok(vec![self.lower_statement(other)?]),
178        }
179    }
180
181    fn lower_var_decl(&mut self, decl: &ast::VariableDeclaration<'_>) -> Result<Statement> {
182        let span = self.span(decl.span);
183        let kind = match decl.kind {
184            ast::VariableDeclarationKind::Const => VarKind::Const,
185            ast::VariableDeclarationKind::Let => VarKind::Let,
186            ast::VariableDeclarationKind::Var => VarKind::Var,
187            ast::VariableDeclarationKind::Using | ast::VariableDeclarationKind::AwaitUsing => {
188                return Err(self.unsupported(decl.span, "using declarations are not supported"));
189            }
190        };
191        let mut declarations = Vec::new();
192        for declarator in &decl.declarations {
193            let pattern = self.lower_binding_pattern(&declarator.id)?;
194            let init = match &declarator.init {
195                Some(expr) => Some(self.lower_expr(expr)?),
196                None => None,
197            };
198            declarations.push(VarDeclarator { pattern, init });
199        }
200        Ok(Statement::VariableDecl {
201            kind,
202            declarations,
203            span,
204        })
205    }
206
207    fn lower_binding_pattern(&mut self, pat: &ast::BindingPattern<'_>) -> Result<AssignTarget> {
208        match pat {
209            ast::BindingPattern::BindingIdentifier(id) => {
210                Ok(AssignTarget::Ident(id.name.to_string()))
211            }
212            ast::BindingPattern::ObjectPattern(obj) => {
213                let mut fields = Vec::new();
214                for prop in &obj.properties {
215                    let key = property_key_to_string(&prop.key);
216                    let alias = match &prop.value {
217                        ast::BindingPattern::BindingIdentifier(id) => {
218                            let name = id.name.to_string();
219                            if name != key {
220                                Some(name)
221                            } else {
222                                None
223                            }
224                        }
225                        _ => None,
226                    };
227                    let default = match &prop.value {
228                        ast::BindingPattern::AssignmentPattern(assign) => {
229                            Some(self.lower_expr(&assign.right)?)
230                        }
231                        _ => None,
232                    };
233                    fields.push(DestructureField {
234                        key,
235                        alias,
236                        default,
237                    });
238                }
239                Ok(AssignTarget::ObjectDestructure(fields))
240            }
241            ast::BindingPattern::ArrayPattern(arr) => {
242                let mut elements = Vec::new();
243                for elem in &arr.elements {
244                    match elem {
245                        Some(pat) => elements.push(Some(self.lower_binding_pattern(pat)?)),
246                        None => elements.push(None),
247                    }
248                }
249                Ok(AssignTarget::ArrayDestructure(elements))
250            }
251            ast::BindingPattern::AssignmentPattern(assign) => {
252                self.lower_binding_pattern(&assign.left)
253            }
254        }
255    }
256
257    fn lower_binding_pattern_to_param(
258        &mut self,
259        pat: &ast::BindingPattern<'_>,
260    ) -> Result<ParamPattern> {
261        match pat {
262            ast::BindingPattern::BindingIdentifier(id) => {
263                Ok(ParamPattern::Ident(id.name.to_string()))
264            }
265            ast::BindingPattern::ObjectPattern(obj) => {
266                let mut fields = Vec::new();
267                for prop in &obj.properties {
268                    let key = property_key_to_string(&prop.key);
269                    let alias = match &prop.value {
270                        ast::BindingPattern::BindingIdentifier(id) => {
271                            let name = id.name.to_string();
272                            if name != key {
273                                Some(name)
274                            } else {
275                                None
276                            }
277                        }
278                        _ => None,
279                    };
280                    fields.push(DestructureField {
281                        key,
282                        alias,
283                        default: None,
284                    });
285                }
286                Ok(ParamPattern::ObjectDestructure(fields))
287            }
288            ast::BindingPattern::ArrayPattern(arr) => {
289                let mut elems = Vec::new();
290                for elem in &arr.elements {
291                    match elem {
292                        Some(p) => elems.push(Some(self.lower_binding_pattern_to_param(p)?)),
293                        None => elems.push(None),
294                    }
295                }
296                Ok(ParamPattern::ArrayDestructure(elems))
297            }
298            ast::BindingPattern::AssignmentPattern(assign) => {
299                let inner = self.lower_binding_pattern_to_param(&assign.left)?;
300                let default = self.lower_expr(&assign.right)?;
301                Ok(ParamPattern::DefaultValue {
302                    pattern: Box::new(inner),
303                    default,
304                })
305            }
306        }
307    }
308
309    fn lower_if(&mut self, if_stmt: &ast::IfStatement<'_>) -> Result<Statement> {
310        let span = self.span(if_stmt.span);
311        let test = self.lower_expr(&if_stmt.test)?;
312        let consequent = self.lower_statement_as_block(&if_stmt.consequent)?;
313        let alternate = match &if_stmt.alternate {
314            Some(alt) => Some(self.lower_statement_as_block(alt)?),
315            None => None,
316        };
317        Ok(Statement::If {
318            test,
319            consequent,
320            alternate,
321            span,
322        })
323    }
324
325    fn lower_for(&mut self, for_stmt: &ast::ForStatement<'_>) -> Result<Statement> {
326        let span = self.span(for_stmt.span);
327        let init = match &for_stmt.init {
328            Some(init) => match init {
329                ast::ForStatementInit::VariableDeclaration(decl) => {
330                    Some(Box::new(self.lower_var_decl(decl)?))
331                }
332                other => {
333                    if let Some(expr_ref) = other.as_expression() {
334                        let expr = self.lower_expr(expr_ref)?;
335                        Some(Box::new(Statement::Expression { expr, span }))
336                    } else {
337                        return Err(ZapcodeError::CompileError(
338                            "unsupported for-loop initializer".to_string(),
339                        ));
340                    }
341                }
342            },
343            None => None,
344        };
345        let test = match &for_stmt.test {
346            Some(t) => Some(self.lower_expr(t)?),
347            None => None,
348        };
349        let update = match &for_stmt.update {
350            Some(u) => Some(self.lower_expr(u)?),
351            None => None,
352        };
353        let body = self.lower_statement_as_block(&for_stmt.body)?;
354        Ok(Statement::For {
355            init,
356            test,
357            update,
358            body,
359            span,
360        })
361    }
362
363    fn lower_for_of(&mut self, for_of: &ast::ForOfStatement<'_>) -> Result<Statement> {
364        let span = self.span(for_of.span);
365        let binding = match &for_of.left {
366            ast::ForStatementLeft::VariableDeclaration(decl) => {
367                if let Some(declarator) = decl.declarations.first() {
368                    match &declarator.id {
369                        ast::BindingPattern::BindingIdentifier(id) => {
370                            ForBinding::Ident(id.name.to_string())
371                        }
372                        _ => {
373                            let pat = self.lower_binding_pattern_to_param(&declarator.id)?;
374                            ForBinding::Destructure(pat)
375                        }
376                    }
377                } else {
378                    return Err(self.unsupported(for_of.span, "empty for-of binding"));
379                }
380            }
381            _ => return Err(self.unsupported(for_of.span, "unsupported for-of left-hand side")),
382        };
383        let iterable = self.lower_expr(&for_of.right)?;
384        let body = self.lower_statement_as_block(&for_of.body)?;
385        Ok(Statement::ForOf {
386            binding,
387            iterable,
388            body,
389            span,
390        })
391    }
392
393    fn lower_try(&mut self, try_stmt: &ast::TryStatement<'_>) -> Result<Statement> {
394        let span = self.span(try_stmt.span);
395        let try_body = self.lower_statements(&try_stmt.block.body)?;
396        let (catch_param, catch_body) = match &try_stmt.handler {
397            Some(handler) => {
398                let param = handler.param.as_ref().and_then(|p| match &p.pattern {
399                    ast::BindingPattern::BindingIdentifier(id) => Some(id.name.to_string()),
400                    _ => None,
401                });
402                let body = self.lower_statements(&handler.body.body)?;
403                (param, body)
404            }
405            None => (None, Vec::new()),
406        };
407        let finally_body = match &try_stmt.finalizer {
408            Some(block) => Some(self.lower_statements(&block.body)?),
409            None => None,
410        };
411        Ok(Statement::TryCatch {
412            try_body,
413            catch_param,
414            catch_body,
415            finally_body,
416            span,
417        })
418    }
419
420    fn lower_func_decl(&mut self, func: &ast::Function<'_>) -> Result<Statement> {
421        let span = self.span(func.span);
422        let func_def = self.lower_function(func)?;
423        let func_index = self.functions.len();
424        self.functions.push(func_def);
425        Ok(Statement::FunctionDecl { func_index, span })
426    }
427
428    fn lower_function(&mut self, func: &ast::Function<'_>) -> Result<FunctionDef> {
429        let name = func.id.as_ref().map(|id| id.name.to_string());
430        let params = self.lower_formal_params(&func.params)?;
431        let body = match &func.body {
432            Some(body) => self.lower_statements(&body.statements)?,
433            None => Vec::new(),
434        };
435        Ok(FunctionDef {
436            name,
437            params,
438            body,
439            is_async: func.r#async,
440            is_generator: func.generator,
441            is_arrow: false,
442            span: self.span(func.span),
443        })
444    }
445
446    fn lower_formal_params(
447        &mut self,
448        params: &ast::FormalParameters<'_>,
449    ) -> Result<Vec<ParamPattern>> {
450        let mut result = Vec::new();
451        for param in &params.items {
452            let pat = self.lower_binding_pattern_to_param(&param.pattern)?;
453            result.push(pat);
454        }
455        if let Some(rest) = &params.rest {
456            match &rest.rest.argument {
457                ast::BindingPattern::BindingIdentifier(id) => {
458                    result.push(ParamPattern::Rest(id.name.to_string()));
459                }
460                _ => {
461                    return Err(self.unsupported(
462                        rest.span,
463                        "complex rest parameter patterns are not supported",
464                    ));
465                }
466            }
467        }
468        Ok(result)
469    }
470
471    fn lower_class_decl(&mut self, class: &ast::Class<'_>) -> Result<Statement> {
472        let span = self.span(class.span);
473        let name = class
474            .id
475            .as_ref()
476            .map(|id| id.name.to_string())
477            .unwrap_or_else(|| "AnonymousClass".to_string());
478
479        let super_class = match &class.super_class {
480            Some(expr) => {
481                if let ast::Expression::Identifier(id) = expr {
482                    Some(id.name.to_string())
483                } else {
484                    return Err(self.unsupported(
485                        class.span,
486                        "computed super class expressions are not supported",
487                    ));
488                }
489            }
490            None => None,
491        };
492
493        let (constructor, methods, static_methods) = self.lower_class_body(&class.body)?;
494
495        Ok(Statement::ClassDecl {
496            name,
497            super_class,
498            constructor,
499            methods,
500            static_methods,
501            span,
502        })
503    }
504
505    fn lower_class_expr(&mut self, class: &ast::Class<'_>) -> Result<Expr> {
506        let name = class.id.as_ref().map(|id| id.name.to_string());
507
508        let super_class = match &class.super_class {
509            Some(expr) => {
510                if let ast::Expression::Identifier(id) = expr {
511                    Some(id.name.to_string())
512                } else {
513                    return Err(self.unsupported(
514                        class.span,
515                        "computed super class expressions are not supported",
516                    ));
517                }
518            }
519            None => None,
520        };
521
522        let (constructor, methods, static_methods) = self.lower_class_body(&class.body)?;
523
524        Ok(Expr::ClassExpr {
525            name,
526            super_class,
527            constructor,
528            methods,
529            static_methods,
530        })
531    }
532
533    fn lower_class_body(&mut self, body: &ast::ClassBody<'_>) -> Result<ClassBodyParts> {
534        let mut constructor = None;
535        let mut methods = Vec::new();
536        let mut static_methods = Vec::new();
537
538        for element in &body.body {
539            match element {
540                ast::ClassElement::MethodDefinition(method) => {
541                    let method_name = match &method.key {
542                        ast::PropertyKey::StaticIdentifier(id) => id.name.to_string(),
543                        ast::PropertyKey::StringLiteral(s) => s.value.to_string(),
544                        _ => continue, // skip computed method names
545                    };
546
547                    let func = &method.value;
548                    let params = self.lower_formal_params(&func.params)?;
549                    let body_stmts = match &func.body {
550                        Some(body) => self.lower_statements(&body.statements)?,
551                        None => Vec::new(),
552                    };
553
554                    let func_def = FunctionDef {
555                        name: Some(method_name.clone()),
556                        params,
557                        body: body_stmts,
558                        is_async: func.r#async,
559                        is_generator: false,
560                        is_arrow: false,
561                        span: self.span(func.span),
562                    };
563
564                    match method.kind {
565                        ast::MethodDefinitionKind::Constructor => {
566                            constructor = Some(Box::new(func_def));
567                        }
568                        ast::MethodDefinitionKind::Method => {
569                            if method.r#static {
570                                static_methods.push(ClassMethod {
571                                    name: method_name,
572                                    func: func_def,
573                                });
574                            } else {
575                                methods.push(ClassMethod {
576                                    name: method_name,
577                                    func: func_def,
578                                });
579                            }
580                        }
581                        ast::MethodDefinitionKind::Get | ast::MethodDefinitionKind::Set => {
582                            // Getters/setters: treat as regular methods for now
583                            if method.r#static {
584                                static_methods.push(ClassMethod {
585                                    name: method_name,
586                                    func: func_def,
587                                });
588                            } else {
589                                methods.push(ClassMethod {
590                                    name: method_name,
591                                    func: func_def,
592                                });
593                            }
594                        }
595                    }
596                }
597                ast::ClassElement::PropertyDefinition(_) => {
598                    // Class property declarations (e.g., `name: string;`) are type-level
599                    // and are handled at runtime through constructor assignments.
600                    // Skip them in the IR.
601                }
602                ast::ClassElement::AccessorProperty(s) => {
603                    return Err(self
604                        .unsupported(s.span, "accessor properties in classes are not supported"));
605                }
606                ast::ClassElement::TSIndexSignature(_) => {
607                    // TypeScript-only, skip
608                }
609                ast::ClassElement::StaticBlock(s) => {
610                    return Err(self.unsupported(s.span, "static blocks are not supported"));
611                }
612            }
613        }
614
615        Ok((constructor, methods, static_methods))
616    }
617
618    fn lower_switch(&mut self, switch: &ast::SwitchStatement<'_>) -> Result<Statement> {
619        let span = self.span(switch.span);
620        let discriminant = self.lower_expr(&switch.discriminant)?;
621        let mut cases = Vec::new();
622        for case in &switch.cases {
623            let test = match &case.test {
624                Some(t) => Some(self.lower_expr(t)?),
625                None => None,
626            };
627            let consequent = self.lower_statements(&case.consequent)?;
628            cases.push(SwitchCase { test, consequent });
629        }
630        Ok(Statement::Switch {
631            discriminant,
632            cases,
633            span,
634        })
635    }
636
637    fn lower_expr(&mut self, expr: &ast::Expression<'_>) -> Result<Expr> {
638        match expr {
639            ast::Expression::NumericLiteral(lit) => Ok(Expr::NumberLit(lit.value)),
640            ast::Expression::StringLiteral(lit) => Ok(Expr::StringLit(lit.value.to_string())),
641            ast::Expression::BooleanLiteral(lit) => Ok(Expr::BoolLit(lit.value)),
642            ast::Expression::NullLiteral(_) => Ok(Expr::NullLit),
643            ast::Expression::TemplateLiteral(tpl) => {
644                let quasis: Vec<String> =
645                    tpl.quasis.iter().map(|q| q.value.raw.to_string()).collect();
646                let exprs: Result<Vec<Expr>> =
647                    tpl.expressions.iter().map(|e| self.lower_expr(e)).collect();
648                Ok(Expr::TemplateLit {
649                    quasis,
650                    exprs: exprs?,
651                })
652            }
653            ast::Expression::RegExpLiteral(re) => Ok(Expr::RegExpLit {
654                pattern: format!("{:?}", re.regex.pattern),
655                flags: re.regex.flags.to_string(),
656            }),
657            ast::Expression::Identifier(id) => {
658                let name = id.name.to_string();
659                match name.as_str() {
660                    "undefined" => Ok(Expr::UndefinedLit),
661                    "NaN" => Ok(Expr::NumberLit(f64::NAN)),
662                    "Infinity" => Ok(Expr::NumberLit(f64::INFINITY)),
663                    "eval" => Err(ZapcodeError::SandboxViolation(
664                        "eval is forbidden in the sandbox".to_string(),
665                    )),
666                    "Function" => Err(ZapcodeError::SandboxViolation(
667                        "Function constructor is forbidden in the sandbox".to_string(),
668                    )),
669                    "process" => Err(ZapcodeError::SandboxViolation(
670                        "process is forbidden in the sandbox".to_string(),
671                    )),
672                    "globalThis" | "global" => Err(ZapcodeError::SandboxViolation(
673                        "globalThis/global is forbidden in the sandbox".to_string(),
674                    )),
675                    "require" => Err(ZapcodeError::SandboxViolation(
676                        "require is forbidden in the sandbox".to_string(),
677                    )),
678                    _ => Ok(Expr::Ident(name)),
679                }
680            }
681            ast::Expression::ArrayExpression(arr) => {
682                let mut elements = Vec::new();
683                for elem in &arr.elements {
684                    match elem {
685                        ast::ArrayExpressionElement::SpreadElement(spread) => {
686                            let expr = self.lower_expr(&spread.argument)?;
687                            elements.push(Some(Expr::Spread(Box::new(expr))));
688                        }
689                        ast::ArrayExpressionElement::Elision(_) => {
690                            elements.push(None);
691                        }
692                        other => {
693                            let expr_ref = other.to_expression();
694                            let expr = self.lower_expr(expr_ref)?;
695                            elements.push(Some(expr));
696                        }
697                    }
698                }
699                Ok(Expr::Array(elements))
700            }
701            ast::Expression::ObjectExpression(obj) => {
702                let mut props = Vec::new();
703                for prop in &obj.properties {
704                    match prop {
705                        ast::ObjectPropertyKind::ObjectProperty(p) => {
706                            let key = self.lower_property_key(&p.key)?;
707                            let computed = p.computed;
708
709                            if p.shorthand {
710                                props.push(ObjProperty {
711                                    kind: PropKind::Shorthand,
712                                    key: key.clone(),
713                                    value: Expr::Ident(key),
714                                    computed: false,
715                                });
716                            } else if p.method {
717                                let value = self.lower_expr(&p.value)?;
718                                props.push(ObjProperty {
719                                    kind: PropKind::Method,
720                                    key,
721                                    value,
722                                    computed,
723                                });
724                            } else {
725                                let value = self.lower_expr(&p.value)?;
726                                props.push(ObjProperty {
727                                    kind: PropKind::Init,
728                                    key,
729                                    value,
730                                    computed,
731                                });
732                            }
733                        }
734                        ast::ObjectPropertyKind::SpreadProperty(spread) => {
735                            let expr = self.lower_expr(&spread.argument)?;
736                            props.push(ObjProperty {
737                                kind: PropKind::Spread,
738                                key: String::new(),
739                                value: expr,
740                                computed: false,
741                            });
742                        }
743                    }
744                }
745                Ok(Expr::Object(props))
746            }
747            ast::Expression::BinaryExpression(bin) => {
748                let op = lower_binary_op(bin.operator)?;
749                let left = self.lower_expr(&bin.left)?;
750                let right = self.lower_expr(&bin.right)?;
751                Ok(Expr::Binary {
752                    op,
753                    left: Box::new(left),
754                    right: Box::new(right),
755                })
756            }
757            ast::Expression::UnaryExpression(unary) => {
758                if matches!(unary.operator, ast::UnaryOperator::Typeof) {
759                    let operand = self.lower_expr(&unary.argument)?;
760                    return Ok(Expr::TypeOf(Box::new(operand)));
761                }
762                if matches!(unary.operator, ast::UnaryOperator::Delete) {
763                    return Err(self.unsupported(unary.span, "delete operator is not supported"));
764                }
765                let op = match unary.operator {
766                    ast::UnaryOperator::UnaryNegation => UnaryOp::Neg,
767                    ast::UnaryOperator::LogicalNot => UnaryOp::Not,
768                    ast::UnaryOperator::BitwiseNot => UnaryOp::BitNot,
769                    ast::UnaryOperator::Void => UnaryOp::Void,
770                    ast::UnaryOperator::UnaryPlus => {
771                        let operand = self.lower_expr(&unary.argument)?;
772                        return Ok(Expr::Binary {
773                            op: BinOp::Mul,
774                            left: Box::new(operand),
775                            right: Box::new(Expr::NumberLit(1.0)),
776                        });
777                    }
778                    _ => {
779                        return Err(self.unsupported(unary.span, "unsupported unary operator"));
780                    }
781                };
782                let operand = self.lower_expr(&unary.argument)?;
783                Ok(Expr::Unary {
784                    op,
785                    operand: Box::new(operand),
786                })
787            }
788            ast::Expression::UpdateExpression(update) => {
789                let op = match update.operator {
790                    ast::UpdateOperator::Increment => UpdateOp::Increment,
791                    ast::UpdateOperator::Decrement => UpdateOp::Decrement,
792                };
793                let operand = self.lower_simple_assign_target(&update.argument)?;
794                Ok(Expr::Update {
795                    op,
796                    prefix: update.prefix,
797                    operand: Box::new(operand),
798                })
799            }
800            ast::Expression::LogicalExpression(logical) => {
801                let op = match logical.operator {
802                    ast::LogicalOperator::And => LogicalOp::And,
803                    ast::LogicalOperator::Or => LogicalOp::Or,
804                    ast::LogicalOperator::Coalesce => LogicalOp::NullishCoalescing,
805                };
806                let left = self.lower_expr(&logical.left)?;
807                let right = self.lower_expr(&logical.right)?;
808                Ok(Expr::Logical {
809                    op,
810                    left: Box::new(left),
811                    right: Box::new(right),
812                })
813            }
814            ast::Expression::ConditionalExpression(cond) => {
815                let test = self.lower_expr(&cond.test)?;
816                let consequent = self.lower_expr(&cond.consequent)?;
817                let alternate = self.lower_expr(&cond.alternate)?;
818                Ok(Expr::Conditional {
819                    test: Box::new(test),
820                    consequent: Box::new(consequent),
821                    alternate: Box::new(alternate),
822                })
823            }
824            ast::Expression::AssignmentExpression(assign) => {
825                let op = lower_assign_op(assign.operator);
826                let target = self.lower_assignment_target(&assign.left)?;
827                let value = self.lower_expr(&assign.right)?;
828                Ok(Expr::Assignment {
829                    op,
830                    target: Box::new(target),
831                    value: Box::new(value),
832                })
833            }
834            ast::Expression::SequenceExpression(seq) => {
835                let exprs: Result<Vec<Expr>> =
836                    seq.expressions.iter().map(|e| self.lower_expr(e)).collect();
837                Ok(Expr::Sequence(exprs?))
838            }
839            ast::Expression::CallExpression(call) => {
840                let callee = self.lower_expr(&call.callee)?;
841                let args = self.lower_args(&call.arguments)?;
842                Ok(Expr::Call {
843                    callee: Box::new(callee),
844                    args,
845                    optional: call.optional,
846                })
847            }
848            ast::Expression::NewExpression(new_expr) => {
849                let callee = self.lower_expr(&new_expr.callee)?;
850                let args = self.lower_args(&new_expr.arguments)?;
851                Ok(Expr::New {
852                    callee: Box::new(callee),
853                    args,
854                })
855            }
856            ast::Expression::StaticMemberExpression(member) => {
857                let object = self.lower_expr(&member.object)?;
858                let property = member.property.name.to_string();
859                Ok(Expr::Member {
860                    object: Box::new(object),
861                    property,
862                    optional: member.optional,
863                })
864            }
865            ast::Expression::ComputedMemberExpression(member) => {
866                let object = self.lower_expr(&member.object)?;
867                let property = self.lower_expr(&member.expression)?;
868                Ok(Expr::ComputedMember {
869                    object: Box::new(object),
870                    property: Box::new(property),
871                    optional: member.optional,
872                })
873            }
874            ast::Expression::PrivateFieldExpression(s) => {
875                Err(self.unsupported(s.span, "private fields are not supported"))
876            }
877            ast::Expression::ArrowFunctionExpression(arrow) => {
878                let params = self.lower_formal_params(&arrow.params)?;
879                let body = if arrow.expression {
880                    match arrow.body.statements.first() {
881                        Some(ast::Statement::ExpressionStatement(expr)) => {
882                            let ret_expr = self.lower_expr(&expr.expression)?;
883                            vec![Statement::Return {
884                                value: Some(ret_expr),
885                                span: self.span(arrow.span),
886                            }]
887                        }
888                        _ => self.lower_statements(&arrow.body.statements)?,
889                    }
890                } else {
891                    self.lower_statements(&arrow.body.statements)?
892                };
893                let func_index = self.functions.len();
894                self.functions.push(FunctionDef {
895                    name: None,
896                    params,
897                    body,
898                    is_async: arrow.r#async,
899                    is_generator: false,
900                    is_arrow: true,
901                    span: self.span(arrow.span),
902                });
903                Ok(Expr::ArrowFunction { func_index })
904            }
905            ast::Expression::FunctionExpression(func) => {
906                let func_def = self.lower_function(func)?;
907                let func_index = self.functions.len();
908                self.functions.push(func_def);
909                Ok(Expr::FunctionExpr { func_index })
910            }
911            ast::Expression::AwaitExpression(await_expr) => {
912                let expr = self.lower_expr(&await_expr.argument)?;
913                Ok(Expr::Await(Box::new(expr)))
914            }
915            ast::Expression::ParenthesizedExpression(paren) => self.lower_expr(&paren.expression),
916            ast::Expression::ChainExpression(chain) => self.lower_chain_expr(&chain.expression),
917            ast::Expression::TaggedTemplateExpression(s) => {
918                Err(self.unsupported(s.span, "tagged template expressions are not supported"))
919            }
920            ast::Expression::ThisExpression(_) => Ok(Expr::Ident("this".to_string())),
921            ast::Expression::Super(_) => Ok(Expr::Ident("super".to_string())),
922            ast::Expression::YieldExpression(yield_expr) => {
923                let value = match &yield_expr.argument {
924                    Some(arg) => Some(Box::new(self.lower_expr(arg)?)),
925                    None => None,
926                };
927                Ok(Expr::Yield {
928                    value,
929                    delegate: yield_expr.delegate,
930                })
931            }
932            ast::Expression::ClassExpression(class) => self.lower_class_expr(class),
933            ast::Expression::MetaProperty(s) => {
934                Err(self.unsupported(s.span, "meta properties are not supported"))
935            }
936            ast::Expression::ImportExpression(s) => Err(ZapcodeError::SandboxViolation(format!(
937                "dynamic import() is forbidden in the sandbox (at {}..{})",
938                s.span.start, s.span.end
939            ))),
940            ast::Expression::TSAsExpression(ts) => self.lower_expr(&ts.expression),
941            ast::Expression::TSSatisfiesExpression(ts) => self.lower_expr(&ts.expression),
942            ast::Expression::TSNonNullExpression(ts) => self.lower_expr(&ts.expression),
943            ast::Expression::TSTypeAssertion(ts) => self.lower_expr(&ts.expression),
944            ast::Expression::TSInstantiationExpression(ts) => self.lower_expr(&ts.expression),
945            _ => Err(ZapcodeError::UnsupportedSyntax {
946                span: "unknown".to_string(),
947                description: "unsupported expression type".to_string(),
948            }),
949        }
950    }
951
952    fn lower_chain_expr(&mut self, expr: &ast::ChainElement<'_>) -> Result<Expr> {
953        match expr {
954            ast::ChainElement::CallExpression(call) => {
955                let callee = self.lower_expr(&call.callee)?;
956                let args = self.lower_args(&call.arguments)?;
957                Ok(Expr::Call {
958                    callee: Box::new(callee),
959                    args,
960                    optional: call.optional,
961                })
962            }
963            ast::ChainElement::StaticMemberExpression(member) => {
964                let object = self.lower_expr(&member.object)?;
965                Ok(Expr::Member {
966                    object: Box::new(object),
967                    property: member.property.name.to_string(),
968                    optional: member.optional,
969                })
970            }
971            ast::ChainElement::ComputedMemberExpression(member) => {
972                let object = self.lower_expr(&member.object)?;
973                let property = self.lower_expr(&member.expression)?;
974                Ok(Expr::ComputedMember {
975                    object: Box::new(object),
976                    property: Box::new(property),
977                    optional: member.optional,
978                })
979            }
980            ast::ChainElement::PrivateFieldExpression(s) => {
981                Err(self.unsupported(s.span, "private fields are not supported"))
982            }
983            ast::ChainElement::TSNonNullExpression(ts) => self.lower_expr(&ts.expression),
984        }
985    }
986
987    fn lower_args(&mut self, args: &[ast::Argument<'_>]) -> Result<Vec<Expr>> {
988        let mut result = Vec::new();
989        for arg in args {
990            match arg {
991                ast::Argument::SpreadElement(spread) => {
992                    let expr = self.lower_expr(&spread.argument)?;
993                    result.push(Expr::Spread(Box::new(expr)));
994                }
995                other => {
996                    let expr_ref = other.to_expression();
997                    let expr = self.lower_expr(expr_ref)?;
998                    result.push(expr);
999                }
1000            }
1001        }
1002        Ok(result)
1003    }
1004
1005    fn lower_property_key(&mut self, key: &ast::PropertyKey<'_>) -> Result<String> {
1006        Ok(property_key_to_string_from_key(key))
1007    }
1008
1009    fn lower_assignment_target(&mut self, target: &ast::AssignmentTarget<'_>) -> Result<Expr> {
1010        match target {
1011            ast::AssignmentTarget::AssignmentTargetIdentifier(id) => {
1012                Ok(Expr::Ident(id.name.to_string()))
1013            }
1014            ast::AssignmentTarget::StaticMemberExpression(member) => {
1015                let object = self.lower_expr(&member.object)?;
1016                Ok(Expr::Member {
1017                    object: Box::new(object),
1018                    property: member.property.name.to_string(),
1019                    optional: false,
1020                })
1021            }
1022            ast::AssignmentTarget::ComputedMemberExpression(member) => {
1023                let object = self.lower_expr(&member.object)?;
1024                let property = self.lower_expr(&member.expression)?;
1025                Ok(Expr::ComputedMember {
1026                    object: Box::new(object),
1027                    property: Box::new(property),
1028                    optional: false,
1029                })
1030            }
1031            _ => Err(ZapcodeError::CompileError(
1032                "unsupported assignment target".to_string(),
1033            )),
1034        }
1035    }
1036
1037    fn lower_simple_assign_target(
1038        &mut self,
1039        target: &ast::SimpleAssignmentTarget<'_>,
1040    ) -> Result<Expr> {
1041        match target {
1042            ast::SimpleAssignmentTarget::AssignmentTargetIdentifier(id) => {
1043                Ok(Expr::Ident(id.name.to_string()))
1044            }
1045            ast::SimpleAssignmentTarget::StaticMemberExpression(member) => {
1046                let object = self.lower_expr(&member.object)?;
1047                Ok(Expr::Member {
1048                    object: Box::new(object),
1049                    property: member.property.name.to_string(),
1050                    optional: false,
1051                })
1052            }
1053            ast::SimpleAssignmentTarget::ComputedMemberExpression(member) => {
1054                let object = self.lower_expr(&member.object)?;
1055                let property = self.lower_expr(&member.expression)?;
1056                Ok(Expr::ComputedMember {
1057                    object: Box::new(object),
1058                    property: Box::new(property),
1059                    optional: false,
1060                })
1061            }
1062            _ => Err(ZapcodeError::CompileError(
1063                "unsupported update target".to_string(),
1064            )),
1065        }
1066    }
1067}
1068
1069fn property_key_to_string(key: &ast::PropertyKey<'_>) -> String {
1070    property_key_to_string_from_key(key)
1071}
1072
1073fn property_key_to_string_from_key(key: &ast::PropertyKey<'_>) -> String {
1074    match key {
1075        ast::PropertyKey::StaticIdentifier(id) => id.name.to_string(),
1076        ast::PropertyKey::StringLiteral(s) => s.value.to_string(),
1077        ast::PropertyKey::NumericLiteral(n) => n.value.to_string(),
1078        _ => "<computed>".to_string(),
1079    }
1080}
1081
1082fn lower_binary_op(op: ast::BinaryOperator) -> Result<BinOp> {
1083    match op {
1084        ast::BinaryOperator::Addition => Ok(BinOp::Add),
1085        ast::BinaryOperator::Subtraction => Ok(BinOp::Sub),
1086        ast::BinaryOperator::Multiplication => Ok(BinOp::Mul),
1087        ast::BinaryOperator::Division => Ok(BinOp::Div),
1088        ast::BinaryOperator::Remainder => Ok(BinOp::Rem),
1089        ast::BinaryOperator::Exponential => Ok(BinOp::Pow),
1090        ast::BinaryOperator::Equality => Ok(BinOp::Eq),
1091        ast::BinaryOperator::Inequality => Ok(BinOp::Neq),
1092        ast::BinaryOperator::StrictEquality => Ok(BinOp::StrictEq),
1093        ast::BinaryOperator::StrictInequality => Ok(BinOp::StrictNeq),
1094        ast::BinaryOperator::LessThan => Ok(BinOp::Lt),
1095        ast::BinaryOperator::LessEqualThan => Ok(BinOp::Lte),
1096        ast::BinaryOperator::GreaterThan => Ok(BinOp::Gt),
1097        ast::BinaryOperator::GreaterEqualThan => Ok(BinOp::Gte),
1098        ast::BinaryOperator::BitwiseAnd => Ok(BinOp::BitAnd),
1099        ast::BinaryOperator::BitwiseOR => Ok(BinOp::BitOr),
1100        ast::BinaryOperator::BitwiseXOR => Ok(BinOp::BitXor),
1101        ast::BinaryOperator::ShiftLeft => Ok(BinOp::Shl),
1102        ast::BinaryOperator::ShiftRight => Ok(BinOp::Shr),
1103        ast::BinaryOperator::ShiftRightZeroFill => Ok(BinOp::Ushr),
1104        ast::BinaryOperator::In => Ok(BinOp::In),
1105        ast::BinaryOperator::Instanceof => Ok(BinOp::InstanceOf),
1106    }
1107}
1108
1109fn lower_assign_op(op: ast::AssignmentOperator) -> AssignOp {
1110    match op {
1111        ast::AssignmentOperator::Assign => AssignOp::Assign,
1112        ast::AssignmentOperator::Addition => AssignOp::AddAssign,
1113        ast::AssignmentOperator::Subtraction => AssignOp::SubAssign,
1114        ast::AssignmentOperator::Multiplication => AssignOp::MulAssign,
1115        ast::AssignmentOperator::Division => AssignOp::DivAssign,
1116        ast::AssignmentOperator::Remainder => AssignOp::RemAssign,
1117        ast::AssignmentOperator::Exponential => AssignOp::PowAssign,
1118        ast::AssignmentOperator::BitwiseAnd => AssignOp::BitAndAssign,
1119        ast::AssignmentOperator::BitwiseOR => AssignOp::BitOrAssign,
1120        ast::AssignmentOperator::BitwiseXOR => AssignOp::BitXorAssign,
1121        ast::AssignmentOperator::ShiftLeft => AssignOp::ShlAssign,
1122        ast::AssignmentOperator::ShiftRight => AssignOp::ShrAssign,
1123        ast::AssignmentOperator::ShiftRightZeroFill => AssignOp::UshrAssign,
1124        ast::AssignmentOperator::LogicalNullish => AssignOp::NullishAssign,
1125        ast::AssignmentOperator::LogicalAnd => AssignOp::AndAssign,
1126        ast::AssignmentOperator::LogicalOr => AssignOp::OrAssign,
1127    }
1128}