diff --git a/crates/fuse-ast/src/ast.rs b/crates/fuse-ast/src/ast.rs index 5111d0c..562d81d 100644 --- a/crates/fuse-ast/src/ast.rs +++ b/crates/fuse-ast/src/ast.rs @@ -423,7 +423,7 @@ pub enum ConstructionField { pub struct ImplStatement { pub span: Span, pub target: TypeAnnotation, - pub r#trait: Option<()>, + pub r#trait: Option, pub methods: Vec, } diff --git a/crates/fuse-parser/src/parsers/binding.rs b/crates/fuse-parser/src/parsers/binding.rs index e6335c5..3b7646a 100644 --- a/crates/fuse-parser/src/parsers/binding.rs +++ b/crates/fuse-parser/src/parsers/binding.rs @@ -33,7 +33,15 @@ impl<'a> Parser<'a> { } let identifier = self.parse_binding_identifier(); - Ok(self.ast.binding_identifier_pattern(identifier, None, false)) + let type_annotation = if self.consume_if(TokenKind::Colon).is_some() { + Some(self.parse_type_annotation()?) + } else { + None + }; + + Ok(self + .ast + .binding_identifier_pattern(identifier, type_annotation, false)) } pub(crate) fn parse_binding_identifier(&mut self) -> BindingIdentifier { diff --git a/crates/fuse-parser/src/parsers/statements.rs b/crates/fuse-parser/src/parsers/statements.rs index 7f7052c..28ccb77 100644 --- a/crates/fuse-parser/src/parsers/statements.rs +++ b/crates/fuse-parser/src/parsers/statements.rs @@ -91,12 +91,18 @@ impl<'a> Parser<'a> { } fn parse_impl_statement(&mut self) -> ParserResult { - debug_assert!(self.at(TokenKind::Trait)); + debug_assert!(self.at(TokenKind::Impl)); let start = self.start_span(); // Consume the struct keyword. self.consume(); - let target = self.parse_type_annotation()?; + let (target, r#trait) = { + let first_type = self.parse_type_annotation()?; + match self.consume_if(TokenKind::For) { + Some(_) => (self.parse_type_annotation()?, Some(first_type)), + None => (first_type, None), + } + }; let mut methods: Vec = Vec::new(); while !self.at(TokenKind::End) { let modifier = self.try_parse_visibility_modifier(); @@ -108,7 +114,7 @@ impl<'a> Parser<'a> { Ok(self.ast.impl_statement(ImplStatement { span: self.end_span(start), target, - r#trait: None, + r#trait, methods, })) } diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-01/ast.snap b/crates/fuse-parser/tests/cases/pass/impl-statement-01/ast.snap new file mode 100644 index 0000000..0385871 --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-01/ast.snap @@ -0,0 +1,33 @@ +--- +source: crates/fuse-parser/tests/cases/mod.rs +description: "impl Test\nend\n" +expression: parsed.chunk +input_file: crates/fuse-parser/tests/cases/pass/impl-statement-01/case.fuse +--- +Some(Chunk( + span: Span( + start: 0, + end: 14, + ), + body: Block( + statements: [ + ImplStatement(ImplStatement( + span: Span( + start: 0, + end: 13, + ), + target: TypeAnnotation( + identifier: Identifier( + span: Span( + start: 5, + end: 9, + ), + name: Atom("Test"), + ), + ), + trait: None, + methods: [], + )), + ], + ), +)) diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-01/case.fuse b/crates/fuse-parser/tests/cases/pass/impl-statement-01/case.fuse new file mode 100644 index 0000000..9a0cbf6 --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-01/case.fuse @@ -0,0 +1,2 @@ +impl Test +end diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-01/tokens.snap b/crates/fuse-parser/tests/cases/pass/impl-statement-01/tokens.snap new file mode 100644 index 0000000..720711a --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-01/tokens.snap @@ -0,0 +1,65 @@ +--- +source: crates/fuse-parser/tests/cases/mod.rs +description: "impl Test\nend\n" +expression: tokens +input_file: crates/fuse-parser/tests/cases/pass/impl-statement-01/case.fuse +--- +[ + TokenReference( + token: Token( + span: Span( + start: 0, + end: 4, + ), + kind: Impl, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 4, + end: 5, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 5, + end: 9, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 9, + end: 10, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 10, + end: 13, + ), + kind: End, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 13, + end: 14, + ), + kind: Whitespace, + ), + ], + ), +] diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-02/ast.snap b/crates/fuse-parser/tests/cases/pass/impl-statement-02/ast.snap new file mode 100644 index 0000000..36a5835 --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-02/ast.snap @@ -0,0 +1,41 @@ +--- +source: crates/fuse-parser/tests/cases/mod.rs +description: "impl Trait for Test\nend\n" +expression: parsed.chunk +input_file: crates/fuse-parser/tests/cases/pass/impl-statement-02/case.fuse +--- +Some(Chunk( + span: Span( + start: 0, + end: 24, + ), + body: Block( + statements: [ + ImplStatement(ImplStatement( + span: Span( + start: 0, + end: 23, + ), + target: TypeAnnotation( + identifier: Identifier( + span: Span( + start: 15, + end: 19, + ), + name: Atom("Test"), + ), + ), + trait: Some(TypeAnnotation( + identifier: Identifier( + span: Span( + start: 5, + end: 10, + ), + name: Atom("Trait"), + ), + )), + methods: [], + )), + ], + ), +)) diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-02/case.fuse b/crates/fuse-parser/tests/cases/pass/impl-statement-02/case.fuse new file mode 100644 index 0000000..9cb5d1d --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-02/case.fuse @@ -0,0 +1,2 @@ +impl Trait for Test +end diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-02/tokens.snap b/crates/fuse-parser/tests/cases/pass/impl-statement-02/tokens.snap new file mode 100644 index 0000000..0ff9d6d --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-02/tokens.snap @@ -0,0 +1,103 @@ +--- +source: crates/fuse-parser/tests/cases/mod.rs +description: "impl Trait for Test\nend\n" +expression: tokens +input_file: crates/fuse-parser/tests/cases/pass/impl-statement-02/case.fuse +--- +[ + TokenReference( + token: Token( + span: Span( + start: 0, + end: 4, + ), + kind: Impl, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 4, + end: 5, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 5, + end: 10, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 10, + end: 11, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 11, + end: 14, + ), + kind: For, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 14, + end: 15, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 15, + end: 19, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 19, + end: 20, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 20, + end: 23, + ), + kind: End, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 23, + end: 24, + ), + kind: Whitespace, + ), + ], + ), +] diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-03/ast.snap b/crates/fuse-parser/tests/cases/pass/impl-statement-03/ast.snap new file mode 100644 index 0000000..6f0bbaa --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-03/ast.snap @@ -0,0 +1,162 @@ +--- +source: crates/fuse-parser/tests/cases/mod.rs +expression: parsed.chunk +input_file: crates/fuse-parser/tests/cases/pass/impl-statement-03/case.fuse +--- +Some(Chunk( + span: Span( + start: 0, + end: 80, + ), + body: Block( + statements: [ + ImplStatement(ImplStatement( + span: Span( + start: 0, + end: 79, + ), + target: TypeAnnotation( + identifier: Identifier( + span: Span( + start: 5, + end: 9, + ), + name: Atom("Test"), + ), + ), + trait: None, + methods: [ + ImplMethod( + modifier: Private, + function: Function( + span: Span( + start: 11, + end: 25, + ), + signature: FunctionSignature( + span: Span( + start: 11, + end: 20, + ), + identifier: Some(Identifier( + span: Span( + start: 14, + end: 18, + ), + name: Atom("test"), + )), + params: FunctionParameters( + span: Span( + start: 18, + end: 20, + ), + items: [], + rest: None, + ), + return_type: None, + ), + body: Block(Block( + statements: [], + )), + ), + ), + ImplMethod( + modifier: Private, + function: Function( + span: Span( + start: 28, + end: 75, + ), + signature: FunctionSignature( + span: Span( + start: 28, + end: 70, + ), + identifier: Some(Identifier( + span: Span( + start: 31, + end: 36, + ), + name: Atom("test2"), + )), + params: FunctionParameters( + span: Span( + start: 36, + end: 62, + ), + items: [ + FunctionParameter( + span: Span( + start: 37, + end: 40, + ), + pattern: BindingPattern( + kind: Identifier(BindingIdentifier( + span: Span( + start: 37, + end: 40, + ), + atom: Atom("foo"), + mutable: false, + )), + type_annotation: Some(TypeAnnotation( + identifier: Identifier( + span: Span( + start: 42, + end: 48, + ), + name: Atom("number"), + ), + )), + optional: false, + ), + ), + FunctionParameter( + span: Span( + start: 50, + end: 53, + ), + pattern: BindingPattern( + kind: Identifier(BindingIdentifier( + span: Span( + start: 50, + end: 53, + ), + atom: Atom("bar"), + mutable: false, + )), + type_annotation: Some(TypeAnnotation( + identifier: Identifier( + span: Span( + start: 55, + end: 61, + ), + name: Atom("number"), + ), + )), + optional: false, + ), + ), + ], + rest: None, + ), + return_type: Some(TypeAnnotation( + identifier: Identifier( + span: Span( + start: 66, + end: 70, + ), + name: Atom("Type"), + ), + )), + ), + body: Block(Block( + statements: [], + )), + ), + ), + ], + )), + ], + ), +)) diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-03/case.fuse b/crates/fuse-parser/tests/cases/pass/impl-statement-03/case.fuse new file mode 100644 index 0000000..b4a0567 --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-03/case.fuse @@ -0,0 +1,7 @@ +impl Test + fn test() + end + + fn test2(foo: number, bar: number) -> Type + end +end diff --git a/crates/fuse-parser/tests/cases/pass/impl-statement-03/tokens.snap b/crates/fuse-parser/tests/cases/pass/impl-statement-03/tokens.snap new file mode 100644 index 0000000..e983d12 --- /dev/null +++ b/crates/fuse-parser/tests/cases/pass/impl-statement-03/tokens.snap @@ -0,0 +1,361 @@ +--- +source: crates/fuse-parser/tests/cases/mod.rs +expression: tokens +input_file: crates/fuse-parser/tests/cases/pass/impl-statement-03/case.fuse +--- +[ + TokenReference( + token: Token( + span: Span( + start: 0, + end: 4, + ), + kind: Impl, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 4, + end: 5, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 5, + end: 9, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 9, + end: 11, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 11, + end: 13, + ), + kind: Fn, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 13, + end: 14, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 14, + end: 18, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 18, + end: 19, + ), + kind: LParen, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 19, + end: 20, + ), + kind: RParen, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 20, + end: 22, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 22, + end: 25, + ), + kind: End, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 25, + end: 28, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 28, + end: 30, + ), + kind: Fn, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 30, + end: 31, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 31, + end: 36, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 36, + end: 37, + ), + kind: LParen, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 37, + end: 40, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 40, + end: 41, + ), + kind: Colon, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 41, + end: 42, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 42, + end: 48, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 48, + end: 49, + ), + kind: Comma, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 49, + end: 50, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 50, + end: 53, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 53, + end: 54, + ), + kind: Colon, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 54, + end: 55, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 55, + end: 61, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [], + ), + TokenReference( + token: Token( + span: Span( + start: 61, + end: 62, + ), + kind: RParen, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 62, + end: 63, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 63, + end: 65, + ), + kind: ThinArrow, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 65, + end: 66, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 66, + end: 70, + ), + kind: Identifier, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 70, + end: 72, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 72, + end: 75, + ), + kind: End, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 75, + end: 76, + ), + kind: Whitespace, + ), + ], + ), + TokenReference( + token: Token( + span: Span( + start: 76, + end: 79, + ), + kind: End, + ), + leading_trivia: [], + trailing_trivia: [ + Token( + span: Span( + start: 79, + end: 80, + ), + kind: Whitespace, + ), + ], + ), +]