Proper errors for closure arity mismatch
This commit is contained in:
+37
-1
@@ -1,4 +1,4 @@
|
||||
use std::{fmt, io, rc::Rc};
|
||||
use std::{fmt, io, ops::RangeInclusive, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
compile::CompileError,
|
||||
@@ -37,6 +37,13 @@ pub enum ReadError {
|
||||
Io(io::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct ArgumentCountError {
|
||||
pub function: Rc<BytecodeFunction>,
|
||||
pub expected_range: RangeInclusive<usize>,
|
||||
pub actual: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, thiserror::Error)]
|
||||
pub enum MachineError {
|
||||
// VM itself
|
||||
@@ -70,6 +77,8 @@ pub enum MachineError {
|
||||
InvalidBranchTarget(usize, isize),
|
||||
#[error("GET_TEMP with an empty temp register")]
|
||||
TempRegisterEmpty,
|
||||
#[error("{0}")]
|
||||
ArgumentCount(ArgumentCountError),
|
||||
|
||||
// Syntax+evaluation
|
||||
// #[error("evaluation error: {0}")]
|
||||
@@ -131,3 +140,30 @@ impl PartialEq for ReadError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ArgumentCountError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let min_arity = *self.expected_range.start();
|
||||
let max_arity = *self.expected_range.end();
|
||||
let one_argument = min_arity == max_arity;
|
||||
let too_few = self.actual < min_arity;
|
||||
|
||||
write!(
|
||||
f,
|
||||
"too {} arguments for function {}: expected ",
|
||||
if too_few { "few" } else { "many" },
|
||||
self.function
|
||||
)?;
|
||||
|
||||
if one_argument {
|
||||
write!(f, "{min_arity}")?;
|
||||
write!(f, " argument")?;
|
||||
if min_arity != 1 {
|
||||
write!(f, "s")?;
|
||||
}
|
||||
} else {
|
||||
write!(f, "{min_arity}-{max_arity} arguments")?;
|
||||
}
|
||||
write!(f, ", got {}", self.actual)
|
||||
}
|
||||
}
|
||||
|
||||
+17
-11
@@ -1,6 +1,9 @@
|
||||
use crate::{
|
||||
compile::{CompileContext, CompileOptions},
|
||||
error::{MachineError, MachineErrorAt, MachineErrorLocation, ValueConversionError},
|
||||
error::{
|
||||
ArgumentCountError, MachineError, MachineErrorAt, MachineErrorLocation,
|
||||
ValueConversionError,
|
||||
},
|
||||
vm::{
|
||||
Value,
|
||||
env::Environment,
|
||||
@@ -241,11 +244,12 @@ impl Machine {
|
||||
}
|
||||
};
|
||||
|
||||
if argument_count < closure.function.min_arity {
|
||||
todo!("TODO function called with less arguments than expected")
|
||||
}
|
||||
if argument_count > closure.function.max_arity {
|
||||
todo!("TODO function called with more arguments than expected")
|
||||
if !(closure.function.min_arity..=closure.function.max_arity).contains(&argument_count) {
|
||||
return Err(MachineError::ArgumentCount(ArgumentCountError {
|
||||
function: closure.function.clone(),
|
||||
expected_range: closure.function.min_arity..=closure.function.max_arity,
|
||||
actual: argument_count,
|
||||
}));
|
||||
}
|
||||
if closure.function.max_arity == usize::MAX {
|
||||
todo!("VM support for &rest argument")
|
||||
@@ -594,11 +598,13 @@ impl Machine {
|
||||
args: &[Value],
|
||||
) -> Result<Value, MachineErrorAt> {
|
||||
let max_arity = closure.function.max_arity;
|
||||
if args.len() < closure.function.min_arity {
|
||||
todo!()
|
||||
}
|
||||
if args.len() > closure.function.max_arity {
|
||||
todo!()
|
||||
if !(closure.function.min_arity..=closure.function.max_arity).contains(&args.len()) {
|
||||
return Err(MachineError::ArgumentCount(ArgumentCountError {
|
||||
function: closure.function.clone(),
|
||||
expected_range: closure.function.min_arity..=closure.function.max_arity,
|
||||
actual: args.len(),
|
||||
})
|
||||
.at_unknown());
|
||||
}
|
||||
self.push(Value::Closure(closure))
|
||||
.map_err(MachineErrorAt::at_unknown)?;
|
||||
|
||||
Reference in New Issue
Block a user