nu_protocol/ast/
expr.rs

1use chrono::FixedOffset;
2use serde::{Deserialize, Serialize};
3
4use super::{
5    AttributeBlock, Call, CellPath, Expression, ExternalArgument, FullCellPath, Keyword,
6    MatchPattern, Operator, Range, Table, ValueWithUnit,
7};
8use crate::{
9    BlockId, ModuleId, OutDest, Signature, Span, VarId, ast::ImportPattern, engine::StateWorkingSet,
10};
11
12/// An [`Expression`] AST node
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub enum Expr {
15    AttributeBlock(AttributeBlock),
16    Bool(bool),
17    Int(i64),
18    Float(f64),
19    Binary(Vec<u8>),
20    Range(Box<Range>),
21    Var(VarId),
22    VarDecl(VarId),
23    Call(Box<Call>),
24    ExternalCall(Box<Expression>, Box<[ExternalArgument]>), // head, args
25    Operator(Operator),
26    RowCondition(BlockId),
27    UnaryNot(Box<Expression>),
28    BinaryOp(Box<Expression>, Box<Expression>, Box<Expression>), //lhs, op, rhs
29    Collect(VarId, Box<Expression>),
30    Subexpression(BlockId),
31    Block(BlockId),
32    Closure(BlockId),
33    MatchBlock(Vec<(MatchPattern, Expression)>),
34    List(Vec<ListItem>),
35    Table(Table),
36    Record(Vec<RecordItem>),
37    Keyword(Box<Keyword>),
38    ValueWithUnit(Box<ValueWithUnit>),
39    DateTime(chrono::DateTime<FixedOffset>),
40    /// The boolean is `true` if the string is quoted.
41    Filepath(String, bool),
42    /// The boolean is `true` if the string is quoted.
43    Directory(String, bool),
44    /// The boolean is `true` if the string is quoted.
45    GlobPattern(String, bool),
46    String(String),
47    RawString(String),
48    CellPath(CellPath),
49    FullCellPath(Box<FullCellPath>),
50    ImportPattern(Box<ImportPattern>),
51    Overlay(Option<ModuleId>),
52    Signature(Box<Signature>),
53    StringInterpolation(Vec<Expression>),
54    /// The boolean is `true` if the string is quoted.
55    GlobInterpolation(Vec<Expression>, bool),
56    Nothing,
57    Garbage,
58}
59
60// This is to document/enforce the size of `Expr` in bytes.
61// We should try to avoid increasing the size of `Expr`,
62// and PRs that do so will have to change the number below so that it's noted in review.
63const _: () = assert!(std::mem::size_of::<Expr>() <= 40);
64
65impl Expr {
66    pub fn pipe_redirection(
67        &self,
68        working_set: &StateWorkingSet,
69    ) -> (Option<OutDest>, Option<OutDest>) {
70        match self {
71            Expr::AttributeBlock(ab) => ab.item.expr.pipe_redirection(working_set),
72            Expr::Call(call) => working_set.get_decl(call.decl_id).pipe_redirection(),
73            Expr::Collect(_, _) => {
74                // A collect expression always has default redirection, it's just going to collect
75                // stdout unless another type of redirection is specified
76                (None, None)
77            },
78            Expr::Subexpression(block_id) | Expr::Block(block_id) => working_set
79                .get_block(*block_id)
80                .pipe_redirection(working_set),
81            Expr::FullCellPath(cell_path) => cell_path.head.expr.pipe_redirection(working_set),
82            Expr::Bool(_)
83            | Expr::Int(_)
84            | Expr::Float(_)
85            | Expr::Binary(_)
86            | Expr::Range(_)
87            | Expr::Var(_)
88            | Expr::UnaryNot(_)
89            | Expr::BinaryOp(_, _, _)
90            | Expr::Closure(_) // piping into a closure value, not into a closure call
91            | Expr::List(_)
92            | Expr::Table(_)
93            | Expr::Record(_)
94            | Expr::ValueWithUnit(_)
95            | Expr::DateTime(_)
96            | Expr::String(_)
97            | Expr::RawString(_)
98            | Expr::CellPath(_)
99            | Expr::StringInterpolation(_)
100            | Expr::GlobInterpolation(_, _)
101            | Expr::Nothing => {
102                // These expressions do not use the output of the pipeline in any meaningful way,
103                // but we still need to use the pipeline output, so the previous command
104                // can be stopped with SIGPIPE(in unix).
105                (None, None)
106            }
107            Expr::VarDecl(_)
108            | Expr::Operator(_)
109            | Expr::Filepath(_, _)
110            | Expr::Directory(_, _)
111            | Expr::GlobPattern(_, _)
112            | Expr::ImportPattern(_)
113            | Expr::Overlay(_)
114            | Expr::Signature(_)
115            | Expr::Garbage => {
116                // These should be impossible to pipe to,
117                // but even it is, the pipeline output is not used in any way.
118                (Some(OutDest::Null), None)
119            }
120            Expr::RowCondition(_) | Expr::MatchBlock(_) => {
121                // These should be impossible to pipe to,
122                // but if they are, then the pipeline output could be used.
123                (None, None)
124            }
125            Expr::ExternalCall(_, _) => {
126                // No override necessary, pipes will always be created in eval
127                (None, None)
128            }
129            Expr::Keyword(_) => {
130                // Not sure about this; let's return no redirection override for now.
131                (None, None)
132            }
133        }
134    }
135}
136
137/// Expressions permitted inside a record expression/literal
138#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
139pub enum RecordItem {
140    /// A key: val mapping
141    Pair(Expression, Expression),
142    /// Span for the "..." and the expression that's being spread
143    Spread(Span, Expression),
144}
145
146/// Expressions permitted inside a list expression/literal
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148pub enum ListItem {
149    /// A normal expression
150    Item(Expression),
151    /// Span for the "..." and the expression that's being spread
152    Spread(Span, Expression),
153}
154
155impl ListItem {
156    pub fn expr(&self) -> &Expression {
157        let (ListItem::Item(expr) | ListItem::Spread(_, expr)) = self;
158        expr
159    }
160
161    pub fn expr_mut(&mut self) -> &mut Expression {
162        let (ListItem::Item(expr) | ListItem::Spread(_, expr)) = self;
163        expr
164    }
165}