Skip to content

Commit

Permalink
Merge pull request #341 from CohenArthur/parse-generics
Browse files Browse the repository at this point in the history
Parse list of generic types in function declaration
  • Loading branch information
CohenArthur authored Nov 30, 2021
2 parents 892d1d1 + b0ed530 commit c75ee9e
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 5 deletions.
56 changes: 55 additions & 1 deletion src/parser/constructs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,36 @@ fn unit_block(input: &str) -> ParseResult<&str, Box<dyn Instruction>> {
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<T = int>()`)
fn generic_list(input: &str) -> ParseResult<&str, Vec<TypeId>> {
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)?;
Expand Down Expand Up @@ -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())
}
}
4 changes: 2 additions & 2 deletions src/parser/grammar
Original file line number Diff line number Diff line change
Expand Up @@ -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 )* ')'
Expand Down
4 changes: 2 additions & 2 deletions src/parser/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, ']')
}

Expand Down

0 comments on commit c75ee9e

Please sign in to comment.