1use crate::parser::ast::{
6 AssignmentOperator, BinaryOperator, BlockStatementData, DeclarationType,
7 ExpressionOrSpreadElement, ExpressionOrSuper, ExpressionPatternType, ExpressionType,
8 ForIteratorData, FunctionBodyData, LiteralData, LiteralType, LogicalOperator,
9 MemberExpressionType, NumberLiteralType, PatternOrExpression, PatternType, ProgramData,
10 StatementType, SwitchCaseData, UnaryOperator, UpdateOperator, VariableDeclarationData,
11 VariableDeclarationKind, VariableDeclarationOrExpression,
12};
13use crate::runner::ds::value::{JsNumberType, JsValue};
14use std::collections::{HashMap, HashSet};
15
16use super::reg_bytecode::{RegChunk, RegInstruction, RegOpCode};
17
18struct LoopContext {
19 continue_target: usize,
20 break_jumps: Vec<usize>,
21 continue_jumps: Vec<usize>,
22}
23
24pub struct RegCompiler {
25 chunk: RegChunk,
26 loop_stack: Vec<LoopContext>,
27 locals: HashMap<String, u32>,
28 local_regs: HashSet<u32>,
29 lexical_scopes: Vec<HashSet<String>>,
30 next_reg: u32,
31 free_regs: Vec<u32>,
32}
33
34impl RegCompiler {
35 pub fn new() -> Self {
36 RegCompiler {
37 chunk: RegChunk::new(),
38 loop_stack: Vec::new(),
39 locals: HashMap::new(),
40 local_regs: HashSet::new(),
41 lexical_scopes: vec![HashSet::new()],
42 next_reg: 0,
43 free_regs: Vec::new(),
44 }
45 }
46
47 pub fn compile_program(mut self, program: &ProgramData) -> RegChunk {
48 for stmt in &program.body {
49 self.compile_statement(stmt);
50 }
51 self.chunk.emit_op(RegOpCode::Halt);
52 self.chunk.set_register_count(self.next_reg);
53 self.chunk
54 }
55
56 fn alloc_reg(&mut self) -> u32 {
57 if let Some(reg) = self.free_regs.pop() {
58 return reg;
59 }
60 let reg = self.next_reg;
61 self.next_reg += 1;
62 reg
63 }
64
65 fn release_reg(&mut self, reg: u32) {
66 if self.local_regs.contains(®) {
67 return;
68 }
69 self.free_regs.push(reg);
70 }
71
72 fn get_local_reg(&self, name: &str) -> Option<u32> {
73 self.locals.get(name).copied()
74 }
75
76 fn get_or_add_local_reg(&mut self, name: &str) -> u32 {
77 if let Some(reg) = self.locals.get(name) {
78 return *reg;
79 }
80 let reg = self.alloc_reg();
81 let name_idx = self.chunk.add_name(name);
82 self.chunk.add_local(name_idx, reg);
83 self.locals.insert(name.to_string(), reg);
84 self.local_regs.insert(reg);
85 reg
86 }
87
88 fn push_lexical_scope(&mut self) {
89 self.lexical_scopes.push(HashSet::new());
90 }
91
92 fn pop_lexical_scope(&mut self) {
93 self.lexical_scopes.pop();
94 }
95
96 fn declare_lexical(&mut self, name: &str) {
97 if let Some(scope) = self.lexical_scopes.last_mut() {
98 scope.insert(name.to_string());
99 }
100 }
101
102 fn is_lexically_shadowed(&self, name: &str) -> bool {
103 self.lexical_scopes
104 .iter()
105 .rev()
106 .any(|scope| scope.contains(name))
107 }
108
109 fn compile_statement(&mut self, stmt: &StatementType) {
114 match stmt {
115 StatementType::EmptyStatement { .. } => {}
116 StatementType::ExpressionStatement { expression, .. } => {
117 let reg = self.compile_expression(expression);
118 self.release_reg(reg);
119 }
120 StatementType::BlockStatement(block) => {
121 self.compile_block(block);
122 }
123 StatementType::DeclarationStatement(decl) => {
124 self.compile_declaration(decl);
125 }
126 StatementType::IfStatement { test, consequent, alternate, .. } => {
127 self.compile_if(test, consequent, alternate.as_ref().map(|a| a.as_ref()));
128 }
129 StatementType::WhileStatement { test, body, .. } => {
130 self.compile_while(test, body);
131 }
132 StatementType::DoWhileStatement { test, body, .. } => {
133 self.compile_do_while(body, test);
134 }
135 StatementType::ForStatement { init, test, update, body, .. } => {
136 self.compile_for(init.as_ref(), test.as_ref().map(|t| t.as_ref()), update.as_ref().map(|u| u.as_ref()), body);
137 }
138 StatementType::ForInStatement(data) => {
139 self.compile_for_in(data);
140 }
141 StatementType::ForOfStatement(data) => {
142 self.compile_for_of(data);
143 }
144 StatementType::SwitchStatement { discriminant, cases, .. } => {
145 self.compile_switch(discriminant, cases);
146 }
147 StatementType::BreakStatement { .. } => {
148 self.compile_break();
149 }
150 StatementType::ContinueStatement { .. } => {
151 self.compile_continue();
152 }
153 StatementType::ReturnStatement { argument, .. } => {
154 if let Some(arg) = argument {
155 let reg = self.compile_expression(arg);
156 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Return, 0, reg));
157 } else {
158 let reg = self.alloc_reg();
159 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
160 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Return, 0, reg));
161 self.release_reg(reg);
162 }
163 }
164 StatementType::ThrowStatement { argument, .. } => {
165 let reg = self.compile_expression(argument);
166 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Return, 0, reg));
167 }
168 StatementType::TryStatement { block, handler: _, finalizer, .. } => {
169 self.compile_block(block);
170 if let Some(fin) = finalizer {
171 self.compile_block(fin);
172 }
173 }
174 StatementType::DebuggerStatement { .. } => {}
175 StatementType::FunctionBody(body) => {
176 self.compile_function_body(body);
177 }
178 }
179 }
180
181 fn compile_block(&mut self, block: &BlockStatementData) {
182 self.push_lexical_scope();
183 for stmt in &block.body {
184 self.compile_statement(stmt);
185 }
186 self.pop_lexical_scope();
187 }
188
189 fn compile_declaration(&mut self, decl: &DeclarationType) {
190 match decl {
191 DeclarationType::VariableDeclaration(var_decl) => {
192 self.compile_var_declaration(var_decl);
193 }
194 DeclarationType::FunctionOrGeneratorDeclaration(func_data) => {
195 if let Some(ref id) = func_data.id {
196 let reg = self.get_or_add_local_reg(&id.name);
197 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
198 }
199 }
200 DeclarationType::ClassDeclaration(_) => {}
201 }
202 }
203
204 fn compile_var_declaration(&mut self, var_decl: &VariableDeclarationData) {
205 let (declare_op, init_op) = match var_decl.kind {
206 VariableDeclarationKind::Var => (RegOpCode::DeclareVar, RegOpCode::InitVar),
207 VariableDeclarationKind::Let => (RegOpCode::DeclareLet, RegOpCode::InitBinding),
208 VariableDeclarationKind::Const => (RegOpCode::DeclareConst, RegOpCode::InitBinding),
209 };
210
211 for declarator in &var_decl.declarations {
212 if let PatternType::PatternWhichCanBeExpression(ExpressionPatternType::Identifier(ref id)) = declarator.id.as_ref() {
213 if matches!(var_decl.kind, VariableDeclarationKind::Var) {
214 let reg = self.get_or_add_local_reg(&id.name);
215 if let Some(ref init_expr) = declarator.init {
216 let init_reg = self.compile_expression(init_expr);
217 if init_reg != reg {
218 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, reg, init_reg));
219 }
220 self.release_reg(init_reg);
221 } else {
222 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
223 }
224 continue;
225 }
226
227 self.declare_lexical(&id.name);
228 let name_idx = self.chunk.add_name(&id.name);
229 self.chunk.emit(RegInstruction::with_dst_imm(declare_op, 0, name_idx));
230
231 let init_reg = if let Some(ref init_expr) = declarator.init {
232 self.compile_expression(init_expr)
233 } else {
234 let reg = self.alloc_reg();
235 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
236 reg
237 };
238 self.chunk.emit(RegInstruction::with_src_imm(init_op, init_reg, name_idx));
239 self.release_reg(init_reg);
240 }
241 }
242 }
243
244 fn compile_if(&mut self, test: &ExpressionType, consequent: &StatementType, alternate: Option<&StatementType>) {
245 let test_reg = self.compile_expression(test);
246 let jump_to_else = self.emit_jump(RegOpCode::JumpIfFalse, test_reg, 0);
247 self.compile_statement(consequent);
248 if let Some(alt) = alternate {
249 let jump_over_else = self.emit_jump(RegOpCode::Jump, 0, 0);
250 self.patch_jump(jump_to_else);
251 self.compile_statement(alt);
252 self.patch_jump(jump_over_else);
253 } else {
254 self.patch_jump(jump_to_else);
255 }
256 self.release_reg(test_reg);
257 }
258
259 fn compile_while(&mut self, test: &ExpressionType, body: &StatementType) {
260 let loop_start = self.chunk.code.len();
261 self.loop_stack.push(LoopContext { continue_target: loop_start, break_jumps: Vec::new(), continue_jumps: Vec::new() });
262
263 let test_reg = self.compile_expression(test);
264 let exit_jump = self.emit_jump(RegOpCode::JumpIfFalse, test_reg, 0);
265 self.release_reg(test_reg);
266
267 self.compile_statement(body);
268 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::Jump, 0, loop_start as u32));
269
270 self.patch_jump(exit_jump);
271 let ctx = self.loop_stack.pop().unwrap();
272 for bj in ctx.break_jumps {
273 self.patch_jump(bj);
274 }
275 }
276
277 fn compile_do_while(&mut self, body: &StatementType, test: &ExpressionType) {
278 let loop_start = self.chunk.code.len();
279 self.loop_stack.push(LoopContext { continue_target: loop_start, break_jumps: Vec::new(), continue_jumps: Vec::new() });
280
281 self.compile_statement(body);
282
283 let continue_target = self.chunk.code.len();
284 if let Some(ctx) = self.loop_stack.last_mut() {
285 ctx.continue_target = continue_target;
286 }
287 let test_reg = self.compile_expression(test);
288 self.chunk.emit(RegInstruction::with_src_imm(RegOpCode::JumpIfTrue, test_reg, loop_start as u32));
289 self.release_reg(test_reg);
290
291 let ctx = self.loop_stack.pop().unwrap();
292 for cj in &ctx.continue_jumps {
293 self.chunk.code[*cj].imm = continue_target as u32;
294 }
295 for bj in ctx.break_jumps {
296 self.patch_jump(bj);
297 }
298 }
299
300 fn compile_for(
301 &mut self,
302 init: Option<&VariableDeclarationOrExpression>,
303 test: Option<&ExpressionType>,
304 update: Option<&ExpressionType>,
305 body: &StatementType,
306 ) {
307 self.push_lexical_scope();
308
309 if let Some(init) = init {
310 match init {
311 VariableDeclarationOrExpression::VariableDeclaration(var_decl) => {
312 self.compile_var_declaration(var_decl);
313 }
314 VariableDeclarationOrExpression::Expression(expr) => {
315 let reg = self.compile_expression(expr);
316 self.release_reg(reg);
317 }
318 }
319 }
320
321 let loop_start = self.chunk.code.len();
322 self.loop_stack.push(LoopContext { continue_target: loop_start, break_jumps: Vec::new(), continue_jumps: Vec::new() });
323
324 let exit_jump = if let Some(test) = test {
325 let test_reg = self.compile_expression(test);
326 let jump = self.emit_jump(RegOpCode::JumpIfFalse, test_reg, 0);
327 self.release_reg(test_reg);
328 Some(jump)
329 } else {
330 None
331 };
332
333 self.compile_statement(body);
334
335 let update_pos = self.chunk.code.len();
336 if let Some(ctx) = self.loop_stack.last_mut() {
337 ctx.continue_target = update_pos;
338 }
339
340 if let Some(update) = update {
341 let reg = self.compile_expression(update);
342 self.release_reg(reg);
343 }
344
345 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::Jump, 0, loop_start as u32));
346
347 if let Some(jump) = exit_jump {
348 self.patch_jump(jump);
349 }
350
351 let ctx = self.loop_stack.pop().unwrap();
352 for cj in &ctx.continue_jumps {
354 self.chunk.code[*cj].imm = update_pos as u32;
355 }
356 for bj in ctx.break_jumps {
357 self.patch_jump(bj);
358 }
359
360 self.pop_lexical_scope();
361 }
362
363 fn compile_for_in(&mut self, _data: &ForIteratorData) {}
364
365 fn compile_for_of(&mut self, _data: &ForIteratorData) {}
366
367 fn compile_switch(&mut self, discriminant: &ExpressionType, cases: &[SwitchCaseData]) {
368 let disc_reg = self.compile_expression(discriminant);
369 let mut case_body_jumps: Vec<usize> = Vec::new();
370 let mut default_jump: Option<usize> = None;
371
372 for case in cases {
373 if let Some(ref test) = case.test {
374 let test_reg = self.compile_expression(test);
375 let res_reg = self.alloc_reg();
376 self.chunk.emit(RegInstruction::with_dst_srcs(RegOpCode::StrictEqual, res_reg, disc_reg, test_reg));
377 let jump = self.emit_jump(RegOpCode::JumpIfTrue, res_reg, 0);
378 self.release_reg(test_reg);
379 self.release_reg(res_reg);
380 case_body_jumps.push(jump);
381 } else {
382 default_jump = Some(case_body_jumps.len());
383 case_body_jumps.push(0);
384 }
385 }
386
387 let jump_to_default_or_end = self.emit_jump(RegOpCode::Jump, 0, 0);
388
389 self.loop_stack.push(LoopContext { continue_target: 0, break_jumps: Vec::new(), continue_jumps: Vec::new() });
390
391 for (i, case) in cases.iter().enumerate() {
392 let body_pos = self.chunk.code.len();
393 if i < case_body_jumps.len() && case_body_jumps[i] != 0 {
394 self.chunk.code[case_body_jumps[i]].imm = body_pos as u32;
395 }
396 if default_jump == Some(i) {
397 self.chunk.code[jump_to_default_or_end].imm = body_pos as u32;
398 }
399 for stmt in &case.consequent {
400 self.compile_statement(stmt);
401 }
402 }
403
404 let end_pos = self.chunk.code.len();
405 if default_jump.is_none() {
406 self.chunk.code[jump_to_default_or_end].imm = end_pos as u32;
407 }
408
409 let ctx = self.loop_stack.pop().unwrap();
410 for bj in ctx.break_jumps {
411 self.patch_jump(bj);
412 }
413
414 self.release_reg(disc_reg);
415 }
416
417 fn compile_break(&mut self) {
418 if self.loop_stack.is_empty() {
419 return;
420 }
421 let jump = self.emit_jump(RegOpCode::Jump, 0, 0);
422 if let Some(ctx) = self.loop_stack.last_mut() {
423 ctx.break_jumps.push(jump);
424 }
425 }
426
427 fn compile_continue(&mut self) {
428 if let Some(ctx) = self.loop_stack.last() {
429 let target = ctx.continue_target;
430 let jump = self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::Jump, 0, target as u32));
431 if let Some(ctx) = self.loop_stack.last_mut() {
434 ctx.continue_jumps.push(jump);
435 }
436 }
437 }
438
439 fn emit_jump(&mut self, op: RegOpCode, src1: u32, target: u32) -> usize {
440 let instr = match op {
441 RegOpCode::Jump => RegInstruction::with_dst_imm(op, 0, target),
442 RegOpCode::JumpIfFalse | RegOpCode::JumpIfTrue => RegInstruction::with_src_imm(op, src1, target),
443 _ => RegInstruction::with_dst_imm(op, 0, target),
444 };
445 self.chunk.emit(instr)
446 }
447
448 fn patch_jump(&mut self, jump_idx: usize) {
449 let target = self.chunk.code.len() as u32;
450 self.chunk.code[jump_idx].imm = target;
451 }
452
453 fn compile_function_body(&mut self, body: &FunctionBodyData) {
454 for stmt in &body.body {
455 self.compile_statement(stmt);
456 }
457 self.chunk.emit_op(RegOpCode::Halt);
458 }
459
460 fn compile_expression(&mut self, expr: &ExpressionType) -> u32 {
465 match expr {
466 ExpressionType::Literal(lit) => self.compile_literal(lit),
467 ExpressionType::ExpressionWhichCanBePattern(pattern) => self.compile_expression_pattern(pattern),
468 ExpressionType::BinaryExpression { operator, left, right, .. } => self.compile_binary(operator, left, right),
469 ExpressionType::LogicalExpression { operator, left, right, .. } => self.compile_logical(operator, left, right),
470 ExpressionType::AssignmentExpression { operator, left, right, .. } => self.compile_assignment(operator, left, right),
471 ExpressionType::UnaryExpression { operator, argument, .. } => self.compile_unary(operator, argument),
472 ExpressionType::MemberExpression(member) => self.compile_member_expression(member),
473 ExpressionType::CallExpression { callee, arguments, .. } => self.compile_call_expression(callee, arguments),
474 ExpressionType::UpdateExpression { operator, argument, prefix, .. } => self.compile_update(operator, argument, *prefix),
475 ExpressionType::SequenceExpression { expressions, .. } => {
476 let mut last_reg = self.alloc_reg();
477 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, last_reg));
478 for (i, expr) in expressions.iter().enumerate() {
479 if i > 0 {
480 self.release_reg(last_reg);
481 }
482 last_reg = self.compile_expression(expr);
483 }
484 last_reg
485 }
486 ExpressionType::ConditionalExpression { test, consequent, alternate, .. } => {
487 let test_reg = self.compile_expression(test);
488 let result_reg = self.alloc_reg();
489 let jump_to_alt = self.emit_jump(RegOpCode::JumpIfFalse, test_reg, 0);
490 self.release_reg(test_reg);
491 let cons_reg = self.compile_expression(consequent);
492 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, result_reg, cons_reg));
493 self.release_reg(cons_reg);
494 let jump_to_end = self.emit_jump(RegOpCode::Jump, 0, 0);
495 self.patch_jump(jump_to_alt);
496 let alt_reg = self.compile_expression(alternate);
497 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, result_reg, alt_reg));
498 self.release_reg(alt_reg);
499 self.patch_jump(jump_to_end);
500 result_reg
501 }
502 _ => {
503 let reg = self.alloc_reg();
504 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
505 reg
506 }
507 }
508 }
509
510 fn compile_literal(&mut self, lit: &LiteralData) -> u32 {
511 let reg = self.alloc_reg();
512 match &lit.value {
513 LiteralType::NullLiteral => {
514 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadNull, reg));
515 }
516 LiteralType::BooleanLiteral(true) => {
517 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadTrue, reg));
518 }
519 LiteralType::BooleanLiteral(false) => {
520 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadFalse, reg));
521 }
522 LiteralType::StringLiteral(s) => {
523 let idx = self.chunk.add_constant(JsValue::String(s.clone()));
524 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::LoadConst, reg, idx));
525 }
526 LiteralType::NumberLiteral(n) => {
527 let value = match n {
528 NumberLiteralType::IntegerLiteral(i) => JsValue::Number(JsNumberType::Integer(*i)),
529 NumberLiteralType::FloatLiteral(f) => JsValue::Number(JsNumberType::Float(*f)),
530 };
531 let idx = self.chunk.add_constant(value);
532 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::LoadConst, reg, idx));
533 }
534 LiteralType::RegExpLiteral(_) => {
535 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
536 }
537 }
538 reg
539 }
540
541 fn compile_expression_pattern(&mut self, pattern: &ExpressionPatternType) -> u32 {
542 match pattern {
543 ExpressionPatternType::Identifier(id) => {
544 if !self.is_lexically_shadowed(&id.name) {
545 if let Some(reg) = self.get_local_reg(&id.name) {
546 return reg;
547 }
548 }
549 let name_idx = self.chunk.add_name(&id.name);
550 let reg = self.alloc_reg();
551 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::GetVar, reg, name_idx));
552 reg
553 }
554 }
555 }
556
557 fn compile_binary(&mut self, operator: &BinaryOperator, left: &ExpressionType, right: &ExpressionType) -> u32 {
558 let left_reg = self.compile_expression(left);
559 let right_reg = self.compile_expression(right);
560 let dst = self.alloc_reg();
561 let op = match operator {
562 BinaryOperator::Add => RegOpCode::Add,
563 BinaryOperator::Subtract => RegOpCode::Sub,
564 BinaryOperator::Multiply => RegOpCode::Mul,
565 BinaryOperator::Divide => RegOpCode::Div,
566 BinaryOperator::Modulo => RegOpCode::Mod,
567 BinaryOperator::BitwiseAnd => RegOpCode::BitAnd,
568 BinaryOperator::BitwiseOr => RegOpCode::BitOr,
569 BinaryOperator::BitwiseXor => RegOpCode::BitXor,
570 BinaryOperator::BitwiseLeftShift => RegOpCode::ShiftLeft,
571 BinaryOperator::BitwiseRightShift => RegOpCode::ShiftRight,
572 BinaryOperator::BitwiseUnsignedRightShift => RegOpCode::UShiftRight,
573 BinaryOperator::LessThan => RegOpCode::LessThan,
574 BinaryOperator::LessThanEqual => RegOpCode::LessEqual,
575 BinaryOperator::GreaterThan => RegOpCode::GreaterThan,
576 BinaryOperator::GreaterThanEqual => RegOpCode::GreaterEqual,
577 BinaryOperator::LooselyEqual => RegOpCode::Equal,
578 BinaryOperator::LooselyUnequal => RegOpCode::NotEqual,
579 BinaryOperator::StrictlyEqual => RegOpCode::StrictEqual,
580 BinaryOperator::StrictlyUnequal => RegOpCode::StrictNotEqual,
581 _ => RegOpCode::Add,
582 };
583 self.chunk.emit(RegInstruction::with_dst_srcs(op, dst, left_reg, right_reg));
584 self.release_reg(left_reg);
585 self.release_reg(right_reg);
586 dst
587 }
588
589 fn compile_logical(&mut self, operator: &LogicalOperator, left: &ExpressionType, right: &ExpressionType) -> u32 {
590 let left_reg = self.compile_expression(left);
591 let result_reg = self.alloc_reg();
592 let jump_to_else = match operator {
593 LogicalOperator::And => self.emit_jump(RegOpCode::JumpIfFalse, left_reg, 0),
594 LogicalOperator::Or => self.emit_jump(RegOpCode::JumpIfTrue, left_reg, 0),
595 };
596
597 let right_reg = self.compile_expression(right);
598 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, result_reg, right_reg));
599 self.release_reg(right_reg);
600 let jump_to_end = self.emit_jump(RegOpCode::Jump, 0, 0);
601
602 self.patch_jump(jump_to_else);
603 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, result_reg, left_reg));
604 self.patch_jump(jump_to_end);
605
606 self.release_reg(left_reg);
607 result_reg
608 }
609
610 fn compile_assignment(&mut self, op: &AssignmentOperator, left: &PatternOrExpression, right: &ExpressionType) -> u32 {
611 let name = self.extract_assignment_target_name(left);
612 if let Some(name) = name {
613 if !self.is_lexically_shadowed(&name) {
614 if let Some(local_reg) = self.get_local_reg(&name) {
615 match op {
616 AssignmentOperator::Equals => {
617 let rhs = self.compile_expression(right);
618 if rhs != local_reg {
619 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, local_reg, rhs));
620 }
621 return rhs;
622 }
623 _ => {
624 let rhs = self.compile_expression(right);
625 let op_code = self.assignment_op_to_reg(op);
626 self.chunk.emit(RegInstruction::with_dst_srcs(op_code, local_reg, local_reg, rhs));
627 self.release_reg(rhs);
628 return local_reg;
629 }
630 }
631 }
632 }
633
634 let name_idx = self.chunk.add_name(&name);
635 match op {
636 AssignmentOperator::Equals => {
637 let rhs = self.compile_expression(right);
638 self.chunk.emit(RegInstruction::with_src_imm(RegOpCode::SetVar, rhs, name_idx));
639 rhs
640 }
641 _ => {
642 let cur = self.alloc_reg();
643 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::GetVar, cur, name_idx));
644 let rhs = self.compile_expression(right);
645 let op_code = self.assignment_op_to_reg(op);
646 self.chunk.emit(RegInstruction::with_dst_srcs(op_code, cur, cur, rhs));
647 self.chunk.emit(RegInstruction::with_src_imm(RegOpCode::SetVar, cur, name_idx));
648 self.release_reg(rhs);
649 cur
650 }
651 }
652 } else {
653 let rhs = self.compile_expression(right);
655 rhs
656 }
657 }
658
659 fn compile_unary(&mut self, operator: &UnaryOperator, argument: &ExpressionType) -> u32 {
660 let arg = self.compile_expression(argument);
661 let dst = self.alloc_reg();
662 let op = match operator {
663 UnaryOperator::Minus => RegOpCode::Negate,
664 UnaryOperator::Plus => RegOpCode::UnaryPlus,
665 UnaryOperator::LogicalNot => RegOpCode::Not,
666 UnaryOperator::TypeOf => RegOpCode::TypeOf,
667 _ => RegOpCode::Move,
668 };
669 match op {
670 RegOpCode::Move => {
671 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, dst, arg));
672 }
673 _ => {
674 self.chunk.emit(RegInstruction::with_dst_src(op, dst, arg));
675 }
676 }
677 self.release_reg(arg);
678 dst
679 }
680
681 fn compile_member_expression(&mut self, member: &MemberExpressionType) -> u32 {
682 match member {
683 MemberExpressionType::SimpleMemberExpression { object, property, .. } => {
684 let obj_reg = self.compile_expression_or_super(object);
685 let dst = self.alloc_reg();
686 let name_idx = self.chunk.add_name(&property.name);
687 self.chunk.emit(RegInstruction::new(RegOpCode::GetProp, dst, obj_reg, 0, name_idx));
688 self.release_reg(obj_reg);
689 dst
690 }
691 MemberExpressionType::ComputedMemberExpression { object, property, .. } => {
692 let obj_reg = self.compile_expression_or_super(object);
693 let key_reg = self.compile_expression(property);
694 let dst = self.alloc_reg();
695 self.chunk.emit(RegInstruction::with_dst_srcs(RegOpCode::GetElem, dst, obj_reg, key_reg));
696 self.release_reg(obj_reg);
697 self.release_reg(key_reg);
698 dst
699 }
700 }
701 }
702
703 fn compile_call_expression(&mut self, callee: &ExpressionOrSuper, arguments: &[ExpressionOrSpreadElement]) -> u32 {
704 let dst = self.alloc_reg();
705 let callee_reg = self.compile_expression_or_super(callee);
706 let mut arg_regs: Vec<u32> = Vec::with_capacity(arguments.len());
707 for arg in arguments {
708 match arg {
709 ExpressionOrSpreadElement::Expression(e) => arg_regs.push(self.compile_expression(e)),
710 ExpressionOrSpreadElement::SpreadElement(e) => arg_regs.push(self.compile_expression(e)),
711 }
712 }
713 self.chunk.emit(RegInstruction::new(
715 RegOpCode::Call,
716 dst,
717 callee_reg,
718 0,
719 arg_regs.len() as u32,
720 ));
721 self.release_reg(callee_reg);
722 for reg in arg_regs {
723 self.release_reg(reg);
724 }
725 dst
726 }
727
728 fn compile_expression_or_super(&mut self, expr_or_super: &ExpressionOrSuper) -> u32 {
729 match expr_or_super {
730 ExpressionOrSuper::Expression(expr) => self.compile_expression(expr),
731 ExpressionOrSuper::Super => {
732 let reg = self.alloc_reg();
733 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
734 reg
735 }
736 }
737 }
738
739 fn compile_update(&mut self, op: &UpdateOperator, argument: &ExpressionType, prefix: bool) -> u32 {
740 if let ExpressionType::ExpressionWhichCanBePattern(ExpressionPatternType::Identifier(ref id)) = argument {
741 if !self.is_lexically_shadowed(&id.name) {
742 if let Some(local_reg) = self.get_local_reg(&id.name) {
743 let one = self.alloc_reg();
744 let one_idx = self.chunk.add_constant(JsValue::Number(JsNumberType::Integer(1)));
745 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::LoadConst, one, one_idx));
746 let op_code = match op {
747 UpdateOperator::PlusPlus => RegOpCode::Add,
748 UpdateOperator::MinusMinus => RegOpCode::Sub,
749 };
750 if prefix {
751 self.chunk.emit(RegInstruction::with_dst_srcs(op_code, local_reg, local_reg, one));
752 self.release_reg(one);
753 return local_reg;
754 }
755
756 let old = self.alloc_reg();
757 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, old, local_reg));
758 self.chunk.emit(RegInstruction::with_dst_srcs(op_code, local_reg, local_reg, one));
759 self.release_reg(one);
760 return old;
761 }
762 }
763 let name_idx = self.chunk.add_name(&id.name);
764 let cur = self.alloc_reg();
765 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::GetVar, cur, name_idx));
766 let one = self.alloc_reg();
767 let one_idx = self.chunk.add_constant(JsValue::Number(JsNumberType::Integer(1)));
768 self.chunk.emit(RegInstruction::with_dst_imm(RegOpCode::LoadConst, one, one_idx));
769 let op_code = match op {
770 UpdateOperator::PlusPlus => RegOpCode::Add,
771 UpdateOperator::MinusMinus => RegOpCode::Sub,
772 };
773 if prefix {
774 self.chunk.emit(RegInstruction::with_dst_srcs(op_code, cur, cur, one));
775 self.chunk.emit(RegInstruction::with_src_imm(RegOpCode::SetVar, cur, name_idx));
776 self.release_reg(one);
777 cur
778 } else {
779 let old = self.alloc_reg();
780 self.chunk.emit(RegInstruction::with_dst_src(RegOpCode::Move, old, cur));
781 self.chunk.emit(RegInstruction::with_dst_srcs(op_code, cur, cur, one));
782 self.chunk.emit(RegInstruction::with_src_imm(RegOpCode::SetVar, cur, name_idx));
783 self.release_reg(one);
784 old
785 }
786 } else {
787 let reg = self.alloc_reg();
788 self.chunk.emit(RegInstruction::with_dst(RegOpCode::LoadUndefined, reg));
789 reg
790 }
791 }
792
793 fn assignment_op_to_reg(&self, op: &AssignmentOperator) -> RegOpCode {
794 match op {
795 AssignmentOperator::AddEquals => RegOpCode::Add,
796 AssignmentOperator::SubtractEquals => RegOpCode::Sub,
797 AssignmentOperator::MultiplyEquals => RegOpCode::Mul,
798 AssignmentOperator::DivideEquals => RegOpCode::Div,
799 AssignmentOperator::ModuloEquals => RegOpCode::Mod,
800 AssignmentOperator::BitwiseAndEquals => RegOpCode::BitAnd,
801 AssignmentOperator::BitwiseOrEquals => RegOpCode::BitOr,
802 AssignmentOperator::BitwiseXorEquals => RegOpCode::BitXor,
803 AssignmentOperator::BitwiseLeftShiftEquals => RegOpCode::ShiftLeft,
804 AssignmentOperator::BitwiseRightShiftEquals => RegOpCode::ShiftRight,
805 AssignmentOperator::BitwiseUnsignedRightShiftEquals => RegOpCode::UShiftRight,
806 AssignmentOperator::Equals => RegOpCode::Move,
807 }
808 }
809
810 fn extract_assignment_target_name(&self, target: &PatternOrExpression) -> Option<String> {
811 match target {
812 PatternOrExpression::Pattern(pat) => {
813 if let PatternType::PatternWhichCanBeExpression(ExpressionPatternType::Identifier(ref id)) = pat.as_ref() {
814 Some(id.name.clone())
815 } else {
816 None
817 }
818 }
819 PatternOrExpression::Expression(expr) => {
820 if let ExpressionType::ExpressionWhichCanBePattern(ExpressionPatternType::Identifier(ref id)) = expr.as_ref() {
821 Some(id.name.clone())
822 } else {
823 None
824 }
825 }
826 }
827 }
828}