From fb3d11c7ebf4dfeb04cf86e94da0d3a4867c5ba9 Mon Sep 17 00:00:00 2001 From: TomerC-StarkWare <167065153+Tomer-StarkWare@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:00:58 +0300 Subject: [PATCH] Adding support to Const in Statements in Parser (#6245) --- crates/cairo-lang-parser/src/parser.rs | 6 + .../parser_test_data/partial_trees/constant | 143 ++++++++++++++++++ .../cairo-lang-semantic/src/expr/compute.rs | 1 + .../src/cairo_spec.rs | 6 +- crates/cairo-lang-syntax/src/node/ast.rs | 97 ++++++++++++ crates/cairo-lang-syntax/src/node/helpers.rs | 1 + .../cairo-lang-syntax/src/node/key_fields.rs | 3 + crates/cairo-lang-syntax/src/node/kind.rs | 1 + 8 files changed, 257 insertions(+), 1 deletion(-) diff --git a/crates/cairo-lang-parser/src/parser.rs b/crates/cairo-lang-parser/src/parser.rs index c83c2b8b446..6e09fca20c3 100644 --- a/crates/cairo-lang-parser/src/parser.rs +++ b/crates/cairo-lang-parser/src/parser.rs @@ -1983,6 +1983,12 @@ impl<'a> Parser<'a> { let semicolon = self.parse_token::(); Ok(StatementBreak::new_green(self.db, attributes, break_kw, expr, semicolon).into()) } + SyntaxKind::TerminalConst => Ok(StatementItem::new_green( + self.db, + self.expect_item_const(attributes, VisibilityDefault::new_green(self.db).into()) + .into(), + ) + .into()), _ => match self.try_parse_expr() { Ok(expr) => { let optional_semicolon = if self.peek().kind == SyntaxKind::TerminalSemicolon { diff --git a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/constant b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/constant index 3980ea49ef5..6b3be7e8cad 100644 --- a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/constant +++ b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/constant @@ -119,3 +119,146 @@ ItemConstant │ ├── size (kind: OptionFixedSizeArraySizeEmpty) [] │ └── rbrack (kind: TokenRBrack): ']' └── semicolon (kind: TokenSemicolon): ';' + +//! > ========================================================================== + +//! > Const Statements + +//! > test_runner_name +test_partial_parser_tree(expect_diagnostics: false) + +//! > cairo_code +struct A { + member: felt252, +} + +fn foo() { + const X: felt252 = 3; + const Y: A = A { member: 3 }; +} + +//! > top_level_kind +ItemConstant + +//! > ignored_kinds + +//! > expected_diagnostics + +//! > expected_tree +└── Top level kind: ItemConstant + ├── attributes (kind: AttributeList) [] + ├── visibility (kind: VisibilityDefault) [] + ├── const_kw (kind: TokenConst): 'const' + ├── name (kind: TokenIdentifier): 'X' + ├── type_clause (kind: TypeClause) + │ ├── colon (kind: TokenColon): ':' + │ └── ty (kind: ExprPath) + │ └── item #0 (kind: PathSegmentSimple) + │ └── ident (kind: TokenIdentifier): 'felt252' + ├── eq (kind: TokenEq): '=' + ├── value (kind: TokenLiteralNumber): '3' + └── semicolon (kind: TokenSemicolon): ';' +└── Top level kind: ItemConstant + ├── attributes (kind: AttributeList) [] + ├── visibility (kind: VisibilityDefault) [] + ├── const_kw (kind: TokenConst): 'const' + ├── name (kind: TokenIdentifier): 'Y' + ├── type_clause (kind: TypeClause) + │ ├── colon (kind: TokenColon): ':' + │ └── ty (kind: ExprPath) + │ └── item #0 (kind: PathSegmentSimple) + │ └── ident (kind: TokenIdentifier): 'A' + ├── eq (kind: TokenEq): '=' + ├── value (kind: ExprStructCtorCall) + │ ├── path (kind: ExprPath) + │ │ └── item #0 (kind: PathSegmentSimple) + │ │ └── ident (kind: TokenIdentifier): 'A' + │ └── arguments (kind: StructArgListBraced) + │ ├── lbrace (kind: TokenLBrace): '{' + │ ├── arguments (kind: StructArgList) + │ │ └── item #0 (kind: StructArgSingle) + │ │ ├── identifier (kind: TokenIdentifier): 'member' + │ │ └── arg_expr (kind: StructArgExpr) + │ │ ├── colon (kind: TokenColon): ':' + │ │ └── expr (kind: TokenLiteralNumber): '3' + │ └── rbrace (kind: TokenRBrace): '}' + └── semicolon (kind: TokenSemicolon): ';' + +//! > ========================================================================== + +//! > Const Statements Missing Type + +//! > test_runner_name +test_partial_parser_tree(expect_diagnostics: true) + +//! > cairo_code +fn foo() { + const X = 3; +} + +//! > top_level_kind +ItemConstant + +//! > ignored_kinds + +//! > expected_diagnostics +error: Unexpected token, expected ':' followed by a type. + --> dummy_file.cairo:2:12 + const X = 3; + ^ + +//! > expected_tree +└── Top level kind: ItemConstant + ├── attributes (kind: AttributeList) [] + ├── visibility (kind: VisibilityDefault) [] + ├── const_kw (kind: TokenConst): 'const' + ├── name (kind: TokenIdentifier): 'X' + ├── type_clause (kind: TypeClause) + │ ├── colon: Missing + │ └── ty: Missing [] + ├── eq (kind: TokenEq): '=' + ├── value (kind: TokenLiteralNumber): '3' + └── semicolon (kind: TokenSemicolon): ';' + +//! > ========================================================================== + +//! > Const Statements with attribute + +//! > test_runner_name +test_partial_parser_tree(expect_diagnostics: false) + +//! > cairo_code +fn foo() { + #[flat] + const X: felt252 = 3; +} + +//! > top_level_kind +ItemConstant + +//! > ignored_kinds + +//! > expected_diagnostics + +//! > expected_tree +└── Top level kind: ItemConstant + ├── attributes (kind: AttributeList) + │ └── child #0 (kind: Attribute) + │ ├── hash (kind: TokenHash): '#' + │ ├── lbrack (kind: TokenLBrack): '[' + │ ├── attr (kind: ExprPath) + │ │ └── item #0 (kind: PathSegmentSimple) + │ │ └── ident (kind: TokenIdentifier): 'flat' + │ ├── arguments (kind: OptionArgListParenthesizedEmpty) [] + │ └── rbrack (kind: TokenRBrack): ']' + ├── visibility (kind: VisibilityDefault) [] + ├── const_kw (kind: TokenConst): 'const' + ├── name (kind: TokenIdentifier): 'X' + ├── type_clause (kind: TypeClause) + │ ├── colon (kind: TokenColon): ':' + │ └── ty (kind: ExprPath) + │ └── item #0 (kind: PathSegmentSimple) + │ └── ident (kind: TokenIdentifier): 'felt252' + ├── eq (kind: TokenEq): '=' + ├── value (kind: TokenLiteralNumber): '3' + └── semicolon (kind: TokenSemicolon): ';' diff --git a/crates/cairo-lang-semantic/src/expr/compute.rs b/crates/cairo-lang-semantic/src/expr/compute.rs index baecdea9b39..117b3a327ae 100644 --- a/crates/cairo-lang-semantic/src/expr/compute.rs +++ b/crates/cairo-lang-semantic/src/expr/compute.rs @@ -3401,6 +3401,7 @@ pub fn compute_statement_semantic( stable_ptr: syntax.stable_ptr(), }) } + ast::Statement::Item(_) => todo!(), ast::Statement::Missing(_) => todo!(), }; ctx.resolver.data.feature_config.restore(feature_restore); diff --git a/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs b/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs index 2a7302157d3..5dd90728cf6 100644 --- a/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs +++ b/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs @@ -361,6 +361,7 @@ pub fn get_spec() -> Vec { .node("Continue") .node("Return") .node("Break") + .node("Item") ) .add_list("StatementList", "Statement") .add_struct(StructBuilder::new("StatementMissing")) @@ -399,6 +400,9 @@ pub fn get_spec() -> Vec { .node("expr_clause", "OptionExprClause") .node("semicolon", "TerminalSemicolon") ) + .add_struct(StructBuilder::new("StatementItem") + .node("item", "ModuleItem") + ) // --- Functions --- .add_struct(StructBuilder::new("Param") .node("modifiers", "ModifierList") @@ -497,7 +501,7 @@ pub fn get_spec() -> Vec { .add_enum(EnumBuilder::new("MaybeModuleBody") .node_with_explicit_kind("Some", "ModuleBody") .node_with_explicit_kind("None", "TerminalSemicolon") - ) + ) .add_struct(StructBuilder::new("ModuleBody") .node("lbrace", "TerminalLBrace") .node("items", "ModuleItemList") diff --git a/crates/cairo-lang-syntax/src/node/ast.rs b/crates/cairo-lang-syntax/src/node/ast.rs index 31eea6a72ac..fd20e6e0f71 100644 --- a/crates/cairo-lang-syntax/src/node/ast.rs +++ b/crates/cairo-lang-syntax/src/node/ast.rs @@ -8958,6 +8958,7 @@ pub enum Statement { Continue(StatementContinue), Return(StatementReturn), Break(StatementBreak), + Item(StatementItem), Missing(StatementMissing), } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -9001,6 +9002,11 @@ impl From for StatementPtr { Self(value.0) } } +impl From for StatementPtr { + fn from(value: StatementItemPtr) -> Self { + Self(value.0) + } +} impl From for StatementPtr { fn from(value: StatementMissingPtr) -> Self { Self(value.0) @@ -9031,6 +9037,11 @@ impl From for StatementGreen { Self(value.0) } } +impl From for StatementGreen { + fn from(value: StatementItemGreen) -> Self { + Self(value.0) + } +} impl From for StatementGreen { fn from(value: StatementMissingGreen) -> Self { Self(value.0) @@ -9059,6 +9070,7 @@ impl TypedSyntaxNode for Statement { SyntaxKind::StatementBreak => { Statement::Break(StatementBreak::from_syntax_node(db, node)) } + SyntaxKind::StatementItem => Statement::Item(StatementItem::from_syntax_node(db, node)), SyntaxKind::StatementMissing => { Statement::Missing(StatementMissing::from_syntax_node(db, node)) } @@ -9072,6 +9084,7 @@ impl TypedSyntaxNode for Statement { Statement::Continue(x) => x.as_syntax_node(), Statement::Return(x) => x.as_syntax_node(), Statement::Break(x) => x.as_syntax_node(), + Statement::Item(x) => x.as_syntax_node(), Statement::Missing(x) => x.as_syntax_node(), } } @@ -9093,6 +9106,7 @@ impl Statement { SyntaxKind::StatementContinue => true, SyntaxKind::StatementReturn => true, SyntaxKind::StatementBreak => true, + SyntaxKind::StatementItem => true, SyntaxKind::StatementMissing => true, _ => false, } @@ -10202,6 +10216,89 @@ impl From<&StatementBreak> for SyntaxStablePtrId { } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct StatementItem { + node: SyntaxNode, + children: Arc<[SyntaxNode]>, +} +impl StatementItem { + pub const INDEX_ITEM: usize = 0; + pub fn new_green(db: &dyn SyntaxGroup, item: ModuleItemGreen) -> StatementItemGreen { + let children: Vec = vec![item.0]; + let width = children.iter().copied().map(|id| id.lookup_intern(db).width()).sum(); + StatementItemGreen( + Arc::new(GreenNode { + kind: SyntaxKind::StatementItem, + details: GreenNodeDetails::Node { children, width }, + }) + .intern(db), + ) + } +} +impl StatementItem { + pub fn item(&self, db: &dyn SyntaxGroup) -> ModuleItem { + ModuleItem::from_syntax_node(db, self.children[0].clone()) + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct StatementItemPtr(pub SyntaxStablePtrId); +impl StatementItemPtr {} +impl TypedStablePtr for StatementItemPtr { + type SyntaxNode = StatementItem; + fn untyped(&self) -> SyntaxStablePtrId { + self.0 + } + fn lookup(&self, db: &dyn SyntaxGroup) -> StatementItem { + StatementItem::from_syntax_node(db, self.0.lookup(db)) + } +} +impl From for SyntaxStablePtrId { + fn from(ptr: StatementItemPtr) -> Self { + ptr.untyped() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct StatementItemGreen(pub GreenId); +impl TypedSyntaxNode for StatementItem { + const OPTIONAL_KIND: Option = Some(SyntaxKind::StatementItem); + type StablePtr = StatementItemPtr; + type Green = StatementItemGreen; + fn missing(db: &dyn SyntaxGroup) -> Self::Green { + StatementItemGreen( + Arc::new(GreenNode { + kind: SyntaxKind::StatementItem, + details: GreenNodeDetails::Node { + children: vec![ModuleItem::missing(db).0], + width: TextWidth::default(), + }, + }) + .intern(db), + ) + } + fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self { + let kind = node.kind(db); + assert_eq!( + kind, + SyntaxKind::StatementItem, + "Unexpected SyntaxKind {:?}. Expected {:?}.", + kind, + SyntaxKind::StatementItem + ); + let children = db.get_children(node.clone()); + Self { node, children } + } + fn as_syntax_node(&self) -> SyntaxNode { + self.node.clone() + } + fn stable_ptr(&self) -> Self::StablePtr { + StatementItemPtr(self.node.0.stable_ptr) + } +} +impl From<&StatementItem> for SyntaxStablePtrId { + fn from(node: &StatementItem) -> Self { + node.stable_ptr().untyped() + } +} +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Param { node: SyntaxNode, children: Arc<[SyntaxNode]>, diff --git a/crates/cairo-lang-syntax/src/node/helpers.rs b/crates/cairo-lang-syntax/src/node/helpers.rs index fb5506a8996..59f4386d932 100644 --- a/crates/cairo-lang-syntax/src/node/helpers.rs +++ b/crates/cairo-lang-syntax/src/node/helpers.rs @@ -484,6 +484,7 @@ impl QueryAttrs for Statement { Statement::Return(statement) => statement.attributes_elements(db), Statement::Let(statement) => statement.attributes_elements(db), Statement::Expr(statement) => statement.attributes_elements(db), + Statement::Item(statement) => statement.item(db).attributes_elements(db), Statement::Missing(_) => vec![], } } diff --git a/crates/cairo-lang-syntax/src/node/key_fields.rs b/crates/cairo-lang-syntax/src/node/key_fields.rs index 12e389a6a56..92584cc4523 100644 --- a/crates/cairo-lang-syntax/src/node/key_fields.rs +++ b/crates/cairo-lang-syntax/src/node/key_fields.rs @@ -211,6 +211,9 @@ pub fn get_key_fields(kind: SyntaxKind, children: &[GreenId]) -> Vec { SyntaxKind::StatementBreak => { vec![] } + SyntaxKind::StatementItem => { + vec![] + } SyntaxKind::Param => { vec![/* name */ children[1]] } diff --git a/crates/cairo-lang-syntax/src/node/kind.rs b/crates/cairo-lang-syntax/src/node/kind.rs index 3ecf9fa1b02..00d1fda1c76 100644 --- a/crates/cairo-lang-syntax/src/node/kind.rs +++ b/crates/cairo-lang-syntax/src/node/kind.rs @@ -77,6 +77,7 @@ pub enum SyntaxKind { OptionExprClauseEmpty, StatementReturn, StatementBreak, + StatementItem, Param, ModifierList, ParamList,