mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 添加 do while 与 for-in 语法枚举指令支持
This commit is contained in:
Generated
+1
@@ -817,6 +817,7 @@ dependencies = [
|
||||
name = "oxide_vm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"fast-float",
|
||||
"oxide_compiler",
|
||||
"oxide_kernel",
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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}")?;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user