refactor(compiler): emit loop jumps through fixups
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
use crate::compiler::{CompileCtx, Compiler, Label};
|
use crate::compiler::{CompileCtx, Compiler, Label};
|
||||||
use oxide_bytecode::opcode;
|
|
||||||
use oxide_parser::Statement;
|
use oxide_parser::Statement;
|
||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
@@ -21,14 +20,13 @@ impl Compiler {
|
|||||||
let id = ctx.next_label_id();
|
let id = ctx.next_label_id();
|
||||||
let start_label = Label::DoWhileStart(id);
|
let start_label = Label::DoWhileStart(id);
|
||||||
let end_label = Label::DoWhileEnd(id);
|
let end_label = Label::DoWhileEnd(id);
|
||||||
|
ctx.labels.label_map.insert(start_label, ctx.bytecode.len());
|
||||||
ctx.push_loop(end_label, start_label);
|
ctx.push_loop(end_label, start_label);
|
||||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||||
self.emit_statement(&dw.body, ctx)?;
|
self.emit_statement(&dw.body, ctx)?;
|
||||||
let test_reg = self.emit_expression(&dw.test, ctx)?;
|
let test_reg = self.emit_expression(&dw.test, ctx)?;
|
||||||
let start_pos = ctx.resolve_label(start_label)?;
|
ctx.emit_jmp_if_true_labeled(test_reg, start_label);
|
||||||
let offset = (start_pos as isize) - (ctx.bytecode.len() as isize);
|
ctx.labels.label_map.insert(end_label, ctx.bytecode.len());
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp_if_true(test_reg, offset));
|
|
||||||
ctx.pop_label_scopes(n_labeled);
|
ctx.pop_label_scopes(n_labeled);
|
||||||
ctx.pop_loop();
|
ctx.pop_loop();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|||||||
@@ -72,21 +72,18 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctx.labels.label_map.insert(start_label, ctx.bytecode.len());
|
||||||
if let Some(test) = &fr.test {
|
if let Some(test) = &fr.test {
|
||||||
let test_reg = self.emit_expression(test, ctx)?;
|
let test_reg = self.emit_expression(test, ctx)?;
|
||||||
let end_pos = ctx.resolve_label(end_label)?;
|
ctx.emit_jmp_if_false_labeled(test_reg, end_label);
|
||||||
let offset = (end_pos as isize) - (ctx.bytecode.len() as isize);
|
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp_if_false(test_reg, offset));
|
|
||||||
}
|
}
|
||||||
self.emit_statement(&fr.body, ctx)?;
|
self.emit_statement(&fr.body, ctx)?;
|
||||||
|
ctx.labels.label_map.insert(update_label, ctx.bytecode.len());
|
||||||
if let Some(update) = &fr.update {
|
if let Some(update) = &fr.update {
|
||||||
self.emit_expression(update, ctx)?;
|
self.emit_expression(update, ctx)?;
|
||||||
}
|
}
|
||||||
let start_pos = ctx.resolve_label(start_label)?;
|
ctx.emit_jmp_labeled(start_label);
|
||||||
let offset = (start_pos as isize) - (ctx.bytecode.len() as isize);
|
ctx.labels.label_map.insert(end_label, ctx.bytecode.len());
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp(offset));
|
|
||||||
ctx.pop_label_scopes(n_labeled);
|
ctx.pop_label_scopes(n_labeled);
|
||||||
ctx.pop_loop();
|
ctx.pop_loop();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|||||||
@@ -42,15 +42,13 @@ impl Compiler {
|
|||||||
let end_label = Label::ForInEnd(id);
|
let end_label = Label::ForInEnd(id);
|
||||||
let obj_reg = self.emit_expression(&fi.right, ctx)?;
|
let obj_reg = self.emit_expression(&fi.right, ctx)?;
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_IN_INIT, 0, obj_reg, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_IN_INIT, 0, obj_reg, 0));
|
||||||
|
ctx.labels.label_map.insert(start_label, ctx.bytecode.len());
|
||||||
ctx.push_loop(end_label, start_label);
|
ctx.push_loop(end_label, start_label);
|
||||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||||
let done_reg = ctx.alloc_reg();
|
let done_reg = ctx.alloc_reg();
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_IN_DONE, done_reg, 0, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_IN_DONE, done_reg, 0, 0));
|
||||||
let end_pos = ctx.resolve_label(end_label)?;
|
|
||||||
let cleanup_jmp_offset = (end_pos as isize) - (ctx.bytecode.len() as isize);
|
|
||||||
ctx.emit(opcode::encode_jmp_if_false(done_reg, 2));
|
ctx.emit(opcode::encode_jmp_if_false(done_reg, 2));
|
||||||
let cleanup_jmp_offset = ctx.checked_jump_offset(cleanup_jmp_offset);
|
ctx.emit_jmp_labeled(end_label);
|
||||||
ctx.emit(opcode::encode_jmp(cleanup_jmp_offset));
|
|
||||||
let key_reg = ctx.alloc_reg();
|
let key_reg = ctx.alloc_reg();
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_IN_NEXT, key_reg, 0, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_IN_NEXT, key_reg, 0, 0));
|
||||||
match &fi.left {
|
match &fi.left {
|
||||||
@@ -74,10 +72,8 @@ impl Compiler {
|
|||||||
_ => return Err("unsupported for-in left-hand side".into()),
|
_ => return Err("unsupported for-in left-hand side".into()),
|
||||||
}
|
}
|
||||||
self.emit_statement(&fi.body, ctx)?;
|
self.emit_statement(&fi.body, ctx)?;
|
||||||
let start_pos = ctx.resolve_label(start_label)?;
|
ctx.emit_jmp_labeled(start_label);
|
||||||
let offset = (start_pos as isize) - (ctx.bytecode.len() as isize);
|
ctx.labels.label_map.insert(end_label, ctx.bytecode.len());
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp(offset));
|
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_IN_CLEANUP, 0, 0, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_IN_CLEANUP, 0, 0, 0));
|
||||||
ctx.pop_label_scopes(n_labeled);
|
ctx.pop_label_scopes(n_labeled);
|
||||||
ctx.pop_loop();
|
ctx.pop_loop();
|
||||||
|
|||||||
@@ -48,14 +48,12 @@ impl Compiler {
|
|||||||
let end_label = Label::ForOfEnd(id);
|
let end_label = Label::ForOfEnd(id);
|
||||||
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
|
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_OF_INIT, 0, iter_src_reg, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_OF_INIT, 0, iter_src_reg, 0));
|
||||||
|
ctx.labels.label_map.insert(start_label, ctx.bytecode.len());
|
||||||
ctx.push_loop(end_label, start_label);
|
ctx.push_loop(end_label, start_label);
|
||||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||||
let has_reg = ctx.alloc_reg();
|
let has_reg = ctx.alloc_reg();
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_OF_DONE, has_reg, 0, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_OF_DONE, has_reg, 0, 0));
|
||||||
let end_pos = ctx.resolve_label(end_label)?;
|
ctx.emit_jmp_if_false_labeled(has_reg, end_label);
|
||||||
let offset = (end_pos as isize) - (ctx.bytecode.len() as isize);
|
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp_if_false(has_reg, offset));
|
|
||||||
let val_reg = ctx.alloc_reg();
|
let val_reg = ctx.alloc_reg();
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_OF_NEXT, val_reg, 0, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_OF_NEXT, val_reg, 0, 0));
|
||||||
match &fo.left {
|
match &fo.left {
|
||||||
@@ -78,10 +76,8 @@ impl Compiler {
|
|||||||
_ => return Err("unsupported for-of left-hand side".into()),
|
_ => return Err("unsupported for-of left-hand side".into()),
|
||||||
}
|
}
|
||||||
self.emit_statement(&fo.body, ctx)?;
|
self.emit_statement(&fo.body, ctx)?;
|
||||||
let start_pos = ctx.resolve_label(start_label)?;
|
ctx.emit_jmp_labeled(start_label);
|
||||||
let offset = (start_pos as isize) - (ctx.bytecode.len() as isize);
|
ctx.labels.label_map.insert(end_label, ctx.bytecode.len());
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp(offset));
|
|
||||||
ctx.emit(opcode::encode(OpCode::FOR_OF_CLOSE, 0, 0, 0));
|
ctx.emit(opcode::encode(OpCode::FOR_OF_CLOSE, 0, 0, 0));
|
||||||
ctx.pop_label_scopes(n_labeled);
|
ctx.pop_label_scopes(n_labeled);
|
||||||
ctx.pop_loop();
|
ctx.pop_loop();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::compiler::{CompileCtx, Compiler, Label};
|
use crate::compiler::{CompileCtx, Compiler, Label};
|
||||||
use oxide_bytecode::opcode;
|
|
||||||
use oxide_parser::Statement;
|
use oxide_parser::Statement;
|
||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
@@ -22,18 +21,14 @@ impl Compiler {
|
|||||||
let id = ctx.next_label_id();
|
let id = ctx.next_label_id();
|
||||||
let start_label = Label::WhileStart(id);
|
let start_label = Label::WhileStart(id);
|
||||||
let end_label = Label::WhileEnd(id);
|
let end_label = Label::WhileEnd(id);
|
||||||
|
ctx.labels.label_map.insert(start_label, ctx.bytecode.len());
|
||||||
ctx.push_loop(end_label, start_label);
|
ctx.push_loop(end_label, start_label);
|
||||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||||
let test_reg = self.emit_expression(&wh.test, ctx)?;
|
let test_reg = self.emit_expression(&wh.test, ctx)?;
|
||||||
let end_pos = ctx.resolve_label(end_label)?;
|
ctx.emit_jmp_if_false_labeled(test_reg, end_label);
|
||||||
let offset = (end_pos as isize) - (ctx.bytecode.len() as isize);
|
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp_if_false(test_reg, offset));
|
|
||||||
self.emit_statement(&wh.body, ctx)?;
|
self.emit_statement(&wh.body, ctx)?;
|
||||||
let start_pos = ctx.resolve_label(start_label)?;
|
ctx.emit_jmp_labeled(start_label);
|
||||||
let offset = (start_pos as isize) - (ctx.bytecode.len() as isize);
|
ctx.labels.label_map.insert(end_label, ctx.bytecode.len());
|
||||||
let offset = ctx.checked_jump_offset(offset);
|
|
||||||
ctx.emit(opcode::encode_jmp(offset));
|
|
||||||
ctx.pop_label_scopes(n_labeled);
|
ctx.pop_label_scopes(n_labeled);
|
||||||
ctx.pop_loop();
|
ctx.pop_loop();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|||||||
Reference in New Issue
Block a user