@@ -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 name
33+ /// 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 rather
35+ /// than registered functions, because their dtype comes from where they appear rather than from
36+ /// children and they are not executable. A [`ScalarFnVTable`] can answer neither of those, so they
37+ /// are variants instead.
3338#[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
3439pub enum Expression {
3540 /// A scalar function applied to child expressions.
@@ -41,6 +46,12 @@ pub enum Expression {
4146 } ,
4247 /// The full scope of the expression evaluation.
4348 Root ,
49+ /// A parameter of an enclosing lambda, read by name.
50+ ///
51+ /// Building the [`Lambda`](crate::expr::Lambda) replaces each variable of its parameters with a
52+ /// field of the lambda's row, so a variable left over is not a parameter of any enclosing
53+ /// lambda. It fails to bind and cannot be serialized.
54+ Variable ( FieldName ) ,
4455}
4556
4657impl Expression {
@@ -73,7 +84,7 @@ impl Expression {
7384 pub fn as_scalar ( & self ) -> Option < & ScalarFnRef > {
7485 match self {
7586 Self :: Scalar { scalar_fn, .. } => Some ( scalar_fn) ,
76- Self :: Root => None ,
87+ Self :: Root | Self :: Variable ( _ ) => None ,
7788 }
7889 }
7990
@@ -101,7 +112,7 @@ impl Expression {
101112 pub fn children ( & self ) -> & [ Expression ] {
102113 match self {
103114 Self :: Scalar { children, .. } => children. as_slice ( ) ,
104- Self :: Root => NO_CHILDREN ,
115+ Self :: Root | Self :: Variable ( _ ) => NO_CHILDREN ,
105116 }
106117 }
107118
@@ -125,6 +136,14 @@ impl Expression {
125136 ) ;
126137 Ok ( Self :: Root )
127138 }
139+ Self :: Variable ( name) => {
140+ vortex_ensure ! (
141+ children. is_empty( ) ,
142+ "Expression arity mismatch: variable expects 0 children but got {}" ,
143+ children. len( )
144+ ) ;
145+ Ok ( Self :: Variable ( name. clone ( ) ) )
146+ }
128147 Self :: Scalar { scalar_fn, .. } => {
129148 vortex_ensure ! (
130149 scalar_fn. signature( ) . arity( ) . matches( children. len( ) ) ,
@@ -144,6 +163,7 @@ impl Expression {
144163 pub fn return_dtype ( & self , scope : & DType ) -> VortexResult < DType > {
145164 match self {
146165 Self :: Root => Ok ( scope. clone ( ) ) ,
166+ Self :: Variable ( name) => Err ( unbound_variable ( name) ) ,
147167 Self :: Scalar {
148168 scalar_fn,
149169 children,
@@ -164,6 +184,7 @@ impl Expression {
164184 pub fn fmt_sql ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
165185 match self {
166186 Self :: Root => write ! ( f, "$" ) ,
187+ Self :: Variable ( name) => write ! ( f, "@{name}" ) ,
167188 Self :: Scalar { scalar_fn, .. } => scalar_fn. fmt_sql ( self , f) ,
168189 }
169190 }
@@ -249,6 +270,11 @@ impl Expression {
249270 }
250271}
251272
273+ /// The error for a variable that no enclosing lambda declares.
274+ pub ( crate ) fn unbound_variable ( name : & FieldName ) -> VortexError {
275+ vortex_err ! ( "variable `{name}` is not a parameter of an enclosing lambda" )
276+ }
277+
252278/// The default display implementation for expressions uses the 'SQL'-style format.
253279impl Display for Expression {
254280 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
0 commit comments