it does calls!!!

This commit is contained in:
Devyn Cairns 2024-06-18 22:16:21 -07:00
parent b0d24ea434
commit 3c4877b059
2 changed files with 93 additions and 15 deletions

View File

@ -1,9 +1,9 @@
use nu_protocol::{ use nu_protocol::{
ast::{Bits, Block, Boolean, CellPath, Comparison, Math, Operator}, ast::{Bits, Block, Boolean, CellPath, Comparison, Math, Operator},
debugger::DebugContext, debugger::DebugContext,
engine::{Closure, EngineState, Stack}, engine::{Argument, Closure, EngineState, Stack},
ir::{Instruction, IrBlock, Literal}, ir::{Call, Instruction, IrBlock, Literal},
PipelineData, RegId, ShellError, Span, Value, DeclId, PipelineData, RegId, ShellError, Span, Value,
}; };
/// Evaluate the compiled representation of a [`Block`]. /// Evaluate the compiled representation of a [`Block`].
@ -18,12 +18,14 @@ pub fn eval_ir_block<D: DebugContext>(
let block_span = block.span; let block_span = block.span;
let args_base = stack.argument_stack.get_base();
let mut registers = stack.register_buf_cache.acquire(ir_block.register_count); let mut registers = stack.register_buf_cache.acquire(ir_block.register_count);
let result = eval_ir_block_impl::<D>( let result = eval_ir_block_impl::<D>(
&mut EvalContext { &mut EvalContext {
engine_state, engine_state,
stack, stack,
args_base,
registers: &mut registers[..], registers: &mut registers[..],
}, },
&block_span, &block_span,
@ -52,6 +54,8 @@ pub fn eval_ir_block<D: DebugContext>(
struct EvalContext<'a> { struct EvalContext<'a> {
engine_state: &'a EngineState, engine_state: &'a EngineState,
stack: &'a mut Stack, stack: &'a mut Stack,
/// Base index on the argument stack to reset to after a call
args_base: usize,
registers: &'a mut [PipelineData], registers: &'a mut [PipelineData],
} }
@ -66,6 +70,13 @@ impl<'a> EvalContext<'a> {
fn take_reg(&mut self, reg_id: RegId) -> PipelineData { fn take_reg(&mut self, reg_id: RegId) -> PipelineData {
self.put_reg(reg_id, PipelineData::Empty) self.put_reg(reg_id, PipelineData::Empty)
} }
/// Take and implicitly collect a register to a value
fn collect_reg(&mut self, reg_id: RegId) -> Result<Value, ShellError> {
let pipeline_data = self.take_reg(reg_id);
let span = pipeline_data.span().unwrap_or(Span::unknown());
pipeline_data.into_value(span)
}
} }
/// Eval an IR block on the provided slice of registers. /// Eval an IR block on the provided slice of registers.
@ -86,7 +97,7 @@ fn eval_ir_block_impl<D: DebugContext>(
let instruction = &ir_block.instructions[pc]; let instruction = &ir_block.instructions[pc];
let span = &ir_block.spans[pc]; let span = &ir_block.spans[pc];
log::trace!("{pc:-4}: {}", instruction.display(ctx.engine_state)); log::trace!("{pc:-4}: {}", instruction.display(ctx.engine_state));
match do_instruction(ctx, instruction, span)? { match eval_instruction(ctx, instruction, span)? {
InstructionResult::Continue => { InstructionResult::Continue => {
pc += 1; pc += 1;
} }
@ -121,7 +132,7 @@ enum InstructionResult {
} }
/// Perform an instruction /// Perform an instruction
fn do_instruction( fn eval_instruction(
ctx: &mut EvalContext<'_>, ctx: &mut EvalContext<'_>,
instruction: &Instruction, instruction: &Instruction,
span: &Span, span: &Span,
@ -159,13 +170,50 @@ fn do_instruction(
Instruction::LoadEnv { dst, key } => todo!(), Instruction::LoadEnv { dst, key } => todo!(),
Instruction::LoadEnvOpt { dst, key } => todo!(), Instruction::LoadEnvOpt { dst, key } => todo!(),
Instruction::StoreEnv { key, src } => todo!(), Instruction::StoreEnv { key, src } => todo!(),
Instruction::PushPositional { src } => todo!(), Instruction::PushPositional { src } => {
Instruction::AppendRest { src } => todo!(), let val = ctx.collect_reg(*src)?;
Instruction::PushFlag { name } => todo!(), ctx.stack
Instruction::PushNamed { name, src } => todo!(), .argument_stack
Instruction::RedirectOut { mode } => todo!(), .push(Argument::Positional { span: *span, val });
Instruction::RedirectErr { mode } => todo!(), Ok(InstructionResult::Continue)
Instruction::Call { decl_id, src_dst } => todo!(), }
Instruction::AppendRest { src } => {
let vals = ctx.collect_reg(*src)?;
ctx.stack
.argument_stack
.push(Argument::Spread { span: *span, vals });
Ok(InstructionResult::Continue)
}
Instruction::PushFlag { name } => {
ctx.stack.argument_stack.push(Argument::Flag {
name: name.clone(),
span: *span,
});
Ok(InstructionResult::Continue)
}
Instruction::PushNamed { name, src } => {
let val = ctx.collect_reg(*src)?;
ctx.stack.argument_stack.push(Argument::Named {
name: name.clone(),
span: *span,
val,
});
Ok(InstructionResult::Continue)
}
Instruction::RedirectOut { mode } => {
log::warn!("TODO: RedirectOut");
Ok(InstructionResult::Continue)
}
Instruction::RedirectErr { mode } => {
log::warn!("TODO: RedirectErr");
Ok(InstructionResult::Continue)
}
Instruction::Call { decl_id, src_dst } => {
let input = ctx.take_reg(*src_dst);
let result = eval_call(ctx, *decl_id, *span, input)?;
ctx.put_reg(*src_dst, result);
Ok(InstructionResult::Continue)
}
Instruction::BinaryOp { lhs_dst, op, rhs } => binary_op(ctx, *lhs_dst, op, *rhs, *span), Instruction::BinaryOp { lhs_dst, op, rhs } => binary_op(ctx, *lhs_dst, op, *rhs, *span),
Instruction::FollowCellPath { src_dst, path } => todo!(), Instruction::FollowCellPath { src_dst, path } => todo!(),
Instruction::CloneCellPath { dst, src, path } => todo!(), Instruction::CloneCellPath { dst, src, path } => todo!(),
@ -309,3 +357,33 @@ fn binary_op(
Ok(InstructionResult::Continue) Ok(InstructionResult::Continue)
} }
/// Evaluate a call
fn eval_call(
ctx: &mut EvalContext<'_>,
decl_id: DeclId,
head: Span,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// TODO: handle block eval
let args_len = ctx.stack.argument_stack.get_len(ctx.args_base);
let decl = ctx.engine_state.get_decl(decl_id);
// should this be precalculated? ideally we just use the call builder...
let span = ctx
.stack
.argument_stack
.get_args(ctx.args_base, args_len)
.into_iter()
.fold(head, |span, arg| span.append(arg.span()));
let call = Call {
decl_id,
head,
span,
args_base: ctx.args_base,
args_len,
};
let result = decl.run(ctx.engine_state, ctx.stack, &(&call).into(), input);
// Important that this runs:
ctx.stack.argument_stack.leave_frame(ctx.args_base);
result
}

View File

@ -1,13 +1,13 @@
use crate::{ use crate::{
engine::{self, Argument, Stack}, engine::{self, Argument, Stack},
ShellError, Span, Spanned, Value, DeclId, ShellError, Span, Spanned, Value,
}; };
/// Contains the information for a call being made to a declared command. /// Contains the information for a call being made to a declared command.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Call { pub struct Call {
/// The declaration ID of the command to be invoked. /// The declaration ID of the command to be invoked.
pub decl_id: usize, pub decl_id: DeclId,
/// The span encompassing the command name, before the arguments. /// The span encompassing the command name, before the arguments.
pub head: Span, pub head: Span,
/// The span encompassing the command name and all arguments. /// The span encompassing the command name and all arguments.
@ -23,7 +23,7 @@ pub struct Call {
impl Call { impl Call {
/// Build a new call with arguments. /// Build a new call with arguments.
pub fn build(decl_id: usize, head: Span) -> CallBuilder { pub fn build(decl_id: DeclId, head: Span) -> CallBuilder {
CallBuilder { CallBuilder {
inner: Call { inner: Call {
decl_id, decl_id,