Skip to content

Commit 792aed3

Browse files
committed
Refactor into min_or_max
1 parent b66ed56 commit 792aed3

File tree

1 file changed

+17
-71
lines changed

1 file changed

+17
-71
lines changed

vm/src/builtins/make_module.rs

Lines changed: 17 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -449,23 +449,19 @@ mod decl {
449449
locals.copy().into_ref(vm)
450450
}
451451

452-
#[pyfunction]
453-
fn max(mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
452+
fn min_or_max(mut args: FuncArgs, vm: &VirtualMachine, func_name: &str, op: PyComparisonOp) -> PyResult {
454453
let default = args.take_keyword("default");
455-
let key_func = args.take_keyword("key");
456-
if !args.kwargs.is_empty() {
457-
let invalid_keyword = args.kwargs.get_index(0).unwrap();
458-
return Err(vm.new_type_error(format!(
459-
"'{}' is an invalid keyword argument for max()",
460-
invalid_keyword.0
461-
)));
454+
let mut key_func = args.take_keyword("key");
455+
456+
if let Some(err) = args.check_kwargs_empty(vm) {
457+
return Err(err);
462458
}
459+
463460
let candidates = match args.args.len().cmp(&1) {
464461
std::cmp::Ordering::Greater => {
465462
if default.is_some() {
466463
return Err(vm.new_type_error(
467-
"Cannot specify a default for max() with multiple positional arguments"
468-
.to_owned(),
464+
format!("Cannot specify a default for {} with multiple positional arguments", func_name),
469465
));
470466
}
471467
args.args
@@ -482,7 +478,7 @@ mod decl {
482478
Some(x) => x,
483479
None => {
484480
return default
485-
.ok_or_else(|| vm.new_value_error("max() arg is an empty sequence".to_owned()))
481+
.ok_or_else(|| vm.new_value_error(format!("{} arg is an empty sequence", func_name)))
486482
}
487483
};
488484

@@ -491,14 +487,14 @@ mod decl {
491487
let mut x_key = vm.invoke(key_func, (x.clone(),))?;
492488
for y in candidates_iter {
493489
let y_key = vm.invoke(key_func, (y.clone(),))?;
494-
if vm.bool_cmp(&y_key, &x_key, PyComparisonOp::Gt)? {
490+
if vm.bool_cmp(&y_key, &x_key, op)? {
495491
x = y;
496492
x_key = y_key;
497493
}
498494
}
499495
} else {
500496
for y in candidates_iter {
501-
if vm.bool_cmp(&y, &x, PyComparisonOp::Gt)? {
497+
if vm.bool_cmp(&y, &x, op)? {
502498
x = y;
503499
}
504500
}
@@ -507,65 +503,15 @@ mod decl {
507503
Ok(x)
508504
}
509505

510-
#[pyfunction]
511-
fn min(mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
512-
let (candidates, default_allowed) = match args.args.len().cmp(&1) {
513-
std::cmp::Ordering::Greater => (args.args.clone(), false),
514-
std::cmp::Ordering::Equal => (vm.extract_elements(&args.args[0])?, true),
515-
std::cmp::Ordering::Less => {
516-
// zero arguments means type error:
517-
return Err(vm.new_type_error("Expected 1 or more arguments".to_owned()));
518-
}
519-
};
520-
521-
let default = args.take_keyword("default");
522-
let mut key_func = args.take_keyword("key");
523-
524-
if let Some(err) = args.check_kwargs_empty(vm) {
525-
return Err(err);
526-
}
527506

528-
if default.is_some() && !default_allowed {
529-
return Err(vm.new_type_error(
530-
"Specifying default not allowed with more than 1 argument".to_owned(),
531-
));
532-
}
533-
534-
if candidates.is_empty() {
535-
return default
536-
.ok_or_else(|| vm.new_value_error("min() arg is an empty sequence".to_owned()));
537-
}
538-
539-
if let Some(ref obj) = key_func {
540-
if vm.is_none(obj) {
541-
key_func = None
542-
}
543-
}
544-
545-
let mut candidates_iter = candidates.into_iter();
546-
let mut x = candidates_iter.next().unwrap();
547-
// TODO: this key function looks pretty duplicate. Maybe we can create
548-
// a local function?
549-
let mut x_key = if let Some(ref f) = &key_func {
550-
vm.invoke(f, (x.clone(),))?
551-
} else {
552-
x.clone()
553-
};
554-
555-
for y in candidates_iter {
556-
let y_key = if let Some(ref f) = &key_func {
557-
vm.invoke(f, (y.clone(),))?
558-
} else {
559-
y.clone()
560-
};
561-
562-
if vm.bool_cmp(&x_key, &y_key, PyComparisonOp::Gt)? {
563-
x = y.clone();
564-
x_key = y_key;
565-
}
566-
}
507+
#[pyfunction]
508+
fn max(mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
509+
min_or_max(args, vm, "max()", PyComparisonOp::Gt)
510+
}
567511

568-
Ok(x)
512+
#[pyfunction]
513+
fn min(mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
514+
min_or_max(args, vm, "min()", PyComparisonOp::Lt)
569515
}
570516

571517
#[pyfunction]

0 commit comments

Comments
 (0)