@@ -1022,10 +1022,14 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
1022
1022
// comparison -----------------------------------------------------
1023
1023
"comparison" => {
1024
1024
// comparison can be a chain of comparisons, allowing to compare e.g. `1 < 2 < 3`
1025
+ let mut branches = Vec :: new ( ) ;
1026
+
1025
1027
let children = node[ "children" ] . borrow ( ) ;
1026
- let mut children = children. object :: < List > ( ) . unwrap ( ) . clone ( ) ;
1028
+ let children = children. object :: < List > ( ) . unwrap ( ) ;
1029
+
1030
+ let mut child_iter = children. iter ( ) . peekable ( ) ;
1027
1031
1028
- let first = children . remove ( 0 ) ;
1032
+ let first = child_iter . next ( ) . unwrap ( ) ;
1029
1033
let first = first. borrow ( ) ;
1030
1034
1031
1035
let mut ops = Vec :: new ( ) ;
@@ -1036,28 +1040,37 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
1036
1040
Rvalue :: CallOrLoad ,
1037
1041
) ) ;
1038
1042
1039
- let mut backpatch = Vec :: new ( ) ;
1043
+ while let Some ( op) = child_iter. next ( ) {
1044
+ let op = op. borrow ( ) ;
1045
+ let op = op. object :: < Dict > ( ) . unwrap ( ) ;
1040
1046
1041
- while !children. is_empty ( ) {
1042
- let child = children. remove ( 0 ) ;
1043
- let child = child. borrow ( ) ;
1044
- let child = child. object :: < Dict > ( ) . unwrap ( ) ;
1045
-
1046
- let emit = child[ "emit" ] . borrow ( ) ;
1047
+ let emit = op[ "emit" ] . borrow ( ) ;
1047
1048
let emit = emit. object :: < Str > ( ) . unwrap ( ) . as_str ( ) ;
1048
1049
1049
- let next = child [ "children" ] . borrow ( ) ;
1050
+ let next = op [ "children" ] . borrow ( ) ;
1050
1051
1051
- ops. push ( traverse_node_rvalue (
1052
- scope,
1053
- & next. object :: < Dict > ( ) . unwrap ( ) ,
1054
- Rvalue :: CallOrLoad ,
1055
- ) ) ;
1052
+ // Old (current) path
1053
+ if let Some ( next) = next. object :: < Dict > ( ) {
1054
+ ops. push ( traverse_node_rvalue ( scope, & next, Rvalue :: CallOrLoad ) ) ;
1055
+ }
1056
+ // New (desired) path
1057
+ else {
1058
+ let next = child_iter. next ( ) . unwrap ( ) ;
1059
+ let next = next. borrow ( ) ;
1056
1060
1057
- // Chained comparison requires forperand duplication
1058
- if !children. is_empty ( ) {
1061
+ ops. push ( traverse_node_rvalue (
1062
+ scope,
1063
+ & next. object :: < Dict > ( ) . unwrap ( ) ,
1064
+ Rvalue :: CallOrLoad ,
1065
+ ) ) ;
1066
+ }
1067
+
1068
+ let is_chained = child_iter. peek ( ) . is_some ( ) ;
1069
+
1070
+ // Chained comparison requires for operand duplication
1071
+ if is_chained {
1059
1072
ops. push ( ImlOp :: from ( Op :: Swap ( 2 ) ) ) ; // Swap operands
1060
- ops. push ( ImlOp :: from ( Op :: Copy ( 2 ) ) ) ; // Copy second operand
1073
+ ops. push ( ImlOp :: from ( Op :: Copy ( 2 ) ) ) ; // Copy second operand, to keep a copy
1061
1074
}
1062
1075
1063
1076
ops. push ( ImlOp :: from ( match emit {
@@ -1070,25 +1083,34 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
1070
1083
_ => unimplemented ! ( "{}" , emit) ,
1071
1084
} ) ) ;
1072
1085
1073
- // Push and remember placeholder for later clean-up jump
1074
- if !children. is_empty ( ) {
1075
- backpatch. push ( ops. len ( ) ) ;
1076
- ops. push ( ImlOp :: Nop ) ; // Placeholder for condition
1077
- }
1086
+ // Push this branch
1087
+ branches. push ( ops) ;
1088
+ ops = Vec :: new ( ) ;
1078
1089
}
1079
1090
1080
- if backpatch. len ( ) > 0 {
1081
- // Jump over clean-up part with last result
1082
- ops. push ( ImlOp :: from ( Op :: Forward ( 3 ) ) ) ;
1091
+ let mut branches = branches. into_iter ( ) . rev ( ) . peekable ( ) ;
1092
+
1093
+ while let Some ( mut branch) = branches. next ( ) {
1094
+ // println!("{:?} {:?}", branch, branches.peek().is_none());
1095
+ branch. extend ( ops) ;
1096
+ ops = branch;
1083
1097
1084
- // Otherwise, remember clean-up start
1085
- let clean_up = ops. len ( ) ;
1086
- ops. push ( ImlOp :: from ( Op :: Drop ) ) ;
1087
- ops. push ( ImlOp :: from ( Op :: PushFalse ) ) ;
1098
+ if branches. peek ( ) . is_some ( ) {
1099
+ let then: Vec < _ > = ops. drain ( ..) . collect ( ) ;
1088
1100
1089
- // Backpatch all placeholders to relative jump to the clean-up part
1090
- for index in backpatch {
1091
- ops[ index] = ImlOp :: from ( Op :: ForwardIfFalse ( clean_up - index + 1 ) ) ;
1101
+ ops. push ( ImlOp :: If {
1102
+ peek : false ,
1103
+ test : true ,
1104
+ then : Box :: new ( if then. len ( ) == 0 {
1105
+ ImlOp :: from ( Op :: PushTrue )
1106
+ } else {
1107
+ ImlOp :: from ( then)
1108
+ } ) ,
1109
+ else_ : Box :: new ( ImlOp :: from ( vec ! [
1110
+ ImlOp :: from( Op :: Drop ) ,
1111
+ ImlOp :: from( Op :: PushFalse ) ,
1112
+ ] ) ) ,
1113
+ } )
1092
1114
}
1093
1115
}
1094
1116
0 commit comments