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                // so we can discard the previous output by redirecting it to `Null`.
104                (Some(OutDest::Null), None)
105            }
106            Expr::VarDecl(_)
107            | Expr::Operator(_)
108            | Expr::Filepath(_, _)
109            | Expr::Directory(_, _)
110            | Expr::GlobPattern(_, _)
111            | Expr::ImportPattern(_)
112            | Expr::Overlay(_)
113            | Expr::Signature(_)
114            | Expr::Garbage => {
115                // These should be impossible to pipe to,
116                // but even it is, the pipeline output is not used in any way.
117                (Some(OutDest::Null), None)
118            }
119            Expr::RowCondition(_) | Expr::MatchBlock(_) => {
120                // These should be impossible to pipe to,
121                // but if they are, then the pipeline output could be used.
122                (None, None)
123            }
124            Expr::ExternalCall(_, _) => {
125                // No override necessary, pipes will always be created in eval
126                (None, None)
127            }
128            Expr::Keyword(_) => {
129                // Not sure about this; let's return no redirection override for now.
130                (None, None)
131            }
132        }
133    }
134}
135
136/// Expressions permitted inside a record expression/literal
137#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
138pub enum RecordItem {
139    /// A key: val mapping
140    Pair(Expression, Expression),
141    /// Span for the "..." and the expression that's being spread
142    Spread(Span, Expression),
143}
144
145/// Expressions permitted inside a list expression/literal
146#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
147pub enum ListItem {
148    /// A normal expression
149    Item(Expression),
150    /// Span for the "..." and the expression that's being spread
151    Spread(Span, Expression),
152}
153
154impl ListItem {
155    pub fn expr(&self) -> &Expression {
156        let (ListItem::Item(expr) | ListItem::Spread(_, expr)) = self;
157        expr
158    }
159
160    pub fn expr_mut(&mut self) -> &mut Expression {
161        let (ListItem::Item(expr) | ListItem::Spread(_, expr)) = self;
162        expr
163    }
164}