[rust] Support destructuring

Adds a `Destructure` instruction closely following the design of the TS-based 
compiler. The main change is fairly small: the TS compiler doesn't support rest 
spreads that are not identifiers, such as the `...y[]` in `const [x, ...[y]] = 
z`. I added support for this in the Rust compiler.
This commit is contained in:
Joe Savona
2023-08-11 15:13:21 -04:00
parent 298bf55f25
commit a49335f72a
21 changed files with 781 additions and 333 deletions
@@ -2,14 +2,15 @@ use std::collections::HashSet;
use forget_diagnostics::Diagnostic;
use forget_estree::{
AssignmentTarget, BlockStatement, Expression, ExpressionOrSpread, ExpressionOrSuper, ForInit,
Function, IntoFunction, JsValue, Pattern, Statement, VariableDeclaration,
VariableDeclarationKind,
AssignmentPropertyOrRestElement, AssignmentTarget, BlockStatement, Expression,
ExpressionOrSpread, ExpressionOrSuper, ForInit, Function, IntoFunction, JsValue, Pattern,
Statement, VariableDeclaration, VariableDeclarationKind,
};
use forget_hir::{
BlockKind, BranchTerminal, Environment, ForTerminal, GotoKind, IdentifierOperand,
InstructionKind, InstructionValue, JSXAttribute, JSXElement, LValue, LoadGlobal, LoadLocal,
PlaceOrSpread, TerminalValue,
ArrayDestructureItem, BlockKind, BranchTerminal, Destructure, DestructurePattern, Environment,
ForTerminal, GotoKind, Identifier, IdentifierOperand, InstructionKind, InstructionValue,
JSXAttribute, JSXElement, LValue, LoadGlobal, LoadLocal, ObjectDestructureItem,
ObjectDestructureProperty, PlaceOrSpread, TerminalValue,
};
use crate::builder::{Builder, LoopScope};
@@ -303,8 +304,8 @@ fn lower_variable_declaration(
}
}
_ => {
return Err(Diagnostic::todo(
"Handle non-identifier variable declarations",
return Err(Diagnostic::invalid_syntax(
"Expected an identifier for variable declaration without an intializer. Destructuring requires an initial value",
declaration.range,
));
}
@@ -543,6 +544,7 @@ fn lower_assignment(
})
}
// TODO: change the success type to void, no caller uses it
fn lower_assignment_pattern(
env: &Environment,
builder: &mut Builder,
@@ -558,6 +560,147 @@ fn lower_assignment_pattern(
value,
}))
}
Pattern::ArrayPattern(lvalue) => {
let mut items = Vec::with_capacity(lvalue.elements.len());
let mut followups: Vec<(Identifier, &Pattern)> = Vec::new();
for element in &lvalue.elements {
match element {
None => items.push(ArrayDestructureItem::Hole),
Some(Pattern::Identifier(element)) => {
let identifier =
lower_identifier_for_assignment(env, builder, kind, &element)?;
items.push(ArrayDestructureItem::Value(identifier));
}
Some(Pattern::RestElement(element)) => {
if let Pattern::Identifier(element) = &element.argument {
let identifier = lower_identifier_for_assignment(
env,
builder,
kind,
element.as_ref(),
)?;
items.push(ArrayDestructureItem::Spread(identifier));
} else {
let temporary = env.new_temporary();
items.push(ArrayDestructureItem::Spread(IdentifierOperand {
identifier: temporary.clone(),
effect: None,
}));
followups.push((temporary, &element.argument));
}
}
Some(element) => {
let temporary = env.new_temporary();
items.push(ArrayDestructureItem::Value(IdentifierOperand {
identifier: temporary.clone(),
effect: None,
}));
followups.push((temporary, element));
}
}
}
let temporary = builder.push(InstructionValue::Destructure(Destructure {
kind,
pattern: DestructurePattern::Array(items),
value,
}));
for (temporary, pattern) in followups {
lower_assignment_pattern(
env,
builder,
kind,
pattern,
IdentifierOperand {
identifier: temporary,
effect: None,
},
)?;
}
temporary
}
Pattern::ObjectPattern(lvalue) => {
let mut properties = Vec::with_capacity(lvalue.properties.len());
let mut followups: Vec<(Identifier, &Pattern)> = Vec::new();
for property in &lvalue.properties {
match property {
AssignmentPropertyOrRestElement::RestElement(property) => {
if let Pattern::Identifier(element) = &property.argument {
let identifier = lower_identifier_for_assignment(
env,
builder,
kind,
element.as_ref(),
)?;
properties.push(ObjectDestructureItem::Spread(identifier));
} else {
let temporary = env.new_temporary();
properties.push(ObjectDestructureItem::Spread(IdentifierOperand {
identifier: temporary.clone(),
effect: None,
}));
followups.push((temporary, &property.argument));
}
}
AssignmentPropertyOrRestElement::AssignmentProperty(property) => {
if property.is_computed {
return Err(Diagnostic::todo(
"Handle computed properties in ObjectPattern",
property.range,
));
}
let key = if let Expression::Identifier(key) = &property.key {
key.name.as_str()
} else {
return Err(Diagnostic::todo(
"Support non-identifier object keys in non-computed ObjectPattern",
property.range,
));
};
if let Pattern::Identifier(value) = &property.value {
let value = lower_identifier_for_assignment(env, builder, kind, value)?;
properties.push(ObjectDestructureItem::Property(
ObjectDestructureProperty {
name: key.to_string(),
value,
},
));
} else {
let temporary = env.new_temporary();
properties.push(ObjectDestructureItem::Property(
ObjectDestructureProperty {
name: key.to_string(),
value: IdentifierOperand {
identifier: temporary.clone(),
effect: None,
},
},
));
followups.push((temporary, &property.value));
}
}
}
}
let temporary = builder.push(InstructionValue::Destructure(Destructure {
kind,
pattern: DestructurePattern::Object(properties),
value,
}));
for (temporary, pattern) in followups {
lower_assignment_pattern(
env,
builder,
kind,
pattern,
IdentifierOperand {
identifier: temporary,
effect: None,
},
)?;
}
temporary
}
_ => todo!("lower assignment pattern for {:#?}", lvalue),
})
}
@@ -0,0 +1,5 @@
function Component(a, b) {
const [c, , ...d] = a;
const [[[e]], ...[f]] = b;
return [c, d, e, f];
}
@@ -0,0 +1,15 @@
function Component(a, b) {
const {
c,
d,
e: { e },
f: { _f: f },
g: {
g: {
g: { g, ...h },
},
},
...i
} = a;
return [c, d, e, f, g, h, i];
}
@@ -38,6 +38,7 @@ fn fixtures() {
match build(&environment, &fun.function) {
Ok(mut fun) => {
println!("ok build");
fun.debug();
enter_ssa(&environment, &mut fun).unwrap();
println!("ok enter_ssa");
eliminate_redundant_phis(&environment, &mut fun);
@@ -45,29 +45,73 @@ function Component(
)
entry bb0
bb0 (block)
[0] unknown $0 = 1
[1] unknown $2 = StoreLocal Let unknown a$39 = unknown $0
[2] unknown $4 = DeclareLocal Let unknown b$40
[3] unknown $9 = 1
[4] unknown $10 = 1
[5] unknown $11 = true
[6] unknown $5 = true
[7] unknown $6 = StoreLocal Reassign unknown b$41 = unknown $5
[8] unknown $13 = DeclareLocal Let unknown c$43
[9] unknown $18 = true
[10] unknown $14 = "hello"
[11] unknown $15 = StoreLocal Reassign unknown c$45 = unknown $14
[12] unknown $20 = DeclareLocal Let unknown d$47
[13] unknown $25 = "hello"
[14] unknown $26 = "hello"
[15] unknown $27 = true
[16] unknown $21 = 42
[17] unknown $22 = StoreLocal Reassign unknown d$49 = unknown $21
[18] unknown $29 = DeclareLocal Let unknown e$51
[19] unknown $34 = 42
[20] unknown $35 = 42
[21] unknown $36 = true
[22] unknown $30 = "ok"
[23] unknown $31 = StoreLocal Reassign unknown e$53 = unknown $30
[24] unknown $37 = "ok"
[25] Return unknown $37
[0] unknown $39 = 1
[1] unknown $40 = StoreLocal Let unknown a$41 = unknown $39
[2] unknown $42 = DeclareLocal Let unknown b$43
[3] unknown $44 = LoadLocal unknown a$1
[4] unknown $45 = 1
[5] unknown $46 = Binary unknown $44 === unknown $45
[6] If unknown $11 consequent=bb2 alternate=bb3 fallthrough=bb1
bb2 (block)
predecessors: bb0
[7] unknown $47 = true
[8] unknown $48 = StoreLocal Reassign unknown b$49 = unknown $47
[9] Goto bb1
bb3 (block)
predecessors: bb0
[10] unknown $50 = false
[11] unknown $51 = StoreLocal Reassign unknown b$52 = unknown $50
[12] Goto bb1
bb1 (block)
predecessors: bb2, bb3
[13] unknown $53 = DeclareLocal Let unknown c$54
[14] unknown $55 = LoadLocal unknown b$3
[15] If unknown $18 consequent=bb5 alternate=bb6 fallthrough=bb4
bb5 (block)
predecessors: bb1
[16] unknown $56 = "hello"
[17] unknown $57 = StoreLocal Reassign unknown c$58 = unknown $56
[18] Goto bb4
bb6 (block)
predecessors: bb1
[19] unknown $59 = null
[20] unknown $60 = StoreLocal Reassign unknown c$61 = unknown $59
[21] Goto bb4
bb4 (block)
predecessors: bb5, bb6
[22] unknown $62 = DeclareLocal Let unknown d$63
[23] unknown $64 = LoadLocal unknown c$12
[24] unknown $65 = "hello"
[25] unknown $66 = Binary unknown $64 === unknown $65
[26] If unknown $27 consequent=bb8 alternate=bb9 fallthrough=bb7
bb8 (block)
predecessors: bb4
[27] unknown $67 = 42
[28] unknown $68 = StoreLocal Reassign unknown d$69 = unknown $67
[29] Goto bb7
bb9 (block)
predecessors: bb4
[30] unknown $70 = 42.001
[31] unknown $71 = StoreLocal Reassign unknown d$72 = unknown $70
[32] Goto bb7
bb7 (block)
predecessors: bb8, bb9
[33] unknown $73 = DeclareLocal Let unknown e$74
[34] unknown $75 = LoadLocal unknown d$19
[35] unknown $76 = 42
[36] unknown $77 = Binary unknown $75 === unknown $76
[37] If unknown $36 consequent=bb11 alternate=bb12 fallthrough=bb10
bb11 (block)
predecessors: bb7
[38] unknown $78 = "ok"
[39] unknown $79 = StoreLocal Reassign unknown e$80 = unknown $78
[40] Goto bb10
bb12 (block)
predecessors: bb7
[41] unknown $81 = "nope"
[42] unknown $82 = StoreLocal Reassign unknown e$83 = unknown $81
[43] Goto bb10
bb10 (block)
predecessors: bb11, bb12
[44] unknown $84 = LoadLocal unknown e$28
[45] Return unknown $37
@@ -72,127 +72,125 @@ function Component(
)
entry bb0
bb0 (block)
[0] unknown $2 = DeclareLocal Let unknown a$109
[1] unknown $3 = LoadGlobal Math
[2] unknown $4 = StoreLocal Reassign unknown a$110 = unknown $3
[3] unknown $5 = LoadGlobal Math
[4] unknown $7 = DeclareLocal Let unknown b$111
[5] unknown $12 = LoadLocal unknown props$108
[0] unknown $109 = DeclareLocal Let unknown a$110
[1] unknown $111 = LoadGlobal Math
[2] unknown $112 = StoreLocal Reassign unknown a$113 = unknown $111
[3] unknown $114 = LoadLocal unknown a$1
[4] unknown $115 = DeclareLocal Let unknown b$116
[5] unknown $117 = LoadLocal unknown props$0
[6] If unknown $12 consequent=bb2 alternate=bb3 fallthrough=bb1
bb2 (block)
predecessors: bb0
[7] unknown $8 = true
[8] unknown $9 = StoreLocal Reassign unknown b$112 = unknown $8
[7] unknown $118 = true
[8] unknown $119 = StoreLocal Reassign unknown b$120 = unknown $118
[9] Goto bb1
bb3 (block)
predecessors: bb0
[10] unknown $10 = true
[11] unknown $11 = StoreLocal Reassign unknown b$113 = unknown $10
[10] unknown $121 = true
[11] unknown $122 = StoreLocal Reassign unknown b$123 = unknown $121
[12] Goto bb1
bb1 (block)
predecessors: bb2, bb3
b$114: phi(bb2: b$112, bb3: b$113)
[13] unknown $13 = true
[14] unknown $15 = DeclareLocal Let unknown c$115
[15] unknown $20 = LoadLocal unknown props$108
[13] unknown $124 = LoadLocal unknown b$6
[14] unknown $125 = DeclareLocal Let unknown c$126
[15] unknown $127 = LoadLocal unknown props$0
[16] If unknown $20 consequent=bb5 alternate=bb6 fallthrough=bb4
bb5 (block)
predecessors: bb1
[17] unknown $16 = true
[18] unknown $17 = StoreLocal Reassign unknown c$117 = unknown $16
[17] unknown $128 = true
[18] unknown $129 = StoreLocal Reassign unknown c$130 = unknown $128
[19] Goto bb4
bb6 (block)
predecessors: bb1
[20] unknown $18 = 42
[21] unknown $19 = StoreLocal Reassign unknown c$118 = unknown $18
[20] unknown $131 = 42
[21] unknown $132 = StoreLocal Reassign unknown c$133 = unknown $131
[22] Goto bb4
bb4 (block)
predecessors: bb5, bb6
c$119: phi(bb5: c$117, bb6: c$118)
[23] unknown $21 = LoadLocal unknown c$119
[24] unknown $22 = 42
[25] unknown $23 = 1
[26] unknown $24 = 43
[27] unknown $25 = 42
[28] unknown $26 = 1
[29] unknown $27 = 41
[30] unknown $28 = 42
[31] unknown $29 = 2
[32] unknown $30 = 84
[33] unknown $31 = 42
[34] unknown $32 = 2
[35] unknown $33 = 21
[36] unknown $34 = 0
[37] unknown $35 = 1
[38] unknown $36 = false
[39] unknown $37 = 0
[40] unknown $38 = 1
[41] unknown $39 = true
[42] unknown $40 = 0
[43] unknown $41 = 1
[44] unknown $42 = false
[45] unknown $43 = 0
[46] unknown $44 = 1
[47] unknown $45 = true
[48] unknown $46 = 0
[49] unknown $47 = 0
[50] unknown $48 = true
[51] unknown $49 = LoadGlobal NaN
[52] unknown $50 = LoadGlobal NaN
[53] unknown $51 = Binary unknown $49 == unknown $50
[54] unknown $52 = LoadGlobal NaN
[55] unknown $53 = LoadGlobal NaN
[56] unknown $54 = Binary unknown $52 != unknown $53
[57] unknown $55 = LoadGlobal NaN
[58] unknown $56 = LoadGlobal NaN
[59] unknown $57 = Binary unknown $55 !== unknown $56
[60] unknown $58 = LoadGlobal NaN
[61] unknown $59 = LoadGlobal NaN
[62] unknown $60 = Binary unknown $58 !== unknown $59
[63] unknown $61 = "hello"
[64] unknown $62 = "hello"
[65] unknown $63 = true
[66] unknown $64 = "hello"
[67] unknown $65 = "hello"
[68] unknown $66 = false
[69] unknown $67 = "hello"
[70] unknown $68 = "hello"
[71] unknown $69 = true
[72] unknown $70 = "hello"
[73] unknown $71 = "hello"
[74] unknown $72 = false
[75] unknown $73 = "hello"
[76] unknown $74 = "world"
[77] unknown $75 = false
[78] unknown $76 = "hello"
[79] unknown $77 = "world"
[80] unknown $78 = true
[81] unknown $79 = "hello"
[82] unknown $80 = "world"
[83] unknown $81 = false
[84] unknown $82 = "hello"
[85] unknown $83 = "world"
[86] unknown $84 = true
[87] unknown $85 = true
[88] unknown $86 = true
[89] unknown $87 = true
[90] unknown $88 = true
[91] unknown $89 = true
[92] unknown $90 = false
[93] unknown $91 = true
[94] unknown $92 = true
[95] unknown $93 = true
[96] unknown $94 = true
[97] unknown $95 = true
[98] unknown $96 = false
[99] unknown $97 = 5
[100] unknown $98 = 60
[101] unknown $99 = 300
[102] unknown $100 = 60
[103] unknown $101 = 18000
[104] unknown $102 = 1000
[105] unknown $103 = 18000000
[106] unknown $105 = StoreLocal Let unknown x$120 = unknown $103
[107] unknown $106 = 18000000
[108] unknown $107 = <undefined>
[23] unknown $134 = LoadLocal unknown c$14
[24] unknown $135 = 42
[25] unknown $136 = 1
[26] unknown $137 = 43
[27] unknown $138 = 42
[28] unknown $139 = 1
[29] unknown $140 = 41
[30] unknown $141 = 42
[31] unknown $142 = 2
[32] unknown $143 = 84
[33] unknown $144 = 42
[34] unknown $145 = 2
[35] unknown $146 = 21
[36] unknown $147 = 0
[37] unknown $148 = 1
[38] unknown $149 = false
[39] unknown $150 = 0
[40] unknown $151 = 1
[41] unknown $152 = true
[42] unknown $153 = 0
[43] unknown $154 = 1
[44] unknown $155 = false
[45] unknown $156 = 0
[46] unknown $157 = 1
[47] unknown $158 = true
[48] unknown $159 = 0
[49] unknown $160 = 0
[50] unknown $161 = true
[51] unknown $162 = LoadGlobal NaN
[52] unknown $163 = LoadGlobal NaN
[53] unknown $164 = Binary unknown $162 == unknown $163
[54] unknown $165 = LoadGlobal NaN
[55] unknown $166 = LoadGlobal NaN
[56] unknown $167 = Binary unknown $165 != unknown $166
[57] unknown $168 = LoadGlobal NaN
[58] unknown $169 = LoadGlobal NaN
[59] unknown $170 = Binary unknown $168 !== unknown $169
[60] unknown $171 = LoadGlobal NaN
[61] unknown $172 = LoadGlobal NaN
[62] unknown $173 = Binary unknown $171 !== unknown $172
[63] unknown $174 = "hello"
[64] unknown $175 = "hello"
[65] unknown $176 = true
[66] unknown $177 = "hello"
[67] unknown $178 = "hello"
[68] unknown $179 = false
[69] unknown $180 = "hello"
[70] unknown $181 = "hello"
[71] unknown $182 = true
[72] unknown $183 = "hello"
[73] unknown $184 = "hello"
[74] unknown $185 = false
[75] unknown $186 = "hello"
[76] unknown $187 = "world"
[77] unknown $188 = false
[78] unknown $189 = "hello"
[79] unknown $190 = "world"
[80] unknown $191 = true
[81] unknown $192 = "hello"
[82] unknown $193 = "world"
[83] unknown $194 = false
[84] unknown $195 = "hello"
[85] unknown $196 = "world"
[86] unknown $197 = true
[87] unknown $198 = true
[88] unknown $199 = true
[89] unknown $200 = true
[90] unknown $201 = true
[91] unknown $202 = true
[92] unknown $203 = false
[93] unknown $204 = true
[94] unknown $205 = true
[95] unknown $206 = true
[96] unknown $207 = true
[97] unknown $208 = true
[98] unknown $209 = false
[99] unknown $210 = 5
[100] unknown $211 = 60
[101] unknown $212 = 300
[102] unknown $213 = 60
[103] unknown $214 = 18000
[104] unknown $215 = 1000
[105] unknown $216 = 18000000
[106] unknown $217 = StoreLocal Let unknown x$218 = unknown $216
[107] unknown $219 = LoadLocal unknown x$104
[108] unknown $220 = <undefined>
[109] Return unknown $107
@@ -0,0 +1,33 @@
---
source: crates/forget_fixtures/tests/fixtures_test.rs
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")"
input_file: crates/forget_fixtures/tests/fixtures/destructure-array.js
---
Input:
function Component(a, b) {
const [c, , ...d] = a;
const [[[e]], ...[f]] = b;
return [c, d, e, f];
}
Output:
function Component(
unknown a$22,
unknown b$23,
)
entry bb0
bb0 (block)
[0] unknown $24 = LoadLocal unknown a$0
[1] unknown $25 = Destructure [ unknown c$26, <hole>, ...unknown d$27 ] = unknown $24
[2] unknown $28 = LoadLocal unknown b$1
[3] unknown $29 = Destructure [ unknown $30, ...unknown $31 ] = unknown $28
[4] unknown $32 = Destructure [ unknown $33 ] = unknown $30
[5] unknown $34 = Destructure [ unknown e$35 ] = unknown $33
[6] unknown $36 = Destructure [ unknown f$37 ] = unknown $31
[7] unknown $38 = LoadLocal unknown c$3
[8] unknown $39 = LoadLocal unknown d$4
[9] unknown $40 = LoadLocal unknown e$12
[10] unknown $41 = LoadLocal unknown f$14
[11] unknown $42 = Array [unknown $38, unknown $39, unknown $40, unknown $41]
[12] Return unknown $20
@@ -0,0 +1,46 @@
---
source: crates/forget_fixtures/tests/fixtures_test.rs
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")"
input_file: crates/forget_fixtures/tests/fixtures/destructure-object.js
---
Input:
function Component(a, b) {
const {
c,
d,
e: { e },
f: { _f: f },
g: {
g: {
g: { g, ...h },
},
},
...i
} = a;
return [c, d, e, f, g, h, i];
}
Output:
function Component(
unknown a$30,
unknown b$31,
)
entry bb0
bb0 (block)
[0] unknown $32 = LoadLocal unknown a$0
[1] unknown $33 = Destructure { c: unknown c$34, d: unknown d$35, e: unknown $36, f: unknown $37, g: unknown $38, ...unknown i$39 } = unknown $32
[2] unknown $40 = Destructure { e: unknown e$41 } = unknown $36
[3] unknown $42 = Destructure { _f: unknown f$43 } = unknown $37
[4] unknown $44 = Destructure { g: unknown $45 } = unknown $38
[5] unknown $46 = Destructure { g: unknown $47 } = unknown $45
[6] unknown $48 = Destructure { g: unknown g$49, ...unknown h$50 } = unknown $47
[7] unknown $51 = LoadLocal unknown c$3
[8] unknown $52 = LoadLocal unknown d$4
[9] unknown $53 = LoadLocal unknown e$10
[10] unknown $54 = LoadLocal unknown f$12
[11] unknown $55 = LoadLocal unknown g$18
[12] unknown $56 = LoadLocal unknown h$19
[13] unknown $57 = LoadLocal unknown i$8
[14] unknown $58 = Array [unknown $51, unknown $52, unknown $53, unknown $54, unknown $55, unknown $56, unknown $57]
[15] Return unknown $28
@@ -18,37 +18,35 @@ function foo(
)
entry bb0
bb0 (block)
[0] unknown $0 = 0
[1] unknown $2 = StoreLocal Let unknown x$19 = unknown $0
[0] unknown $19 = 0
[1] unknown $20 = StoreLocal Let unknown x$21 = unknown $19
[2] For init=bb3 test=bb1 update=bb4 body=bb5 fallthrough=bb2
bb3 (loop)
predecessors: bb0
[3] unknown $3 = 0
[4] unknown $5 = StoreLocal Let unknown i$20 = unknown $3
[3] unknown $22 = 0
[4] unknown $23 = StoreLocal Let unknown i$24 = unknown $22
[5] Goto bb1
bb1 (loop)
predecessors: bb3, bb4
i$21: phi(bb3: i$20, bb4: i$24)
x$22: phi(bb3: x$19, bb4: x$23)
[6] unknown $14 = LoadLocal unknown i$21
[7] unknown $15 = 10
[8] unknown $16 = Binary unknown $14 < unknown $15
[6] unknown $25 = LoadLocal unknown i$4
[7] unknown $26 = 10
[8] unknown $27 = Binary unknown $25 < unknown $26
[9] Branch unknown $16 consequent=bb5 alternate=bb2
bb5 (block)
predecessors: bb1
[10] unknown $10 = LoadLocal unknown x$22
[11] unknown $11 = LoadLocal unknown i$21
[12] unknown $12 = Binary unknown $10 + unknown $11
[13] unknown $13 = StoreLocal Reassign unknown x$23 = unknown $12
[10] unknown $28 = LoadLocal unknown x$1
[11] unknown $29 = LoadLocal unknown i$4
[12] unknown $30 = Binary unknown $28 + unknown $29
[13] unknown $31 = StoreLocal Reassign unknown x$32 = unknown $30
[14] Goto bb4
bb4 (loop)
predecessors: bb5
[15] unknown $6 = LoadLocal unknown i$21
[16] unknown $7 = 1
[17] unknown $8 = Binary unknown $6 + unknown $7
[18] unknown $9 = StoreLocal Reassign unknown i$24 = unknown $8
[15] unknown $33 = LoadLocal unknown i$4
[16] unknown $34 = 1
[17] unknown $35 = Binary unknown $33 + unknown $34
[18] unknown $36 = StoreLocal Reassign unknown i$37 = unknown $35
[19] Goto bb1
bb2 (block)
predecessors: bb1
[20] unknown $17 = LoadLocal unknown x$22
[20] unknown $38 = LoadLocal unknown x$1
[21] Return unknown $17
@@ -33,62 +33,74 @@ function Component(
)
entry bb0
bb0 (block)
[0] unknown $1 = 2
[1] unknown $3 = StoreLocal Const unknown x$59 = unknown $1
[2] unknown $54 = Function @deps[] @context[unknown x$59]:
[0] unknown $59 = 2
[1] unknown $60 = StoreLocal Const unknown x$61 = unknown $59
[2] unknown $62 = Function @deps[] @context[unknown x$61]:
function foo(
unknown y$60,
unknown y$63,
)
entry bb1
bb1 (block)
[0] unknown $5 = 1
[1] unknown $7 = StoreLocal Let unknown a$61 = unknown $5
[2] unknown $9 = DeclareLocal Let unknown b$62
[3] unknown $16 = 1
[4] unknown $17 = 1
[5] unknown $18 = true
[6] unknown $10 = 5
[7] unknown $11 = 3
[8] unknown $12 = 8
[9] unknown $13 = StoreLocal Reassign unknown b$63 = unknown $12
[10] unknown $19 = 2
[11] unknown $20 = LoadLocal unknown y$60
[12] unknown $21 = Binary unknown $19 + unknown $20
[13] unknown $22 = 1
[14] unknown $23 = Binary unknown $21 + unknown $22
[15] unknown $24 = 8
[16] unknown $25 = Binary unknown $23 + unknown $24
[17] unknown $48 = Function @deps[] @context[unknown x$59, unknown y$60, unknown a$61, unknown b$63]:
[0] unknown $64 = 1
[1] unknown $65 = StoreLocal Let unknown a$66 = unknown $64
[2] unknown $67 = DeclareLocal Let unknown b$68
[3] unknown $69 = LoadLocal unknown a$6
[4] unknown $70 = 1
[5] unknown $71 = Binary unknown $69 === unknown $70
[6] If unknown $18 consequent=bb3 alternate=bb4 fallthrough=bb2
bb3 (block)
predecessors: bb1
[7] unknown $72 = 5
[8] unknown $73 = 3
[9] unknown $74 = 8
[10] unknown $75 = StoreLocal Reassign unknown b$76 = unknown $74
[11] Goto bb2
bb4 (block)
predecessors: bb1
[12] unknown $77 = false
[13] unknown $78 = StoreLocal Reassign unknown b$79 = unknown $77
[14] Goto bb2
bb2 (block)
predecessors: bb3, bb4
b$91: phi(bb3: b$76, bb4: b$79)
[15] unknown $80 = LoadLocal unknown x$2
[16] unknown $81 = LoadLocal unknown y$4
[17] unknown $82 = Binary unknown $80 + unknown $81
[18] unknown $83 = LoadLocal unknown a$6
[19] unknown $84 = Binary unknown $82 + unknown $83
[20] unknown $85 = LoadLocal unknown b$8
[21] unknown $86 = Binary unknown $84 + unknown $85
[22] unknown $87 = Function @deps[] @context[unknown x$61, unknown y$63, unknown a$66, unknown b$91]:
function bar(
unknown z$69,
unknown z$92,
)
entry bb5
bb5 (block)
[0] unknown $27 = 2
[1] unknown $29 = StoreLocal Let unknown c$70 = unknown $27
[2] unknown $31 = DeclareLocal Let unknown d$71
[3] unknown $32 = 3
[4] unknown $33 = StoreLocal Reassign unknown d$72 = unknown $32
[5] unknown $34 = LoadLocal unknown x$65
[6] unknown $35 = LoadLocal unknown y$66
[7] unknown $36 = Binary unknown $34 + unknown $35
[8] unknown $37 = LoadLocal unknown a$67
[9] unknown $38 = Binary unknown $36 + unknown $37
[10] unknown $39 = LoadLocal unknown b$68
[11] unknown $40 = Binary unknown $38 + unknown $39
[12] unknown $41 = LoadLocal unknown z$69
[13] unknown $42 = Binary unknown $40 + unknown $41
[14] unknown $43 = 2
[15] unknown $44 = Binary unknown $42 + unknown $43
[16] unknown $45 = 3
[17] unknown $46 = Binary unknown $44 + unknown $45
[18] unknown $47 = <undefined>
[0] unknown $93 = 2
[1] unknown $94 = StoreLocal Let unknown c$95 = unknown $93
[2] unknown $96 = DeclareLocal Let unknown d$97
[3] unknown $98 = 3
[4] unknown $99 = StoreLocal Reassign unknown d$100 = unknown $98
[5] unknown $101 = LoadLocal unknown x$2
[6] unknown $102 = LoadLocal unknown y$4
[7] unknown $103 = Binary unknown $101 + unknown $102
[8] unknown $104 = LoadLocal unknown a$6
[9] unknown $105 = Binary unknown $103 + unknown $104
[10] unknown $106 = LoadLocal unknown b$8
[11] unknown $107 = Binary unknown $105 + unknown $106
[12] unknown $108 = LoadLocal unknown z$26
[13] unknown $109 = Binary unknown $107 + unknown $108
[14] unknown $110 = LoadLocal unknown c$28
[15] unknown $111 = Binary unknown $109 + unknown $110
[16] unknown $112 = LoadLocal unknown d$30
[17] unknown $113 = Binary unknown $111 + unknown $112
[18] unknown $114 = <undefined>
[19] Return unknown $47
[18] unknown $50 = StoreLocal Const unknown bar$73 = unknown $48
[19] unknown $51 = LoadLocal unknown bar$73
[20] unknown $52 = LoadGlobal foo
[21] unknown $53 = <undefined>
[22] Return unknown $53
[3] unknown $56 = StoreLocal Const unknown foo$74 = unknown $54
[4] unknown $57 = <undefined>
[23] unknown $115 = StoreLocal Const unknown bar$116 = unknown $87
[24] unknown $117 = LoadLocal unknown bar$49
[25] unknown $118 = LoadGlobal foo
[26] unknown $119 = <undefined>
[27] Return unknown $53
[3] unknown $120 = StoreLocal Const unknown foo$121 = unknown $62
[4] unknown $122 = <undefined>
[5] Return unknown $57
@@ -28,14 +28,14 @@ function id(
)
entry bb0
bb0 (block)
[0] unknown $1 = LoadGlobal Math
[1] unknown $2 = LoadGlobal id
[2] unknown $3 = true
[3] unknown $5 = StoreLocal Let unknown y$15 = unknown $3
[4] unknown $6 = false
[5] unknown $7 = StoreLocal Reassign unknown y$16 = unknown $6
[6] unknown $8 = false
[7] unknown $10 = DeclareLocal Let unknown z$17
[8] unknown $11 = LoadLocal unknown z$17
[9] unknown $12 = LoadLocal unknown x$14
[0] unknown $15 = LoadGlobal Math
[1] unknown $16 = LoadGlobal id
[2] unknown $17 = true
[3] unknown $18 = StoreLocal Let unknown y$19 = unknown $17
[4] unknown $20 = false
[5] unknown $21 = StoreLocal Reassign unknown y$22 = unknown $20
[6] unknown $23 = LoadLocal unknown y$4
[7] unknown $24 = DeclareLocal Let unknown z$25
[8] unknown $26 = LoadLocal unknown z$9
[9] unknown $27 = LoadLocal unknown x$0
[10] Return unknown $12
@@ -23,18 +23,18 @@ function foo(
)
entry bb0
bb0 (block)
[0] unknown $6 = LoadLocal unknown a$9
[0] unknown $13 = LoadLocal unknown a$0
[1] If unknown $6 consequent=bb2 alternate=bb4 fallthrough=bb1
bb2 (block)
predecessors: bb0
[2] unknown $4 = LoadLocal unknown b$10
[2] unknown $14 = LoadLocal unknown b$1
[3] Return unknown $4
bb4 (block)
predecessors: bb0
[4] unknown $5 = LoadLocal unknown c$11
[4] unknown $15 = LoadLocal unknown c$2
[5] Goto bb1
bb1 (block)
predecessors: bb4
[6] unknown $7 = LoadLocal unknown d$12
[7] unknown $8 = <undefined>
[6] unknown $16 = LoadLocal unknown d$3
[7] unknown $17 = <undefined>
[8] Return unknown $8
@@ -21,26 +21,26 @@ function Component(
)
entry bb0
bb0 (block)
[0] unknown $1 = LoadGlobal Math
[1] unknown $2 = 0
[2] unknown $4 = StoreLocal Let unknown b$24 = unknown $2
[3] unknown $17 = Function @deps[] @context[unknown a$23, unknown b$24]:
[0] unknown $24 = LoadGlobal Math
[1] unknown $25 = 0
[2] unknown $26 = StoreLocal Let unknown b$27 = unknown $25
[3] unknown $28 = Function @deps[] @context[unknown a$23, unknown b$27]:
function foo_(
unknown c$25,
unknown c$29,
)
entry bb1
bb1 (block)
[0] unknown $6 = 1
[1] unknown $8 = StoreLocal Let unknown d$26 = unknown $6
[2] unknown $9 = LoadLocal unknown a$23
[3] unknown $10 = 0
[4] unknown $11 = Binary unknown $9 + unknown $10
[5] unknown $12 = LoadLocal unknown c$25
[6] unknown $13 = Binary unknown $11 + unknown $12
[7] unknown $14 = 1
[8] unknown $15 = Binary unknown $13 + unknown $14
[0] unknown $30 = 1
[1] unknown $31 = StoreLocal Let unknown d$32 = unknown $30
[2] unknown $33 = LoadLocal unknown a$0
[3] unknown $34 = LoadLocal unknown b$3
[4] unknown $35 = Binary unknown $33 + unknown $34
[5] unknown $36 = LoadLocal unknown c$5
[6] unknown $37 = Binary unknown $35 + unknown $36
[7] unknown $38 = LoadLocal unknown d$7
[8] unknown $39 = Binary unknown $37 + unknown $38
[9] Return unknown $15
[4] unknown $19 = StoreLocal Const unknown foo$27 = unknown $17
[5] unknown $20 = LoadLocal unknown foo$27
[6] unknown $21 = Call unknown $20()
[4] unknown $40 = StoreLocal Const unknown foo$41 = unknown $28
[5] unknown $42 = LoadLocal unknown foo$18
[6] unknown $43 = Call unknown $42()
[7] Return unknown $21
@@ -15,13 +15,13 @@ function test(
)
entry bb0
bb0 (block)
[0] unknown $0 = true
[1] unknown $1 = false
[2] unknown $2 = null
[3] unknown $3 = 1
[4] unknown $4 = 3.14
[5] unknown $5 = "hello world!"
[6] unknown $6 = Array [unknown $5]
[7] unknown $7 = Array [unknown $0, unknown $1, unknown $2, unknown $3, unknown $4, ...unknown $6]
[8] unknown $8 = 2
[0] unknown $10 = true
[1] unknown $11 = false
[2] unknown $12 = null
[3] unknown $13 = 1
[4] unknown $14 = 3.14
[5] unknown $15 = "hello world!"
[6] unknown $16 = Array [unknown $15]
[7] unknown $17 = Array [unknown $10, unknown $11, unknown $12, unknown $13, unknown $14, ...unknown $16]
[8] unknown $18 = 2
[9] Return unknown $8
@@ -29,45 +29,42 @@ function Component(
)
entry bb0
bb0 (block)
[0] unknown $3 = DeclareLocal Let unknown x$28
[1] unknown $4 = 0
[2] unknown $6 = StoreLocal Let unknown y$29 = unknown $4
[3] unknown $7 = 10
[4] unknown $9 = StoreLocal Let unknown z$30 = unknown $7
[5] unknown $19 = LoadLocal unknown a$26
[0] unknown $28 = DeclareLocal Let unknown x$29
[1] unknown $30 = 0
[2] unknown $31 = StoreLocal Let unknown y$32 = unknown $30
[3] unknown $33 = 10
[4] unknown $34 = StoreLocal Let unknown z$35 = unknown $33
[5] unknown $36 = LoadLocal unknown a$0
[6] If unknown $19 consequent=bb2 alternate=bb6 fallthrough=bb1
bb2 (block)
predecessors: bb0
[7] unknown $10 = 1
[8] unknown $11 = StoreLocal Reassign unknown x$31 = unknown $10
[9] unknown $16 = LoadLocal unknown b$27
[7] unknown $37 = 1
[8] unknown $38 = StoreLocal Reassign unknown x$39 = unknown $37
[9] unknown $40 = LoadLocal unknown b$1
[10] If unknown $16 consequent=bb4 alternate=bb5 fallthrough=bb3
bb4 (block)
predecessors: bb2
[11] unknown $12 = 20
[12] unknown $13 = StoreLocal Reassign unknown z$32 = unknown $12
[11] unknown $41 = 20
[12] unknown $42 = StoreLocal Reassign unknown z$43 = unknown $41
[13] Goto bb3
bb5 (block)
predecessors: bb2
[14] unknown $14 = 30
[15] unknown $15 = StoreLocal Reassign unknown z$33 = unknown $14
[14] unknown $44 = 30
[15] unknown $45 = StoreLocal Reassign unknown z$46 = unknown $44
[16] Goto bb3
bb3 (block)
predecessors: bb4, bb5
z$40: phi(bb4: z$32, bb5: z$33)
[17] Goto bb1
bb6 (block)
predecessors: bb0
[18] unknown $17 = 2
[19] unknown $18 = StoreLocal Reassign unknown x$34 = unknown $17
[18] unknown $47 = 2
[19] unknown $48 = StoreLocal Reassign unknown x$49 = unknown $47
[20] Goto bb1
bb1 (block)
predecessors: bb3, bb6
x$35: phi(bb3: x$31, bb6: x$34)
z$39: phi(bb3: z$40, bb6: z$30)
[21] unknown $20 = LoadLocal unknown x$35
[22] unknown $21 = 0
[23] unknown $22 = Binary unknown $20 + unknown $21
[24] unknown $23 = LoadLocal unknown z$39
[25] unknown $24 = Binary unknown $22 + unknown $23
[21] unknown $50 = LoadLocal unknown x$2
[22] unknown $51 = LoadLocal unknown y$5
[23] unknown $52 = Binary unknown $50 + unknown $51
[24] unknown $53 = LoadLocal unknown z$8
[25] unknown $54 = Binary unknown $52 + unknown $53
[26] Return unknown $24
@@ -18,17 +18,17 @@ function Component(
)
entry bb0
bb0 (block)
[0] unknown $1 = LoadGlobal useMemo
[1] unknown $14 = DeclareLocal Let unknown t$12
[0] unknown $11 = LoadGlobal useMemo
[1] unknown $20 = DeclareLocal Let unknown t$18
[2] Label block=bb1 fallthrough=bb6
bb1 (block)
predecessors: bb0
[3] unknown $2 = LoadGlobal y
[4] unknown $13 = StoreLocal Reassign unknown t$12 = unknown $2
[3] unknown $13 = LoadGlobal y
[4] unknown $19 = StoreLocal Reassign unknown t$18 = unknown $2
[5] Goto bb6
bb6 (block)
predecessors: bb1
[6] unknown $5 = LoadLocal unknown t$12
[7] unknown $7 = StoreLocal Const unknown x$11 = unknown $5
[8] unknown $8 = LoadLocal unknown x$11
[6] unknown $14 = LoadLocal unknown t$18
[7] unknown $15 = StoreLocal Const unknown x$16 = unknown $14
[8] unknown $17 = LoadLocal unknown x$6
[9] Return unknown $8
@@ -16,17 +16,20 @@ pub struct Instruction {
impl Instruction {
pub fn each_identifier_store<F>(&mut self, mut f: F) -> ()
where
F: FnMut(&mut LValue) -> (),
F: FnMut(&mut IdentifierOperand) -> (),
{
match &mut self.value {
InstructionValue::DeclareContext(instr) => {
f(&mut instr.lvalue);
f(&mut instr.lvalue.identifier);
}
InstructionValue::DeclareLocal(instr) => {
f(&mut instr.lvalue);
f(&mut instr.lvalue.identifier);
}
InstructionValue::StoreLocal(instr) => {
f(&mut instr.lvalue);
f(&mut instr.lvalue.identifier);
}
InstructionValue::Destructure(instr) => {
instr.pattern.each_operand(f);
}
InstructionValue::Array(_)
| InstructionValue::Binary(_)
@@ -43,18 +46,19 @@ impl Instruction {
pub fn try_each_identifier_store<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut LValue) -> Result<(), E>,
F: FnMut(&mut IdentifierOperand) -> Result<(), E>,
{
match &mut self.value {
InstructionValue::DeclareContext(instr) => {
f(&mut instr.lvalue)?;
f(&mut instr.lvalue.identifier)?;
}
InstructionValue::DeclareLocal(instr) => {
f(&mut instr.lvalue)?;
f(&mut instr.lvalue.identifier)?;
}
InstructionValue::StoreLocal(instr) => {
f(&mut instr.lvalue)?;
f(&mut instr.lvalue.identifier)?;
}
InstructionValue::Destructure(instr) => instr.pattern.try_each_operand(f)?,
InstructionValue::Array(_)
| InstructionValue::Binary(_)
| InstructionValue::Call(_)
@@ -73,21 +77,23 @@ impl Instruction {
where
F: FnMut(&mut IdentifierOperand) -> (),
{
match &mut self.value {
InstructionValue::LoadLocal(instr) => f(&mut instr.place),
InstructionValue::Array(_)
| InstructionValue::Binary(_)
| InstructionValue::Call(_)
| InstructionValue::DeclareContext(_)
| InstructionValue::DeclareLocal(_)
| InstructionValue::LoadContext(_)
| InstructionValue::LoadGlobal(_)
| InstructionValue::Primitive(_)
| InstructionValue::StoreLocal(_)
| InstructionValue::Function(_)
| InstructionValue::JSXElement(_)
| InstructionValue::Tombstone => {}
}
// match &mut self.value {
// InstructionValue::LoadLocal(instr) => f(&mut instr.place),
// InstructionValue::Array(_)
// | InstructionValue::Binary(_)
// | InstructionValue::Call(_)
// | InstructionValue::DeclareContext(_)
// | InstructionValue::DeclareLocal(_)
// | InstructionValue::Destructure(_)
// | InstructionValue::LoadContext(_)
// | InstructionValue::LoadGlobal(_)
// | InstructionValue::Primitive(_)
// | InstructionValue::StoreLocal(_)
// | InstructionValue::Function(_)
// | InstructionValue::JSXElement(_)
// | InstructionValue::Tombstone => {}
// }
self.each_operand(f);
}
pub fn each_operand<F>(&mut self, mut f: F) -> ()
@@ -139,6 +145,9 @@ impl Instruction {
}
}
}
InstructionValue::Destructure(value) => {
f(&mut value.value);
}
InstructionValue::DeclareContext(_)
| InstructionValue::LoadContext(_)
| InstructionValue::LoadGlobal(_)
@@ -162,7 +171,7 @@ pub enum InstructionValue {
// Debugger(Debugger),
DeclareContext(DeclareContext),
DeclareLocal(DeclareLocal),
// Destructure(Destructure),
Destructure(Destructure),
Function(FunctionExpression),
JSXElement(JSXElement),
// JsxFragment(JsxFragment),
@@ -272,6 +281,94 @@ pub enum JSXAttribute {
},
}
#[derive(Debug)]
pub struct Destructure {
pub kind: InstructionKind,
pub pattern: DestructurePattern,
pub value: IdentifierOperand,
}
#[derive(Debug)]
pub enum DestructurePattern {
Array(Vec<ArrayDestructureItem>),
Object(Vec<ObjectDestructureItem>),
}
impl DestructurePattern {
pub fn try_each_operand<E, F>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut IdentifierOperand) -> Result<(), E>,
{
match self {
Self::Array(elements) => {
for item in elements {
match item {
ArrayDestructureItem::Hole => { /* no-op */ }
ArrayDestructureItem::Value(item) => f(item)?,
ArrayDestructureItem::Spread(item) => f(item)?,
}
}
}
Self::Object(properties) => {
for property in properties {
match property {
ObjectDestructureItem::Property(property) => {
f(&mut property.value)?;
}
ObjectDestructureItem::Spread(property) => f(property)?,
}
}
}
}
Ok(())
}
pub fn each_operand<F>(&mut self, mut f: F) -> ()
where
F: FnMut(&mut IdentifierOperand) -> (),
{
match self {
Self::Array(elements) => {
for item in elements {
match item {
ArrayDestructureItem::Hole => { /* no-op */ }
ArrayDestructureItem::Value(item) => f(item),
ArrayDestructureItem::Spread(item) => f(item),
}
}
}
Self::Object(properties) => {
for property in properties {
match property {
ObjectDestructureItem::Property(property) => {
f(&mut property.value);
}
ObjectDestructureItem::Spread(property) => f(property),
}
}
}
}
}
}
#[derive(Debug)]
pub enum ArrayDestructureItem {
Hole,
Value(IdentifierOperand),
Spread(IdentifierOperand),
}
#[derive(Debug)]
pub enum ObjectDestructureItem {
Property(ObjectDestructureProperty),
Spread(IdentifierOperand),
}
#[derive(Debug)]
pub struct ObjectDestructureProperty {
pub name: String,
pub value: IdentifierOperand,
}
#[derive(Clone, Debug)]
pub struct IdentifierOperand {
pub identifier: Identifier,
+57 -2
View File
@@ -4,8 +4,9 @@ use forget_estree::JsValue;
use forget_utils::ensure_sufficient_stack;
use crate::{
BasicBlock, Function, Identifier, IdentifierOperand, Instruction, InstructionValue, LValue,
Phi, PlaceOrSpread, Terminal, TerminalValue, HIR,
ArrayDestructureItem, BasicBlock, DestructurePattern, Function, Identifier, IdentifierOperand,
Instruction, InstructionValue, LValue, ObjectDestructureItem, Phi, PlaceOrSpread, Terminal,
TerminalValue, HIR,
};
/// Trait for HIR types to describe how they print themselves.
@@ -205,6 +206,12 @@ impl Print for InstructionValue {
.collect();
write!(out, "{}", lines.join("\n"))?;
}
InstructionValue::Destructure(value) => {
write!(out, "Destructure ")?;
value.pattern.print(hir, out)?;
write!(out, " = ")?;
value.value.print(hir, out)?;
}
InstructionValue::Tombstone => {
write!(out, "Tombstone!")?;
}
@@ -262,6 +269,54 @@ impl Print for Identifier {
}
}
impl Print for DestructurePattern {
fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
match self {
DestructurePattern::Array(items) => {
write!(out, "[ ")?;
for (index, item) in items.iter().enumerate() {
if index != 0 {
write!(out, ", ")?;
}
match item {
ArrayDestructureItem::Hole => {
write!(out, "<hole>")?;
}
ArrayDestructureItem::Value(item) => {
item.print(hir, out)?;
}
ArrayDestructureItem::Spread(item) => {
write!(out, "...")?;
item.print(hir, out)?;
}
}
}
write!(out, " ]")?;
}
DestructurePattern::Object(properties) => {
write!(out, "{{ ")?;
for (index, property) in properties.iter().enumerate() {
if index != 0 {
write!(out, ", ")?;
}
match property {
ObjectDestructureItem::Property(property) => {
write!(out, "{}: ", &property.name)?;
property.value.print(hir, out)?;
}
ObjectDestructureItem::Spread(property) => {
write!(out, "...")?;
property.print(hir, out)?;
}
}
}
write!(out, " }}")?;
}
}
Ok(())
}
}
impl Print for Terminal {
fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
write!(out, " {} ", self.id)?;
@@ -6,7 +6,8 @@ use forget_estree::{
};
use crate::{
AstNode, DeclarationKind, LabelId, LabelKind, ReferenceKind, ScopeId, ScopeKind, ScopeManager,
AstNode, DeclarationKind, Label, LabelId, LabelKind, ReferenceKind, ScopeId, ScopeKind,
ScopeManager,
};
pub fn analyze(ast: &Program) -> ScopeManager {
@@ -43,18 +44,18 @@ impl Analyzer {
assert_eq!(last, id);
}
fn lookup_break(&self, name: Option<&str>) -> Option<LabelId> {
fn lookup_break(&self, name: Option<&str>) -> Option<&Label> {
for id in self.labels.iter().rev() {
let label = self.manager.label(*id);
match (name, &label.name) {
// If this is a labeled break, only return if an exact match
// is in scope
(Some(name), Some(label_name)) if name == label_name => {
return Some(label.id);
return Some(label);
}
// If this is an unlabeld break, return the innermost label id
(None, _) => {
return Some(label.id);
return Some(label);
}
_ => { /* no-op */ }
}
@@ -62,22 +63,18 @@ impl Analyzer {
None
}
fn lookup_continue(&self, name: Option<&str>) -> Option<LabelId> {
fn lookup_continue(&self, name: Option<&str>) -> Option<&Label> {
for id in self.labels.iter().rev() {
let label = self.manager.label(*id);
// Skip labels that are not for loops, can only continue to a loop
if label.kind != LabelKind::Loop {
continue;
}
match (name, &label.name) {
// If this is a labeled break, only return if an exact match
// is in scope
(Some(name), Some(label_name)) if &name == label_name => {
return Some(label.id);
return Some(label);
}
// If this is an unlabeld break, return the innermost label id
(None, _) => {
return Some(label.id);
return Some(label);
}
_ => { /* no-op */ }
}
@@ -425,16 +422,14 @@ impl Visitor for Analyzer {
}
fn visit_break_statement(&mut self, ast: &forget_estree::BreakStatement) {
if let Some(label_id) =
self.lookup_break(ast.label.as_ref().map(|ident| ident.name.as_str()))
if let Some(label) = self.lookup_break(ast.label.as_ref().map(|ident| ident.name.as_str()))
{
self.manager
.node_labels
.insert(AstNode::from(ast), label_id);
let id = label.id;
self.manager.node_labels.insert(AstNode::from(ast), id);
if let Some(label_node) = &ast.label {
self.manager
.node_labels
.insert(AstNode::from(label_node), label_id);
.insert(AstNode::from(label_node), id);
}
} else {
self.manager.diagnostics.push(Diagnostic::invalid_syntax(
@@ -462,21 +457,31 @@ impl Visitor for Analyzer {
}
fn visit_continue_statement(&mut self, ast: &forget_estree::ContinueStatement) {
if let Some(label_id) =
let range = ast
.label
.as_ref()
.map(|label| label.range)
.unwrap_or(ast.range);
if let Some(label) =
self.lookup_continue(ast.label.as_ref().map(|ident| ident.name.as_str()))
{
self.manager
.node_labels
.insert(AstNode::from(ast), label_id);
let id = label.id;
if label.kind != LabelKind::Loop {
self.manager.diagnostics.push(Diagnostic::invalid_syntax(
"Invalid continue statement, the named label must be for a loop",
range,
));
}
self.manager.node_labels.insert(AstNode::from(ast), id);
if let Some(label_node) = &ast.label {
self.manager
.node_labels
.insert(AstNode::from(label_node), label_id);
.insert(AstNode::from(label_node), id);
}
} else {
self.manager.diagnostics.push(Diagnostic::invalid_syntax(
"Non-syntactic continue, could not resolve continue target",
ast.range,
range,
));
}
}
@@ -70,9 +70,7 @@ pub fn eliminate_redundant_phis(env: &Environment, fun: &mut Function) {
for instr_ix in block.instructions.iter() {
let instr = &mut hir.instructions[usize::from(*instr_ix)];
instr.each_identifier_store(|store| {
rewrite(&rewrites, &mut store.identifier.identifier)
});
instr.each_identifier_store(|store| rewrite(&rewrites, &mut store.identifier));
instr.each_identifier_load(|load| rewrite(&rewrites, &mut load.identifier));
if let InstructionValue::Function(fun) = &mut instr.value {
@@ -47,6 +47,7 @@ fn visit_instructions<'e, 'f>(
builder.each_block(|block, builder| {
for instr_ix in &block.instructions {
let instr = &mut instructions[usize::from(*instr_ix)];
builder.visit_store(&mut instr.lvalue)?;
instr.try_each_identifier_store(|store| builder.visit_store(store))?;
instr.each_identifier_load(|load| builder.visit_load(load));
@@ -139,8 +140,8 @@ impl<'e, 'f> Builder<'e, 'f> {
self.env.next_identifier_id()
}
fn visit_store(&mut self, lvalue: &mut LValue) -> Result<(), Diagnostic> {
let old_identifier = &lvalue.identifier.identifier;
fn visit_store(&mut self, lvalue: &mut IdentifierOperand) -> Result<(), Diagnostic> {
let old_identifier = &lvalue.identifier;
// TODO: use Result (?)
invariant(!self.unknown.contains(&old_identifier.id), || {
Diagnostic::invariant(
@@ -151,14 +152,14 @@ impl<'e, 'f> Builder<'e, 'f> {
if self.context.contains(&old_identifier.id) {
let new_identifier = self.get_id_at(self.current, old_identifier);
lvalue.identifier.identifier = new_identifier;
lvalue.identifier = new_identifier;
return Ok(());
}
let new_identifier = self.make_identifier(old_identifier);
let state = self.states.get_mut(&self.current).unwrap();
state.defs.insert(old_identifier.id, new_identifier.clone());
lvalue.identifier.identifier = new_identifier;
lvalue.identifier = new_identifier;
Ok(())
}