Skip to content

Commit 3e1e6cc

Browse files
authored
Merge pull request #5 from alexmozaidze/bigint_and_refactors
`BigInt` support and refactors
2 parents b1f2c1b + d9cc3c6 commit 3e1e6cc

10 files changed

+321
-160
lines changed

Cargo.lock

+47
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+16
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,19 @@ doc = true
1717
[[bin]]
1818
name = "rust_lisp"
1919
path = "src/main.rs"
20+
21+
[features]
22+
# What integer to use for Value::Int
23+
bigint = ["num-bigint", "num-traits"]
24+
i128 = []
25+
i64 = []
26+
i16 = []
27+
i8 = []
28+
29+
# Use f64 for Value::Float, if unset, use f32
30+
f64 = []
31+
32+
[dependencies]
33+
cfg-if = "1.0"
34+
num-traits = { version = "0.2", optional = true }
35+
num-bigint = { version = "0.4", optional = true }

src/default_environment.rs

+97-70
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ use crate::{
55
utils::{require_int_parameter, require_list_parameter, require_parameter},
66
};
77
use std::collections::HashMap;
8+
use cfg_if::cfg_if;
9+
cfg_if! {
10+
if #[cfg(feature = "bigint")] {
11+
use num_traits::ToPrimitive;
12+
} else {
13+
use crate::model::IntType;
14+
}
15+
}
816

917
/// Initialize an instance of `Env` with several core Lisp functions implemented
1018
/// in Rust. **Without this, you will only have access to the functions you
@@ -18,7 +26,7 @@ pub fn default_env() -> Env {
1826
let expr = require_parameter("print", args, 0)?;
1927

2028
println!("{}", &expr);
21-
return Ok(expr.clone());
29+
Ok(expr.clone())
2230
}),
2331
);
2432

@@ -99,7 +107,7 @@ pub fn default_env() -> Env {
99107
Value::NativeFunc(|_env, args| {
100108
let list = require_list_parameter("car", args, 0)?;
101109

102-
return list.car().map(|c| c.clone());
110+
list.car()
103111
}),
104112
);
105113

@@ -108,7 +116,7 @@ pub fn default_env() -> Env {
108116
Value::NativeFunc(|_env, args| {
109117
let list = require_list_parameter("cdr", args, 0)?;
110118

111-
return Ok(Value::List(list.cdr()));
119+
Ok(Value::List(list.cdr()))
112120
}),
113121
);
114122

@@ -118,26 +126,33 @@ pub fn default_env() -> Env {
118126
let car = require_parameter("cons", args, 0)?;
119127
let cdr = require_list_parameter("cons", args, 1)?;
120128

121-
return Ok(Value::List(cdr.cons(car.clone())));
129+
Ok(Value::List(cdr.cons(car.clone())))
122130
}),
123131
);
124132

125133
entries.insert(
126134
String::from("list"),
127-
Value::NativeFunc(|_env, args| Ok(Value::List(args.into_iter().collect::<List>()))),
135+
Value::NativeFunc(|_env, args| Ok(Value::List(args.iter().collect::<List>()))),
128136
);
129137

130138
entries.insert(
131139
String::from("nth"),
132140
Value::NativeFunc(|_env, args| {
133-
let index = require_int_parameter("nth", args, 0)?;
141+
cfg_if! {
142+
if #[cfg(feature = "bigint")] {
143+
let index = require_int_parameter("nth", args, 0)?
144+
.to_usize()
145+
.ok_or(RuntimeError::new("Failed converting `BigInt` to `usize`"))?;
146+
} else {
147+
let index = require_int_parameter("nth", args, 0)? as usize;
148+
}
149+
}
134150
let list = require_list_parameter("nth", args, 1)?;
135151

136-
return Ok(list
152+
Ok(list
137153
.into_iter()
138-
.nth(index as usize)
139-
.map(|v| v.clone())
140-
.unwrap_or(Value::NIL));
154+
.nth(index)
155+
.unwrap_or(Value::NIL))
141156
}),
142157
);
143158

@@ -150,7 +165,7 @@ pub fn default_env() -> Env {
150165

151166
v.sort();
152167

153-
return Ok(Value::List(v.into_iter().collect()));
168+
Ok(Value::List(v.into_iter().collect()))
154169
}),
155170
);
156171

