mirror of
https://github.com/nushell/nushell.git
synced 2024-11-23 00:43:33 +01:00
Expand tilde in patterns.
This commit is contained in:
parent
1b3a09495d
commit
540cc4016e
@ -367,6 +367,10 @@ impl ShellError {
|
||||
// pub fn string(title: impl Into<String>) -> ShellError {
|
||||
// ProximateShellError::String(StringError::new(title.into(), String::new())).start()
|
||||
// }
|
||||
//
|
||||
// pub(crate) fn unreachable(title: impl Into<String>) -> ShellError {
|
||||
// ShellError::untagged_runtime_error(&format!("BUG: Unreachable: {}", title.into()))
|
||||
// }
|
||||
|
||||
pub(crate) fn unimplemented(title: impl Into<String>) -> ShellError {
|
||||
ShellError::untagged_runtime_error(&format!("Unimplemented: {}", title.into()))
|
||||
@ -375,10 +379,6 @@ impl ShellError {
|
||||
pub(crate) fn unexpected(title: impl Into<String>) -> ShellError {
|
||||
ShellError::untagged_runtime_error(&format!("Unexpected: {}", title.into()))
|
||||
}
|
||||
|
||||
pub(crate) fn unreachable(title: impl Into<String>) -> ShellError {
|
||||
ShellError::untagged_runtime_error(&format!("BUG: Unreachable: {}", title.into()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
|
@ -148,7 +148,7 @@ fn evaluate_literal(literal: Tagged<&hir::Literal>, source: &Text) -> Tagged<Val
|
||||
hir::Literal::Number(int) => int.into(),
|
||||
hir::Literal::Size(int, unit) => unit.compute(int),
|
||||
hir::Literal::String(tag) => Value::string(tag.slice(source)),
|
||||
hir::Literal::GlobPattern => Value::pattern(literal.tag().slice(source)),
|
||||
hir::Literal::GlobPattern(pattern) => Value::pattern(pattern),
|
||||
hir::Literal::Bare => Value::string(literal.tag().slice(source)),
|
||||
};
|
||||
|
||||
|
@ -227,8 +227,8 @@ impl Expression {
|
||||
RawExpression::Literal(Literal::Bare).spanned(span)
|
||||
}
|
||||
|
||||
pub(crate) fn pattern(span: impl Into<Span>) -> Expression {
|
||||
RawExpression::Literal(Literal::GlobPattern).spanned(span.into())
|
||||
pub(crate) fn pattern(inner: impl Into<String>, outer: impl Into<Span>) -> Expression {
|
||||
RawExpression::Literal(Literal::GlobPattern(inner.into())).spanned(outer.into())
|
||||
}
|
||||
|
||||
pub(crate) fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
@ -297,7 +297,7 @@ pub enum Literal {
|
||||
Number(Number),
|
||||
Size(Number, Unit),
|
||||
String(Span),
|
||||
GlobPattern,
|
||||
GlobPattern(String),
|
||||
Bare,
|
||||
}
|
||||
|
||||
@ -315,7 +315,7 @@ impl std::fmt::Display for Tagged<&Literal> {
|
||||
Literal::Number(number) => write!(f, "{}", number),
|
||||
Literal::Size(number, unit) => write!(f, "{}{}", number, unit.as_str()),
|
||||
Literal::String(_) => write!(f, "String{{ {}..{} }}", span.start(), span.end()),
|
||||
Literal::GlobPattern => write!(f, "Glob{{ {}..{} }}", span.start(), span.end()),
|
||||
Literal::GlobPattern(_) => write!(f, "Glob{{ {}..{} }}", span.start(), span.end()),
|
||||
Literal::Bare => write!(f, "Bare{{ {}..{} }}", span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
@ -327,7 +327,7 @@ impl ToDebug for Spanned<&Literal> {
|
||||
Literal::Number(number) => write!(f, "{:?}", number),
|
||||
Literal::Size(number, unit) => write!(f, "{:?}{:?}", *number, unit),
|
||||
Literal::String(tag) => write!(f, "{}", tag.slice(source)),
|
||||
Literal::GlobPattern => write!(f, "{}", self.span.slice(source)),
|
||||
Literal::GlobPattern(_) => write!(f, "{}", self.span.slice(source)),
|
||||
Literal::Bare => write!(f, "{}", self.span.slice(source)),
|
||||
}
|
||||
}
|
||||
@ -340,7 +340,7 @@ impl Literal {
|
||||
Literal::Size(..) => "size",
|
||||
Literal::String(..) => "string",
|
||||
Literal::Bare => "string",
|
||||
Literal::GlobPattern => "pattern",
|
||||
Literal::GlobPattern(_) => "pattern",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use crate::parser::hir::syntax_shape::*;
|
||||
use crate::parser::hir::TokensIterator;
|
||||
use crate::parser::parse::token_tree_builder::{CurriedToken, TokenTreeBuilder as b};
|
||||
use crate::parser::TokenNode;
|
||||
use crate::{Span, SpannedItem, Tag, Tagged, Text};
|
||||
use crate::{Span, SpannedItem, Tag, Text};
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::fmt::Debug;
|
||||
|
||||
@ -63,7 +63,7 @@ fn test_parse_command() {
|
||||
vec![b::bare("ls"), b::sp(), b::pattern("*.txt")],
|
||||
|tokens| {
|
||||
let bare = tokens[0].expect_bare();
|
||||
let pat = tokens[2].span();
|
||||
let pattern = tokens[2].expect_pattern();
|
||||
|
||||
ClassifiedCommand::Internal(InternalCommand::new(
|
||||
"ls".to_string(),
|
||||
@ -73,7 +73,7 @@ fn test_parse_command() {
|
||||
},
|
||||
hir::Call {
|
||||
head: Box::new(hir::RawExpression::Command(bare).spanned(bare)),
|
||||
positional: Some(vec![hir::Expression::pattern(pat)]),
|
||||
positional: Some(vec![hir::Expression::pattern("*.txt", pattern)]),
|
||||
named: None,
|
||||
},
|
||||
))
|
||||
@ -84,41 +84,19 @@ fn test_parse_command() {
|
||||
// )
|
||||
},
|
||||
);
|
||||
|
||||
parse_tokens(
|
||||
VariablePathShape,
|
||||
vec![
|
||||
b::var("cpu"),
|
||||
b::op("."),
|
||||
b::bare("amount"),
|
||||
b::op("."),
|
||||
b::string("max ghz"),
|
||||
],
|
||||
|tokens| {
|
||||
let (outer_var, inner_var) = tokens[0].expect_var();
|
||||
let amount = tokens[2].expect_bare();
|
||||
let (outer_max_ghz, _) = tokens[4].expect_string();
|
||||
|
||||
hir::Expression::path(
|
||||
hir::Expression::variable(inner_var, outer_var),
|
||||
vec!["amount".spanned(amount), "max ghz".spanned(outer_max_ghz)],
|
||||
outer_var.until(outer_max_ghz),
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn parse_tokens<T: Eq + Debug>(
|
||||
shape: impl ExpandSyntax<Output = T>,
|
||||
tokens: Vec<CurriedToken>,
|
||||
expected: impl FnOnce(Tagged<&[TokenNode]>) -> T,
|
||||
expected: impl FnOnce(&[TokenNode]) -> T,
|
||||
) {
|
||||
let tokens = b::token_list(tokens);
|
||||
let (tokens, source) = b::build(tokens);
|
||||
|
||||
ExpandContext::with_empty(&Text::from(source), |context| {
|
||||
let tokens = tokens.expect_list();
|
||||
let mut iterator = TokensIterator::all(tokens.item, *context.span());
|
||||
let mut iterator = TokensIterator::all(tokens, *context.span());
|
||||
|
||||
let expr = expand_syntax(&shape, &mut iterator, &context);
|
||||
|
||||
|
@ -497,18 +497,18 @@ pub(crate) fn expand_expr<'a, 'b, T: ExpandExpression>(
|
||||
token_nodes: &'b mut TokensIterator<'a>,
|
||||
context: &ExpandContext,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
trace!(target: "nu::expand_syntax", "before {} :: {:?}", std::any::type_name::<T>(), debug_tokens(token_nodes.state(), context.source));
|
||||
trace!(target: "nu::expand_expression", "before {} :: {:?}", std::any::type_name::<T>(), debug_tokens(token_nodes.state(), context.source));
|
||||
|
||||
let result = shape.expand_syntax(token_nodes, context);
|
||||
let result = shape.expand_expr(token_nodes, context);
|
||||
|
||||
match result {
|
||||
Err(err) => {
|
||||
trace!(target: "nu::expand_syntax", "error :: {} :: {:?}", err, debug_tokens(token_nodes.state(), context.source));
|
||||
trace!(target: "nu::expand_expression", "error :: {} :: {:?}", err, debug_tokens(token_nodes.state(), context.source));
|
||||
Err(err)
|
||||
}
|
||||
|
||||
Ok(result) => {
|
||||
trace!(target: "nu::expand_syntax", "ok :: {:?} :: {:?}", result, debug_tokens(token_nodes.state(), context.source));
|
||||
trace!(target: "nu::expand_expression", "ok :: {:?} :: {:?}", result, debug_tokens(token_nodes.state(), context.source));
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@ -719,11 +719,7 @@ impl TestSyntax for BareShape {
|
||||
let peeked = token_nodes.peek_any();
|
||||
|
||||
match peeked.node {
|
||||
Some(TokenNode::Token(token)) => match token.item {
|
||||
RawToken::Bare => Some(peeked),
|
||||
_ => None,
|
||||
},
|
||||
|
||||
Some(token) if token.is_bare() => Some(peeked),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,10 @@ impl<'tokens> SpannedAtomicToken<'tokens> {
|
||||
Expression::external_command(*command, self.span)
|
||||
}
|
||||
AtomicToken::ExternalWord { text } => Expression::string(*text, self.span),
|
||||
AtomicToken::GlobPattern { pattern } => Expression::pattern(*pattern),
|
||||
AtomicToken::GlobPattern { pattern } => Expression::pattern(
|
||||
expand_file_path(pattern.slice(context.source), context).to_string_lossy(),
|
||||
self.span,
|
||||
),
|
||||
AtomicToken::Word { text } => Expression::string(*text, *text),
|
||||
AtomicToken::SquareDelimited { .. } => unimplemented!("into_hir"),
|
||||
AtomicToken::ParenDelimited { .. } => unimplemented!("into_hir"),
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::parser::hir::syntax_shape::{
|
||||
expand_atom, expand_bare, expand_syntax, expression::expand_file_path, parse_single_node,
|
||||
AtomicToken, ExpandContext, ExpandExpression, ExpandSyntax, ExpansionRule, FallibleColorSyntax,
|
||||
FlatShape,
|
||||
expand_atom, expand_bare, expression::expand_file_path, AtomicToken, ExpandContext,
|
||||
ExpandExpression, ExpandSyntax, ExpansionRule, FallibleColorSyntax, FlatShape,
|
||||
};
|
||||
use crate::parser::{hir, hir::TokensIterator, Operator, RawToken, TokenNode};
|
||||
use crate::prelude::*;
|
||||
@ -72,43 +71,17 @@ impl ExpandExpression for PatternShape {
|
||||
token_nodes: &mut TokensIterator<'_>,
|
||||
context: &ExpandContext,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
let pattern = expand_syntax(&BarePatternShape, token_nodes, context);
|
||||
let atom = expand_atom(token_nodes, "pattern", context, ExpansionRule::new())?;
|
||||
|
||||
match pattern {
|
||||
Ok(tag) => {
|
||||
return Ok(hir::Expression::pattern(tag));
|
||||
match atom.item {
|
||||
AtomicToken::Word { text: body }
|
||||
| AtomicToken::String { body }
|
||||
| AtomicToken::GlobPattern { pattern: body } => {
|
||||
let path = expand_file_path(body.slice(context.source), context);
|
||||
return Ok(hir::Expression::pattern(path.to_string_lossy(), atom.span));
|
||||
}
|
||||
Err(_) => {}
|
||||
_ => return atom.into_hir(context, "pattern"),
|
||||
}
|
||||
|
||||
parse_single_node(token_nodes, "Pattern", |token, token_tag, _| {
|
||||
Ok(match token {
|
||||
RawToken::GlobPattern => {
|
||||
return Err(ShellError::unreachable(
|
||||
"glob pattern after glob already returned",
|
||||
))
|
||||
}
|
||||
RawToken::Operator(..) => {
|
||||
return Err(ShellError::unreachable("dot after glob already returned"))
|
||||
}
|
||||
RawToken::Bare => {
|
||||
return Err(ShellError::unreachable("bare after glob already returned"))
|
||||
}
|
||||
|
||||
RawToken::Variable(tag) if tag.slice(context.source) == "it" => {
|
||||
hir::Expression::it_variable(tag, token_tag)
|
||||
}
|
||||
RawToken::Variable(tag) => hir::Expression::variable(tag, token_tag),
|
||||
RawToken::ExternalCommand(tag) => hir::Expression::external_command(tag, token_tag),
|
||||
RawToken::ExternalWord => return Err(ShellError::invalid_external_word(token_tag)),
|
||||
RawToken::Number(_) => hir::Expression::bare(token_tag),
|
||||
|
||||
RawToken::String(tag) => hir::Expression::file_path(
|
||||
expand_file_path(tag.slice(context.source), context),
|
||||
token_tag,
|
||||
),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use crate::parser::hir::syntax_shape::{
|
||||
ExpansionRule, FallibleColorSyntax, FlatShape, TestSyntax,
|
||||
};
|
||||
use crate::parser::hir::tokens_iterator::Peeked;
|
||||
use crate::parser::{hir, hir::TokensIterator, RawToken, TokenNode};
|
||||
use crate::parser::{hir, hir::TokensIterator, RawToken};
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@ -118,11 +118,7 @@ impl TestSyntax for StringShape {
|
||||
let peeked = token_nodes.peek_any();
|
||||
|
||||
match peeked.node {
|
||||
Some(TokenNode::Token(token)) => match token.item {
|
||||
RawToken::String(_) => Some(peeked),
|
||||
_ => None,
|
||||
},
|
||||
|
||||
Some(token) if token.is_string() => Some(peeked),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -821,7 +821,7 @@ impl ExpandSyntax for MemberShape {
|
||||
|
||||
if let Some(peeked) = string {
|
||||
let node = peeked.not_eof("column")?.commit();
|
||||
let (outer, inner) = node.expect_string();
|
||||
let (outer, inner) = node.as_string().unwrap();
|
||||
|
||||
return Ok(Member::String(outer, inner));
|
||||
}
|
||||
|
@ -566,7 +566,7 @@ impl<'content> TokensIterator<'content> {
|
||||
impl<'content> Iterator for TokensIterator<'content> {
|
||||
type Item = &'content TokenNode;
|
||||
|
||||
fn next(&mut self) -> Option<&'content TokenNode> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
next(self, self.state.skip_ws)
|
||||
}
|
||||
}
|
||||
|
@ -666,7 +666,7 @@ fn is_glob_specific_char(c: char) -> bool {
|
||||
}
|
||||
|
||||
fn is_start_glob_char(c: char) -> bool {
|
||||
is_start_bare_char(c) || is_glob_specific_char(c)
|
||||
is_start_bare_char(c) || is_glob_specific_char(c) || c == '.'
|
||||
}
|
||||
|
||||
fn is_glob_char(c: char) -> bool {
|
||||
@ -1147,7 +1147,7 @@ mod tests {
|
||||
fn test_patterns() {
|
||||
equal_tokens! {
|
||||
<pipeline>
|
||||
"cp ../formats/*" -> b::pipeline(vec![vec![b::bare("cp"), b::sp(), b::op("."), b::op("."), b::pattern("/formats/*")]])
|
||||
"cp ../formats/*" -> b::pipeline(vec![vec![b::bare("cp"), b::sp(), b::pattern("../formats/*")]])
|
||||
}
|
||||
|
||||
equal_tokens! {
|
||||
|
@ -155,6 +155,26 @@ impl TokenNode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_string(&self) -> bool {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::String(_),
|
||||
..
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_string(&self) -> Option<(Span, Span)> {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::String(inner_span),
|
||||
span: outer_span,
|
||||
}) => Some((*outer_span, *inner_span)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_pattern(&self) -> bool {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
@ -200,16 +220,6 @@ impl TokenNode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_external(&self) -> Span {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::ExternalCommand(span),
|
||||
..
|
||||
}) => *span,
|
||||
_ => panic!("Only call expect_external if you checked is_external first"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_flag(&self, value: &str, source: &Text) -> Option<Spanned<Flag>> {
|
||||
match self {
|
||||
TokenNode::Flag(
|
||||
@ -224,7 +234,7 @@ impl TokenNode {
|
||||
pub fn as_pipeline(&self) -> Result<Pipeline, ShellError> {
|
||||
match self {
|
||||
TokenNode::Pipeline(Spanned { item, .. }) => Ok(item.clone()),
|
||||
_ => Err(ShellError::unimplemented("unimplemented")),
|
||||
_ => Err(ShellError::type_error("pipeline", self.tagged_type_name())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,49 +244,6 @@ impl TokenNode {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_string(&self) -> (Span, Span) {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::String(inner_span),
|
||||
span: outer_span,
|
||||
}) => (*outer_span, *inner_span),
|
||||
other => panic!("Expected string, found {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl TokenNode {
|
||||
pub fn expect_list(&self) -> Tagged<&[TokenNode]> {
|
||||
match self {
|
||||
TokenNode::Nodes(Spanned { item, span }) => (&item[..]).tagged(Tag {
|
||||
span: *span,
|
||||
anchor: None,
|
||||
}),
|
||||
other => panic!("Expected list, found {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_var(&self) -> (Span, Span) {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::Variable(inner_span),
|
||||
span: outer_span,
|
||||
}) => (*outer_span, *inner_span),
|
||||
other => panic!("Expected var, found {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_bare(&self) -> Span {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::Bare,
|
||||
span,
|
||||
}) => *span,
|
||||
other => panic!("Expected bare, found {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Getters, new)]
|
||||
@ -328,3 +295,76 @@ pub struct PathNode {
|
||||
head: Box<TokenNode>,
|
||||
tail: Vec<TokenNode>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl TokenNode {
|
||||
pub fn expect_external(&self) -> Span {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::ExternalCommand(span),
|
||||
..
|
||||
}) => *span,
|
||||
other => panic!(
|
||||
"Only call expect_external if you checked is_external first, found {:?}",
|
||||
other
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_string(&self) -> (Span, Span) {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::String(inner_span),
|
||||
span: outer_span,
|
||||
}) => (*outer_span, *inner_span),
|
||||
other => panic!("Expected string, found {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_list(&self) -> &[TokenNode] {
|
||||
match self {
|
||||
TokenNode::Nodes(token_nodes) => &token_nodes[..],
|
||||
other => panic!("Expected list, found {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_pattern(&self) -> Span {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::GlobPattern,
|
||||
span: outer_span,
|
||||
}) => *outer_span,
|
||||
other => panic!("Expected pattern, found {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_var(&self) -> (Span, Span) {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::Variable(inner_span),
|
||||
span: outer_span,
|
||||
}) => (*outer_span, *inner_span),
|
||||
other => panic!("Expected var, found {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_dot(&self) -> Span {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::Operator(Operator::Dot),
|
||||
span,
|
||||
}) => *span,
|
||||
other => panic!("Expected dot, found {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_bare(&self) -> Span {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
item: RawToken::Bare,
|
||||
span,
|
||||
}) => *span,
|
||||
other => panic!("Expected bare, found {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user