1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! # ksl::builtin::index
//!
//! Built-in function `Index`.
use crate::{Environment, eval::apply::eval_apply, is_number_eq, value::Value};
pub(crate) fn builtin(args: &[Value], env: &Environment) -> Option<(Value, Environment)> {
if let [val, idx] = &args[..] {
match eval_apply(idx, env) {
Some((Value::Number(n), _)) if is_number_eq(n.round(), n) && (n > 0.0 || is_number_eq(n, -1.0)) => {
match eval_apply(val, env) {
Some((Value::List(elements), new_env)) => {
if (n as usize) > elements.len() {
eprintln!(
concat!(
"Error[ksl::builtin::index]: ",
"Index `{}` out of bounds `{}`."
),
n,
elements.len()
);
None
} else if is_number_eq(n, -1.0) {
if elements.is_empty() {
eprintln!(concat!("Error[ksl::builtin::index]: ", "Empty list."));
None
} else {
Some((elements[elements.len() - 1].clone(), new_env))
}
} else {
Some((elements[(n - 1.0) as usize].clone(), new_env))
}
}
Some((Value::String(s), _)) => {
if (n as usize) > s.chars().count() {
eprintln!(concat!(
"Error[ksl::builtin::index]: ",
"Index out of bounds."
));
None
} else if is_number_eq(n, -1.0) {
if let Some(ch) = s.chars().last() {
Some((Value::String(String::from(ch)), Environment::new()))
} else {
eprintln!(concat!("Error[ksl::builtin::index]: ", "Empty string."));
None
}
} else {
Some((
Value::String(
s.chars()
.enumerate()
.filter(|(idx, _)| &((n - 1.0) as usize) <= idx && idx < &(n as usize))
.map(|(_, ch)| ch)
.collect::<String>(),
),
Environment::new(),
))
}
}
Some((e, _)) => {
eprintln!(
concat!(
"Error[ksl::builtin::index]: ",
"Expected a list or a string, but got `{:?}`."
),
e
);
None
}
None => {
eprintln!(
concat!(
"Error[ksl::builtin::index]: ",
"Cannot evaluate expression {:?}."
),
val
);
None
}
}
}
Some((Value::Number(n), _)) => {
eprintln!(
concat!(
"Error[ksl::builtin::index]: ",
"Index (`{}`) error. Index must be an integer, starting from 1. ",
"Specifically, -1 is the only acceptable negative index, ",
"indicating the last position.",
),
n
);
None
}
Some((e, _)) => {
eprintln!(
concat!(
"Error[ksl::builtin::index]: ",
"Expected a number, but got `{:?}`."
),
e
);
None
}
None => {
eprintln!(
concat!(
"Error[ksl::builtin::index]: ",
"Cannot evaluate expression {:?}."
),
idx
);
None
}
}
} else {
eprintln!(
concat!(
"Error[ksl::builtin::index]: ",
"Only accepts 2 arguments, but {} were passed."
),
args.len()
);
None
}
}