diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index 0720d44..28ffae8 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -105,14 +105,16 @@ pub fn block(input: Span) -> ParseResult { context( "block", map( - tuple(( + delimited( tok(char('{')), + tuple(( many0(statement_delimiter), separated_list0(statement_delimiter, statement), many0(statement_delimiter), + )), tok(char('}')), - )), - |(_, _, items, _, _)| items.into(), + ), + |(_, items, _)| items.into(), ), )(input) } @@ -129,7 +131,60 @@ fn statement(input: Span) -> ParseResult { } fn declaration(input: Span) -> ParseResult { - alt((binding, type_decl, func, annotation, module))(input) + alt((binding, type_decl, func, annotation, module, interface, implementation))(input) +} + +fn implementation(input: Span) -> ParseResult { + alt(( + map( + preceded(kw("impl"), tuple((type_singleton_name, kw("for"), type_identifier, decl_block))), + |(if_name, _, type_name, block)| Declaration::Impl { + type_name, + interface_name: Some(if_name), + block, + }, + ), + map(preceded(kw("impl"), pair(type_identifier, decl_block)), |(type_name, block)| { + Declaration::Impl { type_name, interface_name: None, block } + }), + ))(input) +} + +fn decl_block(input: Span) -> ParseResult> { + delimited( + tok(char('{')), + map( + tuple(( + many0(statement_delimiter), + separated_list0(statement_delimiter, func_decl), + many0(statement_delimiter), + )), + |(_, signatures, _)| signatures, + ), + tok(char('}')), + )(input) +} + +fn interface(input: Span) -> ParseResult { + map(preceded(kw("interface"), pair(tok(identifier), signature_block)), |(name, signatures)| { + Declaration::Interface { name: rc_string(name.fragment()), signatures } + })(input) +} + +//TODO make the blocks parameterizable +fn signature_block(input: Span) -> ParseResult> { + delimited( + tok(char('{')), + map( + tuple(( + many0(statement_delimiter), + separated_list0(statement_delimiter, func_signature), + many0(statement_delimiter), + )), + |(_, signatures, _)| signatures, + ), + tok(char('}')), + )(input) } fn annotation(input: Span) -> ParseResult { diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index 1059bd3..84ce6a2 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -921,7 +921,7 @@ fn functions_with_default_args() { #[test] fn interface() { let glue = TypeIdentifier::Singleton(TypeSingletonName { name: rc("Glue"), params: vec![] }); - assert_ast!( + assert_ast_comb!( "interface Unglueable { fn unglue(a: Glue); fn mar(): Glue }", vec![decl(Declaration::Interface { name: rc("Unglueable"), @@ -953,13 +953,13 @@ fn impls() { ), ]; - assert_ast!( + assert_ast_comb!( "impl Heh { fn yolo() { }; fn swagg() { } }", vec![decl(Impl { type_name: ty_simple("Heh"), interface_name: None, block: block.clone() })] ); //TODO `"impl Heh { fn yolo() { }; fn swagg() { }; }"` ought to work - assert_ast!( + assert_ast_comb!( "impl Heh { fn yolo() { }; fn swagg() { } }", vec![decl(Impl { type_name: TypeIdentifier::Singleton(TypeSingletonName { @@ -971,7 +971,7 @@ fn impls() { })] ); - assert_ast!( + assert_ast_comb!( "impl Heh for Saraz { fn yolo() {}; fn swagg() {} }", vec![decl(Impl { type_name: ty_simple("Saraz"), @@ -980,7 +980,7 @@ fn impls() { })] ); - assert_ast!( + assert_ast_comb!( "impl Heh for (Int, Codepoint) {}", vec![decl(Impl { type_name: TypeIdentifier::Tuple(vec![ty_simple("Int"), ty_simple("Codepoint")]),