1pub mod instruction;
2
3use std::collections::{HashMap, HashSet};
4
5use crate::error::{Result, ZapcodeError};
6use crate::parser::ir::*;
7use instruction::*;
8
9#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
11pub struct CompiledProgram {
12 pub instructions: Vec<Instruction>,
13 pub functions: Vec<CompiledFunction>,
14 pub local_names: Vec<String>,
15}
16
17#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
18pub struct CompiledFunction {
19 pub name: Option<String>,
20 pub params: Vec<ParamPattern>,
21 pub instructions: Vec<Instruction>,
22 pub local_count: usize,
23 pub local_names: Vec<String>,
24 pub is_async: bool,
25 pub is_generator: bool,
26}
27
28struct Compiler {
29 instructions: Vec<Instruction>,
30 locals: Vec<String>,
31 local_indices: HashMap<String, usize>,
32 functions: Vec<CompiledFunction>,
33 loop_stack: Vec<LoopInfo>,
34 external_functions: HashSet<String>,
35}
36
37struct LoopInfo {
38 break_patches: Vec<usize>,
39 continue_patches: Vec<usize>,
40}
41
42impl Compiler {
43 fn new(external_functions: HashSet<String>) -> Self {
44 Self {
45 instructions: Vec::new(),
46 locals: Vec::new(),
47 local_indices: HashMap::new(),
48 functions: Vec::new(),
49 loop_stack: Vec::new(),
50 external_functions,
51 }
52 }
53
54 fn emit(&mut self, instr: Instruction) -> usize {
55 let idx = self.instructions.len();
56 self.instructions.push(instr);
57 idx
58 }
59
60 fn current_offset(&self) -> usize {
61 self.instructions.len()
62 }
63
64 fn patch_jump(&mut self, instr_idx: usize, target: usize) {
65 match &mut self.instructions[instr_idx] {
66 Instruction::Jump(t)
67 | Instruction::JumpIfFalse(t)
68 | Instruction::JumpIfTrue(t)
69 | Instruction::JumpIfNullish(t) => {
70 *t = target;
71 }
72 Instruction::SetupTry(catch_target, _) => {
73 *catch_target = target;
74 }
75 _ => {}
76 }
77 }
78
79 fn declare_local(&mut self, name: &str) -> usize {
80 if let Some(&idx) = self.local_indices.get(name) {
81 return idx;
82 }
83 let idx = self.locals.len();
84 self.locals.push(name.to_string());
85 self.local_indices.insert(name.to_string(), idx);
86 idx
87 }
88
89 fn resolve_local(&self, name: &str) -> Option<usize> {
90 self.local_indices.get(name).copied()
91 }
92
93 fn compile_program(&mut self, program: &Program) -> Result<()> {
94 for func_def in &program.functions {
96 let compiled = self.compile_function_def(func_def)?;
97 self.functions.push(compiled);
98 }
99
100 let len = program.body.len();
103 for (i, stmt) in program.body.iter().enumerate() {
104 let is_last = i == len - 1;
105 if is_last {
106 if let Statement::Expression { expr, .. } = stmt {
107 self.compile_expr(expr)?;
108 } else {
110 self.compile_statement(stmt)?;
111 }
112 } else {
113 self.compile_statement(stmt)?;
114 }
115 }
116
117 Ok(())
118 }
119
120 fn compile_function_def(&mut self, func: &FunctionDef) -> Result<CompiledFunction> {
121 let mut func_compiler = Compiler::new(self.external_functions.clone());
122
123 for param in &func.params {
125 match param {
126 ParamPattern::Ident(name) => {
127 func_compiler.declare_local(name);
128 }
129 ParamPattern::Rest(name) => {
130 func_compiler.declare_local(name);
131 }
132 ParamPattern::DefaultValue { pattern, .. } => {
133 if let ParamPattern::Ident(name) = pattern.as_ref() {
134 func_compiler.declare_local(name);
135 }
136 }
137 ParamPattern::ObjectDestructure(fields) => {
138 for field in fields {
139 let name = field.alias.as_ref().unwrap_or(&field.key);
140 func_compiler.declare_local(name);
141 }
142 }
143 ParamPattern::ArrayDestructure(elems) => {
144 for elem in elems.iter().flatten() {
145 if let ParamPattern::Ident(name) = elem {
146 func_compiler.declare_local(name);
147 }
148 }
149 }
150 }
151 }
152
153 for stmt in &func.body {
154 func_compiler.compile_statement(stmt)?;
155 }
156
157 func_compiler.emit(Instruction::Push(Constant::Undefined));
159 func_compiler.emit(Instruction::Return);
160
161 Ok(CompiledFunction {
162 name: func.name.clone(),
163 params: func.params.clone(),
164 instructions: func_compiler.instructions,
165 local_count: func_compiler.locals.len(),
166 local_names: func_compiler.locals,
167 is_async: func.is_async,
168 is_generator: func.is_generator,
169 })
170 }
171
172 fn compile_statement(&mut self, stmt: &Statement) -> Result<()> {
173 match stmt {
174 Statement::VariableDecl { declarations, .. } => {
175 for decl in declarations {
176 self.compile_var_declarator(decl)?;
177 }
178 }
179 Statement::Expression { expr, .. } => {
180 self.compile_expr(expr)?;
181 self.emit(Instruction::Pop);
182 }
183 Statement::Return { value, .. } => {
184 match value {
185 Some(expr) => self.compile_expr(expr)?,
186 None => {
187 self.emit(Instruction::Push(Constant::Undefined));
188 }
189 }
190 self.emit(Instruction::Return);
191 }
192 Statement::If {
193 test,
194 consequent,
195 alternate,
196 ..
197 } => {
198 self.compile_expr(test)?;
199 let jump_else = self.emit(Instruction::JumpIfFalse(0));
200
201 for s in consequent {
202 self.compile_statement(s)?;
203 }
204
205 if let Some(alt) = alternate {
206 let jump_end = self.emit(Instruction::Jump(0));
207 let else_target = self.current_offset();
208 self.patch_jump(jump_else, else_target);
209
210 for s in alt {
211 self.compile_statement(s)?;
212 }
213 let end_target = self.current_offset();
214 self.patch_jump(jump_end, end_target);
215 } else {
216 let else_target = self.current_offset();
217 self.patch_jump(jump_else, else_target);
218 }
219 }
220 Statement::While { test, body, .. } => {
221 let loop_start = self.current_offset();
222 self.loop_stack.push(LoopInfo {
223 break_patches: Vec::new(),
224 continue_patches: Vec::new(),
225 });
226
227 self.compile_expr(test)?;
228 let exit_jump = self.emit(Instruction::JumpIfFalse(0));
229
230 for s in body {
231 self.compile_statement(s)?;
232 }
233
234 self.emit(Instruction::Jump(loop_start));
235 let loop_end = self.current_offset();
236 self.patch_jump(exit_jump, loop_end);
237
238 let loop_info = self.loop_stack.pop().unwrap();
239 for patch in loop_info.break_patches {
240 self.patch_jump(patch, loop_end);
241 }
242 for patch in loop_info.continue_patches {
243 self.patch_jump(patch, loop_start);
244 }
245 }
246 Statement::DoWhile { body, test, .. } => {
247 let loop_start = self.current_offset();
248 self.loop_stack.push(LoopInfo {
249 break_patches: Vec::new(),
250 continue_patches: Vec::new(),
251 });
252
253 for s in body {
254 self.compile_statement(s)?;
255 }
256
257 let continue_target = self.current_offset();
258 self.compile_expr(test)?;
259 self.emit(Instruction::JumpIfTrue(loop_start));
260
261 let loop_end = self.current_offset();
262 let loop_info = self.loop_stack.pop().unwrap();
263 for patch in loop_info.break_patches {
264 self.patch_jump(patch, loop_end);
265 }
266 for patch in loop_info.continue_patches {
267 self.patch_jump(patch, continue_target);
268 }
269 }
270 Statement::For {
271 init,
272 test,
273 update,
274 body,
275 ..
276 } => {
277 if let Some(init) = init {
278 self.compile_statement(init)?;
279 }
280
281 let loop_start = self.current_offset();
282 self.loop_stack.push(LoopInfo {
283 break_patches: Vec::new(),
284 continue_patches: Vec::new(),
285 });
286
287 let exit_jump = if let Some(test) = test {
288 self.compile_expr(test)?;
289 Some(self.emit(Instruction::JumpIfFalse(0)))
290 } else {
291 None
292 };
293
294 for s in body {
295 self.compile_statement(s)?;
296 }
297
298 let continue_target = self.current_offset();
299 if let Some(update) = update {
300 self.compile_expr(update)?;
301 self.emit(Instruction::Pop);
302 }
303
304 self.emit(Instruction::Jump(loop_start));
305 let loop_end = self.current_offset();
306
307 if let Some(exit) = exit_jump {
308 self.patch_jump(exit, loop_end);
309 }
310
311 let loop_info = self.loop_stack.pop().unwrap();
312 for patch in loop_info.break_patches {
313 self.patch_jump(patch, loop_end);
314 }
315 for patch in loop_info.continue_patches {
316 self.patch_jump(patch, continue_target);
317 }
318 }
319 Statement::ForOf {
320 binding,
321 iterable,
322 body,
323 ..
324 } => {
325 self.compile_expr(iterable)?;
326 self.emit(Instruction::GetIterator);
327
328 let loop_start = self.current_offset();
329 self.loop_stack.push(LoopInfo {
330 break_patches: Vec::new(),
331 continue_patches: Vec::new(),
332 });
333
334 self.emit(Instruction::Dup);
335 self.emit(Instruction::IteratorNext);
336 self.emit(Instruction::IteratorDone);
337 let exit_jump = self.emit(Instruction::JumpIfTrue(0));
338
339 match binding {
341 ForBinding::Ident(name) => {
342 let idx = self.declare_local(name);
343 self.emit(Instruction::StoreLocal(idx));
344 }
345 ForBinding::Destructure(_) => {
346 self.emit(Instruction::Pop); }
348 }
349
350 for s in body {
351 self.compile_statement(s)?;
352 }
353
354 self.emit(Instruction::Jump(loop_start));
355 let loop_end = self.current_offset();
356 self.patch_jump(exit_jump, loop_end);
357 self.emit(Instruction::Pop); let loop_info = self.loop_stack.pop().unwrap();
360 for patch in loop_info.break_patches {
361 self.patch_jump(patch, loop_end);
362 }
363 for patch in loop_info.continue_patches {
364 self.patch_jump(patch, loop_start);
365 }
366 }
367 Statement::Block { body, .. } => {
368 for s in body {
369 self.compile_statement(s)?;
370 }
371 }
372 Statement::Throw { value, .. } => {
373 self.compile_expr(value)?;
374 self.emit(Instruction::Throw);
375 }
376 Statement::TryCatch {
377 try_body,
378 catch_param,
379 catch_body,
380 finally_body,
381 ..
382 } => {
383 let setup = self.emit(Instruction::SetupTry(0, None));
384
385 for s in try_body {
386 self.compile_statement(s)?;
387 }
388 self.emit(Instruction::EndTry);
389 let jump_past_catch = self.emit(Instruction::Jump(0));
390
391 let catch_start = self.current_offset();
393 self.patch_jump(setup, catch_start);
394
395 if let Some(param) = catch_param {
396 let idx = self.declare_local(param);
397 self.emit(Instruction::StoreLocal(idx));
398 } else {
399 self.emit(Instruction::Pop); }
401
402 for s in catch_body {
403 self.compile_statement(s)?;
404 }
405
406 let after_catch = self.current_offset();
407 self.patch_jump(jump_past_catch, after_catch);
408
409 if let Some(finally) = finally_body {
410 for s in finally {
411 self.compile_statement(s)?;
412 }
413 }
414 }
415 Statement::Break { .. } => {
416 let idx = self.emit(Instruction::Jump(0));
417 if let Some(loop_info) = self.loop_stack.last_mut() {
418 loop_info.break_patches.push(idx);
419 }
420 }
421 Statement::Continue { .. } => {
422 let idx = self.emit(Instruction::Jump(0));
423 if let Some(loop_info) = self.loop_stack.last_mut() {
424 loop_info.continue_patches.push(idx);
425 }
426 }
427 Statement::FunctionDecl { func_index, .. } => {
428 self.emit(Instruction::CreateClosure(*func_index));
429 let name = if *func_index < self.functions.len() {
430 self.functions[*func_index].name.clone()
431 } else {
432 None
433 };
434 if let Some(name) = name {
435 self.emit(Instruction::Dup);
437 let idx = self.declare_local(&name);
438 self.emit(Instruction::StoreLocal(idx));
439 self.emit(Instruction::StoreGlobal(name));
440 } else {
441 self.emit(Instruction::Pop);
442 }
443 }
444 Statement::ClassDecl {
445 name,
446 super_class,
447 constructor,
448 methods,
449 static_methods,
450 ..
451 } => {
452 self.compile_class(
453 Some(name),
454 super_class.as_deref(),
455 constructor.as_deref(),
456 methods,
457 static_methods,
458 )?;
459 self.emit(Instruction::Dup);
461 let idx = self.declare_local(name);
462 self.emit(Instruction::StoreLocal(idx));
463 self.emit(Instruction::StoreGlobal(name.clone()));
464 }
465 Statement::Switch {
466 discriminant,
467 cases,
468 ..
469 } => {
470 self.compile_expr(discriminant)?;
471 let mut case_jumps = Vec::new();
472 let mut default_jump = None;
473
474 for case in cases {
476 if let Some(test) = &case.test {
477 self.emit(Instruction::Dup);
478 self.compile_expr(test)?;
479 self.emit(Instruction::StrictEq);
480 let jump = self.emit(Instruction::JumpIfTrue(0));
481 case_jumps.push(jump);
482 } else {
483 default_jump = Some(case_jumps.len());
484 case_jumps.push(0); }
486 }
487
488 let jump_end = self.emit(Instruction::Jump(0));
489
490 let mut body_starts = Vec::new();
492 for case in cases {
493 body_starts.push(self.current_offset());
494 for s in &case.consequent {
495 self.compile_statement(s)?;
496 }
497 }
498
499 let end = self.current_offset();
500 self.emit(Instruction::Pop); for (i, &jump) in case_jumps.iter().enumerate() {
504 if jump != 0 {
505 self.patch_jump(jump, body_starts[i]);
506 }
507 }
508 if let Some(default_idx) = default_jump {
509 self.patch_jump(jump_end, body_starts[default_idx]);
511 } else {
512 self.patch_jump(jump_end, end);
513 }
514 }
515 }
516 Ok(())
517 }
518
519 fn compile_var_declarator(&mut self, decl: &VarDeclarator) -> Result<()> {
520 match &decl.pattern {
521 AssignTarget::Ident(name) => {
522 let idx = self.declare_local(name);
523 match &decl.init {
524 Some(expr) => {
525 self.compile_expr(expr)?;
526 self.emit(Instruction::StoreLocal(idx));
527 }
528 None => {
529 self.emit(Instruction::Push(Constant::Undefined));
530 self.emit(Instruction::StoreLocal(idx));
531 }
532 }
533 }
534 AssignTarget::ObjectDestructure(fields) => {
535 if let Some(expr) = &decl.init {
536 self.compile_expr(expr)?;
537 } else {
538 self.emit(Instruction::Push(Constant::Undefined));
539 }
540 for field in fields {
541 self.emit(Instruction::Dup);
542 self.emit(Instruction::GetProperty(field.key.clone()));
543 let name = field.alias.as_ref().unwrap_or(&field.key);
544 let idx = self.declare_local(name);
545 self.emit(Instruction::StoreLocal(idx));
546 }
547 self.emit(Instruction::Pop); }
549 AssignTarget::ArrayDestructure(elems) => {
550 if let Some(expr) = &decl.init {
551 self.compile_expr(expr)?;
552 } else {
553 self.emit(Instruction::Push(Constant::Undefined));
554 }
555 for (i, elem) in elems.iter().enumerate() {
556 if let Some(target) = elem {
557 self.emit(Instruction::Dup);
558 self.emit(Instruction::Push(Constant::Int(i as i64)));
559 self.emit(Instruction::GetIndex);
560 match target {
561 AssignTarget::Ident(name) => {
562 let idx = self.declare_local(name);
563 self.emit(Instruction::StoreLocal(idx));
564 }
565 _ => {
566 self.emit(Instruction::Pop); }
568 }
569 }
570 }
571 self.emit(Instruction::Pop); }
573 }
574 Ok(())
575 }
576
577 fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
578 match expr {
579 Expr::NumberLit(n) => {
580 if *n == (*n as i64) as f64 && !n.is_nan() && n.is_finite() {
581 self.emit(Instruction::Push(Constant::Int(*n as i64)));
582 } else {
583 self.emit(Instruction::Push(Constant::Float(*n)));
584 }
585 }
586 Expr::StringLit(s) => {
587 self.emit(Instruction::Push(Constant::String(s.clone())));
588 }
589 Expr::BoolLit(b) => {
590 self.emit(Instruction::Push(Constant::Bool(*b)));
591 }
592 Expr::NullLit => {
593 self.emit(Instruction::Push(Constant::Null));
594 }
595 Expr::UndefinedLit => {
596 self.emit(Instruction::Push(Constant::Undefined));
597 }
598 Expr::TemplateLit { quasis, exprs } => {
599 let mut parts = 0;
600 for (i, quasi) in quasis.iter().enumerate() {
601 if !quasi.is_empty() {
602 self.emit(Instruction::Push(Constant::String(quasi.clone())));
603 parts += 1;
604 }
605 if i < exprs.len() {
606 self.compile_expr(&exprs[i])?;
607 parts += 1;
608 }
609 }
610 if parts == 0 {
611 self.emit(Instruction::Push(Constant::String(String::new())));
612 } else if parts > 1 {
613 self.emit(Instruction::ConcatStrings(parts));
614 }
615 }
616 Expr::RegExpLit { .. } => {
617 self.emit(Instruction::Push(Constant::Undefined));
619 }
620 Expr::Ident(name) => {
621 if name == "this" {
622 self.emit(Instruction::LoadThis);
623 } else if let Some(idx) = self.resolve_local(name) {
624 self.emit(Instruction::LoadLocal(idx));
625 } else {
626 self.emit(Instruction::LoadGlobal(name.clone()));
627 }
628 }
629 Expr::Array(elements) => {
630 let mut count = 0;
631 for elem in elements {
632 match elem {
633 Some(e) => {
634 self.compile_expr(e)?;
635 count += 1;
636 }
637 None => {
638 self.emit(Instruction::Push(Constant::Undefined));
639 count += 1;
640 }
641 }
642 }
643 self.emit(Instruction::CreateArray(count));
644 }
645 Expr::Object(props) => {
646 let mut count = 0;
647 for prop in props {
648 match prop.kind {
649 PropKind::Spread => {
650 self.compile_expr(&prop.value)?;
651 self.emit(Instruction::Spread);
652 count += 1;
653 }
654 _ => {
655 self.emit(Instruction::Push(Constant::String(prop.key.clone())));
656 self.compile_expr(&prop.value)?;
657 count += 1;
658 }
659 }
660 }
661 self.emit(Instruction::CreateObject(count));
662 }
663 Expr::Spread(expr) => {
664 self.compile_expr(expr)?;
665 self.emit(Instruction::Spread);
666 }
667 Expr::Binary { op, left, right } => {
668 self.compile_expr(left)?;
669 self.compile_expr(right)?;
670 let instr = match op {
671 BinOp::Add => Instruction::Add,
672 BinOp::Sub => Instruction::Sub,
673 BinOp::Mul => Instruction::Mul,
674 BinOp::Div => Instruction::Div,
675 BinOp::Rem => Instruction::Rem,
676 BinOp::Pow => Instruction::Pow,
677 BinOp::Eq => Instruction::Eq,
678 BinOp::Neq => Instruction::Neq,
679 BinOp::StrictEq => Instruction::StrictEq,
680 BinOp::StrictNeq => Instruction::StrictNeq,
681 BinOp::Lt => Instruction::Lt,
682 BinOp::Lte => Instruction::Lte,
683 BinOp::Gt => Instruction::Gt,
684 BinOp::Gte => Instruction::Gte,
685 BinOp::BitAnd => Instruction::BitAnd,
686 BinOp::BitOr => Instruction::BitOr,
687 BinOp::BitXor => Instruction::BitXor,
688 BinOp::Shl => Instruction::Shl,
689 BinOp::Shr => Instruction::Shr,
690 BinOp::Ushr => Instruction::Ushr,
691 BinOp::In => Instruction::In,
692 BinOp::InstanceOf => Instruction::InstanceOf,
693 };
694 self.emit(instr);
695 }
696 Expr::Unary { op, operand } => {
697 self.compile_expr(operand)?;
698 match op {
699 UnaryOp::Neg => {
700 self.emit(Instruction::Neg);
701 }
702 UnaryOp::Not => {
703 self.emit(Instruction::Not);
704 }
705 UnaryOp::BitNot => {
706 self.emit(Instruction::BitNot);
707 }
708 UnaryOp::Void => {
709 self.emit(Instruction::Void);
710 }
711 }
712 }
713 Expr::Update {
714 op,
715 prefix,
716 operand,
717 } => {
718 self.compile_expr(operand)?;
720
721 if !prefix {
722 self.emit(Instruction::Dup); }
724
725 match op {
726 UpdateOp::Increment => {
727 self.emit(Instruction::Increment);
728 }
729 UpdateOp::Decrement => {
730 self.emit(Instruction::Decrement);
731 }
732 }
733
734 if *prefix {
735 self.emit(Instruction::Dup); }
737
738 self.compile_store(operand)?;
740
741 if !prefix {
742 }
745 }
746 Expr::Logical { op, left, right } => match op {
747 LogicalOp::And => {
748 self.compile_expr(left)?;
749 self.emit(Instruction::Dup);
750 let skip = self.emit(Instruction::JumpIfFalse(0));
751 self.emit(Instruction::Pop);
752 self.compile_expr(right)?;
753 let end = self.current_offset();
754 self.patch_jump(skip, end);
755 }
756 LogicalOp::Or => {
757 self.compile_expr(left)?;
758 self.emit(Instruction::Dup);
759 let skip = self.emit(Instruction::JumpIfTrue(0));
760 self.emit(Instruction::Pop);
761 self.compile_expr(right)?;
762 let end = self.current_offset();
763 self.patch_jump(skip, end);
764 }
765 LogicalOp::NullishCoalescing => {
766 self.compile_expr(left)?;
767 self.emit(Instruction::Dup);
768 let skip = self.emit(Instruction::JumpIfNullish(0));
769 let jump_end = self.emit(Instruction::Jump(0));
770 let nullish_target = self.current_offset();
771 self.patch_jump(skip, nullish_target);
772 self.emit(Instruction::Pop);
773 self.compile_expr(right)?;
774 let end = self.current_offset();
775 self.patch_jump(jump_end, end);
776 }
777 },
778 Expr::Conditional {
779 test,
780 consequent,
781 alternate,
782 } => {
783 self.compile_expr(test)?;
784 let jump_else = self.emit(Instruction::JumpIfFalse(0));
785 self.compile_expr(consequent)?;
786 let jump_end = self.emit(Instruction::Jump(0));
787 let else_target = self.current_offset();
788 self.patch_jump(jump_else, else_target);
789 self.compile_expr(alternate)?;
790 let end = self.current_offset();
791 self.patch_jump(jump_end, end);
792 }
793 Expr::Assignment { op, target, value } => {
794 match op {
795 AssignOp::Assign => {
796 self.compile_expr(value)?;
797 self.emit(Instruction::Dup);
798 self.compile_store(target)?;
799 }
800 _ => {
801 self.compile_expr(target)?;
803 self.compile_expr(value)?;
804 match op {
805 AssignOp::AddAssign => {
806 self.emit(Instruction::Add);
807 }
808 AssignOp::SubAssign => {
809 self.emit(Instruction::Sub);
810 }
811 AssignOp::MulAssign => {
812 self.emit(Instruction::Mul);
813 }
814 AssignOp::DivAssign => {
815 self.emit(Instruction::Div);
816 }
817 AssignOp::RemAssign => {
818 self.emit(Instruction::Rem);
819 }
820 AssignOp::PowAssign => {
821 self.emit(Instruction::Pow);
822 }
823 AssignOp::BitAndAssign => {
824 self.emit(Instruction::BitAnd);
825 }
826 AssignOp::BitOrAssign => {
827 self.emit(Instruction::BitOr);
828 }
829 AssignOp::BitXorAssign => {
830 self.emit(Instruction::BitXor);
831 }
832 AssignOp::ShlAssign => {
833 self.emit(Instruction::Shl);
834 }
835 AssignOp::ShrAssign => {
836 self.emit(Instruction::Shr);
837 }
838 AssignOp::UshrAssign => {
839 self.emit(Instruction::Ushr);
840 }
841 _ => {}
842 }
843 self.emit(Instruction::Dup);
844 self.compile_store(target)?;
845 }
846 }
847 }
848 Expr::Sequence(exprs) => {
849 for (i, e) in exprs.iter().enumerate() {
850 self.compile_expr(e)?;
851 if i < exprs.len() - 1 {
852 self.emit(Instruction::Pop);
853 }
854 }
855 }
856 Expr::Member {
857 object,
858 property,
859 optional,
860 } => {
861 self.compile_expr(object)?;
862 if *optional {
863 self.emit(Instruction::Dup);
864 let skip = self.emit(Instruction::JumpIfNullish(0));
865 self.emit(Instruction::GetProperty(property.clone()));
866 let end = self.emit(Instruction::Jump(0));
867 let nullish = self.current_offset();
868 self.patch_jump(skip, nullish);
869 self.emit(Instruction::Pop);
870 self.emit(Instruction::Push(Constant::Undefined));
871 let after = self.current_offset();
872 self.patch_jump(end, after);
873 } else {
874 self.emit(Instruction::GetProperty(property.clone()));
875 }
876 }
877 Expr::ComputedMember {
878 object,
879 property,
880 optional,
881 } => {
882 self.compile_expr(object)?;
883 if *optional {
884 self.emit(Instruction::Dup);
885 let skip = self.emit(Instruction::JumpIfNullish(0));
886 self.compile_expr(property)?;
887 self.emit(Instruction::GetIndex);
888 let end = self.emit(Instruction::Jump(0));
889 let nullish = self.current_offset();
890 self.patch_jump(skip, nullish);
891 self.emit(Instruction::Pop);
892 self.emit(Instruction::Push(Constant::Undefined));
893 let after = self.current_offset();
894 self.patch_jump(end, after);
895 } else {
896 self.compile_expr(property)?;
897 self.emit(Instruction::GetIndex);
898 }
899 }
900 Expr::Call { callee, args, .. } => {
901 if let Expr::Ident(name) = callee.as_ref() {
903 if name == "super" {
904 for arg in args {
905 self.compile_expr(arg)?;
906 }
907 self.emit(Instruction::CallSuper(args.len()));
908 return Ok(());
909 }
910 }
911 if let Expr::Ident(name) = callee.as_ref() {
913 if self.external_functions.contains(name) {
914 for arg in args {
916 self.compile_expr(arg)?;
917 }
918 self.emit(Instruction::CallExternal(name.clone(), args.len()));
919 return Ok(());
920 }
921 }
922 self.compile_expr(callee)?;
923 for arg in args {
924 self.compile_expr(arg)?;
925 }
926 self.emit(Instruction::Call(args.len()));
927 }
928 Expr::New { callee, args } => {
929 self.compile_expr(callee)?;
930 for arg in args {
931 self.compile_expr(arg)?;
932 }
933 self.emit(Instruction::Construct(args.len()));
934 }
935 Expr::ArrowFunction { func_index } | Expr::FunctionExpr { func_index } => {
936 self.emit(Instruction::CreateClosure(*func_index));
937 }
938 Expr::Await(expr) => {
939 self.compile_expr(expr)?;
940 self.emit(Instruction::Await);
944 }
945 Expr::Yield { value, delegate: _ } => {
946 match value {
948 Some(expr) => self.compile_expr(expr)?,
949 None => {
950 self.emit(Instruction::Push(Constant::Undefined));
951 }
952 }
953 self.emit(Instruction::Yield);
955 }
956 Expr::TypeOf(operand) => {
957 self.compile_expr(operand)?;
958 self.emit(Instruction::TypeOf);
959 }
960 Expr::ClassExpr {
961 name,
962 super_class,
963 constructor,
964 methods,
965 static_methods,
966 } => {
967 self.compile_class(
968 name.as_deref(),
969 super_class.as_deref(),
970 constructor.as_deref(),
971 methods,
972 static_methods,
973 )?;
974 }
975 }
976 Ok(())
977 }
978
979 fn compile_class(
980 &mut self,
981 name: Option<&str>,
982 super_class: Option<&str>,
983 constructor: Option<&FunctionDef>,
984 methods: &[ClassMethod],
985 static_methods: &[ClassMethod],
986 ) -> Result<()> {
987 let class_name = name.unwrap_or("AnonymousClass").to_string();
988
989 if let Some(sc) = super_class {
991 if let Some(idx) = self.resolve_local(sc) {
992 self.emit(Instruction::LoadLocal(idx));
993 } else {
994 self.emit(Instruction::LoadGlobal(sc.to_string()));
995 }
996 }
997
998 for sm in static_methods {
1000 self.emit(Instruction::Push(Constant::String(sm.name.clone())));
1001 let compiled = self.compile_function_def(&sm.func)?;
1002 let func_idx = self.functions.len();
1003 self.functions.push(compiled);
1004 self.emit(Instruction::CreateClosure(func_idx));
1005 }
1006
1007 for m in methods {
1009 self.emit(Instruction::Push(Constant::String(m.name.clone())));
1010 let compiled = self.compile_function_def(&m.func)?;
1011 let func_idx = self.functions.len();
1012 self.functions.push(compiled);
1013 self.emit(Instruction::CreateClosure(func_idx));
1014 }
1015
1016 if let Some(ctor) = constructor {
1018 let compiled = self.compile_function_def(ctor)?;
1019 let func_idx = self.functions.len();
1020 self.functions.push(compiled);
1021 self.emit(Instruction::CreateClosure(func_idx));
1022 } else {
1023 self.emit(Instruction::Push(Constant::Undefined));
1024 }
1025
1026 self.emit(Instruction::CreateClass {
1027 name: class_name,
1028 n_methods: methods.len(),
1029 n_statics: static_methods.len(),
1030 has_super: super_class.is_some(),
1031 });
1032
1033 Ok(())
1034 }
1035
1036 fn compile_store(&mut self, target: &Expr) -> Result<()> {
1037 match target {
1038 Expr::Ident(name) if name == "this" => {
1039 self.emit(Instruction::StoreThis);
1040 }
1041 Expr::Ident(name) => {
1042 if let Some(idx) = self.resolve_local(name) {
1043 self.emit(Instruction::StoreLocal(idx));
1044 } else {
1045 self.emit(Instruction::StoreGlobal(name.clone()));
1046 }
1047 }
1048 Expr::Member {
1049 object, property, ..
1050 } => {
1051 self.compile_expr(object)?;
1052 self.emit(Instruction::SetProperty(property.clone()));
1053 self.compile_store(object)?;
1055 }
1056 Expr::ComputedMember {
1057 object, property, ..
1058 } => {
1059 self.compile_expr(object)?;
1060 self.compile_expr(property)?;
1061 self.emit(Instruction::SetIndex);
1062 self.compile_store(object)?;
1064 }
1065 _ => {
1066 return Err(ZapcodeError::CompileError(
1067 "invalid assignment target".to_string(),
1068 ));
1069 }
1070 }
1071 Ok(())
1072 }
1073}
1074
1075pub fn compile(program: &Program) -> Result<CompiledProgram> {
1076 compile_with_externals(program, HashSet::new())
1077}
1078
1079pub fn compile_with_externals(
1080 program: &Program,
1081 external_functions: HashSet<String>,
1082) -> Result<CompiledProgram> {
1083 let mut compiler = Compiler::new(external_functions);
1084 compiler.compile_program(program)?;
1085
1086 Ok(CompiledProgram {
1087 instructions: compiler.instructions,
1088 functions: compiler.functions,
1089 local_names: compiler.locals,
1090 })
1091}