Skip to content

Commit 7680ed0

Browse files
committed
feat: Implement explicit list_extend()
Cleaned and refactored code for several list-methods. Keep the established behavior that `list_add()` and `list_iadd()` either push or extend. Squashed commit of the following: commit af1256d32c51ae39d2c8a585ae69737526849c36 Author: Jan Max Meyer <[email protected]> Date: Sun Dec 29 13:20:26 2024 +0100 Finalize `list_extend()` commit d26ad4a0db30df5313ac9af5fda3f10c7c9e63f8 Author: Jan Max Meyer <[email protected]> Date: Sun Dec 29 11:49:22 2024 +0100 . commit 7ad5ba4eaaeb4e77084bb73293aa1b06297aba7f Author: Jan Max Meyer <[email protected]> Date: Sun Dec 29 00:32:44 2024 +0100 Implement and use of list_extend()
1 parent ede0377 commit 7680ed0

File tree

7 files changed

+131
-47
lines changed

7 files changed

+131
-47
lines changed

src/_builtins.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use crate::builtin::Builtin;
77

88
/*GENERATE cargo run -- _builtins.tok -- `find . -name "*.rs"` */
9-
pub static BUILTINS: [Builtin; 69] = [
9+
pub static BUILTINS: [Builtin; 70] = [
1010
Builtin {
1111
name: "Float",
1212
func: crate::value::token::tokay_token_float,
@@ -167,6 +167,10 @@ pub static BUILTINS: [Builtin; 69] = [
167167
name: "list_clone",
168168
func: crate::value::list::List::tokay_method_list_clone,
169169
},
170+
Builtin {
171+
name: "list_extend",
172+
func: crate::value::list::List::tokay_method_list_extend,
173+
},
170174
Builtin {
171175
name: "list_flatten",
172176
func: crate::value::list::List::tokay_method_list_flatten,

src/prelude.tok

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Repeat : @<
4848

4949
loop {
5050
P {
51-
res.push($1)
51+
res.push($1) # explicit push!
5252
cnt += 1
5353
if max && cnt == max break
5454
}
@@ -85,7 +85,7 @@ Opt : @<P>{ P | Empty }
8585
List : @<P, Separator: (',' _), empty: true> {
8686
Self Separator P $1 + $3
8787
if empty (Self Separator) # allows for trailing Separator
88-
P ($1, )
88+
P $1,
8989
}
9090

9191
# Parse keywords, which may not be the prefix of another identifier.

src/value/list.rs

+82-34
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! List object
22
use super::{BoxedObject, Iter, Object, RefValue};
3+
use crate::value;
34
use tokay_macros::tokay_method;
45
extern crate self as tokay;
56

@@ -92,7 +93,9 @@ impl List {
9293
if let Some(list) = borrowed.object::<List>() {
9394
Ok(RefValue::from(list.clone()))
9495
} else {
95-
Ok(RefValue::from(List { list: vec![list.clone()] }))
96+
Ok(RefValue::from(List {
97+
list: vec![list.clone()],
98+
}))
9699
}
97100
});
98101

@@ -101,6 +104,8 @@ impl List {
101104

102105
Ok(RefValue::from(if let Some(list) = list.object::<List>() {
103106
list.len()
107+
} else if list.is_void() {
108+
0
104109
} else {
105110
1
106111
}))
@@ -184,7 +189,7 @@ impl List {
184189
}
185190
}
186191

187-
// Extend in-place when possible.
192+
// Append or extend in-place when possible.
188193
if let (Ok(mut inner), Ok(to_append)) = (list.try_borrow_mut(), append.try_borrow()) {
189194
let inner = inner.object_mut::<List>().unwrap();
190195

@@ -218,7 +223,7 @@ impl List {
218223

219224
// In case list is not a list, make it a list.
220225
if !list.is("list") {
221-
list = Self::list(vec![list], None)?;
226+
list = RefValue::from(List::from(list));
222227
}
223228

224229
let mut list = list.borrow().object::<List>().unwrap().clone();
@@ -238,22 +243,20 @@ impl List {
238243
Ok(RefValue::from(list))
239244
});
240245

246+
/** Explicitly pushes `item` to `list`.
247+
248+
When `index` is provided, the value is inserted at the given offset,
249+
otherwise it is appended (pushed) to the list's end. */
241250
tokay_method!("list_push : @list, item, index=void", {
242251
// Don't push void
243252
if item.is_void() {
244-
return Ok(list);
253+
return Ok(value![void]);
245254
}
246255

247-
// In case list is not a list, make it a list.
248-
if !list.is("list") {
249-
list = Self::list(vec![list], None)?;
250-
}
251-
252-
// list_push returns the list itself, therefore this block.
253-
{
254-
let mut list = list.borrow_mut();
255-
let list = list.object_mut::<List>().unwrap();
256+
let mut list = list.borrow_mut();
256257

258+
// If first parameter is not a list, just do nothing!
259+
if let Some(list) = list.object_mut::<List>() {
257260
if index.is_void() {
258261
list.push(item);
259262
} else {
@@ -272,9 +275,64 @@ impl List {
272275
}
273276
}
274277

275-
Ok(list)
278+
Ok(value![void])
276279
});
277280

281+
/** Explicitly extends `extend` to `list`.
282+
283+
When `index` is provided, the list behind extend is inserted at the given offset,
284+
otherwise it is extended to the list's end. */
285+
tokay_method!("list_extend : @list, extend, index=void", {
286+
// Don't extend void
287+
if extend.is_void() {
288+
return Ok(value![void]);
289+
}
290+
291+
// In case extend is not a list, make it a list.
292+
if !extend.is("list") {
293+
extend = RefValue::from(List::from(extend));
294+
}
295+
296+
let mut list = list.borrow_mut();
297+
298+
// If first parameter is not a list, just do nothing!
299+
if let Some(list) = list.object_mut::<List>() {
300+
let extend = extend.borrow();
301+
let extend = extend.object::<List>().unwrap();
302+
303+
list.reserve(extend.len());
304+
305+
if index.is_void() {
306+
for item in extend.iter() {
307+
if !item.is_void() {
308+
list.push(item.clone());
309+
}
310+
}
311+
} else {
312+
let mut index = index.to_usize()?;
313+
let len = list.len();
314+
315+
if index > len {
316+
return Err(format!(
317+
"{} provided index {} out of range in list sized {}",
318+
__function, index, len
319+
)
320+
.into());
321+
}
322+
323+
for item in extend.iter() {
324+
if !item.is_void() {
325+
list.insert(index, item.clone());
326+
index += 1;
327+
}
328+
}
329+
}
330+
}
331+
332+
Ok(value![void])
333+
});
334+
335+
/** Pops item off a list. */
278336
tokay_method!("list_pop : @list, index=void", {
279337
let index = if index.is_void() {
280338
None
@@ -287,39 +345,28 @@ impl List {
287345
return Ok(list); // "pops" the list, which is not a list
288346
}
289347

290-
return Err(format!(
291-
"{} provided index {} out of range",
292-
__function,
293-
index.unwrap()
294-
)
295-
.into());
348+
return Ok(value![void]);
296349
}
297350

298351
let mut list = list.borrow_mut();
299352
let list = list.object_mut::<List>().unwrap();
300353

301354
// Either pop or remove, regarding index setting.
302-
match index {
355+
Ok(match index {
303356
None => match list.pop() {
304-
Some(item) => Ok(item),
305-
None => {
306-
return Err(format!("{} can't pop off empty list", __function).into());
307-
}
357+
Some(item) => item,
358+
None => value![void],
308359
},
309360
Some(index) => {
310361
let len = list.len();
311362

312-
if index >= len {
313-
return Err(format!(
314-
"{} provided index {} out of range of list sized {}",
315-
__function, index, len
316-
)
317-
.into());
363+
if index < len {
364+
list.remove(index)
365+
} else {
366+
value![void]
318367
}
319-
320-
Ok(list.remove(index))
321368
}
322-
}
369+
})
323370
});
324371

325372
tokay_method!("list_sort : @list", {
@@ -379,6 +426,7 @@ impl From<RefValue> for List {
379426
let list = list.object::<List>().unwrap();
380427
(*list).clone()
381428
}
429+
"void" => Self { list: Vec::new() },
382430
_ => Self {
383431
list: vec![refvalue.clone()],
384432
},

tests/list_extend.tok

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#testmode:repl
2+
3+
l = 1,2,3
4+
l
5+
6+
l.extend(4)
7+
l
8+
9+
l.extend((5,6,7))
10+
l
11+
12+
l.extend((10, 20, 30), 1)
13+
l
14+
15+
#---
16+
#(1, 2, 3)
17+
#(1, 2, 3, 4)
18+
#(1, 2, 3, 4, 5, 6, 7)
19+
#(1, 10, 20, 30, 2, 3, 4, 5, 6, 7)

tests/list_len.tok

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#testmode:repl
22

33
list().len
4-
().len
4+
(,).len
55
(1,).len
66
(1, 2, 3).len
77
list_len(5)
8+
list_len(void)
89

910
#---
1011

@@ -13,3 +14,4 @@ list_len(5)
1314
#1
1415
#3
1516
#1
17+
#0

tests/list_pop.tok

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
#testmode:repl
22

33
l = (1,2,3,4); l.pop() l.pop(1)
4+
45
l = (1,2,3,4)
56
l.pop(0)
67
l.pop()
7-
l.pop(2)
8+
type(l.pop(2))
89
l
910

1011
list_pop(1)
11-
list_pop(1, 1)
12+
type(list_pop(1, 1))
1213

1314
#---
1415

1516
#(4, 2)
1617
#1
1718
#4
18-
#ERR:Line 1, column 3: list_pop() provided index 2 out of range of list sized 2
19+
#"void"
1920
#(2, 3)
2021
#1
21-
#ERR:Line 1, column 1: list_pop() provided index 1 out of range
22+
#"void"

tests/list_push.tok

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
#testmode:repl
22

3-
l = (1,)
3+
l = 1,
4+
l
5+
46
l.push(2)
7+
l
8+
59
l.push((3, 4))
10+
l
11+
12+
l.push(99, 1)
13+
l
614

7-
list_push((1,2,3), 99, 1)
8-
list_push((1,2,3), 99, 4)
15+
l.push(99, 10)
16+
l
917

1018
#---
1119

20+
#(1, )
1221
#(1, 2)
1322
#(1, 2, (3, 4))
14-
#(1, 99, 2, 3)
15-
#ERR:Line 1, column 1: list_push() provided index 4 out of range in list sized 3
23+
#(1, 99, 2, (3, 4))
24+
#ERR:Line 1, column 3: list_push() provided index 10 out of range in list sized 4
25+
#(1, 99, 2, (3, 4))

0 commit comments

Comments
 (0)