Skip to main content

nu_protocol/ast/
block.rs

1use super::Pipeline;
2use crate::{OutDest, Signature, Span, Type, VarId, engine::StateWorkingSet, ir::IrBlock};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Block {
7    pub signature: Box<Signature>,
8    pub pipelines: Vec<Pipeline>,
9    pub captures: Vec<(VarId, Span)>,
10    pub redirect_env: bool,
11    /// The block compiled to IR instructions. Not available for subexpressions.
12    pub ir_block: Option<IrBlock>,
13    pub span: Option<Span>, // None option encodes no span to avoid using test_span()
14}
15
16impl Block {
17    pub fn len(&self) -> usize {
18        self.pipelines.len()
19    }
20
21    pub fn is_empty(&self) -> bool {
22        self.pipelines.is_empty()
23    }
24
25    pub fn pipe_redirection(
26        &self,
27        working_set: &StateWorkingSet,
28    ) -> (Option<OutDest>, Option<OutDest>) {
29        if let Some(first) = self.pipelines.first() {
30            first.pipe_redirection(working_set)
31        } else {
32            (None, None)
33        }
34    }
35}
36
37impl Default for Block {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl Block {
44    pub fn new() -> Self {
45        Self {
46            signature: Box::new(Signature::new("")),
47            pipelines: vec![],
48            captures: vec![],
49            redirect_env: false,
50            ir_block: None,
51            span: None,
52        }
53    }
54
55    pub fn new_with_capacity(capacity: usize) -> Self {
56        Self {
57            signature: Box::new(Signature::new("")),
58            pipelines: Vec::with_capacity(capacity),
59            captures: vec![],
60            redirect_env: false,
61            ir_block: None,
62            span: None,
63        }
64    }
65
66    pub fn output_type(&self) -> Type {
67        match self.pipelines.last().and_then(|pl| pl.elements.last()) {
68            Some(pe) if pe.redirection.is_none() => pe.expr.ty.clone(),
69            Some(_) => Type::Any,
70            None => Type::Nothing,
71        }
72    }
73
74    /// Replace any `$in` variables in the initial element of pipelines within the block
75    pub fn replace_in_variable(
76        &mut self,
77        working_set: &mut StateWorkingSet<'_>,
78        new_var_id: VarId,
79    ) {
80        for pipeline in self.pipelines.iter_mut() {
81            if let Some(element) = pipeline.elements.first_mut() {
82                element.replace_in_variable(working_set, new_var_id);
83            }
84        }
85    }
86}
87
88impl<T> From<T> for Block
89where
90    T: Iterator<Item = Pipeline>,
91{
92    fn from(pipelines: T) -> Self {
93        Self {
94            signature: Box::new(Signature::new("")),
95            pipelines: pipelines.collect(),
96            captures: vec![],
97            redirect_env: false,
98            ir_block: None,
99            span: None,
100        }
101    }
102}