mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 14:25:55 +02:00
Merge branch 'main' of https://github.com/nushell/engine-q into source-command
This commit is contained in:
@ -15,6 +15,8 @@ pub enum FlatShape {
|
||||
Operator,
|
||||
Signature,
|
||||
String,
|
||||
Filepath,
|
||||
GlobPattern,
|
||||
Variable,
|
||||
Custom(String),
|
||||
}
|
||||
@ -79,6 +81,12 @@ pub fn flatten_expression(
|
||||
Expr::Float(_) => {
|
||||
vec![(expr.span, FlatShape::Float)]
|
||||
}
|
||||
Expr::ValueWithUnit(x, unit) => {
|
||||
let mut output = flatten_expression(working_set, x);
|
||||
output.push((unit.span, FlatShape::String));
|
||||
|
||||
output
|
||||
}
|
||||
Expr::CellPath(cell_path) => {
|
||||
let mut output = vec![];
|
||||
for path_element in &cell_path.members {
|
||||
@ -118,7 +126,12 @@ pub fn flatten_expression(
|
||||
Expr::Bool(_) => {
|
||||
vec![(expr.span, FlatShape::Bool)]
|
||||
}
|
||||
|
||||
Expr::Filepath(_) => {
|
||||
vec![(expr.span, FlatShape::Filepath)]
|
||||
}
|
||||
Expr::GlobPattern(_) => {
|
||||
vec![(expr.span, FlatShape::GlobPattern)]
|
||||
}
|
||||
Expr::List(list) => {
|
||||
let mut output = vec![];
|
||||
for l in list {
|
||||
|
@ -601,12 +601,90 @@ pub fn parse_hide(
|
||||
let (name_expr, err) = parse_string(working_set, spans[1]);
|
||||
error = error.or(err);
|
||||
|
||||
let name_bytes: Vec<u8> = working_set.get_span_contents(spans[1]).into();
|
||||
let (import_pattern, err) = parse_import_pattern(working_set, spans[1]);
|
||||
error = error.or(err);
|
||||
|
||||
// TODO: Do the import pattern stuff for bulk-hiding
|
||||
let exported_names: Vec<Vec<u8>> =
|
||||
if let Some(block_id) = working_set.find_module(&import_pattern.head) {
|
||||
working_set
|
||||
.get_block(block_id)
|
||||
.exports
|
||||
.iter()
|
||||
.map(|(name, _)| name.clone())
|
||||
.collect()
|
||||
} else if import_pattern.members.is_empty() {
|
||||
// The pattern head can be e.g. a function name, not just a module
|
||||
vec![import_pattern.head.clone()]
|
||||
} else {
|
||||
return (
|
||||
garbage_statement(spans),
|
||||
Some(ParseError::ModuleNotFound(spans[1])),
|
||||
);
|
||||
};
|
||||
|
||||
if working_set.hide_decl(&name_bytes).is_none() {
|
||||
error = error.or_else(|| Some(ParseError::UnknownCommand(spans[1])));
|
||||
// This kind of inverts the import pattern matching found in parse_use()
|
||||
let names_to_hide = if import_pattern.members.is_empty() {
|
||||
exported_names
|
||||
} else {
|
||||
match &import_pattern.members[0] {
|
||||
ImportPatternMember::Glob { .. } => exported_names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
let mut new_name = import_pattern.head.to_vec();
|
||||
new_name.push(b'.');
|
||||
new_name.extend(&name);
|
||||
new_name
|
||||
})
|
||||
.collect(),
|
||||
ImportPatternMember::Name { name, span } => {
|
||||
let new_exports: Vec<Vec<u8>> = exported_names
|
||||
.into_iter()
|
||||
.filter(|n| n == name)
|
||||
.map(|n| {
|
||||
let mut new_name = import_pattern.head.to_vec();
|
||||
new_name.push(b'.');
|
||||
new_name.extend(&n);
|
||||
new_name
|
||||
})
|
||||
.collect();
|
||||
|
||||
if new_exports.is_empty() {
|
||||
error = error.or(Some(ParseError::ExportNotFound(*span)))
|
||||
}
|
||||
|
||||
new_exports
|
||||
}
|
||||
ImportPatternMember::List { names } => {
|
||||
let mut output = vec![];
|
||||
|
||||
for (name, span) in names {
|
||||
let mut new_exports: Vec<Vec<u8>> = exported_names
|
||||
.iter()
|
||||
.filter_map(|n| if n == name { Some(n.clone()) } else { None })
|
||||
.map(|n| {
|
||||
let mut new_name = import_pattern.head.to_vec();
|
||||
new_name.push(b'.');
|
||||
new_name.extend(n);
|
||||
new_name
|
||||
})
|
||||
.collect();
|
||||
|
||||
if new_exports.is_empty() {
|
||||
error = error.or(Some(ParseError::ExportNotFound(*span)))
|
||||
} else {
|
||||
output.append(&mut new_exports)
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for name in names_to_hide {
|
||||
if working_set.hide_decl(&name).is_none() {
|
||||
error = error.or_else(|| Some(ParseError::UnknownCommand(spans[1])));
|
||||
}
|
||||
}
|
||||
|
||||
// Create the Hide command call
|
||||
|
@ -11,7 +11,7 @@ use nu_protocol::{
|
||||
Operator, PathMember, Pipeline, RangeInclusion, RangeOperator, Statement,
|
||||
},
|
||||
engine::StateWorkingSet,
|
||||
span, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId,
|
||||
span, Flag, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, Unit, VarId,
|
||||
};
|
||||
|
||||
use crate::parse_keywords::{
|
||||
@ -1321,6 +1321,255 @@ pub fn parse_full_cell_path(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_filepath(
|
||||
working_set: &mut StateWorkingSet,
|
||||
span: Span,
|
||||
) -> (Expression, Option<ParseError>) {
|
||||
let bytes = working_set.get_span_contents(span);
|
||||
let bytes = if (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
|
||||
|| (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
|
||||
{
|
||||
&bytes[1..(bytes.len() - 1)]
|
||||
} else {
|
||||
bytes
|
||||
};
|
||||
|
||||
if let Ok(token) = String::from_utf8(bytes.into()) {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::Filepath(token),
|
||||
span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
},
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Expected("string".into(), span)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a duration type, eg '10day'
|
||||
pub fn parse_duration(
|
||||
working_set: &mut StateWorkingSet,
|
||||
span: Span,
|
||||
) -> (Expression, Option<ParseError>) {
|
||||
fn parse_decimal_str_to_number(decimal: &str) -> Option<i64> {
|
||||
let string_to_parse = format!("0.{}", decimal);
|
||||
if let Ok(x) = string_to_parse.parse::<f64>() {
|
||||
return Some((1_f64 / x) as i64);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
let bytes = working_set.get_span_contents(span);
|
||||
let token = String::from_utf8_lossy(bytes).to_string();
|
||||
|
||||
let unit_groups = [
|
||||
(Unit::Nanosecond, "NS", None),
|
||||
(Unit::Microsecond, "US", Some((Unit::Nanosecond, 1000))),
|
||||
(Unit::Millisecond, "MS", Some((Unit::Microsecond, 1000))),
|
||||
(Unit::Second, "SEC", Some((Unit::Millisecond, 1000))),
|
||||
(Unit::Minute, "MIN", Some((Unit::Second, 60))),
|
||||
(Unit::Hour, "HR", Some((Unit::Minute, 60))),
|
||||
(Unit::Day, "DAY", Some((Unit::Minute, 1440))),
|
||||
(Unit::Week, "WK", Some((Unit::Day, 7))),
|
||||
];
|
||||
if let Some(unit) = unit_groups
|
||||
.iter()
|
||||
.find(|&x| token.to_uppercase().ends_with(x.1))
|
||||
{
|
||||
let mut lhs = token.clone();
|
||||
for _ in 0..unit.1.len() {
|
||||
lhs.pop();
|
||||
}
|
||||
|
||||
let input: Vec<&str> = lhs.split('.').collect();
|
||||
let (value, unit_to_use) = match &input[..] {
|
||||
[number_str] => (number_str.parse::<i64>().ok(), unit.0),
|
||||
[number_str, decimal_part_str] => match unit.2 {
|
||||
Some(unit_to_convert_to) => match (
|
||||
number_str.parse::<i64>(),
|
||||
parse_decimal_str_to_number(decimal_part_str),
|
||||
) {
|
||||
(Ok(number), Some(decimal_part)) => (
|
||||
Some(
|
||||
(number * unit_to_convert_to.1) + (unit_to_convert_to.1 / decimal_part),
|
||||
),
|
||||
unit_to_convert_to.0,
|
||||
),
|
||||
_ => (None, unit.0),
|
||||
},
|
||||
None => (None, unit.0),
|
||||
},
|
||||
_ => (None, unit.0),
|
||||
};
|
||||
|
||||
if let Some(x) = value {
|
||||
let lhs_span = Span::new(span.start, span.start + lhs.len());
|
||||
let unit_span = Span::new(span.start + lhs.len(), span.end);
|
||||
return (
|
||||
Expression {
|
||||
expr: Expr::ValueWithUnit(
|
||||
Box::new(Expression {
|
||||
expr: Expr::Int(x),
|
||||
span: lhs_span,
|
||||
ty: Type::Number,
|
||||
custom_completion: None,
|
||||
}),
|
||||
Spanned {
|
||||
item: unit_to_use,
|
||||
span: unit_span,
|
||||
},
|
||||
),
|
||||
span,
|
||||
ty: Type::Duration,
|
||||
custom_completion: None,
|
||||
},
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Mismatch(
|
||||
"duration".into(),
|
||||
"non-duration unit".into(),
|
||||
span,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse a unit type, eg '10kb'
|
||||
pub fn parse_filesize(
|
||||
working_set: &mut StateWorkingSet,
|
||||
span: Span,
|
||||
) -> (Expression, Option<ParseError>) {
|
||||
fn parse_decimal_str_to_number(decimal: &str) -> Option<i64> {
|
||||
let string_to_parse = format!("0.{}", decimal);
|
||||
if let Ok(x) = string_to_parse.parse::<f64>() {
|
||||
return Some((1_f64 / x) as i64);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
let bytes = working_set.get_span_contents(span);
|
||||
let token = String::from_utf8_lossy(bytes).to_string();
|
||||
|
||||
let unit_groups = [
|
||||
(Unit::Kilobyte, "KB", Some((Unit::Byte, 1000))),
|
||||
(Unit::Megabyte, "MB", Some((Unit::Kilobyte, 1000))),
|
||||
(Unit::Gigabyte, "GB", Some((Unit::Megabyte, 1000))),
|
||||
(Unit::Terabyte, "TB", Some((Unit::Gigabyte, 1000))),
|
||||
(Unit::Petabyte, "PB", Some((Unit::Terabyte, 1000))),
|
||||
(Unit::Kibibyte, "KIB", Some((Unit::Byte, 1024))),
|
||||
(Unit::Mebibyte, "MIB", Some((Unit::Kibibyte, 1024))),
|
||||
(Unit::Gibibyte, "GIB", Some((Unit::Mebibyte, 1024))),
|
||||
(Unit::Tebibyte, "TIB", Some((Unit::Gibibyte, 1024))),
|
||||
(Unit::Pebibyte, "PIB", Some((Unit::Tebibyte, 1024))),
|
||||
(Unit::Byte, "B", None),
|
||||
];
|
||||
if let Some(unit) = unit_groups
|
||||
.iter()
|
||||
.find(|&x| token.to_uppercase().ends_with(x.1))
|
||||
{
|
||||
let mut lhs = token.clone();
|
||||
for _ in 0..unit.1.len() {
|
||||
lhs.pop();
|
||||
}
|
||||
|
||||
let input: Vec<&str> = lhs.split('.').collect();
|
||||
let (value, unit_to_use) = match &input[..] {
|
||||
[number_str] => (number_str.parse::<i64>().ok(), unit.0),
|
||||
[number_str, decimal_part_str] => match unit.2 {
|
||||
Some(unit_to_convert_to) => match (
|
||||
number_str.parse::<i64>(),
|
||||
parse_decimal_str_to_number(decimal_part_str),
|
||||
) {
|
||||
(Ok(number), Some(decimal_part)) => (
|
||||
Some(
|
||||
(number * unit_to_convert_to.1) + (unit_to_convert_to.1 / decimal_part),
|
||||
),
|
||||
unit_to_convert_to.0,
|
||||
),
|
||||
_ => (None, unit.0),
|
||||
},
|
||||
None => (None, unit.0),
|
||||
},
|
||||
_ => (None, unit.0),
|
||||
};
|
||||
|
||||
if let Some(x) = value {
|
||||
let lhs_span = Span::new(span.start, span.start + lhs.len());
|
||||
let unit_span = Span::new(span.start + lhs.len(), span.end);
|
||||
return (
|
||||
Expression {
|
||||
expr: Expr::ValueWithUnit(
|
||||
Box::new(Expression {
|
||||
expr: Expr::Int(x),
|
||||
span: lhs_span,
|
||||
ty: Type::Number,
|
||||
custom_completion: None,
|
||||
}),
|
||||
Spanned {
|
||||
item: unit_to_use,
|
||||
span: unit_span,
|
||||
},
|
||||
),
|
||||
span,
|
||||
ty: Type::Filesize,
|
||||
custom_completion: None,
|
||||
},
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Mismatch(
|
||||
"filesize".into(),
|
||||
"non-filesize unit".into(),
|
||||
span,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_glob_pattern(
|
||||
working_set: &mut StateWorkingSet,
|
||||
span: Span,
|
||||
) -> (Expression, Option<ParseError>) {
|
||||
let bytes = working_set.get_span_contents(span);
|
||||
let bytes = if (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
|
||||
|| (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
|
||||
{
|
||||
&bytes[1..(bytes.len() - 1)]
|
||||
} else {
|
||||
bytes
|
||||
};
|
||||
|
||||
if let Ok(token) = String::from_utf8(bytes.into()) {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::GlobPattern(token),
|
||||
span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
},
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Expected("string".into(), span)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_string(
|
||||
working_set: &mut StateWorkingSet,
|
||||
span: Span,
|
||||
@ -1365,7 +1614,7 @@ pub fn parse_shape_name(
|
||||
b"number" => SyntaxShape::Number,
|
||||
b"range" => SyntaxShape::Range,
|
||||
b"int" => SyntaxShape::Int,
|
||||
b"path" => SyntaxShape::FilePath,
|
||||
b"path" => SyntaxShape::Filepath,
|
||||
b"glob" => SyntaxShape::GlobPattern,
|
||||
b"block" => SyntaxShape::Block(None), //FIXME
|
||||
b"cond" => SyntaxShape::RowCondition,
|
||||
@ -2320,10 +2569,12 @@ pub fn parse_value(
|
||||
}
|
||||
SyntaxShape::Number => parse_number(bytes, span),
|
||||
SyntaxShape::Int => parse_int(bytes, span),
|
||||
SyntaxShape::Duration => parse_duration(working_set, span),
|
||||
SyntaxShape::Filesize => parse_filesize(working_set, span),
|
||||
SyntaxShape::Range => parse_range(working_set, span),
|
||||
SyntaxShape::String | SyntaxShape::GlobPattern | SyntaxShape::FilePath => {
|
||||
parse_string(working_set, span)
|
||||
}
|
||||
SyntaxShape::Filepath => parse_filepath(working_set, span),
|
||||
SyntaxShape::GlobPattern => parse_glob_pattern(working_set, span),
|
||||
SyntaxShape::String => parse_string(working_set, span),
|
||||
SyntaxShape::Block(_) => {
|
||||
if bytes.starts_with(b"{") {
|
||||
parse_block_expression(working_set, shape, span)
|
||||
|
@ -29,6 +29,9 @@ pub fn math_result_type(
|
||||
(Type::Int, Type::Float) => (Type::Float, None),
|
||||
(Type::Float, Type::Float) => (Type::Float, None),
|
||||
(Type::String, Type::String) => (Type::String, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Duration, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Filesize, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Unknown, None),
|
||||
(_, Type::Unknown) => (Type::Unknown, None),
|
||||
(Type::Int, _) => {
|
||||
@ -64,6 +67,9 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Float, None),
|
||||
(Type::Int, Type::Float) => (Type::Float, None),
|
||||
(Type::Float, Type::Float) => (Type::Float, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Duration, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Filesize, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Unknown, None),
|
||||
(_, Type::Unknown) => (Type::Unknown, None),
|
||||
_ => {
|
||||
@ -85,6 +91,7 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Float, None),
|
||||
(Type::Int, Type::Float) => (Type::Float, None),
|
||||
(Type::Float, Type::Float) => (Type::Float, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Unknown, None),
|
||||
(_, Type::Unknown) => (Type::Unknown, None),
|
||||
_ => {
|
||||
@ -106,6 +113,7 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Float, None),
|
||||
(Type::Int, Type::Float) => (Type::Float, None),
|
||||
(Type::Float, Type::Float) => (Type::Float, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Unknown, None),
|
||||
(_, Type::Unknown) => (Type::Unknown, None),
|
||||
_ => {
|
||||
@ -127,6 +135,9 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Bool, None),
|
||||
(Type::Int, Type::Float) => (Type::Bool, None),
|
||||
(Type::Float, Type::Float) => (Type::Bool, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Bool, None),
|
||||
(_, Type::Unknown) => (Type::Bool, None),
|
||||
_ => {
|
||||
@ -148,6 +159,9 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Bool, None),
|
||||
(Type::Int, Type::Float) => (Type::Bool, None),
|
||||
(Type::Float, Type::Float) => (Type::Bool, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Bool, None),
|
||||
(_, Type::Unknown) => (Type::Bool, None),
|
||||
_ => {
|
||||
@ -169,6 +183,9 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Bool, None),
|
||||
(Type::Int, Type::Float) => (Type::Bool, None),
|
||||
(Type::Float, Type::Float) => (Type::Bool, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Bool, None),
|
||||
(_, Type::Unknown) => (Type::Bool, None),
|
||||
_ => {
|
||||
@ -190,6 +207,9 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Bool, None),
|
||||
(Type::Int, Type::Float) => (Type::Bool, None),
|
||||
(Type::Float, Type::Float) => (Type::Bool, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Bool, None),
|
||||
(_, Type::Unknown) => (Type::Bool, None),
|
||||
_ => {
|
||||
@ -209,6 +229,9 @@ pub fn math_result_type(
|
||||
Operator::Equal => match (&lhs.ty, &rhs.ty) {
|
||||
(Type::Float, Type::Int) => (Type::Bool, None),
|
||||
(Type::Int, Type::Float) => (Type::Bool, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
||||
|
||||
(x, y) if x == y => (Type::Bool, None),
|
||||
(Type::Unknown, _) => (Type::Bool, None),
|
||||
(_, Type::Unknown) => (Type::Bool, None),
|
||||
@ -231,6 +254,9 @@ pub fn math_result_type(
|
||||
(Type::Float, Type::Int) => (Type::Bool, None),
|
||||
(Type::Int, Type::Float) => (Type::Bool, None),
|
||||
(Type::Float, Type::Float) => (Type::Bool, None),
|
||||
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
||||
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
||||
|
||||
(Type::Unknown, _) => (Type::Bool, None),
|
||||
(_, Type::Unknown) => (Type::Bool, None),
|
||||
_ => {
|
||||
|
Reference in New Issue
Block a user