Split blocks and closures (#7075)

* Split closures and blocks

* Tests mostly working

* finish last fixes, passes all tests

* fmt
This commit is contained in:
JT
2022-11-10 21:21:49 +13:00
committed by GitHub
parent 921a66554e
commit 63433f1bc8
57 changed files with 576 additions and 220 deletions

View File

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

View File

@ -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) => {

View File

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

View File

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

View File

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

View File

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

View File

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