diff --git a/src/parser/constructs.rs b/src/parser/constructs.rs index 1b54c074..ab51af94 100644 --- a/src/parser/constructs.rs +++ b/src/parser/constructs.rs @@ -305,9 +305,36 @@ fn unit_block(input: &str) -> ParseResult<&str, Box> { Ok((input, Box::new(block))) } -/// function_declaration = spaced_identifier '(' next typed_args next return_type +// FIXME: This does not parse default generic types yet (`func f()`) +fn generic_list(input: &str) -> ParseResult<&str, Vec> { + fn whitespace_plus_id(input: &str) -> ParseResult<&str, String> { + let input = next(input); + let (input, id) = Token::identifier(input)?; + let input = next(input); + + Ok((input, id)) + } + + let (input, first_type) = whitespace_plus_id(input)?; + let (input, mut generics) = many0(preceded(Token::comma, whitespace_plus_id))(input)?; + let (input, _) = Token::right_bracket(input)?; + + generics.insert(0, first_type); + Ok((input, generics.into_iter().map(TypeId::new).collect())) +} + +/// function_declaration = next spaced_identifier [ next '[' spaced_identifier ( ',' spaced_identifier )* ']' ] next '(' next typed_arg next return_type fn func_declaration(input: &str) -> ParseResult<&str, FunctionDec> { + let input = next(input); let (input, id) = spaced_identifier(input)?; + let input = next(input); + + let (input, _generics) = if let Ok((input, _)) = Token::left_bracket(input) { + generic_list(input)? + } else { + (input, vec![]) + }; + let (input, _) = Token::left_parenthesis(input)?; let input = next(input); let (input, args) = typed_args(input)?; @@ -1188,4 +1215,31 @@ func void() { }"##; fn multi_type_in_type_dec() { assert!(expr("type MultiTy(a: int | string | float | char | bool);").is_ok()) } + + #[test] + fn func_dec_one_generic() { + assert!(expr("func a[T]() {}").is_ok()) + } + + #[test] + fn func_dec_multiple_generic() { + assert!(expr("func a[T, U, V]() {}").is_ok()) + } + + #[test] + fn func_dec_generic_and_whitespace() { + assert!(expr("func a[ T]() {}").is_ok()); + assert!(expr("func a[ T ]() {}").is_ok()); + assert!(expr("func a[ T , U , V]() {}").is_ok()) + } + + #[test] + fn func_dec_empty_generic_list() { + assert!(expr("func a[]() {}").is_err()) + } + + #[test] + fn func_dec_no_generic_delimiter() { + assert!(expr("func a[T, U() {}").is_err()) + } } diff --git a/src/parser/grammar b/src/parser/grammar index 2394ebe5..8c36db50 100644 --- a/src/parser/grammar +++ b/src/parser/grammar @@ -53,8 +53,8 @@ inner_block = '}' | expr '}' (* The only case where block is an expr *) | expr ';' next inner_block -function_declaration = spaced_identifier '(' next typed_arg next return_type -return_type = '->' spaced_identifier +function_declaration = next spaced_identifier [ next '<' spaced_identifier ( ',' spaced_identifier )* '>' ] next '(' next typed_arg next return_type +return_type = '->' next spaced_identifier next | ε typed_args = typed_arg ( ',' typed_arg )* ')' diff --git a/src/parser/tokens.rs b/src/parser/tokens.rs index 34576dd1..5c122b81 100644 --- a/src/parser/tokens.rs +++ b/src/parser/tokens.rs @@ -92,11 +92,11 @@ impl Token { Token::specific_char(input, '}') } - pub fn _left_bracket(input: &str) -> ParseResult<&str, char> { + pub fn left_bracket(input: &str) -> ParseResult<&str, char> { Token::specific_char(input, '[') } - pub fn _right_bracket(input: &str) -> ParseResult<&str, char> { + pub fn right_bracket(input: &str) -> ParseResult<&str, char> { Token::specific_char(input, ']') }