6
};
7
use hir::{
8
ArrayElement, BlockKind, BranchTerminal, Environment, ForTerminal, Function, GotoKind,
9
- Identifier, InstructionKind, InstructionValue, LValue, LoadGlobal, LoadLocal, Place,
10
- PrimitiveValue, TerminalValue,
9
+ Identifier, IdentifierOperand, InstrIx, InstructionKind, InstructionValue, LValue, LoadGlobal,
10
+ LoadLocal, Operand, PrimitiveValue, TerminalValue,
11
};
12
13
use crate::{
33
lower_block_statement(environment, &mut builder, *body, None)?
34
}
35
Some(estree::FunctionBody::Expression(body)) => {
36
- lower_expression_to_temporary(environment, &mut builder, body)?;
36
+ lower_expression(environment, &mut builder, body)?;
37
}
38
None => {
39
return Err(BuildDiagnostic::new(
56
);
57
builder.terminate(
58
TerminalValue::Return(hir::ReturnTerminal {
59
- value: implicit_return_value,
59
+ value: Operand {
60
+ ix: implicit_return_value,
61
+ effect: None,
62
+ },
63
}),
64
hir::BlockKind::Block,
65
);
117
);
118
}
119
Statement::ReturnStatement(stmt) => {
117
- let value = match stmt.argument {
118
- Some(argument) => lower_expression_to_temporary(env, builder, argument)?,
120
+ let ix = match stmt.argument {
121
+ Some(argument) => lower_expression(env, builder, argument)?,
122
None => lower_value_to_temporary(
123
env,
124
builder,
128
),
129
};
130
builder.terminate(
128
- TerminalValue::Return(hir::ReturnTerminal { value }),
131
+ TerminalValue::Return(hir::ReturnTerminal {
132
+ value: Operand { ix, effect: None },
133
+ }),
134
BlockKind::Block,
135
);
136
}
137
Statement::ExpressionStatement(stmt) => {
133
- lower_expression_to_temporary(env, builder, stmt.expression)?;
138
+ lower_expression(env, builder, stmt.expression)?;
139
}
140
Statement::EmptyStatement(_) => {
141
// no-op
154
};
155
for declaration in stmt.declarations {
156
if let Some(init) = declaration.init {
152
- let value = lower_expression_to_temporary(env, builder, init)?;
157
+ let value = lower_expression(env, builder, init)?;
158
lower_assignment(
159
env,
160
builder,
176
));
177
}
178
};
174
- let place = Place {
175
- effect: None,
176
- identifier,
177
- };
179
lower_value_to_temporary(
180
env,
181
builder,
182
InstructionValue::DeclareLocal(hir::DeclareLocal {
182
- lvalue: LValue { place, kind },
183
+ lvalue: LValue {
184
+ identifier: IdentifierOperand {
185
+ identifier,
186
+ effect: None,
187
+ },
188
+ kind,
189
+ },
190
}),
191
);
192
}
223
}))
224
})?;
225
219
- let test = lower_expression_to_temporary(env, builder, test)?;
226
+ let test = lower_expression(env, builder, test)?;
227
let terminal = TerminalValue::If(hir::IfTerminal {
221
- test,
228
+ test: Operand {
229
+ ix: test,
230
+ effect: None,
231
+ },
232
consequent: consequent_block,
233
alternate: alternate_block,
234
fallthrough: Some(fallthrough_block.id),
269
let update_block = update
270
.map(|update| {
271
builder.enter(BlockKind::Loop, |builder| {
262
- lower_expression_to_temporary(env, builder, update)?;
272
+ lower_expression(env, builder, update)?;
273
Ok(TerminalValue::Goto(hir::GotoTerminal {
274
block: test_block.id,
275
kind: GotoKind::Break,
303
builder.terminate_with_fallthrough(terminal, test_block);
304
305
if let Some(test) = test {
296
- let test_value = lower_expression_to_temporary(env, builder, test)?;
306
+ let test_value = lower_expression(env, builder, test)?;
307
let terminal = TerminalValue::Branch(BranchTerminal {
298
- test: test_value,
308
+ test: Operand {
309
+ ix: test_value,
310
+ effect: None,
311
+ },
312
consequent: body_block,
313
alternate: fallthrough_block.id,
314
});
326
Ok(())
327
}
328
316
-/// Shortcut for lowering an expression and saving the result to a temporary
317
-fn lower_expression_to_temporary<'a>(
318
- env: &'a Environment<'a>,
319
- builder: &mut Builder<'a>,
320
- expr: Expression,
321
-) -> Result<Place<'a>, BuildDiagnostic> {
322
- let value = lower_expression(env, builder, expr)?;
323
- Ok(lower_value_to_temporary(env, builder, value))
324
-}
325
-
329
/// Converts an ESTree Expression into an HIR InstructionValue. Note that while only a single
330
/// InstructionValue is returned, this function is recursive and may cause multiple instructions
331
/// to be emitted, possibly across multiple basic blocks (in the case of expressions with control
334
env: &'a Environment<'a>,
335
builder: &mut Builder<'a>,
336
expr: Expression,
334
-) -> Result<InstructionValue<'a>, BuildDiagnostic> {
335
- Ok(match expr {
337
+) -> Result<InstrIx, BuildDiagnostic> {
338
+ let value = match expr {
339
Expression::Identifier(expr) => {
340
// TODO: handle unbound variables
341
let binding = builder.resolve_binding(&expr)?;
342
match binding {
343
Binding::Local(identifier) => {
341
- let place = Place {
344
+ let place = IdentifierOperand {
345
effect: None,
346
identifier,
347
};
360
for expr in expr.elements {
361
let element = match expr {
362
Some(estree::ExpressionOrSpread::SpreadElement(expr)) => {
360
- Some(ArrayElement::Spread(lower_expression_to_temporary(
361
- env,
362
- builder,
363
- expr.argument,
364
- )?))
363
+ Some(ArrayElement::Spread(Operand {
364
+ ix: lower_expression(env, builder, expr.argument)?,
365
+ effect: None,
366
+ }))
367
+ }
368
+ Some(estree::ExpressionOrSpread::Expression(expr)) => {
369
+ Some(ArrayElement::Place(Operand {
370
+ ix: lower_expression(env, builder, expr)?,
371
+ effect: None,
372
+ }))
373
}
366
- Some(estree::ExpressionOrSpread::Expression(expr)) => Some(
367
- ArrayElement::Place(lower_expression_to_temporary(env, builder, expr)?),
368
- ),
374
None => None,
375
};
376
elements.push(element);
380
381
Expression::AssignmentExpression(expr) => match expr.operator {
382
estree::AssignmentOperator::Equals => {
378
- let right = lower_expression_to_temporary(env, builder, expr.right)?;
379
- lower_assignment(env, builder, InstructionKind::Reassign, expr.left, right)?
383
+ let right = lower_expression(env, builder, expr.right)?;
384
+ return Ok(lower_assignment(
385
+ env,
386
+ builder,
387
+ InstructionKind::Reassign,
388
+ expr.left,
389
+ right,
390
+ )?);
391
}
392
_ => todo!("lower assignment expr {:#?}", expr),
393
},
399
right,
400
..
401
} = *expr;
391
- let left = lower_expression_to_temporary(env, builder, left)?;
392
- let right = lower_expression_to_temporary(env, builder, right)?;
402
+ let left = lower_expression(env, builder, left)?;
403
+ let right = lower_expression(env, builder, right)?;
404
InstructionValue::Binary(hir::Binary {
394
- left,
405
+ left: Operand {
406
+ ix: left,
407
+ effect: None,
408
+ },
409
operator,
396
- right,
410
+ right: Operand {
411
+ ix: right,
412
+ effect: None,
413
+ },
414
})
415
}
416
417
_ => todo!("Lower expr {expr:#?}"),
401
- })
418
+ };
419
+ Ok(builder.push(value))
420
}
421
422
fn lower_assignment<'a>(
424
builder: &mut Builder<'a>,
425
kind: InstructionKind,
426
lvalue: AssignmentTarget,
409
- value: Place<'a>,
410
-) -> Result<InstructionValue<'a>, BuildDiagnostic> {
427
+ value: InstrIx,
428
+) -> Result<InstrIx, BuildDiagnostic> {
429
Ok(match lvalue {
430
AssignmentTarget::Pattern(lvalue) => match lvalue {
431
Pattern::Identifier(lvalue) => {
414
- let place = lower_identifier_for_assignment(env, builder, kind, *lvalue)?;
415
- let temporary = lower_value_to_temporary(
432
+ let identifier = lower_identifier_for_assignment(env, builder, kind, *lvalue)?;
433
+ lower_value_to_temporary(
434
env,
435
builder,
436
InstructionValue::StoreLocal(hir::StoreLocal {
419
- lvalue: LValue { place, kind },
420
- value,
437
+ lvalue: LValue { identifier, kind },
438
+ value: Operand {
439
+ ix: value,
440
+ effect: None,
441
+ },
442
}),
422
- );
423
- InstructionValue::LoadLocal(LoadLocal { place: temporary })
443
+ )
444
}
445
_ => todo!("lower assignment pattern for {:#?}", lvalue),
446
},
453
builder: &mut Builder<'a>,
454
_kind: InstructionKind,
455
identifier: estree::Identifier,
436
-) -> Result<Place<'a>, BuildDiagnostic> {
456
+) -> Result<IdentifierOperand<'a>, BuildDiagnostic> {
457
let binding = builder.resolve_binding(&identifier)?;
458
match binding {
459
Binding::Module(..) | Binding::Global => Err(BuildDiagnostic::new(
461
ErrorSeverity::InvalidReact,
462
identifier.range,
463
)),
444
- Binding::Local(id) => Ok(Place {
464
+ Binding::Local(id) => Ok(IdentifierOperand {
465
identifier: id,
466
effect: None,
467
}),
477
env: &'a Environment<'a>,
478
builder: &mut Builder<'a>,
479
value: InstructionValue<'a>,
460
-) -> Place<'a> {
461
- if let InstructionValue::LoadLocal(LoadLocal {
462
- place:
463
- place @ Place {
464
- identifier: Identifier { name: None, .. },
465
- ..
466
- },
467
- }) = value
468
- {
469
- return place;
470
- }
471
- let place = build_temporary_place(env, builder);
472
- builder.push(place.clone(), value);
473
- return place;
480
+) -> InstrIx {
481
+ // if let InstructionValue::LoadLocal(LoadLocal {
482
+ // place:
483
+ // place @ Operand {
484
+ // identifier: Identifier { name: None, .. },
485
+ // ..
486
+ // },
487
+ // }) = value
488
+ // {
489
+ // return place;
490
+ // }
491
+ builder.push(value)
492
}
493
494
/// Constructs a temporary Identifier and Place wrapper, which can be used as an Instruction lvalue
495
/// or other places where a temporary target is required
478
-fn build_temporary_place<'a>(_env: &'a Environment<'a>, builder: &mut Builder<'a>) -> Place<'a> {
479
- Place {
496
+fn build_temporary_place<'a>(
497
+ _env: &'a Environment<'a>,
498
+ builder: &mut Builder<'a>,
499
+) -> IdentifierOperand<'a> {
500
+ IdentifierOperand {
501
identifier: builder.make_temporary(),
502
effect: None,
503
}