range support

This commit is contained in:
Devyn Cairns 2024-06-26 19:15:44 -07:00
parent 69b2d00756
commit 2202118efb
No known key found for this signature in database

View File

@ -252,7 +252,18 @@ fn compile_expression(
in_reg: Option<RegId>, in_reg: Option<RegId>,
out_reg: RegId, out_reg: RegId,
) -> Result<(), CompileError> { ) -> Result<(), CompileError> {
let drop_input = |builder: &mut BlockBuilder| {
if let Some(in_reg) = in_reg {
if in_reg != out_reg {
builder.drop_reg(in_reg)?;
}
}
Ok(())
};
let lit = |builder: &mut BlockBuilder, literal: Literal| { let lit = |builder: &mut BlockBuilder, literal: Literal| {
drop_input(builder)?;
builder builder
.push( .push(
Instruction::LoadLiteral { Instruction::LoadLiteral {
@ -265,11 +276,7 @@ fn compile_expression(
}; };
let ignore = |builder: &mut BlockBuilder| { let ignore = |builder: &mut BlockBuilder| {
if let Some(in_reg) = in_reg { drop_input(builder)?;
if in_reg != out_reg {
builder.drop_reg(in_reg)?;
}
}
builder.load_empty(out_reg) builder.load_empty(out_reg)
}; };
@ -281,16 +288,56 @@ fn compile_expression(
let data_slice = builder.data(bin)?; let data_slice = builder.data(bin)?;
lit(builder, Literal::Binary(data_slice)) lit(builder, Literal::Binary(data_slice))
} }
Expr::Range(_) => Err(CompileError::Todo("Range")), Expr::Range(range) => {
Expr::Var(var_id) => builder // Compile the subexpressions of the range
.push( let compile_part = |builder: &mut BlockBuilder,
part_expr: Option<&Expression>|
-> Result<RegId, CompileError> {
let reg = builder.next_register()?;
if let Some(part_expr) = part_expr {
compile_expression(
working_set,
builder,
part_expr,
redirect_modes.with_capture_out(part_expr.span),
None,
reg,
)?;
} else {
builder.load_literal(reg, Literal::Nothing.into_spanned(expr.span))?;
}
Ok(reg)
};
drop_input(builder)?;
let start = compile_part(builder, range.from.as_ref())?;
let step = compile_part(builder, range.next.as_ref())?;
let end = compile_part(builder, range.to.as_ref())?;
// Assemble the range
builder.load_literal(
out_reg,
Literal::Range {
start,
step,
end,
inclusion: range.operator.inclusion,
}
.into_spanned(expr.span),
)
}
Expr::Var(var_id) => {
drop_input(builder)?;
builder.push(
Instruction::LoadVariable { Instruction::LoadVariable {
dst: out_reg, dst: out_reg,
var_id: *var_id, var_id: *var_id,
} }
.into_spanned(expr.span), .into_spanned(expr.span),
) )?;
.map(|_| ()), Ok(())
}
Expr::VarDecl(_) => Err(CompileError::Todo("VarDecl")), Expr::VarDecl(_) => Err(CompileError::Todo("VarDecl")),
Expr::Call(call) => { Expr::Call(call) => {
// Ensure that out_reg contains the input value, because a call only uses one register // Ensure that out_reg contains the input value, because a call only uses one register
@ -316,10 +363,7 @@ fn compile_expression(
Expr::Operator(_) => Err(CompileError::Todo("Operator")), Expr::Operator(_) => Err(CompileError::Todo("Operator")),
Expr::RowCondition(_) => Err(CompileError::Todo("RowCondition")), Expr::RowCondition(_) => Err(CompileError::Todo("RowCondition")),
Expr::UnaryNot(subexpr) => { Expr::UnaryNot(subexpr) => {
if let Some(in_reg) = in_reg { drop_input(builder)?;
// Discard the input
builder.drop_reg(in_reg)?;
}
compile_expression( compile_expression(
working_set, working_set,
builder, builder,
@ -333,10 +377,7 @@ fn compile_expression(
} }
Expr::BinaryOp(lhs, op, rhs) => { Expr::BinaryOp(lhs, op, rhs) => {
if let Expr::Operator(ref operator) = op.expr { if let Expr::Operator(ref operator) = op.expr {
if let Some(in_reg) = in_reg { drop_input(builder)?;
// Discard the input
builder.drop_reg(in_reg)?;
}
compile_binary_op( compile_binary_op(
working_set, working_set,
builder, builder,
@ -1081,7 +1122,46 @@ impl BlockBuilder {
/// Returns the offset of the inserted instruction. /// Returns the offset of the inserted instruction.
fn push(&mut self, instruction: Spanned<Instruction>) -> Result<usize, CompileError> { fn push(&mut self, instruction: Spanned<Instruction>) -> Result<usize, CompileError> {
match &instruction.item { match &instruction.item {
Instruction::LoadLiteral { dst, lit: _ } => self.mark_register(*dst)?, Instruction::LoadLiteral { dst, lit } => {
self.mark_register(*dst)?;
// Free any registers on the literal
match lit {
Literal::Range {
start,
step,
end,
inclusion: _,
} => {
self.free_register(*start)?;
self.free_register(*step)?;
self.free_register(*end)?;
}
Literal::Bool(_)
| Literal::Int(_)
| Literal::Float(_)
| Literal::Binary(_)
| Literal::Block(_)
| Literal::Closure(_)
| Literal::List { capacity: _ }
| Literal::Record { capacity: _ }
| Literal::Filepath {
val: _,
no_expand: _,
}
| Literal::Directory {
val: _,
no_expand: _,
}
| Literal::GlobPattern {
val: _,
no_expand: _,
}
| Literal::String(_)
| Literal::RawString(_)
| Literal::CellPath(_)
| Literal::Nothing => (),
}
}
Instruction::Move { dst, src } => { Instruction::Move { dst, src } => {
self.free_register(*src)?; self.free_register(*src)?;
self.mark_register(*dst)?; self.mark_register(*dst)?;