mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 17:45:03 +02:00
Restructure and streamline token expansion (#1123)
Restructure and streamline token expansion The purpose of this commit is to streamline the token expansion code, by removing aspects of the code that are no longer relevant, removing pointless duplication, and eliminating the need to pass the same arguments to `expand_syntax`. The first big-picture change in this commit is that instead of a handful of `expand_` functions, which take a TokensIterator and ExpandContext, a smaller number of methods on the `TokensIterator` do the same job. The second big-picture change in this commit is fully eliminating the coloring traits, making coloring a responsibility of the base expansion implementations. This also means that the coloring tracer is merged into the expansion tracer, so you can follow a single expansion and see how the expansion process produced colored tokens. One side effect of this change is that the expander itself is marginally more error-correcting. The error correction works by switching from structured expansion to `BackoffColoringMode` when an unexpected token is found, which guarantees that all spans of the source are colored, but may not be the most optimal error recovery strategy. That said, because `BackoffColoringMode` only extends as far as a closing delimiter (`)`, `]`, `}`) or pipe (`|`), it does result in fairly granular correction strategy. The current code still produces an `Err` (plus a complete list of colored shapes) from the parsing process if any errors are encountered, but this could easily be addressed now that the underlying expansion is error-correcting. This commit also colors any spans that are syntax errors in red, and causes the parser to include some additional information about what tokens were expected at any given point where an error was encountered, so that completions and hinting could be more robust in the future. Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com> Co-authored-by: Andrés N. Robalino <andres@androbtech.com>
This commit is contained in:
committed by
Andrés N. Robalino
parent
c8dd7838a8
commit
7efb31a4e4
@ -1,8 +1,11 @@
|
||||
use ansi_term::Color;
|
||||
use bigdecimal::BigDecimal;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use language_reporting::{Diagnostic, Label, Severity};
|
||||
use nu_source::{b, DebugDocBuilder, PrettyDebug, Span, Spanned, SpannedItem, TracableContext};
|
||||
use nu_source::{
|
||||
b, DebugDocBuilder, HasFallibleSpan, PrettyDebug, Span, Spanned, SpannedItem, TracableContext,
|
||||
};
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::ToPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -12,16 +15,16 @@ use std::ops::Range;
|
||||
/// A structured reason for a ParseError. Note that parsing in nu is more like macro expansion in
|
||||
/// other languages, so the kinds of errors that can occur during parsing are more contextual than
|
||||
/// you might expect.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum ParseErrorReason {
|
||||
/// The parser encountered an EOF rather than what it was expecting
|
||||
Eof { expected: &'static str, span: Span },
|
||||
Eof { expected: String, span: Span },
|
||||
/// The parser expected to see the end of a token stream (possibly the token
|
||||
/// stream from inside a delimited token node), but found something else.
|
||||
ExtraTokens { actual: Spanned<String> },
|
||||
/// The parser encountered something other than what it was expecting
|
||||
Mismatch {
|
||||
expected: &'static str,
|
||||
expected: String,
|
||||
actual: Spanned<String>,
|
||||
},
|
||||
|
||||
@ -37,16 +40,20 @@ pub enum ParseErrorReason {
|
||||
}
|
||||
|
||||
/// A newtype for `ParseErrorReason`
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Getters)]
|
||||
pub struct ParseError {
|
||||
#[get = "pub"]
|
||||
reason: ParseErrorReason,
|
||||
}
|
||||
|
||||
impl ParseError {
|
||||
/// Construct a [ParseErrorReason::Eof](ParseErrorReason::Eof)
|
||||
pub fn unexpected_eof(expected: &'static str, span: Span) -> ParseError {
|
||||
pub fn unexpected_eof(expected: impl Into<String>, span: Span) -> ParseError {
|
||||
ParseError {
|
||||
reason: ParseErrorReason::Eof { expected, span },
|
||||
reason: ParseErrorReason::Eof {
|
||||
expected: expected.into(),
|
||||
span,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,12 +69,12 @@ impl ParseError {
|
||||
}
|
||||
|
||||
/// Construct a [ParseErrorReason::Mismatch](ParseErrorReason::Mismatch)
|
||||
pub fn mismatch(expected: &'static str, actual: Spanned<impl Into<String>>) -> ParseError {
|
||||
pub fn mismatch(expected: impl Into<String>, actual: Spanned<impl Into<String>>) -> ParseError {
|
||||
let Spanned { span, item } = actual;
|
||||
|
||||
ParseError {
|
||||
reason: ParseErrorReason::Mismatch {
|
||||
expected,
|
||||
expected: expected.into(),
|
||||
actual: item.into().spanned(span),
|
||||
},
|
||||
}
|
||||
@ -728,6 +735,30 @@ impl ProximateShellError {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasFallibleSpan for ShellError {
|
||||
fn maybe_span(&self) -> Option<Span> {
|
||||
self.error.maybe_span()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasFallibleSpan for ProximateShellError {
|
||||
fn maybe_span(&self) -> Option<Span> {
|
||||
Some(match self {
|
||||
ProximateShellError::SyntaxError { problem } => problem.span,
|
||||
ProximateShellError::UnexpectedEof { span, .. } => *span,
|
||||
ProximateShellError::TypeError { actual, .. } => actual.span,
|
||||
ProximateShellError::MissingProperty { subpath, .. } => subpath.span,
|
||||
ProximateShellError::InvalidIntegerIndex { subpath, .. } => subpath.span,
|
||||
ProximateShellError::MissingValue { span, .. } => return *span,
|
||||
ProximateShellError::ArgumentError { command, .. } => command.span,
|
||||
ProximateShellError::RangeError { actual_kind, .. } => actual_kind.span,
|
||||
ProximateShellError::Diagnostic(_) => return None,
|
||||
ProximateShellError::CoerceError { left, right } => left.span.until(right.span),
|
||||
ProximateShellError::UntaggedRuntimeError { .. } => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ShellDiagnostic {
|
||||
pub(crate) diagnostic: Diagnostic<Span>,
|
||||
|
Reference in New Issue
Block a user