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