diff --git a/pkg/rudus.js b/pkg/rudus.js index b37dd12..b048e8d 100644 --- a/pkg/rudus.js +++ b/pkg/rudus.js @@ -403,7 +403,7 @@ function __wbg_get_imports() { _assertBoolean(ret); return ret; }; - imports.wbg.__wbindgen_closure_wrapper8087 = function() { return logError(function (arg0, arg1, arg2) { + imports.wbg.__wbindgen_closure_wrapper8088 = function() { return logError(function (arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 354, __wbg_adapter_20); return ret; }, arguments) }; diff --git a/pkg/rudus_bg.wasm b/pkg/rudus_bg.wasm index fb31310..ec8f808 100644 Binary files a/pkg/rudus_bg.wasm and b/pkg/rudus_bg.wasm differ diff --git a/src/validator.rs b/src/validator.rs index fdd73cf..3c6527f 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -1,12 +1,11 @@ // TODO: -// * [ ] ensure `or` and `and` never get passed by reference -// * [ ] ensure no placeholder in `or` and `and` args // * [ ] ensure loops have fixed arity (no splats) // * [ ] ensure fn pattern splats are always highest (and same) arity use crate::ast::{Ast, StringPart}; use crate::spans::{Span, Spanned}; use crate::value::{Key, Value}; +use std::cmp::max; use std::collections::{HashMap, HashSet}; #[derive(Clone, Debug, PartialEq)] @@ -230,6 +229,9 @@ impl<'a> Validator<'a> { if members.is_empty() { return; } + if members.len() > 7 { + self.err("tuples may not have more than 7 members".to_string()); + } let tailpos = self.status.tail_position; self.status.tail_position = false; for member in members { @@ -242,6 +244,9 @@ impl<'a> Validator<'a> { if args.is_empty() { return; } + if args.len() > 7 { + self.err("tuples may not have more than 7 members".to_string()); + } let tailpos = self.status.tail_position; self.status.tail_position = false; for arg in args { @@ -423,6 +428,43 @@ impl<'a> Validator<'a> { self.validate(); } + let mut max_arity = 0; + let mut has_splat = false; + for arity in arities.iter() { + match arity { + Arity::Fixed(n) => { + max_arity = max(*n, max_arity); + } + Arity::Splat(n) => { + max_arity = max(*n, max_arity); + has_splat = true; + } + } + } + + for arity in arities.iter() { + match arity { + Arity::Fixed(n) => { + if *n == max_arity && has_splat { + self.err( + "splats must be the longest arity in function clauses" + .to_string(), + ); + break; + } + } + Arity::Splat(n) => { + if *n > max_arity { + self.err( + "splats must be the longest arity in function clauses" + .to_string(), + ); + break; + } + } + } + } + // collect info about what the function closes over let mut closed_over = HashSet::new(); for binding in self.status.used_bindings.iter().skip(from) { @@ -497,7 +539,7 @@ impl<'a> Validator<'a> { } Arity::Splat(clause_arity) => { if clause_arity > loop_arity { - self.err(format!("mismathced arity: expected {loop_arity} arguments in `loop` clause; this clause takes {clause_arity} or more")) + self.err("loop clauses may not have splats".to_string()) } } }; @@ -516,6 +558,9 @@ impl<'a> Validator<'a> { if !self.status.tail_position { self.err("you may only use `recur` in tail position".to_string()); } + if args.len() > 7 { + self.err("tuples may only have 7 members".to_string()); + } let num_args = args.len() as u8; let loop_arity = self.status.loop_arity; @@ -583,7 +628,25 @@ impl<'a> Validator<'a> { } } } - TuplePattern(terms) | ListPattern(terms) | DictPattern(terms) => { + TuplePattern(terms) => { + if terms.is_empty() { + return; + } + + if terms.len() > 7 { + self.err("tuples may only have 7 arguments".to_string()) + } + + for term in terms.iter().take(terms.len() - 1) { + self.visit(term); + } + + self.status.last_term = true; + let last = terms.last().unwrap(); + self.visit(last); + self.status.last_term = false; + } + ListPattern(terms) | DictPattern(terms) => { if terms.is_empty() { return; }