feat: 添加 do while 与 for-in 语法枚举指令支持
This commit is contained in:
Generated
+1
@@ -817,6 +817,7 @@ dependencies = [
|
|||||||
name = "oxide_vm"
|
name = "oxide_vm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
"fast-float",
|
"fast-float",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
"oxide_kernel",
|
"oxide_kernel",
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ serde = "1"
|
|||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
dashmap = "6"
|
dashmap = "6"
|
||||||
rayon = "1"
|
rayon = "1"
|
||||||
bumpalo = "3"
|
bumpalo = { version = "3", features = ["collections"] }
|
||||||
hashbrown = "0.14"
|
hashbrown = "0.14"
|
||||||
proptest = "1"
|
proptest = "1"
|
||||||
rustc-hash = "2"
|
rustc-hash = "2"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ pub(crate) fn is_side_effect_free(expr: &Expression) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) enum Label {
|
pub(crate) enum Label {
|
||||||
IfElse(u32),
|
IfElse(u32),
|
||||||
IfEnd(u32),
|
IfEnd(u32),
|
||||||
@@ -36,6 +37,12 @@ pub(crate) enum Label {
|
|||||||
ForEnd(u32),
|
ForEnd(u32),
|
||||||
TernaryEnd(u32),
|
TernaryEnd(u32),
|
||||||
TernaryElse(u32),
|
TernaryElse(u32),
|
||||||
|
DoWhileStart(u32),
|
||||||
|
DoWhileEnd(u32),
|
||||||
|
ForInStart(u32),
|
||||||
|
ForInEnd(u32),
|
||||||
|
SwitchEnd(u32),
|
||||||
|
SwitchCase(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CompileCtx {
|
pub(crate) struct CompileCtx {
|
||||||
@@ -46,6 +53,8 @@ pub(crate) struct CompileCtx {
|
|||||||
symbols: SymbolTable,
|
symbols: SymbolTable,
|
||||||
pub(crate) label_map: HashMap<Label, usize>,
|
pub(crate) label_map: HashMap<Label, usize>,
|
||||||
pub(crate) loop_stack: Vec<(Label, Label)>,
|
pub(crate) loop_stack: Vec<(Label, Label)>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) switch_stack: Vec<Label>,
|
||||||
pub(crate) label_counter: u32,
|
pub(crate) label_counter: u32,
|
||||||
pub(crate) projected_pc: usize,
|
pub(crate) projected_pc: usize,
|
||||||
}
|
}
|
||||||
@@ -60,6 +69,7 @@ impl CompileCtx {
|
|||||||
symbols: SymbolTable::new(),
|
symbols: SymbolTable::new(),
|
||||||
label_map: HashMap::new(),
|
label_map: HashMap::new(),
|
||||||
loop_stack: Vec::new(),
|
loop_stack: Vec::new(),
|
||||||
|
switch_stack: Vec::new(),
|
||||||
label_counter: 0,
|
label_counter: 0,
|
||||||
projected_pc: 0,
|
projected_pc: 0,
|
||||||
}
|
}
|
||||||
@@ -142,6 +152,18 @@ impl CompileCtx {
|
|||||||
pub(crate) fn current_loop(&self) -> Option<&(Label, Label)> {
|
pub(crate) fn current_loop(&self) -> Option<&(Label, Label)> {
|
||||||
self.loop_stack.last()
|
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 {
|
impl Compiler {
|
||||||
|
|||||||
@@ -82,6 +82,28 @@ fn hash_statement(stmt: &Statement, h: &mut rustc_hash::FxHasher) {
|
|||||||
Statement::ContinueStatement(_) => {
|
Statement::ContinueStatement(_) => {
|
||||||
8u8.hash(h);
|
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);
|
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 => {
|
OpCode::JMP | OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE => {
|
||||||
write!(f, " r{rd}, {offset:+}", offset = opcode::offset16(instr))?;
|
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 => {
|
OpCode::RETURN | OpCode::HALT | OpCode::NOP => {
|
||||||
write!(f, " r{rd}")?;
|
write!(f, " r{rd}")?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ pub enum OpCode {
|
|||||||
JMP = 0x20,
|
JMP = 0x20,
|
||||||
JMP_IF_FALSE = 0x21,
|
JMP_IF_FALSE = 0x21,
|
||||||
JMP_IF_TRUE = 0x22,
|
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) ──
|
// ── Variable (0x30-0x3F) ──
|
||||||
LOAD_VAR = 0x30,
|
LOAD_VAR = 0x30,
|
||||||
@@ -109,6 +114,11 @@ impl TryFrom<u8> for OpCode {
|
|||||||
0x20 => Ok(OpCode::JMP),
|
0x20 => Ok(OpCode::JMP),
|
||||||
0x21 => Ok(OpCode::JMP_IF_FALSE),
|
0x21 => Ok(OpCode::JMP_IF_FALSE),
|
||||||
0x22 => Ok(OpCode::JMP_IF_TRUE),
|
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),
|
0x30 => Ok(OpCode::LOAD_VAR),
|
||||||
0x31 => Ok(OpCode::STORE_VAR),
|
0x31 => Ok(OpCode::STORE_VAR),
|
||||||
0x32 => Ok(OpCode::LOAD_CONST),
|
0x32 => Ok(OpCode::LOAD_CONST),
|
||||||
@@ -160,6 +170,11 @@ impl fmt::Display for OpCode {
|
|||||||
OpCode::JMP => "JMP",
|
OpCode::JMP => "JMP",
|
||||||
OpCode::JMP_IF_FALSE => "JMP_IF_FALSE",
|
OpCode::JMP_IF_FALSE => "JMP_IF_FALSE",
|
||||||
OpCode::JMP_IF_TRUE => "JMP_IF_TRUE",
|
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::LOAD_VAR => "LOAD_VAR",
|
||||||
OpCode::STORE_VAR => "STORE_VAR",
|
OpCode::STORE_VAR => "STORE_VAR",
|
||||||
OpCode::LOAD_CONST => "LOAD_CONST",
|
OpCode::LOAD_CONST => "LOAD_CONST",
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ impl StringForge {
|
|||||||
inner.entries.get(idx as usize).map(|e| e.data.clone())
|
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) {
|
pub fn decref(&self, idx: u32) {
|
||||||
let inner = self.inner.read().unwrap();
|
let inner = self.inner.read().unwrap();
|
||||||
if let Some(entry) = inner.entries.get(idx as usize) {
|
if let Some(entry) = inner.entries.get(idx as usize) {
|
||||||
|
|||||||
Reference in New Issue
Block a user