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 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 ¶ms.items {
452 let pat = self.lower_binding_pattern_to_param(¶m.pattern)?;
453 result.push(pat);
454 }
455 if let Some(rest) = ¶ms.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, };
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 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 }
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 }
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}