feat: 添加 do while 与 for-in 语法枚举指令支持

This commit is contained in:
2026-06-06 18:18:31 +08:00
parent 35dd5c39bc
commit a2762fe3c9
7 changed files with 70 additions and 1 deletions
Generated
+1
View File
@@ -817,6 +817,7 @@ dependencies = [
name = "oxide_vm"
version = "0.1.0"
dependencies = [
"bumpalo",
"fast-float",
"oxide_compiler",
"oxide_kernel",
+1 -1
View File
@@ -30,7 +30,7 @@ serde = "1"
serde_json = "1"
dashmap = "6"
rayon = "1"
bumpalo = "3"
bumpalo = { version = "3", features = ["collections"] }
hashbrown = "0.14"
proptest = "1"
rustc-hash = "2"
+22
View File
@@ -26,6 +26,7 @@ pub(crate) fn is_side_effect_free(expr: &Expression) -> bool {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(dead_code)]
pub(crate) enum Label {
IfElse(u32),
IfEnd(u32),
@@ -36,6 +37,12 @@ pub(crate) enum Label {
ForEnd(u32),
TernaryEnd(u32),
TernaryElse(u32),
DoWhileStart(u32),
DoWhileEnd(u32),
ForInStart(u32),
ForInEnd(u32),
SwitchEnd(u32),
SwitchCase(u32),
}
pub(crate) struct CompileCtx {
@@ -46,6 +53,8 @@ pub(crate) struct CompileCtx {
symbols: SymbolTable,
pub(crate) label_map: HashMap<Label, usize>,
pub(crate) loop_stack: Vec<(Label, Label)>,
#[allow(dead_code)]
pub(crate) switch_stack: Vec<Label>,
pub(crate) label_counter: u32,
pub(crate) projected_pc: usize,
}
@@ -60,6 +69,7 @@ impl CompileCtx {
symbols: SymbolTable::new(),
label_map: HashMap::new(),
loop_stack: Vec::new(),
switch_stack: Vec::new(),
label_counter: 0,
projected_pc: 0,
}
@@ -142,6 +152,18 @@ impl CompileCtx {
pub(crate) fn current_loop(&self) -> Option<&(Label, Label)> {
self.loop_stack.last()
}
pub(crate) fn push_switch(&mut self, break_label: Label) {
self.switch_stack.push(break_label);
}
pub(crate) fn pop_switch(&mut self) {
self.switch_stack.pop();
}
pub(crate) fn current_switch(&self) -> Option<&Label> {
self.switch_stack.last()
}
}
impl Compiler {
+22
View File
@@ -82,6 +82,28 @@ fn hash_statement(stmt: &Statement, h: &mut rustc_hash::FxHasher) {
Statement::ContinueStatement(_) => {
8u8.hash(h);
}
Statement::DoWhileStatement(dw) => {
9u8.hash(h);
hash_statement(&dw.body, h);
hash_expression(&dw.test, h);
}
Statement::ForInStatement(fi) => {
10u8.hash(h);
hash_expression(&fi.right, h);
hash_statement(&fi.body, h);
}
Statement::SwitchStatement(sw) => {
11u8.hash(h);
hash_expression(&sw.discriminant, h);
for case in &sw.cases {
if let Some(test) = &case.test {
hash_expression(test, h);
}
for s in &case.consequent {
hash_statement(s, h);
}
}
}
_ => {
std::mem::discriminant(stmt).hash(h);
}
+4
View File
@@ -39,6 +39,10 @@ impl fmt::Display for CompiledModule {
OpCode::JMP | OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE => {
write!(f, " r{rd}, {offset:+}", offset = opcode::offset16(instr))?;
}
OpCode::SWITCH_TABLE => {
let n_cases = rd as u16 | ((b as u16) << 8);
write!(f, " r{disc_reg}={a}, {n_cases} cases", disc_reg = a)?;
}
OpCode::RETURN | OpCode::HALT | OpCode::NOP => {
write!(f, " r{rd}")?;
}
+15
View File
@@ -33,6 +33,11 @@ pub enum OpCode {
JMP = 0x20,
JMP_IF_FALSE = 0x21,
JMP_IF_TRUE = 0x22,
FOR_IN_INIT = 0x29,
FOR_IN_NEXT = 0x2A,
FOR_IN_DONE = 0x2B,
SWITCH_TABLE = 0x2C,
FOR_IN_CLEANUP = 0x2D,
// ── Variable (0x30-0x3F) ──
LOAD_VAR = 0x30,
@@ -109,6 +114,11 @@ impl TryFrom<u8> for OpCode {
0x20 => Ok(OpCode::JMP),
0x21 => Ok(OpCode::JMP_IF_FALSE),
0x22 => Ok(OpCode::JMP_IF_TRUE),
0x29 => Ok(OpCode::FOR_IN_INIT),
0x2A => Ok(OpCode::FOR_IN_NEXT),
0x2B => Ok(OpCode::FOR_IN_DONE),
0x2C => Ok(OpCode::SWITCH_TABLE),
0x2D => Ok(OpCode::FOR_IN_CLEANUP),
0x30 => Ok(OpCode::LOAD_VAR),
0x31 => Ok(OpCode::STORE_VAR),
0x32 => Ok(OpCode::LOAD_CONST),
@@ -160,6 +170,11 @@ impl fmt::Display for OpCode {
OpCode::JMP => "JMP",
OpCode::JMP_IF_FALSE => "JMP_IF_FALSE",
OpCode::JMP_IF_TRUE => "JMP_IF_TRUE",
OpCode::FOR_IN_INIT => "FOR_IN_INIT",
OpCode::FOR_IN_NEXT => "FOR_IN_NEXT",
OpCode::FOR_IN_DONE => "FOR_IN_DONE",
OpCode::SWITCH_TABLE => "SWITCH_TABLE",
OpCode::FOR_IN_CLEANUP => "FOR_IN_CLEANUP",
OpCode::LOAD_VAR => "LOAD_VAR",
OpCode::STORE_VAR => "STORE_VAR",
OpCode::LOAD_CONST => "LOAD_CONST",
+5
View File
@@ -69,6 +69,11 @@ impl StringForge {
inner.entries.get(idx as usize).map(|e| e.data.clone())
}
pub fn get_hash(&self, idx: u32) -> Option<u16> {
let inner = self.inner.read().unwrap();
inner.entries.get(idx as usize).map(|e| e.hash)
}
pub fn decref(&self, idx: u32) {
let inner = self.inner.read().unwrap();
if let Some(entry) = inner.entries.get(idx as usize) {