@@ -163,7 +178,7 @@ pub fn default_env() -> Env {
163178

164179
v.reverse();
165180

166-
return Ok(Value::List(v.into_iter().collect()));
181+
Ok(Value::List(v.into_iter().collect()))
167182
}),
168183
);
169184

@@ -173,18 +188,19 @@ pub fn default_env() -> Env {
173188
let func = require_parameter("map", args, 0)?;
174189
let list = require_list_parameter("map", args, 1)?;
175190

176-
return list
191+
list
177192
.into_iter()
178193
.map(|val| {
179-
let expr = lisp! { ({func.clone()} {val.clone()}) };
194+
let expr = lisp! { ({func.clone()} {val}) };
180195

181196
eval(env.clone(), &expr)
182197
})
183198
.collect::<Result<List, RuntimeError>>()
184-
.map(|l| Value::List(l));
199+
.map(Value::List)
185200
}),
186201
);
187202

203+
// 🦀 Oh the poor `filter`, you must feel really sad being unused.
188204
// entries.insert(
189205
// String::from("filter"),
190206
// Value::NativeFunc(
@@ -208,7 +224,13 @@ pub fn default_env() -> Env {
208224
Value::NativeFunc(|_env, args| {
209225
let list = require_list_parameter("length", args, 0)?;
210226

211-
return Ok(Value::Int(list.into_iter().len() as i32));
227+
cfg_if! {
228+
if #[cfg(feature = "bigint")] {
229+
Ok(Value::Int(list.into_iter().len().into()))
230+
} else {
231+
Ok(Value::Int(list.into_iter().len() as IntType))
232+
}
233+
}
212234
}),
213235
);
214236

@@ -218,9 +240,24 @@ pub fn default_env() -> Env {
218240
let start = require_int_parameter("range", args, 0)?;
219241
let end = require_int_parameter("range", args, 1)?;
220242

221-
Ok(Value::List(
222-
(start..end).map(|i| Value::Int(i)).collect::<List>(),
223-
))
243+
cfg_if! {
244+
if #[cfg(feature = "bigint")] {
245+
let mut i = start.clone();
246+
let mut res = Vec::with_capacity((end.clone() - start)
247+
.to_usize()
248+
.ok_or(RuntimeError::new("Failed converting `BigInt` to `usize`"))?
249+
);
250+
251+
while i < end {
252+
res.push(i.clone());
253+
i += 1;
254+
}
255+
256+
Ok(Value::List(res.into_iter().map(Value::Int).collect::<List>()))
257+
} else {
258+
Ok(Value::List((start..end).map(Value::Int).collect::<List>()))
259+
}
260+
}
224261
}),
225262
);
226263

@@ -230,24 +267,21 @@ pub fn default_env() -> Env {
230267
let a = require_parameter("+", args, 0)?;
231268
let b = require_parameter("+", args, 1)?;
232269

233-
match (a.as_int(), b.as_int()) {
234-
(Some(a), Some(b)) => return Ok(Value::Int(a + b)),
235-
_ => (),
236-
};
270+
if let (Some(a), Some(b)) = (a.as_int(), b.as_int()) {
271+
return Ok(Value::Int(a + b))
272+
}
237273

238-
match (a.as_float(), b.as_float()) {
239-
(Some(a), Some(b)) => return Ok(Value::Float(a + b)),
240-
_ => (),
241-
};
274+
if let (Some(a), Some(b)) = (a.as_float(), b.as_float()) {
275+
return Ok(Value::Float(a + b))
276+
}
242277

243-
match (a.as_string(), b.as_string()) {
244-
(Some(a), Some(b)) => return Ok(Value::String(String::from(a) + b)),
245-
_ => (),
246-
};
278+
if let (Some(a), Some(b)) = (a.as_string(), b.as_string()) {
279+
return Ok(Value::String(String::from(a) + b))
280+
}
247281

248-
return Err(RuntimeError {
282+
Err(RuntimeError {
249283
msg: String::from("Function \"+\" requires arguments to be numbers or strings"),
250-
});
284+
})
251285
}),
252286
);
253287

