1use crate::parser::ast::{
7 AssignmentOperator, BinaryOperator, BlockStatementData, DeclarationType,
8 ExpressionOrSpreadElement, ExpressionOrSuper, ExpressionPatternType, ExpressionType,
9 ForIteratorData, FunctionBodyData, LiteralData, LiteralType, LogicalOperator,
10 MemberExpressionType, NumberLiteralType, PatternOrExpression, PatternType, ProgramData,
11 StatementType, SwitchCaseData, UnaryOperator, UpdateOperator, VariableDeclarationData,
12 VariableDeclarationKind, VariableDeclarationOrExpression,
13};
14use crate::runner::ds::value::{JsNumberType, JsValue};
15use std::collections::{HashMap, HashSet};
16
17use super::bytecode::{Chunk, FunctionTemplate, Instruction, OpCode};
18
19struct LoopContext {
21 continue_target: usize,
23 break_jumps: Vec<usize>,
25 continue_jumps: Vec<usize>,
28}
29
30pub struct Compiler {
32 chunk: Chunk,
33 loop_stack: Vec<LoopContext>,
35 locals: HashMap<String, u32>,
37 lexical_scopes: Vec<HashSet<String>>,
39}
40
41impl Compiler {
42 pub fn new() -> Self {
43 Compiler {
44 chunk: Chunk::new(),
45 loop_stack: Vec::new(),
46 locals: HashMap::new(),
47 lexical_scopes: vec![HashSet::new()],
48 }
49 }
50
51 fn get_local_slot(&self, name: &str) -> Option<u32> {
52 self.locals.get(name).copied()
53 }
54
55 fn get_or_add_local_slot(&mut self, name: &str) -> u32 {
56 if let Some(slot) = self.locals.get(name) {
57 return *slot;
58 }
59 let name_idx = self.chunk.add_name(name);
60 let slot = self.chunk.add_local(name_idx);
61 self.locals.insert(name.to_string(), slot);
62 slot
63 }
64
65 fn push_lexical_scope(&mut self) {
66 self.lexical_scopes.push(HashSet::new());
67 }
68
69 fn pop_lexical_scope(&mut self) {
70 self.lexical_scopes.pop();
71 }
72
73 fn declare_lexical(&mut self, name: &str) {
74 if let Some(scope) = self.lexical_scopes.last_mut() {
75 scope.insert(name.to_string());
76 }
77 }
78
79 fn is_lexically_shadowed(&self, name: &str) -> bool {
80 self.lexical_scopes
81 .iter()
82 .rev()
83 .any(|scope| scope.contains(name))
84 }
85
86 pub fn compile_program(mut self, program: &ProgramData) -> Chunk {
88 for stmt in &program.body {
89 self.compile_statement(stmt);
90 }
91 self.chunk.emit_op(OpCode::Halt);
92 self.chunk
93 }
94
95 fn compile_statement(&mut self, stmt: &StatementType) {
100 match stmt {
101 StatementType::EmptyStatement { .. } => {}
102
103 StatementType::ExpressionStatement { expression, .. } => {
104 self.compile_expression(expression);
105 self.chunk.emit_op(OpCode::Pop);
106 }
107
108 StatementType::BlockStatement(block) => {
109 self.compile_block(block);
110 }
111
112 StatementType::DeclarationStatement(decl) => {
113 self.compile_declaration(decl);
114 }
115
116 StatementType::IfStatement { test, consequent, alternate, .. } => {
117 self.compile_if(test, consequent, alternate.as_ref().map(|a| a.as_ref()));
118 }
119
120 StatementType::WhileStatement { test, body, .. } => {
121 self.compile_while(test, body);
122 }
123
124 StatementType::DoWhileStatement { test, body, .. } => {
125 self.compile_do_while(body, test);
126 }
127
128 StatementType::ForStatement { init, test, update, body, .. } => {
129 self.compile_for(
130 init.as_ref(),
131 test.as_ref().map(|t| t.as_ref()),
132 update.as_ref().map(|u| u.as_ref()),
133 body,
134 );
135 }
136
137 StatementType::ForInStatement(data) => {
138 self.compile_for_in(data);
139 }
140
141 StatementType::ForOfStatement(data) => {
142 self.compile_for_of(data);
143 }
144
145 StatementType::SwitchStatement { discriminant, cases, .. } => {
146 self.compile_switch(discriminant, cases);
147 }
148
149 StatementType::BreakStatement { .. } => {
150 self.compile_break();
151 }
152
153 StatementType::ContinueStatement { .. } => {
154 self.compile_continue();
155 }
156
157 StatementType::ReturnStatement { argument, .. } => {
158 if let Some(arg) = argument {
159 self.compile_expression(arg);
160 } else {
161 self.chunk.emit_op(OpCode::Undefined);
162 }
163 self.chunk.emit_op(OpCode::Return);
164 }
165
166 StatementType::ThrowStatement { argument, .. } => {
167 self.compile_expression(argument);
168 self.chunk.emit_op(OpCode::Return);
171 }
172
173 StatementType::TryStatement { block, handler, finalizer, .. } => {
174 self.compile_block(block);
177 if let Some(_handler) = handler {
178 }
180 if let Some(fin) = finalizer {
181 self.compile_block(fin);
182 }
183 }
184
185 StatementType::DebuggerStatement { .. } => {}
186
187 StatementType::FunctionBody(body) => {
188 self.compile_function_body(body);
189 }
190 }
191 }
192
193 fn compile_block(&mut self, block: &BlockStatementData) {
194 self.push_lexical_scope();
195 self.chunk.emit_op(OpCode::PushScope);
196 for stmt in block.body.iter() {
197 self.compile_statement(stmt);
198 }
199 self.chunk.emit_op(OpCode::PopScope);
200 self.pop_lexical_scope();
201 }
202
203 fn compile_function_body(&mut self, body: &FunctionBodyData) {
204 self.push_lexical_scope();
205 for stmt in body.body.iter() {
206 self.compile_statement(stmt);
207 }
208 self.pop_lexical_scope();
209 }
210
211 fn compile_declaration(&mut self, decl: &DeclarationType) {
212 match decl {
213 DeclarationType::VariableDeclaration(var_decl) => {
214 self.compile_var_declaration(var_decl);
215 }
216 DeclarationType::FunctionOrGeneratorDeclaration(func_data) => {
217 if let Some(ref id) = func_data.id {
218 let slot = self.get_or_add_local_slot(&id.name);
219 let name_idx = self.chunk.add_name(&id.name);
220 let func_idx = self.chunk.add_function(FunctionTemplate {
221 body_ptr: func_data.body.as_ref() as *const _,
222 params_ptr: &func_data.params.list as *const _,
223 });
224 self.chunk.emit_with(OpCode::DeclareVar, name_idx);
227 self.chunk.emit_with(OpCode::MakeClosure, func_idx);
228 self.chunk.emit_op(OpCode::Dup);
229 self.chunk.emit_with(OpCode::InitVar, name_idx);
230 self.chunk.emit_with(OpCode::InitLocal, slot);
231 }
232 }
233 DeclarationType::ClassDeclaration(_class_data) => {
234 }
236 }
237 }
238
239 fn compile_var_declaration(&mut self, var_decl: &VariableDeclarationData) {
240 let (declare_op, init_op) = match var_decl.kind {
241 VariableDeclarationKind::Var => (OpCode::DeclareVar, OpCode::InitVar),
242 VariableDeclarationKind::Let => (OpCode::DeclareLet, OpCode::InitBinding),
243 VariableDeclarationKind::Const => (OpCode::DeclareConst, OpCode::InitBinding),
244 };
245
246 for declarator in &var_decl.declarations {
247 if let PatternType::PatternWhichCanBeExpression(
248 ExpressionPatternType::Identifier(ref id),
249 ) = declarator.id.as_ref()
250 {
251 if matches!(var_decl.kind, VariableDeclarationKind::Var) {
252 let slot = self.get_or_add_local_slot(&id.name);
253 if let Some(ref init_expr) = declarator.init {
254 self.compile_expression(init_expr);
255 } else {
256 self.chunk.emit_op(OpCode::Undefined);
257 }
258 self.chunk.emit_with(OpCode::InitLocal, slot);
259 continue;
260 }
261
262 self.declare_lexical(&id.name);
264
265 let name_idx = self.chunk.add_name(&id.name);
266 self.chunk.emit_with(declare_op, name_idx);
267
268 if let Some(ref init_expr) = declarator.init {
269 self.compile_expression(init_expr);
270 } else {
271 self.chunk.emit_op(OpCode::Undefined);
272 }
273 self.chunk.emit_with(init_op, name_idx);
274 }
275 }
276 }
277
278 fn compile_if(
281 &mut self,
282 test: &ExpressionType,
283 consequent: &StatementType,
284 alternate: Option<&StatementType>,
285 ) {
286 self.compile_expression(test);
287 let jump_to_else = self.chunk.emit_with(OpCode::JumpIfFalse, 0);
288
289 self.compile_statement(consequent);
290
291 if let Some(alt) = alternate {
292 let jump_over_else = self.chunk.emit_with(OpCode::Jump, 0);
293 self.chunk.patch_jump(jump_to_else);
294 self.compile_statement(alt);
295 self.chunk.patch_jump(jump_over_else);
296 } else {
297 self.chunk.patch_jump(jump_to_else);
298 }
299 }
300
301 fn compile_while(&mut self, test: &ExpressionType, body: &StatementType) {
302 let loop_start = self.chunk.current_pos();
303
304 self.loop_stack.push(LoopContext {
305 continue_target: loop_start,
306 break_jumps: Vec::new(),
307 continue_jumps: Vec::new(),
308 });
309
310 self.compile_expression(test);
311 let exit_jump = self.chunk.emit_with(OpCode::JumpIfFalse, 0);
312
313 self.compile_statement(body);
314 self.chunk.emit_with(OpCode::Jump, loop_start as u32);
315
316 self.chunk.patch_jump(exit_jump);
317
318 let ctx = self.loop_stack.pop().unwrap();
319 for bj in ctx.break_jumps {
320 self.chunk.patch_jump(bj);
321 }
322 }
323
324 fn compile_do_while(&mut self, body: &StatementType, test: &ExpressionType) {
325 let loop_start = self.chunk.current_pos();
326
327 self.loop_stack.push(LoopContext {
328 continue_target: loop_start,
329 break_jumps: Vec::new(),
330 continue_jumps: Vec::new(),
331 });
332
333 self.compile_statement(body);
334
335 let continue_target = self.chunk.current_pos();
337 if let Some(ctx) = self.loop_stack.last_mut() {
338 ctx.continue_target = continue_target;
339 }
340
341 self.compile_expression(test);
342 self.chunk.emit_with(OpCode::JumpIfTrue, loop_start as u32);
343
344 let ctx = self.loop_stack.pop().unwrap();
345 for cj in &ctx.continue_jumps {
346 self.chunk.code[*cj].operand = continue_target as u32;
347 }
348 for bj in ctx.break_jumps {
349 self.chunk.patch_jump(bj);
350 }
351 }
352
353 fn compile_for(
354 &mut self,
355 init: Option<&VariableDeclarationOrExpression>,
356 test: Option<&ExpressionType>,
357 update: Option<&ExpressionType>,
358 body: &StatementType,
359 ) {
360 self.push_lexical_scope();
361 self.chunk.emit_op(OpCode::PushScope);
362
363 if let Some(init) = init {
365 match init {
366 VariableDeclarationOrExpression::VariableDeclaration(var_decl) => {
367 self.compile_var_declaration(var_decl);
368 }
369 VariableDeclarationOrExpression::Expression(expr) => {
370 self.compile_expression(expr);
371 self.chunk.emit_op(OpCode::Pop);
372 }
373 }
374 }
375
376 let loop_start = self.chunk.current_pos();
377
378 self.loop_stack.push(LoopContext {
381 continue_target: loop_start, break_jumps: Vec::new(),
383 continue_jumps: Vec::new(),
384 });
385
386 let exit_jump = if let Some(test) = test {
388 self.compile_expression(test);
389 Some(self.chunk.emit_with(OpCode::JumpIfFalse, 0))
390 } else {
391 None
392 };
393
394 self.compile_statement(body);
396
397 let update_pos = self.chunk.current_pos();
399 if let Some(ctx) = self.loop_stack.last_mut() {
400 ctx.continue_target = update_pos;
401 }
402
403 if let Some(update) = update {
404 self.compile_expression(update);
405 self.chunk.emit_op(OpCode::Pop);
406 }
407
408 self.chunk.emit_with(OpCode::Jump, loop_start as u32);
409
410 if let Some(ej) = exit_jump {
411 self.chunk.patch_jump(ej);
412 }
413
414 let ctx = self.loop_stack.pop().unwrap();
415 for cj in &ctx.continue_jumps {
417 self.chunk.code[*cj].operand = update_pos as u32;
418 }
419 for bj in ctx.break_jumps {
420 self.chunk.patch_jump(bj);
421 }
422
423 self.chunk.emit_op(OpCode::PopScope);
424 self.pop_lexical_scope();
425 }
426
427 fn compile_for_in(&mut self, _data: &ForIteratorData) {
428 }
431
432 fn compile_for_of(&mut self, _data: &ForIteratorData) {
433 }
436
437 fn compile_switch(
438 &mut self,
439 discriminant: &ExpressionType,
440 cases: &[SwitchCaseData],
441 ) {
442 self.compile_expression(discriminant);
443
444 let mut case_body_jumps: Vec<usize> = Vec::new();
447 let mut default_jump: Option<usize> = None;
448
449 for case in cases {
451 if let Some(ref test) = case.test {
452 self.chunk.emit_op(OpCode::Dup);
453 self.compile_expression(test);
454 self.chunk.emit_op(OpCode::StrictEqual);
455 let jump = self.chunk.emit_with(OpCode::JumpIfTrue, 0);
456 case_body_jumps.push(jump);
457 } else {
458 default_jump = Some(case_body_jumps.len());
460 case_body_jumps.push(0); }
462 }
463
464 let jump_to_default_or_end = self.chunk.emit_with(OpCode::Jump, 0);
466
467 self.loop_stack.push(LoopContext {
469 continue_target: 0, break_jumps: Vec::new(),
471 continue_jumps: Vec::new(),
472 });
473
474 for (i, case) in cases.iter().enumerate() {
476 let body_pos = self.chunk.current_pos();
477 if i < case_body_jumps.len() && case_body_jumps[i] != 0 {
478 self.chunk.code[case_body_jumps[i]].operand = body_pos as u32;
479 }
480 if default_jump == Some(i) {
481 self.chunk.code[jump_to_default_or_end].operand = body_pos as u32;
482 }
483 for stmt in &case.consequent {
484 self.compile_statement(stmt);
485 }
486 }
487
488 if default_jump.is_none() {
490 self.chunk.patch_jump(jump_to_default_or_end);
491 }
492
493 self.chunk.emit_op(OpCode::Pop);
495
496 let ctx = self.loop_stack.pop().unwrap();
497 for bj in ctx.break_jumps {
498 self.chunk.patch_jump(bj);
499 }
500 }
501
502 fn compile_break(&mut self) {
503 if let Some(ctx) = self.loop_stack.last_mut() {
504 let jump = self.chunk.emit_with(OpCode::Jump, 0);
505 ctx.break_jumps.push(jump);
506 }
507 }
508
509 fn compile_continue(&mut self) {
510 if let Some(ctx) = self.loop_stack.last() {
511 let target = ctx.continue_target;
512 let jump = self.chunk.emit_with(OpCode::Jump, target as u32);
513 if let Some(ctx) = self.loop_stack.last_mut() {
516 ctx.continue_jumps.push(jump);
517 }
518 }
519 }
520
521 fn compile_expression(&mut self, expr: &ExpressionType) {
526 match expr {
527 ExpressionType::Literal(lit) => {
528 self.compile_literal(lit);
529 }
530
531 ExpressionType::ExpressionWhichCanBePattern(pattern) => {
532 self.compile_expression_pattern(pattern);
533 }
534
535 ExpressionType::ThisExpression { .. } => {
536 self.chunk.emit_op(OpCode::Undefined);
538 }
539
540 ExpressionType::BinaryExpression { operator, left, right, .. } => {
541 self.compile_expression(left);
542 self.compile_expression(right);
543 self.compile_binary_op(operator);
544 }
545
546 ExpressionType::LogicalExpression { operator, left, right, .. } => {
547 self.compile_logical(operator, left, right);
548 }
549
550 ExpressionType::UnaryExpression { operator, argument, .. } => {
551 self.compile_expression(argument);
552 self.compile_unary_op(operator);
553 }
554
555 ExpressionType::UpdateExpression { operator, argument, prefix, .. } => {
556 self.compile_update(operator, argument, *prefix);
557 }
558
559 ExpressionType::AssignmentExpression { operator, left, right, .. } => {
560 self.compile_assignment(operator, left, right);
561 }
562
563 ExpressionType::ConditionalExpression { test, consequent, alternate, .. } => {
564 self.compile_expression(test);
565 let jump_to_alt = self.chunk.emit_with(OpCode::JumpIfFalse, 0);
566 self.compile_expression(consequent);
567 let jump_over = self.chunk.emit_with(OpCode::Jump, 0);
568 self.chunk.patch_jump(jump_to_alt);
569 self.compile_expression(alternate);
570 self.chunk.patch_jump(jump_over);
571 }
572
573 ExpressionType::SequenceExpression { expressions, .. } => {
574 for (i, expr) in expressions.iter().enumerate() {
575 self.compile_expression(expr);
576 if i < expressions.len() - 1 {
577 self.chunk.emit_op(OpCode::Pop);
578 }
579 }
580 }
581
582 ExpressionType::CallExpression { callee, arguments, .. } => {
583 self.compile_call(callee, arguments);
584 }
585
586 ExpressionType::MemberExpression(member_expr) => {
587 self.compile_member_expression(member_expr);
588 }
589
590 ExpressionType::ArrayExpression { .. } => {
591 self.chunk.emit_op(OpCode::Undefined);
594 }
595
596 ExpressionType::ObjectExpression { .. } => {
597 self.chunk.emit_op(OpCode::Undefined);
599 }
600
601 ExpressionType::FunctionOrGeneratorExpression(func_data) => {
602 let func_idx = self.chunk.add_function(FunctionTemplate {
603 body_ptr: func_data.body.as_ref() as *const _,
604 params_ptr: &func_data.params.list as *const _,
605 });
606 self.chunk.emit_with(OpCode::MakeClosure, func_idx);
607 }
608
609 ExpressionType::NewExpression { .. } => {
610 self.chunk.emit_op(OpCode::Undefined);
611 }
612
613 ExpressionType::ArrowFunctionExpression { params, body, .. } => {
614 match body.as_ref() {
615 crate::parser::ast::FunctionBodyOrExpression::FunctionBody(func_body) => {
616 let func_idx = self.chunk.add_function(FunctionTemplate {
617 body_ptr: func_body as *const _,
618 params_ptr: params as *const _,
619 });
620 self.chunk.emit_with(OpCode::MakeClosure, func_idx);
621 }
622 crate::parser::ast::FunctionBodyOrExpression::Expression(_) => {
623 self.chunk.emit_op(OpCode::Undefined);
625 }
626 }
627 }
628
629 ExpressionType::YieldExpression { .. } => {
630 self.chunk.emit_op(OpCode::Undefined);
631 }
632
633 ExpressionType::TemplateLiteral(_) => {
634 self.chunk.emit_op(OpCode::Undefined);
635 }
636
637 ExpressionType::TaggedTemplateExpression { .. } => {
638 self.chunk.emit_op(OpCode::Undefined);
639 }
640
641 ExpressionType::ClassExpression(_) => {
642 self.chunk.emit_op(OpCode::Undefined);
643 }
644
645 ExpressionType::MetaProperty { .. } => {
646 self.chunk.emit_op(OpCode::Undefined);
647 }
648 }
649 }
650
651 fn compile_literal(&mut self, lit: &LiteralData) {
652 match &lit.value {
653 LiteralType::NullLiteral => {
654 self.chunk.emit_op(OpCode::Null);
655 }
656 LiteralType::BooleanLiteral(true) => {
657 self.chunk.emit_op(OpCode::True);
658 }
659 LiteralType::BooleanLiteral(false) => {
660 self.chunk.emit_op(OpCode::False);
661 }
662 LiteralType::StringLiteral(s) => {
663 let idx = self.chunk.add_constant(JsValue::String(s.clone()));
664 self.chunk.emit_with(OpCode::Constant, idx);
665 }
666 LiteralType::NumberLiteral(n) => {
667 let value = match n {
668 NumberLiteralType::IntegerLiteral(i) => {
669 JsValue::Number(JsNumberType::Integer(*i))
670 }
671 NumberLiteralType::FloatLiteral(f) => {
672 JsValue::Number(JsNumberType::Float(*f))
673 }
674 };
675 let idx = self.chunk.add_constant(value);
676 self.chunk.emit_with(OpCode::Constant, idx);
677 }
678 LiteralType::RegExpLiteral(_) => {
679 self.chunk.emit_op(OpCode::Undefined);
680 }
681 }
682 }
683
684 fn compile_expression_pattern(&mut self, pattern: &ExpressionPatternType) {
685 match pattern {
686 ExpressionPatternType::Identifier(id) => {
687 if !self.is_lexically_shadowed(&id.name) {
688 if let Some(slot) = self.get_local_slot(&id.name) {
689 self.chunk.emit_with(OpCode::GetLocal, slot);
690 return;
691 }
692 }
693 let name_idx = self.chunk.add_name(&id.name);
694 self.chunk.emit_with(OpCode::GetVar, name_idx);
695 }
696 }
697 }
698
699 fn compile_binary_op(&mut self, op: &BinaryOperator) {
700 match op {
701 BinaryOperator::Add => self.chunk.emit_op(OpCode::Add),
702 BinaryOperator::Subtract => self.chunk.emit_op(OpCode::Sub),
703 BinaryOperator::Multiply => self.chunk.emit_op(OpCode::Mul),
704 BinaryOperator::Divide => self.chunk.emit_op(OpCode::Div),
705 BinaryOperator::Modulo => self.chunk.emit_op(OpCode::Mod),
706 BinaryOperator::StrictlyEqual => self.chunk.emit_op(OpCode::StrictEqual),
707 BinaryOperator::StrictlyUnequal => self.chunk.emit_op(OpCode::StrictNotEqual),
708 BinaryOperator::LooselyEqual => self.chunk.emit_op(OpCode::Equal),
709 BinaryOperator::LooselyUnequal => self.chunk.emit_op(OpCode::NotEqual),
710 BinaryOperator::LessThan => self.chunk.emit_op(OpCode::LessThan),
711 BinaryOperator::LessThanEqual => self.chunk.emit_op(OpCode::LessEqual),
712 BinaryOperator::GreaterThan => self.chunk.emit_op(OpCode::GreaterThan),
713 BinaryOperator::GreaterThanEqual => self.chunk.emit_op(OpCode::GreaterEqual),
714 BinaryOperator::BitwiseAnd => self.chunk.emit_op(OpCode::BitAnd),
715 BinaryOperator::BitwiseOr => self.chunk.emit_op(OpCode::BitOr),
716 BinaryOperator::BitwiseXor => self.chunk.emit_op(OpCode::BitXor),
717 BinaryOperator::BitwiseLeftShift => self.chunk.emit_op(OpCode::ShiftLeft),
718 BinaryOperator::BitwiseRightShift => self.chunk.emit_op(OpCode::ShiftRight),
719 BinaryOperator::BitwiseUnsignedRightShift => self.chunk.emit_op(OpCode::UShiftRight),
720 BinaryOperator::In | BinaryOperator::InstanceOf => {
721 self.chunk.emit_op(OpCode::Undefined);
723 0
724 }
725 };
726 }
727
728 fn compile_unary_op(&mut self, op: &UnaryOperator) {
729 match op {
730 UnaryOperator::Minus => { self.chunk.emit_op(OpCode::Negate); }
731 UnaryOperator::Plus => { self.chunk.emit_op(OpCode::UnaryPlus); }
732 UnaryOperator::LogicalNot => { self.chunk.emit_op(OpCode::Not); }
733 UnaryOperator::BitwiseNot => { self.chunk.emit_op(OpCode::BitNot); }
734 UnaryOperator::TypeOf => { self.chunk.emit_op(OpCode::TypeOf); }
735 UnaryOperator::Void => { self.chunk.emit_op(OpCode::Void); }
736 _ => { self.chunk.emit_op(OpCode::Undefined); }
737 };
738 }
739
740 fn compile_logical(
741 &mut self,
742 op: &LogicalOperator,
743 left: &ExpressionType,
744 right: &ExpressionType,
745 ) {
746 self.compile_expression(left);
747 match op {
748 LogicalOperator::And => {
749 self.chunk.emit_op(OpCode::Dup);
751 let jump = self.chunk.emit_with(OpCode::JumpIfFalse, 0);
752 self.chunk.emit_op(OpCode::Pop);
753 self.compile_expression(right);
754 self.chunk.patch_jump(jump);
755 }
756 LogicalOperator::Or => {
757 self.chunk.emit_op(OpCode::Dup);
759 let jump = self.chunk.emit_with(OpCode::JumpIfTrue, 0);
760 self.chunk.emit_op(OpCode::Pop);
761 self.compile_expression(right);
762 self.chunk.patch_jump(jump);
763 }
764 }
765 }
766
767 fn compile_update(
768 &mut self,
769 op: &UpdateOperator,
770 argument: &ExpressionType,
771 prefix: bool,
772 ) {
773 if let ExpressionType::ExpressionWhichCanBePattern(
775 ExpressionPatternType::Identifier(ref id),
776 ) = argument
777 {
778 if !self.is_lexically_shadowed(&id.name) {
779 if let Some(slot) = self.get_local_slot(&id.name) {
780 let one_idx = self
781 .chunk
782 .add_constant(JsValue::Number(JsNumberType::Integer(1)));
783 match (op, prefix) {
784 (UpdateOperator::PlusPlus, true) => {
785 self.chunk.emit_with(OpCode::GetLocal, slot);
786 self.chunk.emit_with(OpCode::Constant, one_idx);
787 self.chunk.emit_op(OpCode::Add);
788 self.chunk.emit_op(OpCode::Dup);
789 self.chunk.emit_with(OpCode::SetLocal, slot);
790 }
791 (UpdateOperator::MinusMinus, true) => {
792 self.chunk.emit_with(OpCode::GetLocal, slot);
793 self.chunk.emit_with(OpCode::Constant, one_idx);
794 self.chunk.emit_op(OpCode::Sub);
795 self.chunk.emit_op(OpCode::Dup);
796 self.chunk.emit_with(OpCode::SetLocal, slot);
797 }
798 (UpdateOperator::PlusPlus, false) => {
799 self.chunk.emit_with(OpCode::GetLocal, slot);
800 self.chunk.emit_op(OpCode::Dup);
801 self.chunk.emit_with(OpCode::Constant, one_idx);
802 self.chunk.emit_op(OpCode::Add);
803 self.chunk.emit_with(OpCode::SetLocal, slot);
804 }
805 (UpdateOperator::MinusMinus, false) => {
806 self.chunk.emit_with(OpCode::GetLocal, slot);
807 self.chunk.emit_op(OpCode::Dup);
808 self.chunk.emit_with(OpCode::Constant, one_idx);
809 self.chunk.emit_op(OpCode::Sub);
810 self.chunk.emit_with(OpCode::SetLocal, slot);
811 }
812 }
813 return;
814 }
815 }
816 let name_idx = self.chunk.add_name(&id.name);
817 match (op, prefix) {
818 (UpdateOperator::PlusPlus, true) => {
819 self.chunk.emit_with(OpCode::PreIncVar, name_idx);
820 }
821 (UpdateOperator::MinusMinus, true) => {
822 self.chunk.emit_with(OpCode::PreDecVar, name_idx);
823 }
824 (UpdateOperator::PlusPlus, false) => {
825 self.chunk.emit_with(OpCode::PostIncVar, name_idx);
826 }
827 (UpdateOperator::MinusMinus, false) => {
828 self.chunk.emit_with(OpCode::PostDecVar, name_idx);
829 }
830 }
831 } else {
832 self.chunk.emit_op(OpCode::Undefined);
834 }
835 }
836
837 fn compile_assignment(
838 &mut self,
839 op: &AssignmentOperator,
840 left: &PatternOrExpression,
841 right: &ExpressionType,
842 ) {
843 let name = self.extract_assignment_target_name(left);
845
846 if let Some(name) = name {
847 if !self.is_lexically_shadowed(&name) {
848 if let Some(slot) = self.get_local_slot(&name) {
849 match op {
850 AssignmentOperator::Equals => {
851 self.compile_expression(right);
852 self.chunk.emit_op(OpCode::Dup);
853 self.chunk.emit_with(OpCode::SetLocal, slot);
854 }
855 _ => {
856 self.chunk.emit_with(OpCode::GetLocal, slot);
857 self.compile_expression(right);
858 self.compile_compound_op(op);
859 self.chunk.emit_op(OpCode::Dup);
860 self.chunk.emit_with(OpCode::SetLocal, slot);
861 }
862 }
863 return;
864 }
865 }
866 let name_idx = self.chunk.add_name(&name);
867 match op {
868 AssignmentOperator::Equals => {
869 self.compile_expression(right);
870 self.chunk.emit_op(OpCode::Dup); self.chunk.emit_with(OpCode::SetVar, name_idx);
872 }
873 _ => {
874 self.chunk.emit_with(OpCode::GetVar, name_idx);
876 self.compile_expression(right);
877 self.compile_compound_op(op);
878 self.chunk.emit_op(OpCode::Dup);
879 self.chunk.emit_with(OpCode::SetVar, name_idx);
880 }
881 }
882 } else {
883 self.compile_member_assignment(op, left, right);
885 }
886 }
887
888 fn extract_assignment_target_name(&self, target: &PatternOrExpression) -> Option<String> {
889 match target {
890 PatternOrExpression::Pattern(pat) => {
891 if let PatternType::PatternWhichCanBeExpression(
892 ExpressionPatternType::Identifier(ref id),
893 ) = pat.as_ref()
894 {
895 Some(id.name.clone())
896 } else {
897 None
898 }
899 }
900 PatternOrExpression::Expression(expr) => {
901 if let ExpressionType::ExpressionWhichCanBePattern(
902 ExpressionPatternType::Identifier(ref id),
903 ) = expr.as_ref()
904 {
905 Some(id.name.clone())
906 } else {
907 None
908 }
909 }
910 }
911 }
912
913 fn compile_member_assignment(
914 &mut self,
915 op: &AssignmentOperator,
916 left: &PatternOrExpression,
917 right: &ExpressionType,
918 ) {
919 if let PatternOrExpression::Expression(expr) = left {
920 if let ExpressionType::MemberExpression(member) = expr.as_ref() {
921 match member {
922 MemberExpressionType::SimpleMemberExpression { object, property, .. } => {
923 match object {
924 ExpressionOrSuper::Expression(obj_expr) => {
925 self.compile_expression(obj_expr);
926 }
927 ExpressionOrSuper::Super => {
928 self.chunk.emit_op(OpCode::Undefined);
929 }
930 }
931
932 let prop_idx = self.chunk.add_name(&property.name);
933 if matches!(op, AssignmentOperator::Equals) {
934 self.compile_expression(right);
935 self.chunk.emit_with(OpCode::SetProp, prop_idx);
936 } else {
937 self.chunk.emit_op(OpCode::Dup);
938 self.chunk.emit_with(OpCode::GetProp, prop_idx);
939 self.compile_expression(right);
940 self.compile_compound_op(op);
941 self.chunk.emit_with(OpCode::SetProp, prop_idx);
942 }
943 return;
944 }
945 MemberExpressionType::ComputedMemberExpression { object, property, .. } => {
946 match object {
947 ExpressionOrSuper::Expression(obj_expr) => {
948 self.compile_expression(obj_expr);
949 }
950 ExpressionOrSuper::Super => {
951 self.chunk.emit_op(OpCode::Undefined);
952 }
953 }
954 self.compile_expression(property);
955
956 if matches!(op, AssignmentOperator::Equals) {
957 self.compile_expression(right);
958 self.chunk.emit_op(OpCode::SetElem);
959 } else {
960 self.chunk.emit_op(OpCode::Dup2);
961 self.chunk.emit_op(OpCode::GetElem);
962 self.compile_expression(right);
963 self.compile_compound_op(op);
964 self.chunk.emit_op(OpCode::SetElem);
965 }
966 return;
967 }
968 }
969 }
970 }
971
972 self.compile_expression(right);
974 }
975
976 fn compile_compound_op(&mut self, op: &AssignmentOperator) {
977 match op {
978 AssignmentOperator::AddEquals => { self.chunk.emit_op(OpCode::Add); }
979 AssignmentOperator::SubtractEquals => { self.chunk.emit_op(OpCode::Sub); }
980 AssignmentOperator::MultiplyEquals => { self.chunk.emit_op(OpCode::Mul); }
981 AssignmentOperator::DivideEquals => { self.chunk.emit_op(OpCode::Div); }
982 AssignmentOperator::ModuloEquals => { self.chunk.emit_op(OpCode::Mod); }
983 AssignmentOperator::BitwiseAndEquals => { self.chunk.emit_op(OpCode::BitAnd); }
984 AssignmentOperator::BitwiseOrEquals => { self.chunk.emit_op(OpCode::BitOr); }
985 AssignmentOperator::BitwiseXorEquals => { self.chunk.emit_op(OpCode::BitXor); }
986 AssignmentOperator::BitwiseLeftShiftEquals => { self.chunk.emit_op(OpCode::ShiftLeft); }
987 AssignmentOperator::BitwiseRightShiftEquals => { self.chunk.emit_op(OpCode::ShiftRight); }
988 AssignmentOperator::BitwiseUnsignedRightShiftEquals => { self.chunk.emit_op(OpCode::UShiftRight); }
989 AssignmentOperator::Equals => {}
990 };
991 }
992
993 fn compile_call(
994 &mut self,
995 callee: &ExpressionOrSuper,
996 arguments: &[ExpressionOrSpreadElement],
997 ) {
998 match callee {
1000 ExpressionOrSuper::Expression(expr) => {
1001 if let ExpressionType::MemberExpression(
1002 MemberExpressionType::SimpleMemberExpression { object, property, .. },
1003 ) = expr.as_ref()
1004 {
1005 match object {
1007 ExpressionOrSuper::Expression(obj_expr) => {
1008 self.compile_expression(obj_expr);
1009 }
1010 ExpressionOrSuper::Super => {
1011 self.chunk.emit_op(OpCode::Undefined);
1012 }
1013 }
1014
1015 let argc = arguments.len();
1016 for arg in arguments {
1017 match arg {
1018 ExpressionOrSpreadElement::Expression(e) => {
1019 self.compile_expression(e);
1020 }
1021 ExpressionOrSpreadElement::SpreadElement(e) => {
1022 self.compile_expression(e);
1023 }
1024 }
1025 }
1026
1027 let method_idx = self.chunk.add_name(&property.name);
1028 let obj_name_idx = match object {
1030 ExpressionOrSuper::Expression(obj_expr) => {
1031 if let ExpressionType::ExpressionWhichCanBePattern(
1032 ExpressionPatternType::Identifier(id)
1033 ) = obj_expr.as_ref() {
1034 self.chunk.add_name(&id.name)
1035 } else {
1036 self.chunk.add_name("")
1037 }
1038 }
1039 _ => self.chunk.add_name(""),
1040 };
1041 self.chunk.emit(Instruction::with_three_operands(
1042 OpCode::CallMethod,
1043 argc as u32,
1044 method_idx,
1045 obj_name_idx,
1046 ));
1047 } else {
1048 self.compile_expression(expr);
1050 let argc = arguments.len();
1051 for arg in arguments {
1052 match arg {
1053 ExpressionOrSpreadElement::Expression(e) => {
1054 self.compile_expression(e);
1055 }
1056 ExpressionOrSpreadElement::SpreadElement(e) => {
1057 self.compile_expression(e);
1058 }
1059 }
1060 }
1061 self.chunk.emit_with(OpCode::Call, argc as u32);
1062 }
1063 }
1064 ExpressionOrSuper::Super => {
1065 self.chunk.emit_op(OpCode::Undefined);
1066 }
1067 }
1068 }
1069
1070 fn compile_member_expression(&mut self, member: &MemberExpressionType) {
1071 match member {
1072 MemberExpressionType::SimpleMemberExpression { object, property, .. } => {
1073 match object {
1074 ExpressionOrSuper::Expression(expr) => {
1075 self.compile_expression(expr);
1076 }
1077 ExpressionOrSuper::Super => {
1078 self.chunk.emit_op(OpCode::Undefined);
1079 }
1080 }
1081 let prop_idx = self.chunk.add_name(&property.name);
1082 self.chunk.emit_with(OpCode::GetProp, prop_idx);
1083 }
1084 MemberExpressionType::ComputedMemberExpression { object, property, .. } => {
1085 match object {
1086 ExpressionOrSuper::Expression(expr) => {
1087 self.compile_expression(expr);
1088 }
1089 ExpressionOrSuper::Super => {
1090 self.chunk.emit_op(OpCode::Undefined);
1091 }
1092 }
1093 self.compile_expression(property);
1094 self.chunk.emit_op(OpCode::GetElem);
1095 }
1096 }
1097 }
1098}