@@ -5,7 +5,7 @@ use std::str::Chars;
5
5
6
6
use crate :: { BoolValue , ExecutionError , Result , Value , Variables } ;
7
7
8
- pub fn evaluate_expression ( raw_expr : String , ctx : EvalContext ) -> Result < Value > {
8
+ pub fn evaluate_expression ( raw_expr : String , mut ctx : EvalContext ) -> Result < Value > {
9
9
// TODO: this got real ugly, figure out some better way to do this
10
10
let tokens = match lex_expr ( raw_expr) {
11
11
Ok ( r) => r,
@@ -17,43 +17,62 @@ pub fn evaluate_expression(raw_expr: String, ctx: EvalContext) -> Result<Value>
17
17
Err ( ExecutionError :: ExpressionParseError ( s) ) => return Ok ( Value :: Error ( s) ) ,
18
18
Err ( e) => return Err ( e) ,
19
19
} ;
20
- match eval_expr ( expr, & ctx) {
20
+ match eval_expr ( expr, & mut ctx) {
21
21
Ok ( r) => Ok ( r) ,
22
22
Err ( ExecutionError :: ExpressionParseError ( s) ) => return Ok ( Value :: Error ( s) ) ,
23
23
Err ( e) => return Err ( e) ,
24
24
}
25
25
}
26
26
27
27
pub struct EvalContext < ' a > {
28
- variables : & ' a Variables ,
28
+ variables : & ' a mut Variables ,
29
29
// request content for metadata
30
30
}
31
31
impl EvalContext < ' _ > {
32
- pub fn new ( variables : & Variables ) -> EvalContext {
32
+ pub fn new ( variables : & mut Variables ) -> EvalContext {
33
33
EvalContext { variables }
34
34
}
35
- pub fn get_variable ( & self , key : & str , _subkey : Option < String > ) -> Value {
35
+ pub fn get_variable ( & self , key : & str , subkey : Option < String > ) -> Value {
36
36
match key {
37
37
"HTTP_HOST" => Value :: Null ,
38
38
"QUERY_STRING" => Value :: Null ,
39
- s => self . variables . get ( & s ) . clone ( ) ,
39
+ _ => self . variables . get ( & format_key ( key , subkey ) ) . clone ( ) ,
40
40
}
41
41
}
42
+
43
+ pub fn set_variable ( & mut self , key : & str , subkey : Option < String > , value : Value ) {
44
+ self . variables . insert ( format_key ( key, subkey) , value) ;
45
+ }
42
46
}
43
47
44
- fn eval_expr ( expr : Expr , ctx : & EvalContext ) -> Result < Value > {
48
+ fn format_key ( key : & str , subkey : Option < String > ) -> String {
49
+ match subkey {
50
+ Some ( subkey) => format ! ( "{}[{}]" , key, subkey) ,
51
+ None => format ! ( "{}" , key) ,
52
+ }
53
+ }
54
+
55
+ fn eval_expr ( expr : Expr , ctx : & mut EvalContext ) -> Result < Value > {
45
56
let result = match expr {
46
57
Expr :: Integer ( i) => Value :: Integer ( i) ,
47
58
Expr :: String ( s) => Value :: String ( s) ,
48
- Expr :: Variable ( s , _ ) => ctx. get_variable ( & s , None ) . clone ( ) ,
59
+ Expr :: Variable ( key , subkey ) => ctx. get_variable ( & key , subkey ) . clone ( ) ,
49
60
Expr :: Comparison ( c) => {
50
61
let left = eval_expr ( c. left , ctx) ?;
51
62
let right = eval_expr ( c. right , ctx) ?;
52
63
match c. operator {
53
64
Operator :: Matches => match ( left, right) {
54
65
( Value :: String ( test) , Value :: String ( pattern) ) => {
55
66
let re = Regex :: new ( & pattern) ?;
56
- if re. is_match ( & test) {
67
+ if let Some ( captures) = re. captures ( & test) {
68
+ for ( i, cap) in captures. iter ( ) . enumerate ( ) {
69
+ let capval = match cap {
70
+ Some ( s) => Value :: String ( s. as_str ( ) . to_string ( ) ) ,
71
+ None => Value :: Null ,
72
+ } ;
73
+ ctx. set_variable ( "MATCHES" , Some ( i. to_string ( ) ) , capval) ;
74
+ }
75
+
57
76
Value :: Boolean ( BoolValue :: True )
58
77
} else {
59
78
Value :: Boolean ( BoolValue :: False )
@@ -276,8 +295,6 @@ enum Token {
276
295
Identifier ( String ) ,
277
296
OpenParen ,
278
297
CloseParen ,
279
- OpenBracket ,
280
- CloseBracket ,
281
298
Comma ,
282
299
}
283
300
@@ -767,7 +784,7 @@ mod tests {
767
784
#[ test]
768
785
fn test_eval_string ( ) -> Result < ( ) > {
769
786
let expr = Expr :: String ( "hello" . to_string ( ) ) ;
770
- let result = eval_expr ( expr, & EvalContext :: new ( & Variables :: new ( ) ) ) ?;
787
+ let result = eval_expr ( expr, & mut EvalContext :: new ( & mut Variables :: new ( ) ) ) ?;
771
788
assert_eq ! ( result, Value :: String ( "hello" . to_string( ) ) ) ;
772
789
Ok ( ( ) )
773
790
}
@@ -777,7 +794,7 @@ mod tests {
777
794
let expr = Expr :: Variable ( "hello" . to_string ( ) , None ) ;
778
795
let result = eval_expr (
779
796
expr,
780
- & EvalContext :: new ( & Variables :: from ( [ (
797
+ & mut EvalContext :: new ( & mut Variables :: from ( [ (
781
798
"hello" . to_string ( ) ,
782
799
Value :: String ( "goodbye" . to_string ( ) ) ,
783
800
) ] ) ) ,
@@ -786,10 +803,23 @@ mod tests {
786
803
Ok ( ( ) )
787
804
}
788
805
#[ test]
806
+ fn test_eval_subscripted_variable ( ) -> Result < ( ) > {
807
+ let expr = Expr :: Variable ( "hello" . to_string ( ) , Some ( "abc" . to_string ( ) ) ) ;
808
+ let result = eval_expr (
809
+ expr,
810
+ & mut EvalContext :: new ( & mut Variables :: from ( [ (
811
+ "hello[abc]" . to_string ( ) ,
812
+ Value :: String ( "goodbye" . to_string ( ) ) ,
813
+ ) ] ) ) ,
814
+ ) ?;
815
+ assert_eq ! ( result, Value :: String ( "goodbye" . to_string( ) ) ) ;
816
+ Ok ( ( ) )
817
+ }
818
+ #[ test]
789
819
fn test_eval_matches_comparison ( ) -> Result < ( ) > {
790
820
let result = evaluate_expression (
791
821
"$(hello) matches '^foo'" . to_string ( ) ,
792
- EvalContext :: new ( & Variables :: from ( [ (
822
+ EvalContext :: new ( & mut Variables :: from ( [ (
793
823
"hello" . to_string ( ) ,
794
824
Value :: String ( "foobar" . to_string ( ) ) ,
795
825
) ] ) ) ,
@@ -798,10 +828,25 @@ mod tests {
798
828
Ok ( ( ) )
799
829
}
800
830
#[ test]
831
+ fn test_eval_matches_with_captures ( ) -> Result < ( ) > {
832
+ let mut vars =
833
+ Variables :: from ( [ ( "hello" . to_string ( ) , Value :: String ( "foobar" . to_string ( ) ) ) ] ) ;
834
+
835
+ let result = evaluate_expression (
836
+ "$(hello) matches '^(fo)o'" . to_string ( ) ,
837
+ EvalContext :: new ( & mut vars) ,
838
+ ) ?;
839
+ assert_eq ! ( result, Value :: Boolean ( BoolValue :: True ) ) ;
840
+
841
+ let result = evaluate_expression ( "$(MATCHES{1})" . to_string ( ) , EvalContext :: new ( & mut vars) ) ?;
842
+ assert_eq ! ( result, Value :: String ( "fo" . to_string( ) ) ) ;
843
+ Ok ( ( ) )
844
+ }
845
+ #[ test]
801
846
fn test_eval_matches_comparison_negative ( ) -> Result < ( ) > {
802
847
let result = evaluate_expression (
803
848
"$(hello) matches '^foo'" . to_string ( ) ,
804
- EvalContext :: new ( & Variables :: from ( [ (
849
+ EvalContext :: new ( & mut Variables :: from ( [ (
805
850
"hello" . to_string ( ) ,
806
851
Value :: String ( "nope" . to_string ( ) ) ,
807
852
) ] ) ) ,
@@ -811,16 +856,18 @@ mod tests {
811
856
}
812
857
#[ test]
813
858
fn test_eval_function_call ( ) -> Result < ( ) > {
814
- let result =
815
- evaluate_expression ( "$ping()" . to_string ( ) , EvalContext :: new ( & Variables :: new ( ) ) ) ?;
859
+ let result = evaluate_expression (
860
+ "$ping()" . to_string ( ) ,
861
+ EvalContext :: new ( & mut Variables :: new ( ) ) ,
862
+ ) ?;
816
863
assert_eq ! ( result, Value :: String ( "pong" . to_string( ) ) ) ;
817
864
Ok ( ( ) )
818
865
}
819
866
#[ test]
820
867
fn test_eval_lower_call ( ) -> Result < ( ) > {
821
868
let result = evaluate_expression (
822
869
"$lower('FOO')" . to_string ( ) ,
823
- EvalContext :: new ( & Variables :: new ( ) ) ,
870
+ EvalContext :: new ( & mut Variables :: new ( ) ) ,
824
871
) ?;
825
872
assert_eq ! ( result, Value :: String ( "foo" . to_string( ) ) ) ;
826
873
Ok ( ( ) )
@@ -829,7 +876,7 @@ mod tests {
829
876
fn test_eval_html_encode_call ( ) -> Result < ( ) > {
830
877
let result = evaluate_expression (
831
878
"$html_encode('a > b < c')" . to_string ( ) ,
832
- EvalContext :: new ( & Variables :: new ( ) ) ,
879
+ EvalContext :: new ( & mut Variables :: new ( ) ) ,
833
880
) ?;
834
881
assert_eq ! ( result, Value :: String ( "a > b < c" . to_string( ) ) ) ;
835
882
Ok ( ( ) )
@@ -838,7 +885,7 @@ mod tests {
838
885
fn test_eval_replace_call ( ) -> Result < ( ) > {
839
886
let result = evaluate_expression (
840
887
"$replace('abc-def-ghi-', '-', '==')" . to_string ( ) ,
841
- EvalContext :: new ( & Variables :: new ( ) ) ,
888
+ EvalContext :: new ( & mut Variables :: new ( ) ) ,
842
889
) ?;
843
890
assert_eq ! ( result, Value :: String ( "abc==def==ghi==" . to_string( ) ) ) ;
844
891
Ok ( ( ) )
@@ -848,7 +895,7 @@ mod tests {
848
895
fn test_eval_replace_call_with_count ( ) -> Result < ( ) > {
849
896
let result = evaluate_expression (
850
897
"$replace('abc-def-ghi-', '-', '==', 2)" . to_string ( ) ,
851
- EvalContext :: new ( & Variables :: new ( ) ) ,
898
+ EvalContext :: new ( & mut Variables :: new ( ) ) ,
852
899
) ?;
853
900
assert_eq ! ( result, Value :: String ( "abc==def==ghi-" . to_string( ) ) ) ;
854
901
Ok ( ( ) )
0 commit comments