@@ -257,19 +291,17 @@ pub fn default_env() -> Env {
257291
let a = require_parameter("-", args, 0)?;
258292
let b = require_parameter("-", args, 1)?;
259293

260-
match (a.as_int(), b.as_int()) {
261-
(Some(a), Some(b)) => return Ok(Value::Int(a - b)),
262-
_ => (),
263-
};
294+
if let (Some(a), Some(b)) = (a.as_int(), b.as_int()) {
295+
return Ok(Value::Int(a - b))
296+
}
264297

265-
match (a.as_float(), b.as_float()) {
266-
(Some(a), Some(b)) => return Ok(Value::Float(a - b)),
267-
_ => (),
268-
};
298+
if let (Some(a), Some(b)) = (a.as_float(), b.as_float()) {
299+
return Ok(Value::Float(a - b))
300+
}
269301

270-
return Err(RuntimeError {
302+
Err(RuntimeError {
271303
msg: String::from("Function \"-\" requires arguments to be numbers"),
272-
});
304+
})
273305
}),
274306
);
275307

@@ -279,19 +311,17 @@ pub fn default_env() -> Env {
279311
let a = require_parameter("*", args, 0)?;
280312
let b = require_parameter("*", args, 1)?;
281313

282-
match (a.as_int(), b.as_int()) {
283-
(Some(a), Some(b)) => return Ok(Value::Int(a * b)),
284-
_ => (),
285-
};
314+
if let (Some(a), Some(b)) = (a.as_int(), b.as_int()) {
315+
return Ok(Value::Int(a * b))
316+
}
286317

287-
match (a.as_float(), b.as_float()) {
288-
(Some(a), Some(b)) => return Ok(Value::Float(a * b)),
289-
_ => (),
290-
};
318+
if let (Some(a), Some(b)) = (a.as_float(), b.as_float()) {
319+
return Ok(Value::Float(a * b))
320+
}
291321

292-
return Err(RuntimeError {
322+
Err(RuntimeError {
293323
msg: String::from("Function \"*\" requires arguments to be numbers"),
294-
});
324+
})
295325
}),
296326
);
297327

@@ -301,19 +331,17 @@ pub fn default_env() -> Env {
301331
let a = require_parameter("/", args, 0)?;
302332
let b = require_parameter("/", args, 1)?;
303333

304-
match (a.as_int(), b.as_int()) {
305-
(Some(a), Some(b)) => return Ok(Value::Int(a / b)),
306-
_ => (),
307-
};
334+
if let (Some(a), Some(b)) = (a.as_int(), b.as_int()) {
335+
return Ok(Value::Int(a / b))
336+
}
308337

309-
match (a.as_float(), b.as_float()) {
310-
(Some(a), Some(b)) => return Ok(Value::Float(a / b)),
311-
_ => (),
312-
};
338+
if let (Some(a), Some(b)) = (a.as_float(), b.as_float()) {
339+
return Ok(Value::Float(a / b))
340+
}
313341

314-
return Err(RuntimeError {
342+
Err(RuntimeError {
315343
msg: String::from("Function \"/\" requires arguments to be numbers"),
316-
});
344+
})
317345
}),
318346
);
319347

@@ -323,14 +351,13 @@ pub fn default_env() -> Env {
323351
let a = require_parameter("truncate", args, 0)?;
324352
let b = require_parameter("truncate", args, 1)?;
325353

326-
match (a.as_int(), b.as_int()) {
327-
(Some(a), Some(b)) => return Ok(Value::Int(a / b)),
328-
_ => (),
329-
};
354+
if let (Some(a), Some(b)) = (a.as_int(), b.as_int()) {
355+
return Ok(Value::Int(a / b))
356+
}
330357

331-
return Err(RuntimeError {
358+
Err(RuntimeError {
332359
msg: String::from("Function \"truncate\" requires arguments to be integers"),
333-
});
360+
})
334361
}),
335362
);
336363

@@ -418,7 +445,7 @@ pub fn default_env() -> Env {
418445
let func = require_parameter("apply", args, 0)?;
419446
let params = require_list_parameter("apply", args, 1)?;
420447

421-
eval(env.clone(), &Value::List(params.cons(func.clone())))
448+
eval(env, &Value::List(params.cons(func.clone())))
422449
}),
423450
);
424451

0 commit comments

Comments
 (0)