nushell/crates/nu-protocol/src/ast/expr.rs
Stefan Holderbach 076a29ae19
Document public types in nu-protocol (#12906)
- **Doc-comment public `nu-protocol` modules**
- **Doccomment argument/signature/call stuff**
- **Doccomment cell path types**
- **Doccomment expression stuff**
- **Doccomment import patterns**
- **Doccomment pattern matching AST nodes**
2024-07-11 13:30:12 +02:00

160 lines
5.5 KiB
Rust

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,
};
/// An [`Expression`] AST node
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Expr {
Bool(bool),
Int(i64),
Float(f64),
Binary(Vec<u8>),
Range(Box<Range>),
Var(VarId),
VarDecl(VarId),
Call(Box<Call>),
ExternalCall(Box<Expression>, Box<[ExternalArgument]>), // head, args
Operator(Operator),
RowCondition(BlockId),
UnaryNot(Box<Expression>),
BinaryOp(Box<Expression>, Box<Expression>, Box<Expression>), //lhs, op, rhs
Subexpression(BlockId),
Block(BlockId),
Closure(BlockId),
MatchBlock(Vec<(MatchPattern, Expression)>),
List(Vec<ListItem>),
Table(Table),
Record(Vec<RecordItem>),
Keyword(Box<Keyword>),
ValueWithUnit(Box<ValueWithUnit>),
DateTime(chrono::DateTime<FixedOffset>),
/// 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<FullCellPath>),
ImportPattern(Box<ImportPattern>),
Overlay(Option<BlockId>), // block ID of the overlay's origin module
Signature(Box<Signature>),
StringInterpolation(Vec<Expression>),
/// The boolean is `true` if the string is quoted.
GlobInterpolation(Vec<Expression>, 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::<Expr>() <= 40);
impl Expr {
pub fn pipe_redirection(
&self,
working_set: &StateWorkingSet,
) -> (Option<OutDest>, Option<OutDest>) {
// 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)
}
}
}
}
/// Expressions permitted inside a record expression/literal
#[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),
}
/// Expressions permitted inside a list expression/literal
#[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
}
}