@@ -3,10 +3,11 @@ use crate::authoring::*;
3
3
4
4
// NOTE: roll and drop are not implemented yet
5
5
#[ rustfmt:: skip]
6
- pub const STACK_GAMUT : [ OpParameter ; 5 ] = [
6
+ pub const STACK_GAMUT : [ OpParameter ; 6 ] = [
7
7
OpParameter :: Series { key : "push" , default : Some ( "" ) } ,
8
8
OpParameter :: Series { key : "pop" , default : Some ( "" ) } ,
9
9
OpParameter :: Series { key : "roll" , default : Some ( "" ) } ,
10
+ OpParameter :: Series { key : "unroll" , default : Some ( "" ) } ,
10
11
OpParameter :: Flag { key : "swap" } ,
11
12
OpParameter :: Flag { key : "drop" } ,
12
13
] ;
@@ -56,12 +57,26 @@ pub fn new(parameters: &RawParameters, _ctx: &dyn Context) -> Result<Op, Error>
56
57
|| roll_args[ 0 ] <= roll_args[ 1 ] . abs ( )
57
58
{
58
59
return Err ( Error :: MissingParam (
59
- "roll takes exactly two integer parameters, ´(m,n): |n|<m´" . to_string ( ) ,
60
+ "roll takes exactly two integer parameters, ´(m,n): |n|<= m´" . to_string ( ) ,
60
61
) ) ;
61
62
}
62
63
params. text . insert ( "action" , "roll" . to_string ( ) ) ;
63
64
}
64
65
66
+ if let Ok ( roll_args) = params. series ( "unroll" ) {
67
+ subcommands_given += 1 ;
68
+ if roll_args. len ( ) != 2
69
+ || roll_args[ 0 ] . fract ( ) != 0.
70
+ || roll_args[ 1 ] . fract ( ) != 0.
71
+ || roll_args[ 0 ] <= roll_args[ 1 ] . abs ( )
72
+ {
73
+ return Err ( Error :: MissingParam (
74
+ "unroll takes exactly two integer parameters, ´(m,n): |n|<=m´" . to_string ( ) ,
75
+ ) ) ;
76
+ }
77
+ params. text . insert ( "action" , "unroll" . to_string ( ) ) ;
78
+ }
79
+
65
80
if params. boolean ( "swap" ) {
66
81
subcommands_given += 1 ;
67
82
params. text . insert ( "action" , "swap" . to_string ( ) ) ;
@@ -74,7 +89,7 @@ pub fn new(parameters: &RawParameters, _ctx: &dyn Context) -> Result<Op, Error>
74
89
75
90
if subcommands_given != 1 {
76
91
return Err ( Error :: MissingParam (
77
- "stack: must specify exactly one of push/pop/roll/swap/drop" . to_string ( ) ,
92
+ "stack: must specify exactly one of push/pop/roll/swap/unroll/ drop" . to_string ( ) ,
78
93
) ) ;
79
94
}
80
95
@@ -103,34 +118,24 @@ pub(super) fn stack_fwd(
103
118
104
119
let successes = match action. as_str ( ) {
105
120
"push" => {
106
- // Turn f64 dimensions 1-4 into usize indices 0-3
107
- let args: Vec < usize > = params
108
- . series ( "push" )
109
- . unwrap ( )
110
- . iter ( )
111
- . map ( |i| * i as usize - 1 )
112
- . collect ( ) ;
121
+ let args = params. series_as_usize ( "push" ) . unwrap ( ) ;
113
122
stack_push ( stack, operands, & args)
114
123
}
115
124
116
125
"pop" => {
117
- // Turn f64 dimensions 1-4 into usize indices 0-3
118
- let args: Vec < usize > = params
119
- . series ( "pop" )
120
- . unwrap ( )
121
- . iter ( )
122
- . map ( |i| * i as usize - 1 )
123
- . collect ( ) ;
126
+ let args = params. series_as_usize ( "pop" ) . unwrap ( ) ;
124
127
stack_pop ( stack, operands, & args)
125
128
}
126
129
127
130
"roll" => {
128
- let args: Vec < i64 > = params
129
- . series ( "roll" )
130
- . unwrap ( )
131
- . iter ( )
132
- . map ( |i| * i as i64 )
133
- . collect ( ) ;
131
+ let args = params. series_as_i64 ( "roll" ) . unwrap ( ) ;
132
+ stack_roll ( stack, operands, & args)
133
+ }
134
+
135
+ "unroll" => {
136
+ let mut args = params. series_as_i64 ( "unroll" ) . unwrap ( ) ;
137
+ args[ 1 ] = args[ 0 ] - args[ 1 ] ;
138
+ dbg ! ( & args) ;
134
139
stack_roll ( stack, operands, & args)
135
140
}
136
141
@@ -165,38 +170,28 @@ pub(super) fn stack_inv(
165
170
} ;
166
171
167
172
let successes = match action. as_str ( ) {
173
+ // An inverse push is a pop with reversed args
168
174
"push" => {
169
- // Turn f64 dimensions 1-4 into **reversed** usize indices 0-3 ******
170
- let args: Vec < usize > = params
171
- . series ( "push" )
172
- . unwrap ( )
173
- . iter ( )
174
- . rev ( )
175
- . map ( |i| * i as usize - 1 )
176
- . collect ( ) ;
175
+ let mut args = params. series_as_usize ( "push" ) . unwrap ( ) ;
176
+ args. reverse ( ) ;
177
177
stack_pop ( stack, operands, & args)
178
178
}
179
179
180
+ // And an inverse pop is a push with reversed args
180
181
"pop" => {
181
- // Turn f64 dimensions 1-4 into **reversed** usize indices 0-3
182
- let args: Vec < usize > = params
183
- . series ( "pop" )
184
- . unwrap ( )
185
- . iter ( )
186
- . rev ( )
187
- . map ( |i| * i as usize - 1 )
188
- . collect ( ) ;
189
- return stack_push ( stack, operands, & args) ;
182
+ let mut args = params. series_as_usize ( "pop" ) . unwrap ( ) ;
183
+ args. reverse ( ) ;
184
+ stack_push ( stack, operands, & args)
190
185
}
191
186
192
187
"roll" => {
193
- let mut args: Vec < i64 > = params
194
- . series ( "roll" )
195
- . unwrap ( )
196
- . iter ( )
197
- . map ( |i| * i as i64 )
198
- . collect ( ) ;
199
- args[ 1 ] = -args [ 1 ] ;
188
+ let mut args = params. series_as_i64 ( "roll" ) . unwrap ( ) ;
189
+ args [ 1 ] = args [ 0 ] - args [ 1 ] ;
190
+ stack_roll ( stack , operands , & args )
191
+ }
192
+
193
+ "unroll" => {
194
+ let args = params . series_as_i64 ( "roll" ) . unwrap ( ) ;
200
195
stack_roll ( stack, operands, & args)
201
196
}
202
197
@@ -234,7 +229,8 @@ fn stack_push(
234
229
for i in 0 ..number_of_operands {
235
230
let coord = operands. get_coord ( i) ;
236
231
for j in 0 ..number_of_pushes {
237
- ext[ j] [ i] = coord[ args[ j] ] ;
232
+ // args are 1 based so we adjust
233
+ ext[ j] [ i] = coord[ args[ j] - 1 ] ;
238
234
}
239
235
}
240
236
@@ -245,8 +241,8 @@ fn stack_push(
245
241
246
242
/// roll m,n: On the sub-stack consisting of the m upper elements,
247
243
/// roll n elements from the top, to the bottom of the sub-stack.
248
- /// Hence, roll is a "large flip ", essentially flipping the n upper
249
- /// elements with the m - n lower
244
+ /// Hence, roll is a "big swap ", essentially swapping the n upper
245
+ /// elements with the m - n lower.
250
246
fn stack_roll ( stack : & mut Vec < Vec < f64 > > , operands : & mut dyn CoordinateSet , args : & [ i64 ] ) -> usize {
251
247
let m = args[ 0 ] . abs ( ) ;
252
248
let mut n = args[ 1 ] ;
@@ -294,21 +290,18 @@ fn stack_pop(stack: &mut Vec<Vec<f64>>, operands: &mut dyn CoordinateSet, args:
294
290
}
295
291
296
292
// Remove the correct number of elements and obtain a reversed version.
297
- // Incidentally, this is both the easiest way to obtain the popped
298
- // subset, and the easiest way to make the top-of-stack (i.e. the
299
- // element first popped) have the index 0, which makes the 'for j...'
300
- // loop below slightly more straightforward
301
293
let mut ext = Vec :: with_capacity ( number_of_pops) ;
302
294
for _ in args {
303
295
ext. push ( stack. pop ( ) . unwrap ( ) ) ;
304
296
}
305
297
306
- // Extract the required stack elements into the proper
298
+ // Inject the required stack elements into the proper
307
299
// positions of the coordinate elements
308
300
for i in 0 ..number_of_operands {
309
301
let mut coord = operands. get_coord ( i) ;
310
302
for j in 0 ..number_of_pops {
311
- coord[ args[ j] ] = ext[ j] [ i] ;
303
+ // args are 1 based so we adjust
304
+ coord[ args[ j] - 1 ] = ext[ j] [ i] ;
312
305
}
313
306
operands. set_coord ( i, & coord) ;
314
307
}
@@ -435,6 +428,64 @@ mod tests {
435
428
assert_eq ! ( data[ 0 ] [ 0 ] , 14. ) ;
436
429
assert_eq ! ( data[ 0 ] [ 1 ] , 13. ) ;
437
430
431
+ // Roundrip roll using the unroll syntactic sugar
432
+ let mut data = master_data. clone ( ) ;
433
+ let op =
434
+ ctx. op ( "stack push=1,2,3,4 | stack roll=3,2 | stack unroll=3,2 | stack pop=1,2" ) ?;
435
+ ctx. apply ( op, Fwd , & mut data) ?;
436
+ assert_eq ! ( data[ 0 ] [ 0 ] , 14. ) ;
437
+ assert_eq ! ( data[ 0 ] [ 1 ] , 13. ) ;
438
+
439
+ Ok ( ( ) )
440
+ }
441
+
442
+ #[ test]
443
+ fn stack_examples_from_rumination_002 ( ) -> Result < ( ) , Error > {
444
+ let mut ctx = Minimal :: default ( ) ;
445
+ let master_data = vec ! [ Coor4D ( [ 1. , 2. , 3. , 4. ] ) ] ;
446
+
447
+ // Roll
448
+ let op = ctx. op ( "stack push=1,2,3,4 | stack roll=3,2 | stack pop=4,3,2,1" ) ?;
449
+ let mut data = master_data. clone ( ) ;
450
+ ctx. apply ( op, Fwd , & mut data) ?;
451
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 3. , 4. , 2. ] ) ;
452
+
453
+ let op = ctx. op ( "stack push=1,2,3,4 | stack roll=3,-2 | stack pop=4,3,2,1" ) ?;
454
+ let mut data = master_data. clone ( ) ;
455
+ ctx. apply ( op, Fwd , & mut data) ?;
456
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 4. , 2. , 3. ] ) ;
457
+
458
+ let op = ctx. op ( "stack push=1,2,3,4 | stack roll=3,2 | stack pop=4,3,2,1" ) ?;
459
+ let mut data = master_data. clone ( ) ;
460
+ ctx. apply ( op, Fwd , & mut data) ?;
461
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 3. , 4. , 2. ] ) ;
462
+ let op = ctx. op ( "stack push=1,2,3,4 | stack roll=3,1 | stack pop=4,3,2,1" ) ?;
463
+ ctx. apply ( op, Fwd , & mut data) ?;
464
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 2. , 3. , 4. ] ) ;
465
+
466
+ // Unroll
467
+ let op = ctx. op ( "stack push=1,2,3,4 | stack unroll=3,2 | stack pop=4,3,2,1" ) ?;
468
+ let mut data = master_data. clone ( ) ;
469
+ ctx. apply ( op, Fwd , & mut data) ?;
470
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 4. , 2. , 3. ] ) ;
471
+
472
+ let op = ctx. op ( "stack push=1,2,3,4 | stack unroll=3,-2 | stack pop=4,3,2,1" ) ?;
473
+ let mut data = master_data. clone ( ) ;
474
+ ctx. apply ( op, Fwd , & mut data) ?;
475
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 3. , 4. , 2. ] ) ;
476
+
477
+ let op = ctx. op ( "stack push=1,2,3,4 | stack unroll=3,2 | stack pop=4,3,2,1" ) ?;
478
+ ctx. apply ( op, Fwd , & mut data) ?;
479
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 2. , 3. , 4. ] ) ;
480
+
481
+ let op = ctx. op ( "stack push=1,2,3,4 | stack roll=3,2 | stack pop=4,3,2,1" ) ?;
482
+ ctx. apply ( op, Fwd , & mut data) ?;
483
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 3. , 4. , 2. ] ) ;
484
+
485
+ let op = ctx. op ( "stack push=1,2,3,4 | stack unroll=3,2 | stack pop=4,3,2,1" ) ?;
486
+ ctx. apply ( op, Fwd , & mut data) ?;
487
+ assert_eq ! ( data[ 0 ] . 0 , [ 1. , 2. , 3. , 4. ] ) ;
488
+
438
489
Ok ( ( ) )
439
490
}
440
491
}
0 commit comments