mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 02:55:07 +02:00
Add cell paths
This commit is contained in:
19
crates/nu-protocol/src/ast/cell_path.rs
Normal file
19
crates/nu-protocol/src/ast/cell_path.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use super::Expression;
|
||||
use crate::Span;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PathMember {
|
||||
String { val: String, span: Span },
|
||||
Int { val: usize, span: Span },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CellPath {
|
||||
pub members: Vec<PathMember>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FullCellPath {
|
||||
pub head: Expression,
|
||||
pub tail: Vec<PathMember>,
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use super::{Call, Expression, Operator, RangeOperator};
|
||||
use super::{Call, Expression, FullCellPath, Operator, RangeOperator};
|
||||
use crate::{BlockId, Signature, Span, VarId};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -22,6 +22,7 @@ pub enum Expr {
|
||||
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
||||
Keyword(Vec<u8>, Span, Box<Expression>),
|
||||
String(String), // FIXME: improve this in the future?
|
||||
FullCellPath(Box<FullCellPath>),
|
||||
Signature(Box<Signature>),
|
||||
Garbage,
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
mod block;
|
||||
mod call;
|
||||
mod cell_path;
|
||||
mod expr;
|
||||
mod expression;
|
||||
mod operator;
|
||||
@ -8,6 +9,7 @@ mod statement;
|
||||
|
||||
pub use block::*;
|
||||
pub use call::*;
|
||||
pub use cell_path::*;
|
||||
pub use expr::*;
|
||||
pub use expression::*;
|
||||
pub use operator::*;
|
||||
|
@ -17,4 +17,8 @@ pub enum ShellError {
|
||||
CantConvert(String, Span),
|
||||
DivisionByZero(Span),
|
||||
CannotCreateRange(Span),
|
||||
AccessBeyondEnd(usize, Span),
|
||||
AccessBeyondEndOfStream(Span),
|
||||
IncompatiblePathAccess(String, Span),
|
||||
CantFindColumn(Span),
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ pub enum SyntaxShape {
|
||||
String,
|
||||
|
||||
/// A dotted path to navigate the table
|
||||
ColumnPath,
|
||||
CellPath,
|
||||
|
||||
/// A dotted path to navigate the table (including variable)
|
||||
FullColumnPath,
|
||||
FullCellPath,
|
||||
|
||||
/// Only a numeric (integer or decimal) value is allowed
|
||||
Number,
|
||||
@ -76,12 +76,12 @@ impl SyntaxShape {
|
||||
match self {
|
||||
SyntaxShape::Any => Type::Unknown,
|
||||
SyntaxShape::Block => Type::Block,
|
||||
SyntaxShape::ColumnPath => Type::Unknown,
|
||||
SyntaxShape::CellPath => Type::Unknown,
|
||||
SyntaxShape::Duration => Type::Duration,
|
||||
SyntaxShape::Expression => Type::Unknown,
|
||||
SyntaxShape::FilePath => Type::FilePath,
|
||||
SyntaxShape::Filesize => Type::Filesize,
|
||||
SyntaxShape::FullColumnPath => Type::Unknown,
|
||||
SyntaxShape::FullCellPath => Type::Unknown,
|
||||
SyntaxShape::GlobPattern => Type::String,
|
||||
SyntaxShape::Int => Type::Int,
|
||||
SyntaxShape::List(x) => {
|
||||
|
@ -8,7 +8,7 @@ pub enum Type {
|
||||
Bool,
|
||||
String,
|
||||
Block,
|
||||
ColumnPath,
|
||||
CellPath,
|
||||
Duration,
|
||||
FilePath,
|
||||
Filesize,
|
||||
@ -27,7 +27,7 @@ impl Display for Type {
|
||||
match self {
|
||||
Type::Block => write!(f, "block"),
|
||||
Type::Bool => write!(f, "bool"),
|
||||
Type::ColumnPath => write!(f, "column path"),
|
||||
Type::CellPath => write!(f, "cell path"),
|
||||
Type::Duration => write!(f, "duration"),
|
||||
Type::FilePath => write!(f, "filepath"),
|
||||
Type::Filesize => write!(f, "filesize"),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{cell::RefCell, fmt::Debug, rc::Rc};
|
||||
|
||||
use crate::ast::RangeInclusion;
|
||||
use crate::ast::{PathMember, RangeInclusion};
|
||||
use crate::{span, BlockId, Span, Type};
|
||||
|
||||
use crate::ShellError;
|
||||
@ -364,21 +364,26 @@ impl Value {
|
||||
}
|
||||
Value::String { val, .. } => val,
|
||||
Value::ValueStream { stream, .. } => stream.into_string(),
|
||||
Value::List { val, .. } => val
|
||||
.into_iter()
|
||||
.map(|x| x.into_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
Value::Table { val, .. } => val
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
x.into_iter()
|
||||
.map(|x| x.into_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
Value::List { val, .. } => format!(
|
||||
"[{}]",
|
||||
val.into_iter()
|
||||
.map(|x| x.into_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
Value::Table { val, headers, .. } => format!(
|
||||
"[= {} =\n {}]",
|
||||
headers.join(", "),
|
||||
val.into_iter()
|
||||
.map(|x| {
|
||||
x.into_iter()
|
||||
.map(|x| x.into_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
),
|
||||
Value::RowStream {
|
||||
headers, stream, ..
|
||||
} => stream.into_string(headers),
|
||||
@ -393,6 +398,138 @@ impl Value {
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn follow_column_path(self, column_path: &[PathMember]) -> Result<Value, ShellError> {
|
||||
let mut current = self;
|
||||
for member in column_path {
|
||||
// FIXME: this uses a few extra clones for simplicity, but there may be a way
|
||||
// to traverse the path without them
|
||||
match member {
|
||||
PathMember::Int {
|
||||
val: count,
|
||||
span: origin_span,
|
||||
} => {
|
||||
// Treat a numeric path member as `nth <val>`
|
||||
match &mut current {
|
||||
Value::List { val, .. } => {
|
||||
if let Some(item) = val.get(*count) {
|
||||
current = item.clone();
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEnd(val.len(), *origin_span));
|
||||
}
|
||||
}
|
||||
Value::ValueStream { stream, .. } => {
|
||||
if let Some(item) = stream.nth(*count) {
|
||||
current = item;
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEndOfStream(*origin_span));
|
||||
}
|
||||
}
|
||||
Value::Table { headers, val, span } => {
|
||||
if let Some(row) = val.get(*count) {
|
||||
current = Value::Table {
|
||||
headers: headers.clone(),
|
||||
val: vec![row.clone()],
|
||||
span: *span,
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEnd(val.len(), *origin_span));
|
||||
}
|
||||
}
|
||||
Value::RowStream {
|
||||
headers,
|
||||
stream,
|
||||
span,
|
||||
} => {
|
||||
if let Some(row) = stream.nth(*count) {
|
||||
current = Value::Table {
|
||||
headers: headers.clone(),
|
||||
val: vec![row.clone()],
|
||||
span: *span,
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEndOfStream(*origin_span));
|
||||
}
|
||||
}
|
||||
x => {
|
||||
return Err(ShellError::IncompatiblePathAccess(
|
||||
format!("{}", x.get_type()),
|
||||
*origin_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
PathMember::String {
|
||||
val,
|
||||
span: origin_span,
|
||||
} => match &mut current {
|
||||
Value::Table {
|
||||
headers,
|
||||
val: cells,
|
||||
span,
|
||||
} => {
|
||||
let mut found = false;
|
||||
for header in headers.iter().enumerate() {
|
||||
if header.1 == val {
|
||||
found = true;
|
||||
|
||||
let mut column = vec![];
|
||||
for row in cells {
|
||||
column.push(row[header.0].clone())
|
||||
}
|
||||
|
||||
current = Value::List {
|
||||
val: column,
|
||||
span: *span,
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return Err(ShellError::CantFindColumn(*origin_span));
|
||||
}
|
||||
}
|
||||
Value::RowStream {
|
||||
headers,
|
||||
stream,
|
||||
span,
|
||||
} => {
|
||||
let mut found = false;
|
||||
for header in headers.iter().enumerate() {
|
||||
if header.1 == val {
|
||||
found = true;
|
||||
|
||||
let mut column = vec![];
|
||||
for row in stream {
|
||||
column.push(row[header.0].clone())
|
||||
}
|
||||
|
||||
current = Value::List {
|
||||
val: column,
|
||||
span: *span,
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
//FIXME: add "did you mean"
|
||||
return Err(ShellError::CantFindColumn(*origin_span));
|
||||
}
|
||||
}
|
||||
x => {
|
||||
return Err(ShellError::IncompatiblePathAccess(
|
||||
format!("{}", x.get_type()),
|
||||
*origin_span,
|
||||
))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(current)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Value {
|
||||
|
Reference in New Issue
Block a user