arity checking--of local functions

This commit is contained in:
Scott Richmond 2024-12-11 00:20:34 -05:00
parent eafe7a7fa9
commit 35e9d0373d
2 changed files with 23 additions and 11 deletions

View File

@ -167,10 +167,9 @@ pub fn run(src: &'static str) {
pub fn main() { pub fn main() {
let src = " let src = "
let bar = :bar let bar = :foo
match :foo with { fn foo (foo, bar, ...) -> bar
:foo -> bar foo (42)
}
"; ";
run(src); run(src);
// struct_scalpel::print_dissection_info::<value::Value>() // struct_scalpel::print_dissection_info::<value::Value>()

View File

@ -37,6 +37,13 @@ pub enum FnInfo {
Unknown, Unknown,
} }
fn match_arities(arities: &HashSet<Arity>, num_args: u8) -> bool {
arities.iter().any(|arity| match arity {
Arity::Fixed(n) => *n == num_args,
Arity::Splat(n) => *n <= num_args,
})
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Validator<'a> { pub struct Validator<'a> {
// TODO: add another term here: FnStatus. See Issue #18. // TODO: add another term here: FnStatus. See Issue #18.
@ -269,9 +276,6 @@ impl<'a> Validator<'a> {
} }
// TODO! // TODO!
// first check all nodes
// then...
// check arity is 1 if first term is keyword
// check arity against fn info if first term is word and second term is args // check arity against fn info if first term is word and second term is args
Synthetic(first, second, rest) => { Synthetic(first, second, rest) => {
match (&first.0, &second.0) { match (&first.0, &second.0) {
@ -290,7 +294,7 @@ impl<'a> Validator<'a> {
self.span = *span; self.span = *span;
self.validate(); self.validate();
} }
(Ast::Word(_), Ast::Arguments(_)) => { (Ast::Word(name), Ast::Arguments(args)) => {
let (expr, span) = first.as_ref(); let (expr, span) = first.as_ref();
self.ast = expr; self.ast = expr;
self.span = *span; self.span = *span;
@ -301,7 +305,14 @@ impl<'a> Validator<'a> {
self.span = *span; self.span = *span;
self.validate(); self.validate();
//TODO: check arity of call //TODO: check arities of prelude fns, too
let fn_binding = self.bound(name);
if let Some((_, _, FnInfo::Defined(arities, _))) = fn_binding {
let num_args = args.len();
if !match_arities(arities, num_args as u8) {
self.err(format!("arity mismatch: no clause in function `{name}` with {num_args} argument(s)"))
}
}
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -412,6 +423,8 @@ impl<'a> Validator<'a> {
} }
} }
// TODO: devise a placeholder binding for recursive functions
let from = self.status.used_bindings.len(); let from = self.status.used_bindings.len();
let mut arities = HashSet::new(); let mut arities = HashSet::new();
@ -588,8 +601,8 @@ impl<'a> Validator<'a> {
self.err("splats in patterns must come last".to_string()); self.err("splats in patterns must come last".to_string());
} }
match splatted.as_ref() { match splatted.as_ref() {
(Ast::Placeholder, _) => (), (PlaceholderPattern, _) => (),
(Ast::Word(name), span) => match self.bound(name) { (Word(name), span) => match self.bound(name) {
Some(_) => { Some(_) => {
self.span = *span; self.span = *span;
self.err(format!("name `{name}` is already bound")) self.err(format!("name `{name}` is already bound"))