@@ -5,6 +5,9 @@ use crate::Node;
55
66#[ derive( Debug , Clone , PartialEq ) ]
77pub ( crate ) enum Expr {
8+ /// An empty expression, which as a formula would evaluate to None.
9+ None ,
10+
811 /// A negation of an expression.
912 Neg { param : Box < Expr > } ,
1013
@@ -35,6 +38,7 @@ impl std::ops::Add for Expr {
3538
3639 fn add ( self , rhs : Self ) -> Self {
3740 match ( self , rhs) {
41+ ( Self :: None , other) | ( other, Self :: None ) => other,
3842 // -a + -b = -(a + b)
3943 ( Self :: Neg { param : lhs } , Self :: Neg { param : rhs } ) => -( * lhs + * rhs) ,
4044 // -a + b = b - a
@@ -68,6 +72,8 @@ impl std::ops::Sub for Expr {
6872
6973 fn sub ( self , rhs : Self ) -> Self {
7074 match ( self , rhs) {
75+ ( Self :: None , other) => -other,
76+ ( other, Self :: None ) => other,
7177 // (a - b) - -c = a - b + c
7278 ( sub @ Self :: Sub { .. } , Self :: Neg { param } ) => sub + * param,
7379 // -a - (b - c) = c - b - a
@@ -98,6 +104,7 @@ impl std::ops::Neg for Expr {
98104
99105 fn neg ( self ) -> Self {
100106 match self {
107+ Self :: None => Self :: None ,
101108 // -(-a) = a
102109 Expr :: Neg { param : inner } => * inner,
103110 // -(a - b) = b - a
@@ -124,28 +131,113 @@ impl<N: Node> From<&N> for Expr {
124131
125132/// Constructors for `FormulaExpression`.
126133impl Expr {
134+ #[ must_use]
127135 pub ( crate ) fn number ( value : f64 ) -> Self {
128136 Self :: Number { value }
129137 }
130138
139+ #[ must_use]
131140 pub ( crate ) fn component ( component_id : u64 ) -> Self {
132141 Self :: Component { component_id }
133142 }
134143
135- pub ( crate ) fn coalesce ( params : Vec < Expr > ) -> Self {
136- if let [ param] = params. as_slice ( ) {
137- param. clone ( )
138- } else {
139- Self :: Coalesce { params }
144+ #[ must_use]
145+ pub ( crate ) fn coalesce ( self , other : Expr ) -> Self {
146+ match ( self , other) {
147+ ( Expr :: None , other) | ( other, Expr :: None ) => other,
148+ (
149+ Expr :: Coalesce { mut params } ,
150+ Expr :: Coalesce {
151+ params : other_params,
152+ } ,
153+ ) => {
154+ // If both parameters are coalesce expressions, merge them.
155+ params. extend ( other_params) ;
156+ Self :: Coalesce { params }
157+ }
158+ ( Expr :: Coalesce { mut params } , other) => {
159+ // If the first parameter is a coalesce expression, add the second
160+ // parameter to it.
161+ params. push ( other) ;
162+ Self :: Coalesce { params }
163+ }
164+ (
165+ param,
166+ Expr :: Coalesce {
167+ params : other_params,
168+ } ,
169+ ) => {
170+ // If the second parameter is a coalesce expression, add the first
171+ // parameter to it.
172+ let mut params = vec ! [ param] ;
173+ params. extend ( other_params) ;
174+ Self :: Coalesce { params }
175+ }
176+ ( first, second) => {
177+ // If neither parameter is a coalesce expression, create a new one.
178+ Self :: Coalesce {
179+ params : vec ! [ first, second] ,
180+ }
181+ }
140182 }
141183 }
142184
143- pub ( crate ) fn min ( params : Vec < Expr > ) -> Self {
144- Self :: Min { params }
185+ #[ must_use]
186+ pub ( crate ) fn min ( self , other : Expr ) -> Self {
187+ match ( self , other) {
188+ ( Expr :: None , expr) | ( expr, Expr :: None ) => expr,
189+ (
190+ Expr :: Min { mut params } ,
191+ Expr :: Min {
192+ params : other_params,
193+ } ,
194+ ) => {
195+ // If both parameters are min expressions, merge them.
196+ params. extend ( other_params) ;
197+ Self :: Min { params }
198+ }
199+ ( Expr :: Min { mut params } , other) | ( other, Expr :: Min { mut params } ) => {
200+ // If one parameter is a min expression, add the other parameter
201+ // to it.
202+ params. push ( other) ;
203+ Self :: Min { params }
204+ }
205+ ( first, second) => {
206+ // If neither parameter is a min expression, create a new one.
207+ Self :: Min {
208+ params : vec ! [ first, second] ,
209+ }
210+ }
211+ }
145212 }
146213
147- pub ( crate ) fn max ( params : Vec < Expr > ) -> Self {
148- Self :: Max { params }
214+ #[ must_use]
215+ pub ( crate ) fn max ( self , other : Expr ) -> Self {
216+ match ( self , other) {
217+ ( Expr :: None , expr) | ( expr, Expr :: None ) => expr,
218+ (
219+ Expr :: Max { mut params } ,
220+ Expr :: Max {
221+ params : other_params,
222+ } ,
223+ ) => {
224+ // If both parameters are max expressions, merge them.
225+ params. extend ( other_params) ;
226+ Self :: Max { params }
227+ }
228+ ( Expr :: Max { mut params } , other) | ( other, Expr :: Max { mut params } ) => {
229+ // If one parameter is a max expression, add the other parameter
230+ // to it.
231+ params. push ( other) ;
232+ Self :: Max { params }
233+ }
234+ ( first, second) => {
235+ // If neither parameter is a max expression, create a new one.
236+ Self :: Max {
237+ params : vec ! [ first, second] ,
238+ }
239+ }
240+ }
149241 }
150242}
151243
@@ -178,6 +270,7 @@ impl Expr {
178270 /// component, the whole expression is enclosed in brackets.
179271 fn generate_string ( & self , bracket_whole : bool ) -> String {
180272 match self {
273+ Self :: None => String :: from ( "None" ) ,
181274 Self :: Neg { param } => format ! ( "-{}" , param. generate_string( true ) ) ,
182275 Self :: Number { value } => {
183276 if value. fract ( ) == 0.0 {
@@ -365,29 +458,26 @@ mod tests {
365458 let comp = Expr :: component;
366459 let coalesce = Expr :: coalesce;
367460 let number = Expr :: number;
368- let min = Expr :: min;
369- let max = Expr :: max;
370461
371462 assert_expr (
372- & [ comp ( 1 )
373- - ( coalesce ( vec ! [ comp( 5 ) , comp( 7 ) + comp( 6 ) ] ) + coalesce ( vec ! [ comp( 2 ) , comp( 3 ) ] ) )
374- + coalesce ( vec ! [
375- max( vec![ number( 0.0 ) , comp( 5 ) ] ) ,
376- max( vec![ number( 0.0 ) , comp( 7 ) ] ) + max( vec![ number( 0.0 ) , comp( 6 ) ] ) ,
377- ] ) ] ,
463+ & [
464+ comp ( 1 ) - ( coalesce ( comp ( 5 ) , comp ( 7 ) + comp ( 6 ) ) + coalesce ( comp ( 2 ) , comp ( 3 ) ) )
465+ + coalesce (
466+ number ( 0.0 ) . max ( comp ( 5 ) ) ,
467+ number ( 0.0 ) . max ( comp ( 7 ) ) + number ( 0.0 ) . max ( comp ( 6 ) ) ,
468+ ) ,
469+ ] ,
378470 concat ! (
379471 "#1 - (COALESCE(#5, #7 + #6) + COALESCE(#2, #3)) + " ,
380472 "COALESCE(MAX(0.0, #5), MAX(0.0, #7) + MAX(0.0, #6))"
381473 ) ,
382474 ) ;
383475
384476 assert_expr (
385- & [ min ( vec ! [ number( 0.0 ) , comp( 5 ) , comp( 7 ) + comp( 6 ) ] )
386- - max ( vec ! [
387- coalesce( vec![ comp( 5 ) , comp( 7 ) + comp( 6 ) ] ) ,
388- comp( 7 ) ,
389- number( 22.44 ) ,
390- ] ) ] ,
477+ & [ number ( 0.0 ) . min ( comp ( 5 ) ) . min ( comp ( 7 ) + comp ( 6 ) )
478+ - coalesce ( comp ( 5 ) , comp ( 7 ) + comp ( 6 ) )
479+ . max ( comp ( 7 ) )
480+ . max ( number ( 22.44 ) ) ] ,
391481 "MIN(0.0, #5, #7 + #6) - MAX(COALESCE(#5, #7 + #6), #7, 22.44)" ,
392482 )
393483 }
0 commit comments