Skip to content

Commit

Permalink
added associated type args in the parser (#6741)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerStarkware authored Nov 27, 2024
1 parent e541b63 commit 3045f6d
Show file tree
Hide file tree
Showing 9 changed files with 663 additions and 30 deletions.
62 changes: 59 additions & 3 deletions crates/cairo-lang-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2565,13 +2565,28 @@ impl<'a> Parser<'a> {
let name = self.parse_identifier();
let colon = self.parse_token::<TerminalColon>();
let trait_path = self.parse_type_path();
Ok(GenericParamImplNamed::new_green(self.db, impl_kw, name, colon, trait_path)
.into())
let associated_item_constraints = self.parse_optional_associated_item_constraints();
Ok(GenericParamImplNamed::new_green(
self.db,
impl_kw,
name,
colon,
trait_path,
associated_item_constraints,
)
.into())
}
SyntaxKind::TerminalPlus => {
let plus = self.take::<TerminalPlus>();
let trait_path = self.parse_type_path();
Ok(GenericParamImplAnonymous::new_green(self.db, plus, trait_path).into())
let associated_item_constraints = self.parse_optional_associated_item_constraints();
Ok(GenericParamImplAnonymous::new_green(
self.db,
plus,
trait_path,
associated_item_constraints,
)
.into())
}
SyntaxKind::TerminalMinus => {
let minus = self.take::<TerminalMinus>();
Expand All @@ -2582,6 +2597,47 @@ impl<'a> Parser<'a> {
}
}

/// Assumes the current token is LBrack.
/// Expected pattern: `[ <associated_item_constraints_list> ]>`
fn expect_associated_item_constraints(&mut self) -> AssociatedItemConstraintsGreen {
let lbrack = self.take::<TerminalLBrack>();
let associated_item_constraints_list = AssociatedItemConstraintList::new_green(
self.db,
self.parse_separated_list::<AssociatedItemConstraint, TerminalComma, AssociatedItemConstraintListElementOrSeparatorGreen>(
Self::try_parse_associated_item_constraint,
is_of_kind!(rbrack,rangle, rparen, block, lbrace, rbrace, module_item_kw),
"associated type argument",
),
);
let rangle = self.parse_token::<TerminalRBrack>();
AssociatedItemConstraints::new_green(
self.db,
lbrack,
associated_item_constraints_list,
rangle,
)
}

fn parse_optional_associated_item_constraints(
&mut self,
) -> OptionAssociatedItemConstraintsGreen {
if self.peek().kind != SyntaxKind::TerminalLBrack {
return OptionAssociatedItemConstraintsEmpty::new_green(self.db).into();
}
self.expect_associated_item_constraints().into()
}

/// Returns a GreenId of a node with kind AssociatedTypeArg or TryParseFailure if an associated
/// type argument can't be parsed.
fn try_parse_associated_item_constraint(
&mut self,
) -> TryParseResult<AssociatedItemConstraintGreen> {
let ident = self.try_parse_identifier()?;
let colon = self.parse_token::<TerminalColon>();
let ty = self.parse_type_expr();
Ok(AssociatedItemConstraint::new_green(self.db, ident, colon, ty))
}

// ------------------------------- Helpers -------------------------------

/// Parses a list of elements (without separators), where the elements are parsed using
Expand Down
1 change: 1 addition & 0 deletions crates/cairo-lang-parser/src/parser_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ cairo_lang_test_utils::test_file_test!(
expr_diagnostics: "expr_diagnostics",
enum_diagnostics: "enum_diagnostics",
fn_: "fn",
generic_params: "generic_params",
if_: "if",
illegal_string_escapes: "illegal_string_escapes",
match_: "match",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! > Test modifier followed by path.

//! > test_runner_name
get_diagnostics

//! > cairo_code
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}

//! > expected_diagnostics
error: Missing token TerminalColon.
--> dummy_file.cairo:1:34
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^

error: Missing tokens. Expected a type expression.
--> dummy_file.cairo:1:34
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^

error: Missing token TerminalComma.
--> dummy_file.cairo:1:37
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^

error: Skipped tokens. Expected: generic param.
--> dummy_file.cairo:1:37
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^

error: Missing token TerminalComma.
--> dummy_file.cairo:1:39
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^

error: Skipped tokens. Expected: generic param.
--> dummy_file.cairo:1:39
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^

error: Missing token TerminalComma.
--> dummy_file.cairo:1:41
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^

error: Skipped tokens. Expected: generic param.
--> dummy_file.cairo:1:41
fn f<+I[a : b], impl C: G<A, B>[c],T[a:b]>() {}
^
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,31 @@ GenericParamList
├── separator #0 (kind: TokenComma): ','
├── item #1 (kind: GenericParamImplAnonymous)
│ ├── plus (kind: TokenPlus): '+'
│ └── trait_path (kind: ExprPath)
│ ├── item #0 (kind: PathSegmentSimple)
│ │ └── ident (kind: TokenIdentifier): 'traits'
│ ├── separator #0 (kind: TokenColonColon): '::'
│ └── item #1 (kind: PathSegmentWithGenericArgs)
│ ├── ident (kind: TokenIdentifier): 'Into'
│ ├── separator (kind: OptionTerminalColonColonEmpty) []
│ └── generic_args (kind: GenericArgs)
│ ├── langle (kind: TokenLT): '<'
│ ├── generic_args (kind: GenericArgList)
│ │ ├── item #0 (kind: GenericArgNamed)
│ │ │ ├── name (kind: TokenIdentifier): 'T'
│ │ │ ├── colon (kind: TokenColon): ':'
│ │ │ └── value (kind: GenericArgValueExpr)
│ │ │ └── expr (kind: ExprPath)
│ │ │ └── item #0 (kind: PathSegmentSimple)
│ │ │ └── ident (kind: TokenIdentifier): 'S'
│ │ ├── separator #0 (kind: TokenComma): ','
│ │ └── item #1 (kind: GenericArgUnnamed)
│ │ └── value (kind: GenericArgValueExpr)
│ │ └── expr (kind: ExprPath)
│ │ └── item #0 (kind: PathSegmentSimple)
│ │ └── ident (kind: TokenIdentifier): 'TEvent'
│ └── rangle (kind: TokenGT): '>'
│ ├── trait_path (kind: ExprPath)
│ │ ├── item #0 (kind: PathSegmentSimple)
│ │ │ └── ident (kind: TokenIdentifier): 'traits'
│ │ ├── separator #0 (kind: TokenColonColon): '::'
│ │ └── item #1 (kind: PathSegmentWithGenericArgs)
│ │ ├── ident (kind: TokenIdentifier): 'Into'
│ │ ├── separator (kind: OptionTerminalColonColonEmpty) []
│ │ └── generic_args (kind: GenericArgs)
│ │ ├── langle (kind: TokenLT): '<'
│ │ ├── generic_args (kind: GenericArgList)
│ │ │ ├── item #0 (kind: GenericArgNamed)
│ │ │ │ ├── name (kind: TokenIdentifier): 'T'
│ │ │ │ ├── colon (kind: TokenColon): ':'
│ │ │ │ └── value (kind: GenericArgValueExpr)
│ │ │ │ └── expr (kind: ExprPath)
│ │ │ │ └── item #0 (kind: PathSegmentSimple)
│ │ │ │ └── ident (kind: TokenIdentifier): 'S'
│ │ │ ├── separator #0 (kind: TokenComma): ','
│ │ │ └── item #1 (kind: GenericArgUnnamed)
│ │ │ └── value (kind: GenericArgValueExpr)
│ │ │ └── expr (kind: ExprPath)
│ │ │ └── item #0 (kind: PathSegmentSimple)
│ │ │ └── ident (kind: TokenIdentifier): 'TEvent'
│ │ └── rangle (kind: TokenGT): '>'
│ └── type_constrains (kind: OptionAssociatedItemConstraintsEmpty) []
├── separator #1 (kind: TokenComma): ','
└── item #2 (kind: GenericParamNegativeImpl)
├── minus (kind: TokenMinus): '-'
Expand Down
14 changes: 14 additions & 0 deletions crates/cairo-lang-semantic/src/items/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use cairo_lang_defs::ids::{
use cairo_lang_diagnostics::{Diagnostics, Maybe};
use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
use cairo_lang_syntax as syntax;
use cairo_lang_syntax::node::ast::OptionAssociatedItemConstraints;
use cairo_lang_syntax::node::{TypedSyntaxNode, ast};
use cairo_lang_utils::{Intern, LookupIntern, extract_matches, try_extract_matches};
use syntax::node::TypedStablePtr;
Expand Down Expand Up @@ -450,10 +451,23 @@ fn semantic_from_generic_param_ast(
}
ast::GenericParam::ImplNamed(syntax) => {
let path_syntax = syntax.trait_path(db.upcast());
if !matches!(
syntax.type_constrains(db.upcast()),
OptionAssociatedItemConstraints::Empty(_)
) {
diagnostics.report(syntax, SemanticDiagnosticKind::Unsupported);
}

GenericParam::Impl(impl_generic_param_semantic(resolver, diagnostics, &path_syntax, id))
}
ast::GenericParam::ImplAnonymous(syntax) => {
let path_syntax = syntax.trait_path(db.upcast());
if !matches!(
syntax.type_constrains(db.upcast()),
OptionAssociatedItemConstraints::Empty(_)
) {
diagnostics.report(syntax, SemanticDiagnosticKind::Unsupported);
}
GenericParam::Impl(impl_generic_param_semantic(resolver, diagnostics, &path_syntax, id))
}
ast::GenericParam::NegativeImpl(syntax) => {
Expand Down
15 changes: 15 additions & 0 deletions crates/cairo-lang-syntax-codegen/src/cairo_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,19 @@ pub fn get_spec() -> Vec<Node> {
.node("rangle", "TerminalGT")
)
.add_separated_list("GenericArgList", "GenericArg", "TerminalComma")
.add_struct(
StructBuilder::new("AssociatedItemConstraint")
.node("item","TerminalIdentifier")
.node("colon","TerminalColon")
.node("value","Expr")
)
.add_struct(StructBuilder::new("AssociatedItemConstraints")
.node("lbrack", "TerminalLBrack")
.node("associated_item_constraints", "AssociatedItemConstraintList")
.node("rbrack", "TerminalRBrack")
)
.add_separated_list("AssociatedItemConstraintList", "AssociatedItemConstraint", "TerminalComma")
.add_option("AssociatedItemConstraints")
.add_option("WrappedGenericParamList")
.add_struct(StructBuilder::new("WrappedGenericParamList")
.node("langle", "TerminalLT")
Expand Down Expand Up @@ -788,10 +801,12 @@ pub fn get_spec() -> Vec<Node> {
.key_node("name", "TerminalIdentifier")
.node("colon", "TerminalColon")
.node("trait_path", "ExprPath")
.node("type_constrains", "OptionAssociatedItemConstraints")
)
.add_struct(StructBuilder::new("GenericParamImplAnonymous")
.node("plus", "TerminalPlus")
.node("trait_path", "ExprPath")
.node("type_constrains", "OptionAssociatedItemConstraints")
)
.add_struct(StructBuilder::new("GenericParamNegativeImpl")
.node("minus", "TerminalMinus")
Expand Down
Loading

0 comments on commit 3045f6d

Please sign in to comment.