mirror of
https://github.com/nushell/nushell.git
synced 2025-08-14 03:08:28 +02:00
WIP improve error infrastructure
Also simplify commands and reduce papercuts
This commit is contained in:
@ -23,7 +23,7 @@ impl language_reporting::ReportingFiles for Files {
|
||||
0
|
||||
}
|
||||
fn file_name(&self, _file: Self::FileId) -> FileName {
|
||||
FileName::Verbatim(format!("<eval>"))
|
||||
FileName::Verbatim(format!("shell"))
|
||||
}
|
||||
fn byte_index(&self, _file: Self::FileId, _line: usize, _column: usize) -> Option<usize> {
|
||||
unimplemented!("byte_index")
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::{ArgumentError, ShellError};
|
||||
use crate::parser::registry::{CommandConfig, CommandRegistry, NamedType};
|
||||
use crate::parser::registry::{CommandConfig, CommandRegistry, NamedType, PositionalType};
|
||||
use crate::parser::{baseline_parse_tokens, CallNode, Span, Spanned};
|
||||
use crate::parser::{
|
||||
hir::{self, NamedArguments},
|
||||
@ -86,30 +86,32 @@ fn parse_command_tail(
|
||||
|
||||
named.insert_switch(name, flag);
|
||||
}
|
||||
NamedType::Mandatory(kind) => match extract_mandatory(name, tail, source, command_span)
|
||||
{
|
||||
Err(err) => return Err(err), // produce a correct diagnostic
|
||||
Ok((pos, flag)) => {
|
||||
tail.move_to(pos);
|
||||
NamedType::Mandatory(kind) => {
|
||||
match extract_mandatory(config, name, tail, source, command_span) {
|
||||
Err(err) => return Err(err), // produce a correct diagnostic
|
||||
Ok((pos, flag)) => {
|
||||
tail.move_to(pos);
|
||||
|
||||
if tail.at_end() {
|
||||
return Err(ShellError::ArgumentError {
|
||||
error: ArgumentError::MissingValueForName(name.to_string()),
|
||||
span: flag.span,
|
||||
});
|
||||
if tail.at_end() {
|
||||
return Err(ShellError::ArgumentError {
|
||||
command: config.name().clone(),
|
||||
error: ArgumentError::MissingValueForName(name.to_string()),
|
||||
span: flag.span,
|
||||
});
|
||||
}
|
||||
|
||||
let expr = hir::baseline_parse_next_expr(
|
||||
tail,
|
||||
registry,
|
||||
source,
|
||||
kind.to_coerce_hint(),
|
||||
)?;
|
||||
|
||||
tail.restart();
|
||||
named.insert_mandatory(name, expr);
|
||||
}
|
||||
|
||||
let expr = hir::baseline_parse_next_expr(
|
||||
tail,
|
||||
registry,
|
||||
source,
|
||||
kind.to_coerce_hint(),
|
||||
)?;
|
||||
|
||||
tail.restart();
|
||||
named.insert_mandatory(name, expr);
|
||||
}
|
||||
},
|
||||
}
|
||||
NamedType::Optional(kind) => match extract_optional(name, tail, source) {
|
||||
Err(err) => return Err(err), // produce a correct diagnostic
|
||||
Ok(Some((pos, flag))) => {
|
||||
@ -117,6 +119,7 @@ fn parse_command_tail(
|
||||
|
||||
if tail.at_end() {
|
||||
return Err(ShellError::ArgumentError {
|
||||
command: config.name().clone(),
|
||||
error: ArgumentError::MissingValueForName(name.to_string()),
|
||||
span: flag.span,
|
||||
});
|
||||
@ -144,16 +147,26 @@ fn parse_command_tail(
|
||||
trace_remaining("after named", tail.clone(), source);
|
||||
|
||||
let mut positional = vec![];
|
||||
let mandatory = config.mandatory_positional();
|
||||
|
||||
for arg in mandatory {
|
||||
trace!("Processing mandatory {:?}", arg);
|
||||
for arg in config.positional() {
|
||||
trace!("Processing positional {:?}", arg);
|
||||
|
||||
if tail.len() == 0 {
|
||||
return Err(ShellError::ArgumentError {
|
||||
error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()),
|
||||
span: command_span,
|
||||
});
|
||||
match arg {
|
||||
PositionalType::Mandatory(..) => {
|
||||
if tail.len() == 0 {
|
||||
return Err(ShellError::ArgumentError {
|
||||
command: config.name().clone(),
|
||||
error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()),
|
||||
span: command_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
PositionalType::Optional(..) => {
|
||||
if tail.len() == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
|
||||
@ -161,21 +174,7 @@ fn parse_command_tail(
|
||||
positional.push(result);
|
||||
}
|
||||
|
||||
trace_remaining("after mandatory", tail.clone(), source);
|
||||
|
||||
let optional = config.optional_positional();
|
||||
|
||||
for arg in optional {
|
||||
if tail.len() == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
|
||||
|
||||
positional.push(result);
|
||||
}
|
||||
|
||||
trace_remaining("after optional", tail.clone(), source);
|
||||
trace_remaining("after positional", tail.clone(), source);
|
||||
|
||||
// TODO: Only do this if rest params are specified
|
||||
let remainder = baseline_parse_tokens(tail, registry, source)?;
|
||||
@ -207,6 +206,7 @@ fn extract_switch(name: &str, tokens: &mut hir::TokensIterator<'_>, source: &Tex
|
||||
}
|
||||
|
||||
fn extract_mandatory(
|
||||
config: &CommandConfig,
|
||||
name: &str,
|
||||
tokens: &mut hir::TokensIterator<'a>,
|
||||
source: &Text,
|
||||
@ -216,6 +216,7 @@ fn extract_mandatory(
|
||||
|
||||
match flag {
|
||||
None => Err(ShellError::ArgumentError {
|
||||
command: config.name().clone(),
|
||||
error: ArgumentError::MissingMandatoryFlag(name.to_string()),
|
||||
span,
|
||||
}),
|
||||
|
@ -36,22 +36,38 @@ impl NamedValue {
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PositionalType {
|
||||
Value(String),
|
||||
Block(String),
|
||||
Mandatory(String, PositionalValue),
|
||||
Optional(String, PositionalValue),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PositionalValue {
|
||||
Value,
|
||||
Block,
|
||||
}
|
||||
|
||||
impl PositionalType {
|
||||
crate fn mandatory(name: &str, kind: &str) -> PositionalType {
|
||||
match kind {
|
||||
"Block" => PositionalType::Mandatory(name.to_string(), PositionalValue::Block),
|
||||
_ => PositionalType::Mandatory(name.to_string(), PositionalValue::Value),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn to_coerce_hint(&self) -> Option<ExpressionKindHint> {
|
||||
match self {
|
||||
PositionalType::Value(_) => None,
|
||||
PositionalType::Block(_) => Some(ExpressionKindHint::Block),
|
||||
PositionalType::Mandatory(_, PositionalValue::Block)
|
||||
| PositionalType::Optional(_, PositionalValue::Block) => {
|
||||
Some(ExpressionKindHint::Block)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn name(&self) -> &str {
|
||||
match self {
|
||||
PositionalType::Value(s) => s,
|
||||
PositionalType::Block(s) => s,
|
||||
PositionalType::Mandatory(s, _) => s,
|
||||
PositionalType::Optional(s, _) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,8 +76,7 @@ impl PositionalType {
|
||||
#[get = "crate"]
|
||||
pub struct CommandConfig {
|
||||
pub name: String,
|
||||
pub mandatory_positional: Vec<PositionalType>,
|
||||
pub optional_positional: Vec<PositionalType>,
|
||||
crate positional: Vec<PositionalType>,
|
||||
pub rest_positional: bool,
|
||||
pub named: IndexMap<String, NamedType>,
|
||||
pub is_filter: bool,
|
||||
|
Reference in New Issue
Block a user