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.
|
/// Builds [`IrBlock`]s progressively by consuming instructions and handles register allocation.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct BlockBuilder {
|
pub(crate) struct BlockBuilder {
|
||||||
|
pub(crate) block_span: Option<Span>,
|
||||||
pub(crate) instructions: Vec<Instruction>,
|
pub(crate) instructions: Vec<Instruction>,
|
||||||
pub(crate) spans: Vec<Span>,
|
pub(crate) spans: Vec<Span>,
|
||||||
/// The actual instruction index that a label refers to. While building IR, branch targets are
|
/// 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 {
|
impl BlockBuilder {
|
||||||
/// Starts a new block, with the first register (`%0`) allocated as input.
|
/// 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 {
|
BlockBuilder {
|
||||||
|
block_span,
|
||||||
instructions: vec![],
|
instructions: vec![],
|
||||||
spans: vec![],
|
spans: vec![],
|
||||||
labels: vec![],
|
labels: vec![],
|
||||||
|
@ -62,7 +64,9 @@ impl BlockBuilder {
|
||||||
self.register_allocation_state.push(true);
|
self.register_allocation_state.push(true);
|
||||||
Ok(reg_id)
|
Ok(reg_id)
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::RegisterOverflow)
|
Err(CompileError::RegisterOverflow {
|
||||||
|
block_span: self.block_span,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +83,9 @@ impl BlockBuilder {
|
||||||
*is_allocated = true;
|
*is_allocated = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::RegisterOverflow)
|
Err(CompileError::RegisterOverflow {
|
||||||
|
block_span: self.block_span,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +372,9 @@ impl BlockBuilder {
|
||||||
self.data.extend_from_slice(data);
|
self.data.extend_from_slice(data);
|
||||||
Ok(slice)
|
Ok(slice)
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::DataOverflow)
|
Err(CompileError::DataOverflow {
|
||||||
|
block_span: self.block_span,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +433,9 @@ impl BlockBuilder {
|
||||||
self.file_count = self
|
self.file_count = self
|
||||||
.file_count
|
.file_count
|
||||||
.checked_add(1)
|
.checked_add(1)
|
||||||
.ok_or(CompileError::FileOverflow)?;
|
.ok_or(CompileError::FileOverflow {
|
||||||
|
block_span: self.block_span,
|
||||||
|
})?;
|
||||||
Ok(next)
|
Ok(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +491,9 @@ impl BlockBuilder {
|
||||||
if ended_loop == loop_ {
|
if ended_loop == loop_ {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} 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
|
/// Compile Nushell pipeline abstract syntax tree (AST) to internal representation (IR) instructions
|
||||||
/// for evaluation.
|
/// for evaluation.
|
||||||
pub fn compile(working_set: &StateWorkingSet, block: &Block) -> Result<IrBlock, CompileError> {
|
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());
|
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);
|
let (out, err) = expression.expr.pipe_redirection(working_set);
|
||||||
Ok(RedirectModes {
|
Ok(RedirectModes {
|
||||||
out: out
|
out: out
|
||||||
|
.map(|r| r.into_spanned(redir_span))
|
||||||
.map(out_dest_to_redirect_mode)
|
.map(out_dest_to_redirect_mode)
|
||||||
.transpose()?
|
.transpose()?,
|
||||||
.map(|mode| mode.into_spanned(redir_span)),
|
|
||||||
err: err
|
err: err
|
||||||
|
.map(|r| r.into_spanned(redir_span))
|
||||||
.map(out_dest_to_redirect_mode)
|
.map(out_dest_to_redirect_mode)
|
||||||
.transpose()?
|
.transpose()?,
|
||||||
.map(|mode| mode.into_spanned(redir_span)),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,12 +141,17 @@ pub(crate) fn finish_redirection(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn out_dest_to_redirect_mode(out_dest: OutDest) -> Result<RedirectMode, CompileError> {
|
pub(crate) fn out_dest_to_redirect_mode(
|
||||||
match out_dest {
|
out_dest: Spanned<OutDest>,
|
||||||
OutDest::Pipe => Ok(RedirectMode::Pipe),
|
) -> Result<Spanned<RedirectMode>, CompileError> {
|
||||||
OutDest::Capture => Ok(RedirectMode::Capture),
|
let span = out_dest.span;
|
||||||
OutDest::Null => Ok(RedirectMode::Null),
|
out_dest
|
||||||
OutDest::Inherit => Ok(RedirectMode::Inherit),
|
.map(|out_dest| match out_dest {
|
||||||
OutDest::File(_) => Err(CompileError::InvalidRedirectMode),
|
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)]
|
#[derive(Debug, Clone, Error, Diagnostic, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum CompileError {
|
pub enum CompileError {
|
||||||
#[error("Register overflow.")]
|
#[error("Register overflow.")]
|
||||||
#[diagnostic(
|
#[diagnostic(code(nu::compile::register_overflow))]
|
||||||
code(nu::compile::register_overflow),
|
RegisterOverflow {
|
||||||
help("the code being compiled is probably too large")
|
#[label("the code being compiled is probably too large")]
|
||||||
)]
|
block_span: Option<Span>,
|
||||||
RegisterOverflow,
|
},
|
||||||
|
|
||||||
#[error("Register {reg_id} was uninitialized when used, possibly reused.")]
|
#[error("Register {reg_id} was uninitialized when used, possibly reused.")]
|
||||||
#[diagnostic(
|
#[diagnostic(
|
||||||
|
@ -39,18 +39,30 @@ pub enum CompileError {
|
||||||
code(nu::compile::data_overflow),
|
code(nu::compile::data_overflow),
|
||||||
help("try loading the string data from a file instead")
|
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.")]
|
#[error("Block contains too many files.")]
|
||||||
#[diagnostic(
|
#[diagnostic(
|
||||||
code(nu::compile::register_overflow),
|
code(nu::compile::register_overflow),
|
||||||
help("try using fewer file redirections")
|
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.")]
|
#[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"))]
|
#[diagnostic(
|
||||||
InvalidRedirectMode,
|
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.")]
|
#[error("Encountered garbage, likely due to parse error.")]
|
||||||
#[diagnostic(code(nu::compile::garbage))]
|
#[diagnostic(code(nu::compile::garbage))]
|
||||||
|
@ -92,10 +104,6 @@ pub enum CompileError {
|
||||||
span: Span,
|
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.
|
/// You're trying to run an unsupported external command.
|
||||||
///
|
///
|
||||||
/// ## Resolution
|
/// ## Resolution
|
||||||
|
@ -212,7 +220,10 @@ pub enum CompileError {
|
||||||
code(nu::compile::incoherent_loop_state),
|
code(nu::compile::incoherent_loop_state),
|
||||||
help("this is a compiler bug. Please report it at https://github.com/nushell/nushell/issues/new"),
|
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}`.")]
|
#[error("Undefined label `{label_id}`.")]
|
||||||
#[diagnostic(
|
#[diagnostic(
|
||||||
|
@ -224,11 +235,4 @@ pub enum CompileError {
|
||||||
#[label("label was used while compiling this code")]
|
#[label("label was used while compiling this code")]
|
||||||
span: Option<Span>,
|
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.
|
/// Helper trait to create [`Spanned`] more ergonomically.
|
||||||
pub trait IntoSpanned: Sized {
|
pub trait IntoSpanned: Sized {
|
||||||
/// Wrap items together with a span into [`Spanned`].
|
/// Wrap items together with a span into [`Spanned`].
|
||||||
|
|
Loading…
Reference in New Issue
Block a user