mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[rust] IfStatement support
Lowering for IfStatements, which includes porting some of the HIRBuilder helpers like enter() and reserve().
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use bumpalo::collections::{CollectIn, String};
|
||||
use estree::{
|
||||
AssignmentTarget, ExpressionLike, FunctionDeclaration, Literal, LiteralValue, Pattern,
|
||||
Statement, VariableDeclarationKind,
|
||||
AssignmentTarget, ExpressionLike, FunctionDeclaration, IfStatement, Literal, LiteralValue,
|
||||
Pattern, Statement, VariableDeclarationKind,
|
||||
};
|
||||
use hir::{
|
||||
ArrayElement, BlockKind, Environment, Function, GotoKind, Identifier, InstructionKind,
|
||||
@@ -144,6 +144,45 @@ fn lower_statement<'a>(
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::IfStatement(stmt) => {
|
||||
// block for what follows the if statement, though this may
|
||||
// not be reachable
|
||||
let fallthrough_block = builder.reserve(BlockKind::Block);
|
||||
|
||||
let IfStatement {
|
||||
test,
|
||||
consequent,
|
||||
alternate,
|
||||
..
|
||||
} = *stmt;
|
||||
|
||||
let consequent_block = builder.enter(BlockKind::Block, |builder| {
|
||||
lower_statement(env, builder, consequent, None).unwrap();
|
||||
TerminalValue::GotoTerminal(hir::GotoTerminal {
|
||||
block: fallthrough_block.id,
|
||||
kind: GotoKind::Break,
|
||||
})
|
||||
});
|
||||
|
||||
let alternate_block = builder.enter(BlockKind::Block, |builder| {
|
||||
if let Some(alternate) = alternate {
|
||||
lower_statement(env, builder, alternate, None).unwrap();
|
||||
}
|
||||
TerminalValue::GotoTerminal(hir::GotoTerminal {
|
||||
block: fallthrough_block.id,
|
||||
kind: GotoKind::Break,
|
||||
})
|
||||
});
|
||||
|
||||
let test = lower_expression_to_temporary(env, builder, test);
|
||||
let terminal = TerminalValue::IfTerminal(hir::IfTerminal {
|
||||
test,
|
||||
consequent: consequent_block,
|
||||
alternate: alternate_block,
|
||||
fallthrough: Some(fallthrough_block.id),
|
||||
});
|
||||
builder.terminate_with_fallthrough(terminal, fallthrough_block);
|
||||
}
|
||||
_ => todo!("Lower {stmt:#?}"),
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -96,7 +96,15 @@ impl<'a> Builder<'a> {
|
||||
kind: next_kind,
|
||||
instructions: Vec::new_in(&self.environment.allocator),
|
||||
};
|
||||
let prev_wip = std::mem::replace(&mut self.wip, next_wip);
|
||||
self.terminate_with_fallthrough(terminal, next_wip)
|
||||
}
|
||||
|
||||
pub(crate) fn terminate_with_fallthrough(
|
||||
&mut self,
|
||||
terminal: TerminalValue<'a>,
|
||||
fallthrough: WipBlock<'a>,
|
||||
) {
|
||||
let prev_wip = std::mem::replace(&mut self.wip, fallthrough);
|
||||
self.completed.insert(
|
||||
prev_wip.id,
|
||||
BasicBlock {
|
||||
@@ -112,6 +120,46 @@ impl<'a> Builder<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn reserve(&mut self, kind: BlockKind) -> WipBlock<'a> {
|
||||
WipBlock {
|
||||
id: self.environment.next_block_id(),
|
||||
kind,
|
||||
instructions: Vec::new_in(&self.environment.allocator),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enter<F>(&mut self, kind: BlockKind, f: F) -> BlockId
|
||||
where
|
||||
F: FnOnce(&mut Self) -> TerminalValue<'a>,
|
||||
{
|
||||
let wip = self.reserve(kind);
|
||||
let id = wip.id;
|
||||
self.enter_reserved(wip, f);
|
||||
id
|
||||
}
|
||||
|
||||
fn enter_reserved<F>(&mut self, wip: WipBlock<'a>, f: F)
|
||||
where
|
||||
F: FnOnce(&mut Self) -> TerminalValue<'a>,
|
||||
{
|
||||
let current = std::mem::replace(&mut self.wip, wip);
|
||||
let terminal = f(self);
|
||||
let completed = std::mem::replace(&mut self.wip, current);
|
||||
self.completed.insert(
|
||||
completed.id,
|
||||
BasicBlock {
|
||||
id: completed.id,
|
||||
kind: completed.kind,
|
||||
instructions: completed.instructions,
|
||||
terminal: Terminal {
|
||||
id: self.id_gen.next(),
|
||||
value: terminal,
|
||||
},
|
||||
predecessors: Default::default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns a new temporary identifier
|
||||
pub(crate) fn make_temporary(&self) -> hir::Identifier<'a> {
|
||||
hir::Identifier {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
function foo(a, b, c, d) {
|
||||
if (a) {
|
||||
return b;
|
||||
} else {
|
||||
c;
|
||||
}
|
||||
d;
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
---
|
||||
source: crates/fixtures/tests/fixtures_test.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")"
|
||||
input_file: crates/fixtures/tests/fixtures/if-statement.js
|
||||
---
|
||||
Input:
|
||||
function foo(a, b, c, d) {
|
||||
if (a) {
|
||||
return b;
|
||||
} else {
|
||||
c;
|
||||
}
|
||||
d;
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
entry bb0
|
||||
bb0
|
||||
[0] unknown $5 = LoadLocal unknown a$4
|
||||
[1] If unknown $5 consequent=bb2 alternate=bb4 fallthrough=bb1
|
||||
bb2
|
||||
[2] unknown $1 = LoadLocal unknown b$0
|
||||
[3] Return unknown $1
|
||||
bb4
|
||||
[4] unknown $3 = LoadLocal unknown c$2
|
||||
[5] Goto bb1
|
||||
bb1
|
||||
[6] unknown $7 = LoadLocal unknown d$6
|
||||
[7] unknown $8 = <undefined>
|
||||
[8] Return unknown $8
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::fmt::{Result, Write};
|
||||
|
||||
use crate::{
|
||||
ArrayElement, BasicBlock, Function, Instruction, InstructionValue, LValue, Place,
|
||||
terminal, ArrayElement, BasicBlock, Function, Instruction, InstructionValue, LValue, Place,
|
||||
PrimitiveValue, Terminal, TerminalValue,
|
||||
};
|
||||
|
||||
@@ -150,6 +150,23 @@ impl<'a> Print for TerminalValue<'a> {
|
||||
write!(out, "Return ")?;
|
||||
terminal.value.print(out)?;
|
||||
}
|
||||
TerminalValue::GotoTerminal(terminal) => {
|
||||
write!(out, "Goto {}", terminal.block)?;
|
||||
}
|
||||
TerminalValue::IfTerminal(terminal) => {
|
||||
write!(out, "If ")?;
|
||||
terminal.test.print(out)?;
|
||||
write!(
|
||||
out,
|
||||
" consequent={} alternate={} fallthrough={}",
|
||||
terminal.consequent,
|
||||
terminal.alternate,
|
||||
match terminal.fallthrough {
|
||||
Some(fallthrough) => format!("{fallthrough}"),
|
||||
None => "<none>".to_string(),
|
||||
}
|
||||
)?;
|
||||
}
|
||||
_ => write!(out, "{:?}", self)?,
|
||||
}
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user