make sure compile errors generally have a span
This commit is contained in:
parent
85922fe50f
commit
78ca94b57c
|
@ -10,6 +10,7 @@ pub(crate) struct LabelId(pub usize);
|
|||
/// Builds [`IrBlock`]s progressively by consuming instructions and handles register allocation.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct BlockBuilder {
|
||||
pub(crate) block_span: Option<Span>,
|
||||
pub(crate) instructions: Vec<Instruction>,
|
||||
pub(crate) spans: Vec<Span>,
|
||||
/// The actual instruction index that a label refers to. While building IR, branch targets are
|
||||
|
@ -28,8 +29,9 @@ pub(crate) struct BlockBuilder {
|
|||
|
||||
impl BlockBuilder {
|
||||
/// Starts a new block, with the first register (`%0`) allocated as input.
|
||||
pub(crate) fn new() -> Self {
|
||||
pub(crate) fn new(block_span: Option<Span>) -> Self {
|
||||
BlockBuilder {
|
||||
block_span,
|
||||
instructions: vec![],
|
||||
spans: vec![],
|
||||
labels: vec![],
|
||||
|
@ -62,7 +64,9 @@ impl BlockBuilder {
|
|||
self.register_allocation_state.push(true);
|
||||
Ok(reg_id)
|
||||
} else {
|
||||
Err(CompileError::RegisterOverflow)
|
||||
Err(CompileError::RegisterOverflow {
|
||||
block_span: self.block_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +83,9 @@ impl BlockBuilder {
|
|||
*is_allocated = true;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CompileError::RegisterOverflow)
|
||||
Err(CompileError::RegisterOverflow {
|
||||
block_span: self.block_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,7 +372,9 @@ impl BlockBuilder {
|
|||
self.data.extend_from_slice(data);
|
||||
Ok(slice)
|
||||
} else {
|
||||
Err(CompileError::DataOverflow)
|
||||
Err(CompileError::DataOverflow {
|
||||
block_span: self.block_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,7 +433,9 @@ impl BlockBuilder {
|
|||
self.file_count = self
|
||||
.file_count
|
||||
.checked_add(1)
|
||||
.ok_or(CompileError::FileOverflow)?;
|
||||
.ok_or(CompileError::FileOverflow {
|
||||
block_span: self.block_span,
|
||||
})?;
|
||||
Ok(next)
|
||||
}
|
||||
|
||||
|
@ -481,7 +491,9 @@ impl BlockBuilder {
|
|||
if ended_loop == loop_ {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CompileError::IncoherentLoopState)
|
||||
Err(CompileError::IncoherentLoopState {
|
||||
block_span: self.block_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ const BLOCK_INPUT: RegId = RegId(0);
|
|||
/// Compile Nushell pipeline abstract syntax tree (AST) to internal representation (IR) instructions
|
||||
/// for evaluation.
|
||||
pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock, CompileError> {
|
||||
let mut builder = BlockBuilder::new();
|
||||
let mut builder = BlockBuilder::new(block.span);
|
||||
|
||||
let span = block.span.unwrap_or(Span::unknown());
|
||||
|
||||
|
|
|
@ -72,13 +72,13 @@ pub(crate) fn redirect_modes_of_expression(
|
|||
let (out, err) = expression.expr.pipe_redirection(working_set);
|
||||
Ok(RedirectModes {
|
||||
out: out
|
||||
.map(|r| r.into_spanned(redir_span))
|
||||
.map(out_dest_to_redirect_mode)
|
||||
.transpose()?
|
||||
.map(|mode| mode.into_spanned(redir_span)),
|
||||
.transpose()?,
|
||||
err: err
|
||||
.map(|r| r.into_spanned(redir_span))
|
||||
.map(out_dest_to_redirect_mode)
|
||||
.transpose()?
|
||||
.map(|mode| mode.into_spanned(redir_span)),
|
||||
.transpose()?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -141,12 +141,17 @@ pub(crate) fn finish_redirection(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn out_dest_to_redirect_mode(out_dest: OutDest) -> Result<RedirectMode, CompileError> {
|
||||
match out_dest {
|
||||
OutDest::Pipe => Ok(RedirectMode::Pipe),
|
||||
OutDest::Capture => Ok(RedirectMode::Capture),
|
||||
OutDest::Null => Ok(RedirectMode::Null),
|
||||
OutDest::Inherit => Ok(RedirectMode::Inherit),
|
||||
OutDest::File(_) => Err(CompileError::InvalidRedirectMode),
|
||||
}
|
||||
pub(crate) fn out_dest_to_redirect_mode(
|
||||
out_dest: Spanned<OutDest>,
|
||||
) -> Result<Spanned<RedirectMode>, CompileError> {
|
||||
let span = out_dest.span;
|
||||
out_dest
|
||||
.map(|out_dest| match out_dest {
|
||||
OutDest::Pipe => Ok(RedirectMode::Pipe),
|
||||
OutDest::Capture => Ok(RedirectMode::Capture),
|
||||
OutDest::Null => Ok(RedirectMode::Null),
|
||||
OutDest::Inherit => Ok(RedirectMode::Inherit),
|
||||
OutDest::File(_) => Err(CompileError::InvalidRedirectMode { span }),
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@ use thiserror::Error;
|
|||
#[derive(Debug, Clone, Error, Diagnostic, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CompileError {
|
||||
#[error("Register overflow.")]
|
||||
#[diagnostic(
|
||||
code(nu::compile::register_overflow),
|
||||
help("the code being compiled is probably too large")
|
||||
)]
|
||||
RegisterOverflow,
|
||||
#[diagnostic(code(nu::compile::register_overflow))]
|
||||
RegisterOverflow {
|
||||
#[label("the code being compiled is probably too large")]
|
||||
block_span: Option<Span>,
|
||||
},
|
||||
|
||||
#[error("Register {reg_id} was uninitialized when used, possibly reused.")]
|
||||
#[diagnostic(
|
||||
|
@ -39,18 +39,30 @@ pub enum CompileError {
|
|||
code(nu::compile::data_overflow),
|
||||
help("try loading the string data from a file instead")
|
||||
)]
|
||||
DataOverflow,
|
||||
DataOverflow {
|
||||
#[label("while compiling this block")]
|
||||
block_span: Option<Span>,
|
||||
},
|
||||
|
||||
#[error("Block contains too many files.")]
|
||||
#[diagnostic(
|
||||
code(nu::compile::register_overflow),
|
||||
help("try using fewer file redirections")
|
||||
)]
|
||||
FileOverflow,
|
||||
FileOverflow {
|
||||
#[label("while compiling this block")]
|
||||
block_span: Option<Span>,
|
||||
},
|
||||
|
||||
#[error("Invalid redirect mode: File should not be specified by commands.")]
|
||||
#[diagnostic(code(nu::compile::invalid_redirect_mode), help("this is a command bug. Please report it at https://github.com/nushell/nushell/issues/new"))]
|
||||
InvalidRedirectMode,
|
||||
#[diagnostic(
|
||||
code(nu::compile::invalid_redirect_mode),
|
||||
help("this is a command bug. Please report it at https://github.com/nushell/nushell/issues/new")
|
||||
)]
|
||||
InvalidRedirectMode {
|
||||
#[label("while compiling this expression")]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[error("Encountered garbage, likely due to parse error.")]
|
||||
#[diagnostic(code(nu::compile::garbage))]
|
||||
|
@ -92,10 +104,6 @@ pub enum CompileError {
|
|||
span: Span,
|
||||
},
|
||||
|
||||
#[error("Instruction index out of range: {index}.")]
|
||||
#[diagnostic(code(nu::compile::instruction_index_out_of_range))]
|
||||
InstructionIndexOutOfRange { index: usize },
|
||||
|
||||
/// You're trying to run an unsupported external command.
|
||||
///
|
||||
/// ## Resolution
|
||||
|
@ -212,7 +220,10 @@ pub enum CompileError {
|
|||
code(nu::compile::incoherent_loop_state),
|
||||
help("this is a compiler bug. Please report it at https://github.com/nushell/nushell/issues/new"),
|
||||
)]
|
||||
IncoherentLoopState,
|
||||
IncoherentLoopState {
|
||||
#[label("while compiling this block")]
|
||||
block_span: Option<Span>,
|
||||
},
|
||||
|
||||
#[error("Undefined label `{label_id}`.")]
|
||||
#[diagnostic(
|
||||
|
@ -224,11 +235,4 @@ pub enum CompileError {
|
|||
#[label("label was used while compiling this code")]
|
||||
span: Option<Span>,
|
||||
},
|
||||
|
||||
#[error("Offset overflow: tried to add {offset} to {here}.")]
|
||||
#[diagnostic(
|
||||
code(nu::compile::offset_overflow),
|
||||
help("this is a compiler bug. Please report it at https://github.com/nushell/nushell/issues/new"),
|
||||
)]
|
||||
OffsetOverflow { here: usize, offset: isize },
|
||||
}
|
||||
|
|
|
@ -53,6 +53,22 @@ impl<T> Spanned<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, E> Spanned<Result<T, E>> {
|
||||
/// Move the `Result` to the outside, resulting in a spanned `Ok` or unspanned `Err`.
|
||||
pub fn transpose(self) -> Result<Spanned<T>, E> {
|
||||
match self {
|
||||
Spanned {
|
||||
item: Ok(item),
|
||||
span,
|
||||
} => Ok(Spanned { item, span }),
|
||||
Spanned {
|
||||
item: Err(err),
|
||||
span: _,
|
||||
} => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait to create [`Spanned`] more ergonomically.
|
||||
pub trait IntoSpanned: Sized {
|
||||
/// Wrap items together with a span into [`Spanned`].
|
||||
|
|
Loading…
Reference in New Issue
Block a user