mirror of
https://github.com/nushell/nushell.git
synced 2025-08-10 01:07:48 +02:00
Merge branch 'main' of https://github.com/nushell/engine-q into externals
This commit is contained in:
@ -25,4 +25,14 @@ impl Call {
|
||||
named: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_flag(&self, flag_name: &str) -> bool {
|
||||
for name in &self.named {
|
||||
if flag_name == name.0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,9 @@ pub enum Expr {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Range(
|
||||
Option<Box<Expression>>,
|
||||
Option<Box<Expression>>,
|
||||
Option<Box<Expression>>, // from
|
||||
Option<Box<Expression>>, // next value after "from"
|
||||
Option<Box<Expression>>, // to
|
||||
RangeOperator,
|
||||
),
|
||||
Var(VarId),
|
||||
|
@ -6,6 +6,7 @@ pub struct Expression {
|
||||
pub expr: Expr,
|
||||
pub span: Span,
|
||||
pub ty: Type,
|
||||
pub custom_completion: Option<String>,
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
@ -14,6 +15,7 @@ impl Expression {
|
||||
expr: Expr::Garbage,
|
||||
span,
|
||||
ty: Type::Unknown,
|
||||
custom_completion: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ pub enum RangeInclusion {
|
||||
pub struct RangeOperator {
|
||||
pub inclusion: RangeInclusion,
|
||||
pub span: Span,
|
||||
pub next_op_span: Span,
|
||||
}
|
||||
|
||||
impl Display for RangeOperator {
|
||||
|
@ -34,7 +34,7 @@ pub enum SyntaxShape {
|
||||
GlobPattern,
|
||||
|
||||
/// A block is allowed, eg `{start this thing}`
|
||||
Block,
|
||||
Block(Option<Vec<SyntaxShape>>),
|
||||
|
||||
/// A table is allowed, eg `[[first, second]; [1, 2]]`
|
||||
Table,
|
||||
@ -69,14 +69,18 @@ pub enum SyntaxShape {
|
||||
|
||||
/// A general expression, eg `1 + 2` or `foo --bar`
|
||||
Expression,
|
||||
|
||||
/// A custom shape with custom completion logic
|
||||
Custom(Box<SyntaxShape>, String),
|
||||
}
|
||||
|
||||
impl SyntaxShape {
|
||||
pub fn to_type(&self) -> Type {
|
||||
match self {
|
||||
SyntaxShape::Any => Type::Unknown,
|
||||
SyntaxShape::Block => Type::Block,
|
||||
SyntaxShape::Block(_) => Type::Block,
|
||||
SyntaxShape::CellPath => Type::Unknown,
|
||||
SyntaxShape::Custom(custom, _) => custom.to_type(),
|
||||
SyntaxShape::Duration => Type::Duration,
|
||||
SyntaxShape::Expression => Type::Unknown,
|
||||
SyntaxShape::FilePath => Type::FilePath,
|
||||
|
@ -8,7 +8,7 @@ pub use stream::*;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::ast::{PathMember, RangeInclusion};
|
||||
use crate::ast::PathMember;
|
||||
use crate::{span, BlockId, Span, Type};
|
||||
|
||||
use crate::ShellError;
|
||||
@ -131,20 +131,10 @@ impl Value {
|
||||
Value::Int { val, .. } => val.to_string(),
|
||||
Value::Float { val, .. } => val.to_string(),
|
||||
Value::Range { val, .. } => {
|
||||
let vals: Vec<i64> = match (&val.from, &val.to) {
|
||||
(Value::Int { val: from, .. }, Value::Int { val: to, .. }) => {
|
||||
match val.inclusion {
|
||||
RangeInclusion::Inclusive => (*from..=*to).collect(),
|
||||
RangeInclusion::RightExclusive => (*from..*to).collect(),
|
||||
}
|
||||
}
|
||||
_ => Vec::new(),
|
||||
};
|
||||
|
||||
format!(
|
||||
"range: [{}]",
|
||||
vals.iter()
|
||||
.map(|x| x.to_string())
|
||||
val.into_iter()
|
||||
.map(|x| x.into_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
)
|
||||
|
@ -1,12 +1,108 @@
|
||||
use crate::{ast::RangeInclusion, *};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::{
|
||||
ast::{RangeInclusion, RangeOperator},
|
||||
*,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Range {
|
||||
pub from: Value,
|
||||
pub incr: Value,
|
||||
pub to: Value,
|
||||
pub inclusion: RangeInclusion,
|
||||
}
|
||||
|
||||
impl Range {
|
||||
pub fn new(
|
||||
expr_span: Span,
|
||||
from: Value,
|
||||
next: Value,
|
||||
to: Value,
|
||||
operator: &RangeOperator,
|
||||
) -> Result<Range, ShellError> {
|
||||
// Select from & to values if they're not specified
|
||||
// TODO: Replace the placeholder values with proper min/max based on data type
|
||||
let from = if let Value::Nothing { .. } = from {
|
||||
Value::Int {
|
||||
val: 0i64,
|
||||
span: Span::unknown(),
|
||||
}
|
||||
} else {
|
||||
from
|
||||
};
|
||||
|
||||
let to = if let Value::Nothing { .. } = to {
|
||||
if let Ok(Value::Bool { val: true, .. }) = next.lt(expr_span, &from) {
|
||||
Value::Int {
|
||||
val: -100i64,
|
||||
span: Span::unknown(),
|
||||
}
|
||||
} else {
|
||||
Value::Int {
|
||||
val: 100i64,
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
to
|
||||
};
|
||||
|
||||
// Check if the range counts up or down
|
||||
let moves_up = matches!(from.lte(expr_span, &to), Ok(Value::Bool { val: true, .. }));
|
||||
|
||||
// Convert the next value into the inctement
|
||||
let incr = if let Value::Nothing { .. } = next {
|
||||
if moves_up {
|
||||
Value::Int {
|
||||
val: 1i64,
|
||||
span: Span::unknown(),
|
||||
}
|
||||
} else {
|
||||
Value::Int {
|
||||
val: -1i64,
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next.sub(operator.next_op_span, &from)?
|
||||
};
|
||||
|
||||
let zero = Value::Int {
|
||||
val: 0i64,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
// Increment must be non-zero, otherwise we iterate forever
|
||||
if matches!(incr.eq(expr_span, &zero), Ok(Value::Bool { val: true, .. })) {
|
||||
return Err(ShellError::CannotCreateRange(expr_span));
|
||||
}
|
||||
|
||||
// If to > from, then incr > 0, otherwise we iterate forever
|
||||
if let (Value::Bool { val: true, .. }, Value::Bool { val: false, .. }) = (
|
||||
to.gt(operator.span, &from)?,
|
||||
incr.gt(operator.next_op_span, &zero)?,
|
||||
) {
|
||||
return Err(ShellError::CannotCreateRange(expr_span));
|
||||
}
|
||||
|
||||
// If to < from, then incr < 0, otherwise we iterate forever
|
||||
if let (Value::Bool { val: true, .. }, Value::Bool { val: false, .. }) = (
|
||||
to.lt(operator.span, &from)?,
|
||||
incr.lt(operator.next_op_span, &zero)?,
|
||||
) {
|
||||
return Err(ShellError::CannotCreateRange(expr_span));
|
||||
}
|
||||
|
||||
Ok(Range {
|
||||
from,
|
||||
incr,
|
||||
to,
|
||||
inclusion: operator.inclusion,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Range {
|
||||
type Item = Value;
|
||||
|
||||
@ -25,8 +121,7 @@ pub struct RangeIterator {
|
||||
span: Span,
|
||||
is_end_inclusive: bool,
|
||||
moves_up: bool,
|
||||
one: Value,
|
||||
negative_one: Value,
|
||||
incr: Value,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
@ -52,41 +147,66 @@ impl RangeIterator {
|
||||
span,
|
||||
is_end_inclusive: matches!(range.inclusion, RangeInclusion::Inclusive),
|
||||
done: false,
|
||||
one: Value::Int { val: 1, span },
|
||||
negative_one: Value::Int { val: -1, span },
|
||||
incr: range.incr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compare two floating point numbers. The decision interval for equality is dynamically scaled
|
||||
// as the value being compared increases in magnitude.
|
||||
fn compare_floats(val: f64, other: f64) -> Option<Ordering> {
|
||||
let prec = f64::EPSILON.max(val.abs() * f64::EPSILON);
|
||||
|
||||
if (other - val).abs() < prec {
|
||||
return Some(Ordering::Equal);
|
||||
}
|
||||
|
||||
val.partial_cmp(&other)
|
||||
}
|
||||
|
||||
impl Iterator for RangeIterator {
|
||||
type Item = Value;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
use std::cmp::Ordering;
|
||||
if self.done {
|
||||
return None;
|
||||
}
|
||||
|
||||
let ordering = if matches!(self.end, Value::Nothing { .. }) {
|
||||
Ordering::Less
|
||||
Some(Ordering::Less)
|
||||
} else {
|
||||
match (&self.curr, &self.end) {
|
||||
(Value::Int { val: x, .. }, Value::Int { val: y, .. }) => x.cmp(y),
|
||||
// (Value::Float { val: x, .. }, Value::Float { val: y, .. }) => x.cmp(y),
|
||||
// (Value::Float { val: x, .. }, Value::Int { val: y, .. }) => x.cmp(y),
|
||||
// (Value::Int { val: x, .. }, Value::Float { val: y, .. }) => x.cmp(y),
|
||||
_ => {
|
||||
self.done = true;
|
||||
return Some(Value::Error {
|
||||
error: ShellError::CannotCreateRange(self.span),
|
||||
});
|
||||
(Value::Int { val: curr, .. }, Value::Int { val: end, .. }) => Some(curr.cmp(end)),
|
||||
(Value::Float { val: curr, .. }, Value::Float { val: end, .. }) => {
|
||||
compare_floats(*curr, *end)
|
||||
}
|
||||
(Value::Float { val: curr, .. }, Value::Int { val: end, .. }) => {
|
||||
compare_floats(*curr, *end as f64)
|
||||
}
|
||||
(Value::Int { val: curr, .. }, Value::Float { val: end, .. }) => {
|
||||
compare_floats(*curr as f64, *end)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
|
||||
if self.moves_up
|
||||
&& (ordering == Ordering::Less || self.is_end_inclusive && ordering == Ordering::Equal)
|
||||
let ordering = if let Some(ord) = ordering {
|
||||
ord
|
||||
} else {
|
||||
self.done = true;
|
||||
return Some(Value::Error {
|
||||
error: ShellError::CannotCreateRange(self.span),
|
||||
});
|
||||
};
|
||||
|
||||
let desired_ordering = if self.moves_up {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
};
|
||||
|
||||
if (ordering == desired_ordering) || (self.is_end_inclusive && ordering == Ordering::Equal)
|
||||
{
|
||||
let next_value = self.curr.add(self.span, &self.one);
|
||||
let next_value = self.curr.add(self.span, &self.incr);
|
||||
|
||||
let mut next = match next_value {
|
||||
Ok(result) => result,
|
||||
@ -98,22 +218,6 @@ impl Iterator for RangeIterator {
|
||||
};
|
||||
std::mem::swap(&mut self.curr, &mut next);
|
||||
|
||||
Some(next)
|
||||
} else if !self.moves_up
|
||||
&& (ordering == Ordering::Greater
|
||||
|| self.is_end_inclusive && ordering == Ordering::Equal)
|
||||
{
|
||||
let next_value = self.curr.add(self.span, &self.negative_one);
|
||||
|
||||
let mut next = match next_value {
|
||||
Ok(result) => result,
|
||||
Err(error) => {
|
||||
self.done = true;
|
||||
return Some(Value::Error { error });
|
||||
}
|
||||
};
|
||||
std::mem::swap(&mut self.curr, &mut next);
|
||||
|
||||
Some(next)
|
||||
} else {
|
||||
None
|
||||
|
Reference in New Issue
Block a user