use chrono::FixedOffset; use serde::{Deserialize, Serialize}; use super::{ Call, CellPath, Expression, ExternalArgument, FullCellPath, Keyword, MatchPattern, Operator, Range, Table, ValueWithUnit, }; use crate::{ ast::ImportPattern, engine::StateWorkingSet, BlockId, OutDest, Signature, Span, VarId, }; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Expr { Bool(bool), Int(i64), Float(f64), Binary(Vec), Range(Box), Var(VarId), VarDecl(VarId), Call(Box), ExternalCall(Box, Box<[ExternalArgument]>), // head, args Operator(Operator), RowCondition(BlockId), UnaryNot(Box), BinaryOp(Box, Box, Box), //lhs, op, rhs Subexpression(BlockId), Block(BlockId), Closure(BlockId), MatchBlock(Vec<(MatchPattern, Expression)>), List(Vec), Table(Table), Record(Vec), Keyword(Box), ValueWithUnit(Box), DateTime(chrono::DateTime), /// The boolean is `true` if the string is quoted. Filepath(String, bool), /// The boolean is `true` if the string is quoted. Directory(String, bool), /// The boolean is `true` if the string is quoted. GlobPattern(String, bool), String(String), RawString(String), CellPath(CellPath), FullCellPath(Box), ImportPattern(Box), Overlay(Option), // block ID of the overlay's origin module Signature(Box), StringInterpolation(Vec), /// The boolean is `true` if the string is quoted. GlobInterpolation(Vec, bool), Nothing, Garbage, } // This is to document/enforce the size of `Expr` in bytes. // We should try to avoid increasing the size of `Expr`, // and PRs that do so will have to change the number below so that it's noted in review. const _: () = assert!(std::mem::size_of::() <= 40); impl Expr { pub fn pipe_redirection( &self, working_set: &StateWorkingSet, ) -> (Option, Option) { // Usages of `$in` will be wrapped by a `collect` call by the parser, // so we do not have to worry about that when considering // which of the expressions below may consume pipeline output. match self { Expr::Call(call) => working_set.get_decl(call.decl_id).pipe_redirection(), Expr::Subexpression(block_id) | Expr::Block(block_id) => working_set .get_block(*block_id) .pipe_redirection(working_set), Expr::FullCellPath(cell_path) => cell_path.head.expr.pipe_redirection(working_set), Expr::Bool(_) | Expr::Int(_) | Expr::Float(_) | Expr::Binary(_) | Expr::Range(_) | Expr::Var(_) | Expr::UnaryNot(_) | Expr::BinaryOp(_, _, _) | Expr::Closure(_) // piping into a closure value, not into a closure call | Expr::List(_) | Expr::Table(_) | Expr::Record(_) | Expr::ValueWithUnit(_) | Expr::DateTime(_) | Expr::String(_) | Expr::RawString(_) | Expr::CellPath(_) | Expr::StringInterpolation(_) | Expr::GlobInterpolation(_, _) | Expr::Nothing => { // These expressions do not use the output of the pipeline in any meaningful way, // so we can discard the previous output by redirecting it to `Null`. (Some(OutDest::Null), None) } Expr::VarDecl(_) | Expr::Operator(_) | Expr::Filepath(_, _) | Expr::Directory(_, _) | Expr::GlobPattern(_, _) | Expr::ImportPattern(_) | Expr::Overlay(_) | Expr::Signature(_) | Expr::Garbage => { // These should be impossible to pipe to, // but even it is, the pipeline output is not used in any way. (Some(OutDest::Null), None) } Expr::RowCondition(_) | Expr::MatchBlock(_) => { // These should be impossible to pipe to, // but if they are, then the pipeline output could be used. (None, None) } Expr::ExternalCall(_, _) => { // No override necessary, pipes will always be created in eval (None, None) } Expr::Keyword(_) => { // Not sure about this; let's return no redirection override for now. (None, None) } } } } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum RecordItem { /// A key: val mapping Pair(Expression, Expression), /// Span for the "..." and the expression that's being spread Spread(Span, Expression), } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum ListItem { /// A normal expression Item(Expression), /// Span for the "..." and the expression that's being spread Spread(Span, Expression), } impl ListItem { pub fn expr(&self) -> &Expression { let (ListItem::Item(expr) | ListItem::Spread(_, expr)) = self; expr } pub fn expr_mut(&mut self) -> &mut Expression { let (ListItem::Item(expr) | ListItem::Spread(_, expr)) = self; expr } }