mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 06:55:36 +02:00
Split blocks and closures (#7075)
* Split closures and blocks * Tests mostly working * finish last fixes, passes all tests * fmt
This commit is contained in:
@ -26,6 +26,7 @@ pub enum Expr {
|
||||
BinaryOp(Box<Expression>, Box<Expression>, Box<Expression>), //lhs, op, rhs
|
||||
Subexpression(BlockId),
|
||||
Block(BlockId),
|
||||
Closure(BlockId),
|
||||
List(Vec<Expression>),
|
||||
Table(Vec<Expression>, Vec<Vec<Expression>>),
|
||||
Record(Vec<(Expression, Expression)>),
|
||||
|
@ -63,6 +63,7 @@ impl Expression {
|
||||
pub fn as_block(&self) -> Option<BlockId> {
|
||||
match self.expr {
|
||||
Expr::Block(block_id) => Some(block_id),
|
||||
Expr::Closure(block_id) => Some(block_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -139,6 +140,22 @@ impl Expression {
|
||||
false
|
||||
}
|
||||
}
|
||||
Expr::Closure(block_id) => {
|
||||
let block = working_set.get_block(*block_id);
|
||||
|
||||
if block.captures.contains(&IN_VARIABLE_ID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(pipeline) = block.pipelines.get(0) {
|
||||
match pipeline.expressions.get(0) {
|
||||
Some(expr) => expr.has_in_variable(working_set),
|
||||
None => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Expr::Binary(_) => false,
|
||||
Expr::Bool(_) => false,
|
||||
Expr::Call(call) => {
|
||||
@ -310,6 +327,37 @@ impl Expression {
|
||||
.map(|x| if *x != IN_VARIABLE_ID { *x } else { new_var_id })
|
||||
.collect();
|
||||
}
|
||||
Expr::Closure(block_id) => {
|
||||
let block = working_set.get_block(*block_id);
|
||||
|
||||
let new_expr = if let Some(pipeline) = block.pipelines.get(0) {
|
||||
if let Some(expr) = pipeline.expressions.get(0) {
|
||||
let mut new_expr = expr.clone();
|
||||
new_expr.replace_in_variable(working_set, new_var_id);
|
||||
Some(new_expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let block = working_set.get_block_mut(*block_id);
|
||||
|
||||
if let Some(new_expr) = new_expr {
|
||||
if let Some(pipeline) = block.pipelines.get_mut(0) {
|
||||
if let Some(expr) = pipeline.expressions.get_mut(0) {
|
||||
*expr = new_expr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
block.captures = block
|
||||
.captures
|
||||
.iter()
|
||||
.map(|x| if *x != IN_VARIABLE_ID { *x } else { new_var_id })
|
||||
.collect();
|
||||
}
|
||||
Expr::Binary(_) => {}
|
||||
Expr::Bool(_) => {}
|
||||
Expr::Call(call) => {
|
||||
@ -456,6 +504,17 @@ impl Expression {
|
||||
|
||||
*block_id = working_set.add_block(block);
|
||||
}
|
||||
Expr::Closure(block_id) => {
|
||||
let mut block = working_set.get_block(*block_id).clone();
|
||||
|
||||
for pipeline in block.pipelines.iter_mut() {
|
||||
for expr in pipeline.expressions.iter_mut() {
|
||||
expr.replace_span(working_set, replaced, new_span)
|
||||
}
|
||||
}
|
||||
|
||||
*block_id = working_set.add_block(block);
|
||||
}
|
||||
Expr::Binary(_) => {}
|
||||
Expr::Bool(_) => {}
|
||||
Expr::Call(call) => {
|
||||
|
@ -3,7 +3,12 @@ use std::collections::HashMap;
|
||||
use crate::{BlockId, Value, VarId};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CaptureBlock {
|
||||
pub struct Closure {
|
||||
pub block_id: BlockId,
|
||||
pub captures: HashMap<VarId, Value>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Block {
|
||||
pub block_id: BlockId,
|
||||
}
|
||||
|
@ -46,8 +46,11 @@ pub enum SyntaxShape {
|
||||
/// A binary literal
|
||||
Binary,
|
||||
|
||||
/// A closure is allowed, eg `{|| start this thing}`
|
||||
Closure(Option<Vec<SyntaxShape>>),
|
||||
|
||||
/// A block is allowed, eg `{start this thing}`
|
||||
Block(Option<Vec<SyntaxShape>>),
|
||||
Block,
|
||||
|
||||
/// A table is allowed, eg `[[first, second]; [1, 2]]`
|
||||
Table,
|
||||
@ -106,7 +109,8 @@ impl SyntaxShape {
|
||||
pub fn to_type(&self) -> Type {
|
||||
match self {
|
||||
SyntaxShape::Any => Type::Any,
|
||||
SyntaxShape::Block(_) => Type::Block,
|
||||
SyntaxShape::Block => Type::Block,
|
||||
SyntaxShape::Closure(_) => Type::Closure,
|
||||
SyntaxShape::Binary => Type::Binary,
|
||||
SyntaxShape::CellPath => Type::Any,
|
||||
SyntaxShape::Custom(custom, _) => custom.to_type(),
|
||||
@ -160,7 +164,8 @@ impl Display for SyntaxShape {
|
||||
SyntaxShape::Directory => write!(f, "directory"),
|
||||
SyntaxShape::GlobPattern => write!(f, "glob"),
|
||||
SyntaxShape::ImportPattern => write!(f, "import"),
|
||||
SyntaxShape::Block(_) => write!(f, "block"),
|
||||
SyntaxShape::Block => write!(f, "block"),
|
||||
SyntaxShape::Closure(_) => write!(f, "closure"),
|
||||
SyntaxShape::Binary => write!(f, "binary"),
|
||||
SyntaxShape::Table => write!(f, "table"),
|
||||
SyntaxShape::List(x) => write!(f, "list<{}>", x),
|
||||
|
@ -13,6 +13,7 @@ pub enum Type {
|
||||
Bool,
|
||||
String,
|
||||
Block,
|
||||
Closure,
|
||||
CellPath,
|
||||
Duration,
|
||||
Date,
|
||||
@ -72,7 +73,8 @@ impl Type {
|
||||
Type::Range => SyntaxShape::Range,
|
||||
Type::Bool => SyntaxShape::Boolean,
|
||||
Type::String => SyntaxShape::String,
|
||||
Type::Block => SyntaxShape::Block(None), // FIXME needs more accuracy
|
||||
Type::Block => SyntaxShape::Block, // FIXME needs more accuracy
|
||||
Type::Closure => SyntaxShape::Closure(None), // FIXME needs more accuracy
|
||||
Type::CellPath => SyntaxShape::CellPath,
|
||||
Type::Duration => SyntaxShape::Duration,
|
||||
Type::Date => SyntaxShape::DateTime,
|
||||
@ -96,6 +98,7 @@ impl Display for Type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Type::Block => write!(f, "block"),
|
||||
Type::Closure => write!(f, "closure"),
|
||||
Type::Bool => write!(f, "bool"),
|
||||
Type::CellPath => write!(f, "cell path"),
|
||||
Type::Date => write!(f, "date"),
|
||||
|
@ -1,8 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::ast::{CellPath, PathMember};
|
||||
use crate::engine::CaptureBlock;
|
||||
use crate::engine::{Block, Closure};
|
||||
use crate::ShellError;
|
||||
use crate::{Range, Spanned, Value};
|
||||
use chrono::{DateTime, FixedOffset};
|
||||
@ -502,13 +503,31 @@ impl FromValue for (Vec<String>, Vec<Value>) {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for CaptureBlock {
|
||||
impl FromValue for Closure {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
match v {
|
||||
Value::Block { val, captures, .. } => Ok(CaptureBlock {
|
||||
Value::Closure { val, captures, .. } => Ok(Closure {
|
||||
block_id: *val,
|
||||
captures: captures.clone(),
|
||||
}),
|
||||
Value::Block { val, .. } => Ok(Closure {
|
||||
block_id: *val,
|
||||
captures: HashMap::new(),
|
||||
}),
|
||||
v => Err(ShellError::CantConvert(
|
||||
"Closure".into(),
|
||||
v.get_type().to_string(),
|
||||
v.span()?,
|
||||
None,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for Block {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
match v {
|
||||
Value::Block { val, .. } => Ok(Block { block_id: *val }),
|
||||
v => Err(ShellError::CantConvert(
|
||||
"Block".into(),
|
||||
v.get_type().to_string(),
|
||||
@ -519,22 +538,22 @@ impl FromValue for CaptureBlock {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for Spanned<CaptureBlock> {
|
||||
impl FromValue for Spanned<Closure> {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
match v {
|
||||
Value::Block {
|
||||
Value::Closure {
|
||||
val,
|
||||
captures,
|
||||
span,
|
||||
} => Ok(Spanned {
|
||||
item: CaptureBlock {
|
||||
item: Closure {
|
||||
block_id: *val,
|
||||
captures: captures.clone(),
|
||||
},
|
||||
span: *span,
|
||||
}),
|
||||
v => Err(ShellError::CantConvert(
|
||||
"Block".into(),
|
||||
"Closure".into(),
|
||||
v.get_type().to_string(),
|
||||
v.span()?,
|
||||
None,
|
||||
|
@ -78,6 +78,10 @@ pub enum Value {
|
||||
span: Span,
|
||||
},
|
||||
Block {
|
||||
val: BlockId,
|
||||
span: Span,
|
||||
},
|
||||
Closure {
|
||||
val: BlockId,
|
||||
captures: HashMap<VarId, Value>,
|
||||
span: Span,
|
||||
@ -146,11 +150,15 @@ impl Clone for Value {
|
||||
vals: vals.clone(),
|
||||
span: *span,
|
||||
},
|
||||
Value::Block {
|
||||
Value::Block { val, span } => Value::Block {
|
||||
val: *val,
|
||||
span: *span,
|
||||
},
|
||||
Value::Closure {
|
||||
val,
|
||||
captures,
|
||||
span,
|
||||
} => Value::Block {
|
||||
} => Value::Closure {
|
||||
val: *val,
|
||||
captures: captures.clone(),
|
||||
span: *span,
|
||||
@ -246,6 +254,7 @@ impl Value {
|
||||
pub fn as_block(&self) -> Result<BlockId, ShellError> {
|
||||
match self {
|
||||
Value::Block { val, .. } => Ok(*val),
|
||||
Value::Closure { val, .. } => Ok(*val),
|
||||
x => Err(ShellError::CantConvert(
|
||||
"block".into(),
|
||||
x.get_type().to_string(),
|
||||
@ -344,6 +353,7 @@ impl Value {
|
||||
Value::Record { span, .. } => Ok(*span),
|
||||
Value::List { span, .. } => Ok(*span),
|
||||
Value::Block { span, .. } => Ok(*span),
|
||||
Value::Closure { span, .. } => Ok(*span),
|
||||
Value::Nothing { span, .. } => Ok(*span),
|
||||
Value::Binary { span, .. } => Ok(*span),
|
||||
Value::CellPath { span, .. } => Ok(*span),
|
||||
@ -364,6 +374,7 @@ impl Value {
|
||||
Value::String { span, .. } => *span = new_span,
|
||||
Value::Record { span, .. } => *span = new_span,
|
||||
Value::List { span, .. } => *span = new_span,
|
||||
Value::Closure { span, .. } => *span = new_span,
|
||||
Value::Block { span, .. } => *span = new_span,
|
||||
Value::Nothing { span, .. } => *span = new_span,
|
||||
Value::Error { .. } => {}
|
||||
@ -418,6 +429,7 @@ impl Value {
|
||||
}
|
||||
Value::Nothing { .. } => Type::Nothing,
|
||||
Value::Block { .. } => Type::Block,
|
||||
Value::Closure { .. } => Type::Closure,
|
||||
Value::Error { .. } => Type::Error,
|
||||
Value::Binary { .. } => Type::Binary,
|
||||
Value::CellPath { .. } => Type::CellPath,
|
||||
@ -490,6 +502,7 @@ impl Value {
|
||||
.join(separator)
|
||||
),
|
||||
Value::Block { val, .. } => format!("<Block {}>", val),
|
||||
Value::Closure { val, .. } => format!("<Closure {}>", val),
|
||||
Value::Nothing { .. } => String::new(),
|
||||
Value::Error { error } => format!("{:?}", error),
|
||||
Value::Binary { val, .. } => format!("{:?}", val),
|
||||
@ -533,6 +546,7 @@ impl Value {
|
||||
if cols.len() == 1 { "" } else { "s" }
|
||||
),
|
||||
Value::Block { val, .. } => format!("<Block {}>", val),
|
||||
Value::Closure { val, .. } => format!("<Closure {}>", val),
|
||||
Value::Nothing { .. } => String::new(),
|
||||
Value::Error { error } => format!("{:?}", error),
|
||||
Value::Binary { val, .. } => format!("{:?}", val),
|
||||
@ -579,6 +593,7 @@ impl Value {
|
||||
.join(separator)
|
||||
),
|
||||
Value::Block { val, .. } => format!("<Block {}>", val),
|
||||
Value::Closure { val, .. } => format!("<Closure {}>", val),
|
||||
Value::Nothing { .. } => String::new(),
|
||||
Value::Error { error } => format!("{:?}", error),
|
||||
Value::Binary { val, .. } => format!("{:?}", val),
|
||||
@ -1330,6 +1345,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1348,6 +1364,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1366,6 +1383,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1384,6 +1402,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1402,6 +1421,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1420,6 +1440,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1438,6 +1459,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1456,6 +1478,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Less),
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1500,6 +1523,7 @@ impl PartialOrd for Value {
|
||||
}
|
||||
Value::List { .. } => Some(Ordering::Less),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1518,6 +1542,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Greater),
|
||||
Value::List { vals: rhs, .. } => lhs.partial_cmp(rhs),
|
||||
Value::Block { .. } => Some(Ordering::Less),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1536,6 +1561,26 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Greater),
|
||||
Value::List { .. } => Some(Ordering::Greater),
|
||||
Value::Block { val: rhs, .. } => lhs.partial_cmp(rhs),
|
||||
Value::Closure { .. } => Some(Ordering::Less),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
Value::CellPath { .. } => Some(Ordering::Less),
|
||||
Value::CustomValue { .. } => Some(Ordering::Less),
|
||||
},
|
||||
(Value::Closure { val: lhs, .. }, rhs) => match rhs {
|
||||
Value::Bool { .. } => Some(Ordering::Greater),
|
||||
Value::Int { .. } => Some(Ordering::Greater),
|
||||
Value::Float { .. } => Some(Ordering::Greater),
|
||||
Value::Filesize { .. } => Some(Ordering::Greater),
|
||||
Value::Duration { .. } => Some(Ordering::Greater),
|
||||
Value::Date { .. } => Some(Ordering::Greater),
|
||||
Value::Range { .. } => Some(Ordering::Greater),
|
||||
Value::String { .. } => Some(Ordering::Greater),
|
||||
Value::Record { .. } => Some(Ordering::Greater),
|
||||
Value::List { .. } => Some(Ordering::Greater),
|
||||
Value::Block { .. } => Some(Ordering::Greater),
|
||||
Value::Closure { val: rhs, .. } => lhs.partial_cmp(rhs),
|
||||
Value::Nothing { .. } => Some(Ordering::Less),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1554,6 +1599,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Greater),
|
||||
Value::List { .. } => Some(Ordering::Greater),
|
||||
Value::Block { .. } => Some(Ordering::Greater),
|
||||
Value::Closure { .. } => Some(Ordering::Greater),
|
||||
Value::Nothing { .. } => Some(Ordering::Equal),
|
||||
Value::Error { .. } => Some(Ordering::Less),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1572,6 +1618,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Greater),
|
||||
Value::List { .. } => Some(Ordering::Greater),
|
||||
Value::Block { .. } => Some(Ordering::Greater),
|
||||
Value::Closure { .. } => Some(Ordering::Greater),
|
||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||
Value::Error { .. } => Some(Ordering::Equal),
|
||||
Value::Binary { .. } => Some(Ordering::Less),
|
||||
@ -1590,6 +1637,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Greater),
|
||||
Value::List { .. } => Some(Ordering::Greater),
|
||||
Value::Block { .. } => Some(Ordering::Greater),
|
||||
Value::Closure { .. } => Some(Ordering::Greater),
|
||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||
Value::Error { .. } => Some(Ordering::Greater),
|
||||
Value::Binary { val: rhs, .. } => lhs.partial_cmp(rhs),
|
||||
@ -1608,6 +1656,7 @@ impl PartialOrd for Value {
|
||||
Value::Record { .. } => Some(Ordering::Greater),
|
||||
Value::List { .. } => Some(Ordering::Greater),
|
||||
Value::Block { .. } => Some(Ordering::Greater),
|
||||
Value::Closure { .. } => Some(Ordering::Greater),
|
||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||
Value::Error { .. } => Some(Ordering::Greater),
|
||||
Value::Binary { .. } => Some(Ordering::Greater),
|
||||
|
Reference in New Issue
Block a user