mirror of
https://github.com/nushell/nushell
synced 2024-12-29 14:33:13 +00:00
refactor positional arg parse
This commit is contained in:
parent
134b45dc03
commit
1aa70c50aa
1 changed files with 84 additions and 80 deletions
156
src/parser.rs
156
src/parser.rs
|
@ -322,10 +322,10 @@ impl ParserWorkingSet {
|
||||||
fn parse_long_flag(
|
fn parse_long_flag(
|
||||||
&mut self,
|
&mut self,
|
||||||
spans: &[Span],
|
spans: &[Span],
|
||||||
arg_offset: &mut usize,
|
spans_idx: &mut usize,
|
||||||
sig: &Signature,
|
sig: &Signature,
|
||||||
) -> (Option<String>, Option<Expression>, Option<ParseError>) {
|
) -> (Option<String>, Option<Expression>, Option<ParseError>) {
|
||||||
let arg_span = spans[*arg_offset];
|
let arg_span = spans[*spans_idx];
|
||||||
let arg_contents = self.get_span_contents(arg_span);
|
let arg_contents = self.get_span_contents(arg_span);
|
||||||
|
|
||||||
if arg_contents.starts_with(&[b'-', b'-']) {
|
if arg_contents.starts_with(&[b'-', b'-']) {
|
||||||
|
@ -342,10 +342,10 @@ impl ParserWorkingSet {
|
||||||
let (arg, err) = self.parse_arg(span, arg_shape.clone());
|
let (arg, err) = self.parse_arg(span, arg_shape.clone());
|
||||||
|
|
||||||
(Some(long_name), Some(arg), err)
|
(Some(long_name), Some(arg), err)
|
||||||
} else if let Some(arg) = spans.get(*arg_offset + 1) {
|
} else if let Some(arg) = spans.get(*spans_idx + 1) {
|
||||||
let (arg, err) = self.parse_arg(*arg, arg_shape.clone());
|
let (arg, err) = self.parse_arg(*arg, arg_shape.clone());
|
||||||
|
|
||||||
*arg_offset += 1;
|
*spans_idx += 1;
|
||||||
(Some(long_name), Some(arg), err)
|
(Some(long_name), Some(arg), err)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
|
@ -376,12 +376,12 @@ impl ParserWorkingSet {
|
||||||
fn parse_short_flags(
|
fn parse_short_flags(
|
||||||
&mut self,
|
&mut self,
|
||||||
spans: &[Span],
|
spans: &[Span],
|
||||||
arg_offset: &mut usize,
|
spans_idx: &mut usize,
|
||||||
positional_idx: usize,
|
positional_idx: usize,
|
||||||
sig: &Signature,
|
sig: &Signature,
|
||||||
) -> (Option<Vec<Flag>>, Option<ParseError>) {
|
) -> (Option<Vec<Flag>>, Option<ParseError>) {
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
let arg_span = spans[*arg_offset];
|
let arg_span = spans[*spans_idx];
|
||||||
|
|
||||||
let arg_contents = self.get_span_contents(arg_span);
|
let arg_contents = self.get_span_contents(arg_span);
|
||||||
|
|
||||||
|
@ -440,6 +440,59 @@ impl ParserWorkingSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_multispan_value(
|
||||||
|
&mut self,
|
||||||
|
spans: &[Span],
|
||||||
|
spans_idx: &mut usize,
|
||||||
|
shape: SyntaxShape,
|
||||||
|
) -> (Expression, Option<ParseError>) {
|
||||||
|
let mut error = None;
|
||||||
|
let arg_span = spans[*spans_idx];
|
||||||
|
|
||||||
|
match shape {
|
||||||
|
SyntaxShape::RowCondition => {
|
||||||
|
let (arg, err) = self.parse_row_condition(spans);
|
||||||
|
error = error.or(err);
|
||||||
|
*spans_idx = spans.len();
|
||||||
|
|
||||||
|
(arg, error)
|
||||||
|
}
|
||||||
|
SyntaxShape::Expression => {
|
||||||
|
let (arg, err) = self.parse_expression(spans);
|
||||||
|
error = error.or(err);
|
||||||
|
*spans_idx = spans.len();
|
||||||
|
|
||||||
|
(arg, error)
|
||||||
|
}
|
||||||
|
SyntaxShape::Literal(literal) => {
|
||||||
|
let arg_contents = self.get_span_contents(arg_span);
|
||||||
|
if arg_contents != literal {
|
||||||
|
// When keywords mismatch, this is a strong indicator of something going wrong.
|
||||||
|
// We won't often override the current error, but as this is a strong indicator
|
||||||
|
// go ahead and override the current error and tell the user about the missing
|
||||||
|
// keyword/literal.
|
||||||
|
error = Some(ParseError::Mismatch(
|
||||||
|
String::from_utf8_lossy(&literal).into(),
|
||||||
|
arg_span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Literal(literal),
|
||||||
|
span: arg_span,
|
||||||
|
},
|
||||||
|
error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let (arg, err) = self.parse_arg(arg_span, shape);
|
||||||
|
error = error.or(err);
|
||||||
|
|
||||||
|
(arg, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_internal_call(
|
pub fn parse_internal_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
spans: &[Span],
|
spans: &[Span],
|
||||||
|
@ -455,34 +508,38 @@ impl ParserWorkingSet {
|
||||||
.expect("internal error: bad DeclId")
|
.expect("internal error: bad DeclId")
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
|
// The index into the positional parameter in the definition
|
||||||
let mut positional_idx = 0;
|
let mut positional_idx = 0;
|
||||||
let mut arg_offset = 1;
|
|
||||||
|
|
||||||
while arg_offset < spans.len() {
|
// The index into the spans of argument data given to parse
|
||||||
let arg_span = spans[arg_offset];
|
// Starting at the first argument
|
||||||
|
let mut spans_idx = 1;
|
||||||
|
|
||||||
let (long_name, arg, err) = self.parse_long_flag(spans, &mut arg_offset, &sig);
|
while spans_idx < spans.len() {
|
||||||
|
let arg_span = spans[spans_idx];
|
||||||
|
|
||||||
|
let (long_name, arg, err) = self.parse_long_flag(spans, &mut spans_idx, &sig);
|
||||||
if let Some(long_name) = long_name {
|
if let Some(long_name) = long_name {
|
||||||
// We found a long flag, like --bar
|
// We found a long flag, like --bar
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
call.named.push((long_name, arg));
|
call.named.push((long_name, arg));
|
||||||
arg_offset += 1;
|
spans_idx += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (short_flags, err) =
|
let (short_flags, err) =
|
||||||
self.parse_short_flags(spans, &mut arg_offset, positional_idx, &sig);
|
self.parse_short_flags(spans, &mut spans_idx, positional_idx, &sig);
|
||||||
|
|
||||||
if let Some(short_flags) = short_flags {
|
if let Some(short_flags) = short_flags {
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
for flag in short_flags {
|
for flag in short_flags {
|
||||||
if let Some(arg_shape) = flag.arg {
|
if let Some(arg_shape) = flag.arg {
|
||||||
if let Some(arg) = spans.get(arg_offset + 1) {
|
if let Some(arg) = spans.get(spans_idx + 1) {
|
||||||
let (arg, err) = self.parse_arg(*arg, arg_shape.clone());
|
let (arg, err) = self.parse_arg(*arg, arg_shape.clone());
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
call.named.push((flag.long.clone(), Some(arg)));
|
call.named.push((flag.long.clone(), Some(arg)));
|
||||||
arg_offset += 1;
|
spans_idx += 1;
|
||||||
} else {
|
} else {
|
||||||
error = error.or(Some(ParseError::MissingFlagParam(arg_span)))
|
error = error.or(Some(ParseError::MissingFlagParam(arg_span)))
|
||||||
}
|
}
|
||||||
|
@ -490,81 +547,28 @@ impl ParserWorkingSet {
|
||||||
call.named.push((flag.long.clone(), None));
|
call.named.push((flag.long.clone(), None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arg_offset += 1;
|
spans_idx += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(positional) = sig.get_positional(positional_idx) {
|
if let Some(positional) = sig.get_positional(positional_idx) {
|
||||||
match positional.shape {
|
//Make sure we leave enough spans for the remaining positionals
|
||||||
SyntaxShape::RowCondition => {
|
|
||||||
let remainder = sig.num_positionals() - positional_idx;
|
let remainder = sig.num_positionals() - positional_idx;
|
||||||
|
|
||||||
if spans.len() < remainder {
|
let (arg, err) = self.parse_multispan_value(
|
||||||
error = error.or_else(|| {
|
&spans[..(spans.len() - remainder + 1)],
|
||||||
Some(ParseError::MissingPositional(
|
&mut spans_idx,
|
||||||
"required args".into(),
|
positional.shape,
|
||||||
arg_span,
|
|
||||||
))
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let (arg, err) = self.parse_row_condition(
|
|
||||||
&spans[arg_offset..(spans.len() - remainder + 1)],
|
|
||||||
);
|
);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
call.positional.push(arg);
|
call.positional.push(arg);
|
||||||
|
|
||||||
arg_offset = spans.len() - remainder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SyntaxShape::Expression => {
|
|
||||||
let remainder = sig.num_positionals() - positional_idx;
|
|
||||||
|
|
||||||
if spans.len() < remainder {
|
|
||||||
error = error.or_else(|| {
|
|
||||||
Some(ParseError::MissingPositional(
|
|
||||||
"required args".into(),
|
|
||||||
arg_span,
|
|
||||||
))
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let (arg, err) = self.parse_expression(
|
|
||||||
&spans[arg_offset..(spans.len() - remainder + 1)],
|
|
||||||
);
|
|
||||||
error = error.or(err);
|
|
||||||
call.positional.push(arg);
|
|
||||||
|
|
||||||
arg_offset = spans.len() - remainder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SyntaxShape::Literal(literal) => {
|
|
||||||
let arg_contents = self.get_span_contents(arg_span);
|
|
||||||
if arg_contents != literal {
|
|
||||||
// When keywords mismatch, this is a strong indicator of something going wrong.
|
|
||||||
// We won't often override the current error, but as this is a strong indicator
|
|
||||||
// go ahead and override the current error and tell the user about the missing
|
|
||||||
// keyword/literal.
|
|
||||||
error = Some(ParseError::Mismatch(
|
|
||||||
String::from_utf8_lossy(&literal).into(),
|
|
||||||
arg_span,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
call.positional.push(Expression {
|
|
||||||
expr: Expr::Literal(literal),
|
|
||||||
span: arg_span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let (arg, err) = self.parse_arg(arg_span, positional.shape);
|
|
||||||
error = error.or(err);
|
|
||||||
|
|
||||||
call.positional.push(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
positional_idx += 1;
|
positional_idx += 1;
|
||||||
} else {
|
} else {
|
||||||
error = error.or(Some(ParseError::ExtraPositional(arg_span)))
|
error = error.or(Some(ParseError::ExtraPositional(arg_span)))
|
||||||
}
|
}
|
||||||
arg_offset += 1;
|
|
||||||
|
error = error.or(err);
|
||||||
|
spans_idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let err = check_call(spans[0], &sig, &call);
|
let err = check_call(spans[0], &sig, &call);
|
||||||
|
|
Loading…
Reference in a new issue