diff --git a/compiler/pipec-ast/src/ast/mod.rs b/compiler/pipec-ast/src/ast/mod.rs index 44c5980..9c5cfd4 100644 --- a/compiler/pipec-ast/src/ast/mod.rs +++ b/compiler/pipec-ast/src/ast/mod.rs @@ -121,20 +121,29 @@ impl<'this> ASTGenerator<'this> { self.advance_stream(); self.consume_whitespace(); let name = self.must_ident(); + let generics = self.consume_generics(); self.consume_whitespace(); match self.peek_stream() { Some(Token::EqualSign) => { self.advance_stream(); let subtype = self.consume_subtype(); self.consume_a_semicolon(); - ASTNode::TypeDeclaration { name, subtype } + ASTNode::TypeDeclaration { + name, + subtype, + generics, + } } Some(Token::Semicolon) => { let subtype = SubType::Empty; self.consume_a_semicolon(); - ASTNode::TypeDeclaration { name, subtype } + ASTNode::TypeDeclaration { + name, + subtype, + generics, + } } - _ => todo!(), + v => todo!("{v:#?}"), } } @@ -230,11 +239,124 @@ impl<'this> ASTGenerator<'this> { ASTNode::Public(Box::new(val)) } + #[inline] + pub(crate) fn consume_generics(&mut self) -> Generics { + self.consume_whitespace(); + if !self.next_is(Token::LeftSquare) { + return Generics(vec![]); + } + self.must(Token::LeftSquare); + let mut out = Vec::new(); + loop { + self.consume_whitespace(); + match self.advance_stream() { + Some(Token::Hash) => { + let name = self.must_ident(); + self.consume_whitespace(); + match self.peek_stream() { + Some(Token::Colon) => { + self.advance_stream(); + let traits = self.consume_traits(); + out.push(Generic { + name, + generictype: GenericType::Lifetime, + traits, + }); + self.consume_whitespace(); + if self.next_is(Token::Comma) { + self.advance_stream(); + continue; + } + } + Some(Token::Comma) => { + self.advance_stream(); + out.push(Generic { + name, + generictype: GenericType::Lifetime, + traits: Traits::default(), + }); + continue; + } + Some(Token::RightSquare) => { + self.advance_stream(); + break; + } + _ => todo!(), + } + } + Some(Token::Ident(name)) => { + self.consume_whitespace(); + match self.peek_stream() { + Some(Token::Colon) => { + self.advance_stream(); + let traits = self.consume_traits(); + out.push(Generic { + name, + generictype: GenericType::Generic, + traits, + }); + self.consume_whitespace(); + if self.next_is(Token::Comma) { + self.advance_stream(); + continue; + } + } + Some(Token::Comma) => { + self.advance_stream(); + out.push(Generic { + name, + generictype: GenericType::Generic, + traits: Traits::default(), + }); + continue; + } + Some(Token::RightSquare) => { + self.advance_stream(); + break; + } + v => todo!("{v:#?}"), + } + } + Some(Token::RightSquare) => { + break; + } + _ => todo!(), + } + } + Generics(out) + } + + #[inline] + pub(crate) fn consume_traits(&mut self) -> Traits { + let mut out = Vec::new(); + loop { + self.consume_whitespace(); + match self.peek_stream() { + Some(Token::Ident(_)) => { + let name = self.must_ident(); + let generics = self.consume_generics(); + out.push(Trait { name, generics }); + self.consume_whitespace(); + if self.next_is(Token::Plus) { + self.advance_stream(); + continue; + } + } + Some(Token::Comma) | Some(Token::RightSquare) => { + break; + } + v => todo!("{v:#?}"), + } + } + Traits(out) + } + #[inline] pub(crate) fn consume_function_keyword(&mut self) -> ASTNode { self.advance_stream(); self.consume_whitespace(); let name = self.must_ident(); + let generics = self.consume_generics(); self.consume_whitespace(); let params = self.consume_function_parameters(); self.consume_whitespace(); @@ -252,6 +374,7 @@ impl<'this> ASTGenerator<'this> { params, block, out_type, + generics, } } @@ -1137,6 +1260,7 @@ pub enum ASTNode { }, FunctionDeclaration { name: Span, + generics: Generics, params: FunctionDeclarationParameters, block: Block, out_type: Option, @@ -1161,6 +1285,7 @@ pub enum ASTNode { }, TypeDeclaration { name: Span, + generics: Generics, subtype: SubType, }, Public(Box), @@ -1336,3 +1461,31 @@ pub struct FunctionDeclarationParameter { pub name: Span, pub arg_type: Path, } + +#[derive(Debug, Clone)] +pub struct Generics(pub Vec); + +#[derive(Debug, Clone)] +#[allow(unused)] +pub struct Generic { + name: Span, + generictype: GenericType, + traits: Traits, +} + +#[derive(Debug, Clone, Default)] +#[allow(unused)] +pub struct Traits(Vec); + +#[derive(Debug, Clone)] +#[allow(unused)] +pub struct Trait { + name: Span, + generics: Generics, +} + +#[derive(Debug, Clone)] +pub enum GenericType { + Lifetime, + Generic, +} diff --git a/compiler/pipec-gst/src/lib.rs b/compiler/pipec-gst/src/lib.rs index 8327891..a49738a 100644 --- a/compiler/pipec-gst/src/lib.rs +++ b/compiler/pipec-gst/src/lib.rs @@ -56,6 +56,7 @@ impl<'this> GlobalSymbolTree<'this> { name, params, block: _, + generics: _, out_type, } => self.parse_function_declaration(name, params, out_type, scope), ASTNode::ViewportDeclaration { diff --git a/compiler/pipec-tests/src/ast/generics/functiongenerics.pipec b/compiler/pipec-tests/src/ast/generics/functiongenerics.pipec new file mode 100644 index 0000000..deb9cc6 --- /dev/null +++ b/compiler/pipec-tests/src/ast/generics/functiongenerics.pipec @@ -0,0 +1,15 @@ +function basic[T](input : T) {} + +function multiple[T,U](input1 : T , input2 : U) {} + +function with_traits[T : Trait](input : T) {} + +function multiple_traits[T : Trait1 + Trait2 + Trait3](input : T) => T {} + +function multiple_with_multiple_traits[T : Trait1 + Trait2 + Trait3 , U : Trait1 + Trait2 + Trait3](input1 : T , input2 : U) {} + +function generic_trait[T: Trait1[T]](input : T) {} + +function multiple_generic_trait[T : Trait1[T] + Trait2[T] + Trait3[T]](input : T) => T {} + +function multiple_generic_with_generic_trait[T : Trait1[T] + Trait2[T] + Trait3[T] , U : Trait1[T] + Trait2[T] + Trait3[T]](input1 : T, input3 : T) => T {} diff --git a/compiler/pipec-tests/src/ast/generics/mod.rs b/compiler/pipec-tests/src/ast/generics/mod.rs new file mode 100644 index 0000000..4aa2c6a --- /dev/null +++ b/compiler/pipec-tests/src/ast/generics/mod.rs @@ -0,0 +1,9 @@ +#[test] +fn test_generics() { + { + crate::test_file_generation!("typegenerics.pipec"); + } + { + crate::test_file_generation!("functiongenerics.pipec"); + } +} diff --git a/compiler/pipec-tests/src/ast/generics/typegenerics.pipec b/compiler/pipec-tests/src/ast/generics/typegenerics.pipec new file mode 100644 index 0000000..76cd025 --- /dev/null +++ b/compiler/pipec-tests/src/ast/generics/typegenerics.pipec @@ -0,0 +1,8 @@ +type Basic[T] = T; +type Multiple[T,U] = (T | U); +type WithTraits[T : Trait] = T; +type MultipleTraits[T : Trait1 + Trait2 + Trait3] = T; +type MultipleWithMultipleTraits[T : Trait1 + Trait2 + Trait3, U : Trait1 + Trait2 + Trait3] = (T | U); +type GenericTrait[T : Trait1[T]] = T; +type MultipleGenericTrait[T : Trait1[T] + Trait2[T] + Trait3[T]] = T; +type MultipleGenericWithGenericTrait[T : Trait1[T] + Trait2[T] + Trait3[T], U : Trait1[T] + Trait2[T] + Trait3[T]] = (T | U); diff --git a/compiler/pipec-tests/src/ast/mod.rs b/compiler/pipec-tests/src/ast/mod.rs index a766a4e..e50318f 100644 --- a/compiler/pipec-tests/src/ast/mod.rs +++ b/compiler/pipec-tests/src/ast/mod.rs @@ -1,3 +1,4 @@ mod functiondeclaration; +mod generics; mod variablemutability; mod viewportdeclaration;