@@ -10,11 +10,14 @@ use std::hash::Hash;
1010use std:: sync:: Arc ;
1111
1212use itertools:: Itertools ;
13+ use vortex_error:: VortexError ;
1314use vortex_error:: VortexExpect ;
1415use vortex_error:: VortexResult ;
1516use vortex_error:: vortex_ensure;
17+ use vortex_error:: vortex_err;
1618
1719use crate :: dtype:: DType ;
20+ use crate :: dtype:: FieldName ;
1821use crate :: expr:: display:: DisplayTreeExpr ;
1922use crate :: expr:: traversal:: TraversalOrder ;
2023use crate :: expr:: traversal:: pre_order_visit_down;
@@ -26,10 +29,12 @@ const NO_CHILDREN: &[Expression] = &[];
2629
2730/// A node in a Vortex expression tree.
2831///
29- /// Most nodes are a scalar function applied to child expressions. [`Expression::Root`] is the scope
30- /// itself: a language primitive rather than a registered function, because its dtype comes from the
31- /// scope rather than from children and it is not executable. A [`ScalarFnVTable`] can answer neither
32- /// of those, so `Root` is a variant instead.
32+ /// Most nodes are a scalar function applied to child expressions. The other two are leaves that
33+ /// name a value rather than compute one: [`Expression::Root`], the scope itself, and
34+ /// [`Expression::Variable`], a parameter of an enclosing lambda. They are language primitives
35+ /// rather than registered functions, because their dtype comes from where they appear rather than
36+ /// from children and they are not executable. A [`ScalarFnVTable`] can answer neither of those, so
37+ /// they are variants instead.
3338#[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
3439pub enum Expression {
3540 /// A scalar function applied to child expressions.
@@ -41,6 +46,11 @@ pub enum Expression {
4146 } ,
4247 /// The full scope of the expression evaluation.
4348 Root ,
49+ /// A parameter of the enclosing lambda, read by name.
50+ ///
51+ /// Binding a [`Lambda`](crate::expr::Lambda) turns its variables into reads of the struct of
52+ /// its inputs. Anywhere else a variable fails to bind, and it is not serializable yet.
53+ Variable ( FieldName ) ,
4454}
4555
4656impl Expression {
@@ -73,7 +83,7 @@ impl Expression {
7383 pub fn as_scalar ( & self ) -> Option < & ScalarFnRef > {
7484 match self {
7585 Self :: Scalar { scalar_fn, .. } => Some ( scalar_fn) ,
76- Self :: Root => None ,
86+ Self :: Root | Self :: Variable ( _ ) => None ,
7787 }
7888 }
7989
@@ -101,7 +111,7 @@ impl Expression {
101111 pub fn children ( & self ) -> & [ Expression ] {
102112 match self {
103113 Self :: Scalar { children, .. } => children. as_slice ( ) ,
104- Self :: Root => NO_CHILDREN ,
114+ Self :: Root | Self :: Variable ( _ ) => NO_CHILDREN ,
105115 }
106116 }
107117
@@ -125,6 +135,14 @@ impl Expression {
125135 ) ;
126136 Ok ( Self :: Root )
127137 }
138+ Self :: Variable ( name) => {
139+ vortex_ensure ! (
140+ children. is_empty( ) ,
141+ "Expression arity mismatch: variable expects 0 children but got {}" ,
142+ children. len( )
143+ ) ;
144+ Ok ( Self :: Variable ( name. clone ( ) ) )
145+ }
128146 Self :: Scalar { scalar_fn, .. } => {
129147 vortex_ensure ! (
130148 scalar_fn. signature( ) . arity( ) . matches( children. len( ) ) ,
@@ -144,6 +162,7 @@ impl Expression {
144162 pub fn return_dtype ( & self , scope : & DType ) -> VortexResult < DType > {
145163 match self {
146164 Self :: Root => Ok ( scope. clone ( ) ) ,
165+ Self :: Variable ( name) => Err ( unbound_variable ( name) ) ,
147166 Self :: Scalar {
148167 scalar_fn,
149168 children,
@@ -164,6 +183,7 @@ impl Expression {
164183 pub fn fmt_sql ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
165184 match self {
166185 Self :: Root => write ! ( f, "$" ) ,
186+ Self :: Variable ( name) => write ! ( f, "@{name}" ) ,
167187 Self :: Scalar { scalar_fn, .. } => scalar_fn. fmt_sql ( self , f) ,
168188 }
169189 }
@@ -249,6 +269,11 @@ impl Expression {
249269 }
250270}
251271
272+ /// The error for a variable that no enclosing lambda declares.
273+ pub ( crate ) fn unbound_variable ( name : & FieldName ) -> VortexError {
274+ vortex_err ! ( "variable @{name} is not a parameter of an enclosing lambda" )
275+ }
276+
252277/// The default display implementation for expressions uses the 'SQL'-style format.
253278impl Display for Expression {
254279 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
0 commit comments