Skip to content

Commit 8bd7b4f

Browse files
feat: if/else
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 386a073 commit 8bd7b4f

File tree

11 files changed

+109
-94
lines changed

11 files changed

+109
-94
lines changed

crates/parser/src/conversion.rs

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ pub fn process_operators<'a>(
114114
mut validator: FuncValidator<ValidatorResources>,
115115
) -> Result<Box<[Instruction]>> {
116116
let mut instructions = Vec::new();
117-
let mut labels_ptrs = Vec::new();
117+
let mut labels_ptrs = Vec::new(); // indexes into the instructions array
118118

119-
for (i, op) in ops.enumerate() {
119+
for op in ops {
120120
info!("op: {:?}", op);
121121

122122
let op = op?;
@@ -146,17 +146,42 @@ pub fn process_operators<'a>(
146146
}
147147
If { blockty } => {
148148
labels_ptrs.push(instructions.len());
149-
Instruction::If(convert_blocktype(blockty), 0)
149+
Instruction::If(convert_blocktype(blockty), None, 0)
150+
}
151+
Else => {
152+
labels_ptrs.push(instructions.len());
153+
Instruction::Else(0)
150154
}
151155
End => {
152156
if let Some(label_pointer) = labels_ptrs.pop() {
157+
info!("ending block: {:?}", instructions[label_pointer]);
158+
159+
let current_instr_ptr = instructions.len();
160+
153161
// last_label_pointer is Some if we're ending a block
154162
match instructions[label_pointer] {
155-
Instruction::Block(_, ref mut end)
156-
| Instruction::Loop(_, ref mut end)
157-
| Instruction::Else(ref mut end)
158-
| Instruction::If(_, ref mut end) => {
159-
*end = i + 1; // Set the end position to be one after the End instruction
163+
Instruction::Else(ref mut else_instr_end_offset) => {
164+
*else_instr_end_offset = current_instr_ptr - label_pointer;
165+
166+
// since we're ending an else block, we need to end the if block as well
167+
let if_label_pointer = labels_ptrs.pop().ok_or(crate::ParseError::UnsupportedOperator(
168+
"Expected to end an if block, but the last label was not an if".to_string(),
169+
))?;
170+
171+
let if_instruction = &mut instructions[if_label_pointer];
172+
let Instruction::If(_, ref mut else_offset, ref mut end_offset) = if_instruction else {
173+
return Err(crate::ParseError::UnsupportedOperator(
174+
"Expected to end an if block, but the last label was not an if".to_string(),
175+
));
176+
};
177+
178+
*else_offset = Some(label_pointer - if_label_pointer);
179+
*end_offset = current_instr_ptr - if_label_pointer;
180+
}
181+
Instruction::Block(_, ref mut end_offset)
182+
| Instruction::Loop(_, ref mut end_offset)
183+
| Instruction::If(_, _, ref mut end_offset) => {
184+
*end_offset = current_instr_ptr - label_pointer;
160185
}
161186
_ => {
162187
return Err(crate::ParseError::UnsupportedOperator(
@@ -171,26 +196,7 @@ pub fn process_operators<'a>(
171196
Instruction::EndFunc
172197
}
173198
}
174-
Else => {
175-
let Some(label_pointer) = labels_ptrs.pop() else {
176-
return Err(crate::ParseError::UnsupportedOperator(
177-
"Expected to end an if block, but the last label was None".to_string(),
178-
));
179-
};
180-
181-
match instructions[label_pointer] {
182-
Instruction::If(_, ref mut end) => {
183-
*end = i + 1; // Set the end position to be one after the Else instruction
184-
}
185-
_ => {
186-
return Err(crate::ParseError::UnsupportedOperator(
187-
"Expected to end an if block, but the last label was not an if".to_string(),
188-
));
189-
}
190-
}
191199

192-
Instruction::Else(0)
193-
}
194200
Br { relative_depth } => Instruction::Br(relative_depth),
195201
BrIf { relative_depth } => Instruction::BrIf(relative_depth),
196202
Return => Instruction::Return,

crates/tinywasm/src/runtime/executor/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ fn exec_one(
8484
Nop => { /* do nothing */ }
8585
Unreachable => return Ok(ExecResult::Trap(crate::Trap::Unreachable)), // we don't need to include the call frame here because it's already on the stack
8686
Drop => stack.values.pop().map(|_| ())?,
87-
Return => todo!("called function returned"),
8887
Select => {
8988
let cond: i32 = stack.values.pop()?.into();
9089
let val2 = stack.values.pop()?;
@@ -117,6 +116,38 @@ fn exec_one(
117116
return Ok(ExecResult::Call);
118117
}
119118

119+
Return => todo!("called function returned"),
120+
121+
If(args, else_offset, end_offset) => {
122+
let end_instr_ptr = cf.instr_ptr + *end_offset;
123+
124+
info!(
125+
"if it's true, we'll jump to the next instruction (@{})",
126+
cf.instr_ptr + 1
127+
);
128+
129+
if let Some(else_offset) = else_offset {
130+
info!(
131+
"else: {:?} (@{})",
132+
instrs[cf.instr_ptr + else_offset],
133+
cf.instr_ptr + else_offset
134+
);
135+
};
136+
137+
info!("end: {:?} (@{})", instrs[end_instr_ptr], end_instr_ptr);
138+
139+
if stack.values.pop_t::<i32>()? != 0 {
140+
cf.labels.push(LabelFrame {
141+
instr_ptr: cf.instr_ptr,
142+
end_instr_ptr: cf.instr_ptr + *end_offset,
143+
stack_ptr: stack.values.len(),
144+
args: *args,
145+
ty: BlockType::If,
146+
});
147+
stack.values.push_block_args(*args)?;
148+
}
149+
}
150+
120151
Loop(args, end_offset) => {
121152
cf.labels.push(LabelFrame {
122153
instr_ptr: cf.instr_ptr,

crates/tinywasm/src/runtime/stack/call_stack.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,12 @@ impl CallFrame {
105105
BlockType::Block => {
106106
debug!("current instr_ptr: {}", self.instr_ptr);
107107

108-
// this is a block, so we want to jump to the end of the block
109-
self.instr_ptr = break_to.end_instr_ptr;
108+
// this is a block, so we want to jump to the next instruction after the block ends
109+
self.instr_ptr = break_to.end_instr_ptr + 1;
110110
value_stack.trim(break_to.stack_ptr);
111111

112112
// we also want to trim the label stack, including the block
113113
self.labels.trim(self.labels.len() - break_to_relative as usize + 1);
114-
115-
debug!("break_to.end_instr_ptr: {}", self.instr_ptr);
116-
117114
panic!()
118115
}
119116
_ => unimplemented!("break to block type: {:?}", current_label.ty),

crates/tinywasm/src/runtime/stack/value_stack.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ impl ValueStack {
4040
pub(crate) fn push_block_args(&self, args: BlockArgs) -> Result<()> {
4141
match args {
4242
BlockArgs::Empty => Ok(()),
43-
BlockArgs::Type(_t) => todo!(),
44-
BlockArgs::FuncType(_t) => todo!(),
43+
BlockArgs::Type(_t) => todo!("support block args (type)"),
44+
BlockArgs::FuncType(_t) => todo!("support block args (func type)"),
4545
}
4646
}
4747

@@ -65,7 +65,7 @@ impl ValueStack {
6565
#[inline]
6666
pub(crate) fn pop_t<T: From<RawWasmValue>>(&mut self) -> Result<T> {
6767
self.top -= 1;
68-
Ok(self.pop()?.into())
68+
Ok(self.stack.pop().ok_or(Error::StackUnderflow)?.into())
6969
}
7070

7171
#[inline]

crates/tinywasm/tests/charts/progress.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ pub fn create_progress_chart(csv_path: &Path, output_path: &Path) -> Result<()>
2020

2121
if parts.len() > 3 {
2222
let version = format!("v{}", parts[0]);
23-
let failed: u32 = parts[1].parse()?;
24-
let passed: u32 = parts[2].parse()?;
23+
let passed: u32 = parts[1].parse()?;
24+
let failed: u32 = parts[2].parse()?;
2525
let total = failed + passed;
2626

2727
if total > max_tests {

0 commit comments

Comments
 (0)