Expand tilde in patterns.

This commit is contained in:
Andrés N. Robalino 2019-10-26 20:01:58 -05:00
parent 1b3a09495d
commit 540cc4016e
12 changed files with 135 additions and 149 deletions

View File

@ -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)]

View File

@ -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)),
};

View File

@ -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",
}
}
}

View File

@ -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);

View File

@ -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,
}
}

View File

@ -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"),

View File

@ -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,
),
})
})
}
}

View File

@ -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,
}
}

View File

@ -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));
}

View File

@ -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)
}
}

View File

@ -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! {

View File

@ -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),
}
}
}