instructions: list-spread, record-spread
This commit is contained in:
parent
ed59f80b35
commit
73b092bfdc
|
@ -344,42 +344,37 @@ fn compile_expression(
|
|||
},
|
||||
)?;
|
||||
for item in items {
|
||||
// Compile the expression of the item / spread
|
||||
let reg = builder.next_register()?;
|
||||
let expr = match item {
|
||||
ListItem::Item(expr) | ListItem::Spread(_, expr) => expr,
|
||||
};
|
||||
compile_expression(
|
||||
working_set,
|
||||
builder,
|
||||
expr,
|
||||
redirect_modes.with_capture_out(expr.span),
|
||||
None,
|
||||
reg,
|
||||
)?;
|
||||
|
||||
match item {
|
||||
ListItem::Item(expr) => {
|
||||
// Add each item using push-list
|
||||
let item_reg = builder.next_register()?;
|
||||
compile_expression(
|
||||
working_set,
|
||||
builder,
|
||||
expr,
|
||||
redirect_modes.with_capture_out(expr.span),
|
||||
None,
|
||||
item_reg,
|
||||
)?;
|
||||
ListItem::Item(_) => {
|
||||
// Add each item using list-push
|
||||
builder.push(
|
||||
Instruction::ListPush {
|
||||
src_dst: out_reg,
|
||||
item: item_reg,
|
||||
item: reg,
|
||||
}
|
||||
.into_spanned(expr.span),
|
||||
)?;
|
||||
}
|
||||
ListItem::Spread(spread_span, expr) => {
|
||||
// Implement a spread as a ++ binary operation
|
||||
let rhs_reg = builder.next_register()?;
|
||||
compile_expression(
|
||||
working_set,
|
||||
builder,
|
||||
expr,
|
||||
redirect_modes.with_capture_out(expr.span),
|
||||
None,
|
||||
rhs_reg,
|
||||
)?;
|
||||
// Spread the list using list-spread
|
||||
builder.push(
|
||||
Instruction::BinaryOp {
|
||||
lhs_dst: out_reg,
|
||||
op: Operator::Math(Math::Append),
|
||||
rhs: rhs_reg,
|
||||
Instruction::ListSpread {
|
||||
src_dst: out_reg,
|
||||
items: reg,
|
||||
}
|
||||
.into_spanned(*spread_span),
|
||||
)?;
|
||||
|
@ -471,7 +466,7 @@ fn compile_expression(
|
|||
working_set,
|
||||
builder,
|
||||
key,
|
||||
redirect_modes.with_capture_out(expr.span),
|
||||
redirect_modes.with_capture_out(key.span),
|
||||
None,
|
||||
key_reg,
|
||||
)?;
|
||||
|
@ -479,7 +474,7 @@ fn compile_expression(
|
|||
working_set,
|
||||
builder,
|
||||
val,
|
||||
redirect_modes.with_capture_out(expr.span),
|
||||
redirect_modes.with_capture_out(val.span),
|
||||
None,
|
||||
val_reg,
|
||||
)?;
|
||||
|
@ -493,7 +488,23 @@ fn compile_expression(
|
|||
)?;
|
||||
}
|
||||
RecordItem::Spread(spread_span, expr) => {
|
||||
return Err(CompileError::Todo("Record with spread"))
|
||||
// Spread the expression using record-spread
|
||||
let reg = builder.next_register()?;
|
||||
compile_expression(
|
||||
working_set,
|
||||
builder,
|
||||
expr,
|
||||
redirect_modes.with_capture_out(expr.span),
|
||||
None,
|
||||
reg,
|
||||
)?;
|
||||
builder.push(
|
||||
Instruction::RecordSpread {
|
||||
src_dst: out_reg,
|
||||
items: reg,
|
||||
}
|
||||
.into_spanned(*spread_span),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -923,6 +934,7 @@ impl BlockBuilder {
|
|||
src_dst: _,
|
||||
} => (),
|
||||
Instruction::ListPush { src_dst: _, item } => self.free_register(*item)?,
|
||||
Instruction::ListSpread { src_dst: _, items } => self.free_register(*items)?,
|
||||
Instruction::RecordInsert {
|
||||
src_dst: _,
|
||||
key,
|
||||
|
@ -931,6 +943,7 @@ impl BlockBuilder {
|
|||
self.free_register(*key)?;
|
||||
self.free_register(*val)?;
|
||||
}
|
||||
Instruction::RecordSpread { src_dst: _, items } => self.free_register(*items)?,
|
||||
Instruction::BinaryOp {
|
||||
lhs_dst: _,
|
||||
op: _,
|
||||
|
|
|
@ -304,6 +304,20 @@ fn eval_instruction(
|
|||
ctx.put_reg(*src_dst, Value::list(list, list_span).into_pipeline_data());
|
||||
Ok(Continue)
|
||||
}
|
||||
Instruction::ListSpread { src_dst, items } => {
|
||||
let list_value = ctx.collect_reg(*src_dst, *span)?;
|
||||
let items = ctx.collect_reg(*items, *span)?;
|
||||
let list_span = list_value.span();
|
||||
let items_span = items.span();
|
||||
let mut list = list_value.into_list()?;
|
||||
list.extend(
|
||||
items
|
||||
.into_list()
|
||||
.map_err(|_| ShellError::CannotSpreadAsList { span: items_span })?,
|
||||
);
|
||||
ctx.put_reg(*src_dst, Value::list(list, list_span).into_pipeline_data());
|
||||
Ok(Continue)
|
||||
}
|
||||
Instruction::RecordInsert { src_dst, key, val } => {
|
||||
let record_value = ctx.collect_reg(*src_dst, *span)?;
|
||||
let key = ctx.collect_reg(*key, *span)?;
|
||||
|
@ -317,6 +331,25 @@ fn eval_instruction(
|
|||
);
|
||||
Ok(Continue)
|
||||
}
|
||||
Instruction::RecordSpread { src_dst, items } => {
|
||||
let record_value = ctx.collect_reg(*src_dst, *span)?;
|
||||
let items = ctx.collect_reg(*items, *span)?;
|
||||
let record_span = record_value.span();
|
||||
let items_span = items.span();
|
||||
let mut record = record_value.into_record()?;
|
||||
// Not using .extend() here because it doesn't handle duplicates
|
||||
for (key, val) in items
|
||||
.into_record()
|
||||
.map_err(|_| ShellError::CannotSpreadAsRecord { span: items_span })?
|
||||
{
|
||||
record.insert(key, val);
|
||||
}
|
||||
ctx.put_reg(
|
||||
*src_dst,
|
||||
Value::record(record, record_span).into_pipeline_data(),
|
||||
);
|
||||
Ok(Continue)
|
||||
}
|
||||
Instruction::BinaryOp { lhs_dst, op, rhs } => binary_op(ctx, *lhs_dst, op, *rhs, *span),
|
||||
Instruction::FollowCellPath { src_dst, path } => {
|
||||
let data = ctx.take_reg(*src_dst);
|
||||
|
|
|
@ -115,9 +115,15 @@ impl<'a> fmt::Display for FmtInstruction<'a> {
|
|||
Instruction::ListPush { src_dst, item } => {
|
||||
write!(f, "{:WIDTH$} {src_dst}, {item}", "list-push")
|
||||
}
|
||||
Instruction::ListSpread { src_dst, items } => {
|
||||
write!(f, "{:WIDTH$} {src_dst}, {items}", "list-spread")
|
||||
}
|
||||
Instruction::RecordInsert { src_dst, key, val } => {
|
||||
write!(f, "{:WIDTH$} {src_dst}, {key}, {val}", "record-insert")
|
||||
}
|
||||
Instruction::RecordSpread { src_dst, items } => {
|
||||
write!(f, "{:WIDTH$} {src_dst}, {items}", "record-spread")
|
||||
}
|
||||
Instruction::BinaryOp { lhs_dst, op, rhs } => {
|
||||
write!(f, "{:WIDTH$} {lhs_dst}, {op:?}, {rhs}", "binary-op")
|
||||
}
|
||||
|
|
|
@ -90,12 +90,18 @@ pub enum Instruction {
|
|||
Call { decl_id: DeclId, src_dst: RegId },
|
||||
/// Push a value onto the end of a list. Used to construct list literals.
|
||||
ListPush { src_dst: RegId, item: RegId },
|
||||
/// Insert a key-value pair into a record. Any existing value for the key is overwritten.
|
||||
/// Spread a value onto the end of a list. Used to construct list literals.
|
||||
ListSpread { src_dst: RegId, items: RegId },
|
||||
/// Insert a key-value pair into a record. Used to construct record literals. Any existing value
|
||||
/// for the key is overwritten.
|
||||
RecordInsert {
|
||||
src_dst: RegId,
|
||||
key: RegId,
|
||||
val: RegId,
|
||||
},
|
||||
/// Spread a record onto a record. Used to construct record literals. Any existing value for the
|
||||
/// key is overwritten.
|
||||
RecordSpread { src_dst: RegId, items: RegId },
|
||||
/// Do a binary operation on `lhs_dst` (left) and `rhs` (right) and write the result to
|
||||
/// `lhs_dst`.
|
||||
BinaryOp {
|
||||
|
|
Loading…
Reference in New Issue
Block a user