diff --git a/corelib/src/ops.cairo b/corelib/src/ops.cairo index 2f238ace4e0..ca4c975d53f 100644 --- a/corelib/src/ops.cairo +++ b/corelib/src/ops.cairo @@ -67,7 +67,7 @@ pub mod index; pub use index::{Index, IndexView}; mod range; -// `RangeOp` is used internally by the compiler. +pub use range::{Range, RangeInclusive, RangeInclusiveIterator, RangeIterator, RangeTrait}; +// `RangeOp` and `RangeInclusiveOp` are used internally by the compiler. #[allow(unused_imports)] -use range::RangeOp; -pub use range::{Range, RangeIterator, RangeTrait}; +use range::{RangeInclusiveOp, RangeOp}; diff --git a/corelib/src/ops/range.cairo b/corelib/src/ops/range.cairo index df4f2a938e9..7645203fbf0 100644 --- a/corelib/src/ops/range.cairo +++ b/corelib/src/ops/range.cairo @@ -139,6 +139,88 @@ impl RangeIntoIterator< } } +/// Represents the range [start, end]. +#[derive(Clone, Drop, PartialEq)] +pub struct RangeInclusive { + /// The lower bound of the range (inclusive). + pub start: T, + /// The upper bound of the range (inclusive). + pub end: T, +} + +#[derive(Clone, Drop)] +pub struct RangeInclusiveIterator { + /// The current value of the iterator. + pub(crate) cur: T, + /// The upper bound of the range (inclusive). + pub(crate) end: T, + // This field is: + // - `false` upon construction + // - `false` when iteration has yielded an element and the iterator is not exhausted + // - `true` when iteration has been used to exhaust the iterator + // + // This is required to differentiate between the last element and the end of the range. + pub(crate) exhausted: bool, +} + +/// Handles the range inclusive operator (`..=`). +#[generate_trait] +pub impl RangeInclusiveOpImpl of RangeInclusiveOp { + /// Handles the `..=` operator. Returns the value of the expression `start..=end`. + fn range_inclusive(start: T, end: T) -> RangeInclusive { + RangeInclusive { start, end } + } +} + +impl RangeInclusiveDebug< + T, impl TDebug: crate::fmt::Debug, +> of crate::fmt::Debug> { + fn fmt( + self: @RangeInclusive, ref f: crate::fmt::Formatter, + ) -> Result<(), crate::fmt::Error> { + self.start.fmt(ref f)?; + write!(f, "..=")?; + self.end.fmt(ref f)?; + Result::Ok(()) + } +} + +impl RangeInclusiveIteratorImpl< + T, +One, +Add, +Copy, +Drop, +PartialEq, +PartialOrd, +> of Iterator> { + type Item = T; + + fn next(ref self: RangeInclusiveIterator) -> Option { + if self.exhausted { + return Option::None; + } + + let current = self.cur; + + // If this is the last element, mark as exhausted for next iteration + if current == self.end { + self.exhausted = true; + return Option::Some(current); + } + + // We know current < self.end here, because the iterator is not exhausted + self.cur = current + One::one(); + Option::Some(current) + } +} + +pub impl RangeInclusiveIntoIterator< + T, +One, +Add, +Copy, +Drop, +PartialEq, +PartialOrd, +> of IntoIterator> { + type IntoIter = RangeInclusiveIterator; + + fn into_iter(self: RangeInclusive) -> Self::IntoIter { + let exhausted = self.start > self.end; + Self::IntoIter { cur: self.start, end: self.end, exhausted } + } +} + + // Sierra optimization. mod internal { diff --git a/corelib/src/test/range_test.cairo b/corelib/src/test/range_test.cairo index fd7b9fe65de..7dd5ef8c6c5 100644 --- a/corelib/src/test/range_test.cairo +++ b/corelib/src/test/range_test.cairo @@ -22,3 +22,29 @@ fn test_range_contains() { fn test_range_format() { assert!(format!("{:?}", 1..5) == "1..5"); } + +#[test] +fn test_range_inclusive_iterator() { + let mut iter = (1_usize..=3).into_iter(); + assert!(iter.next() == Option::Some(1)); + assert!(iter.next() == Option::Some(2)); + assert!(iter.next() == Option::Some(3)); + assert!(iter.next() == Option::None); +} + +#[test] +fn test_range_inclusive_iterator_range_end() { + let mut iter = (253_u8..=255).into_iter(); + assert!(iter.next() == Option::Some(253)); + assert!(iter.next() == Option::Some(254)); + assert!(iter.next() == Option::Some(255)); + assert!(iter.next() == Option::None); +} + +#[test] +fn test_range_inclusive_empty_ranges() { + let mut iter = (255_u8..=125).into_iter(); + assert!(iter.next() == Option::None); + let mut iter = (255_u8..=0).into_iter(); + assert!(iter.next() == Option::None); +} diff --git a/crates/cairo-lang-formatter/src/node_properties.rs b/crates/cairo-lang-formatter/src/node_properties.rs index 014266a7bee..b5068390e78 100644 --- a/crates/cairo-lang-formatter/src/node_properties.rs +++ b/crates/cairo-lang-formatter/src/node_properties.rs @@ -103,7 +103,7 @@ impl SyntaxNodeFormat for SyntaxNode { | SyntaxKind::TokenLParen | SyntaxKind::TokenLBrack | SyntaxKind::TokenImplicits => true, - SyntaxKind::TerminalDotDot + SyntaxKind::TerminalDotDot | SyntaxKind::TerminalDotDotEq if matches!(parent_kind(db, self), Some(SyntaxKind::ExprBinary)) => { true @@ -171,7 +171,7 @@ impl SyntaxNodeFormat for SyntaxNode { { true } - SyntaxKind::TokenDotDot + SyntaxKind::TokenDotDot | SyntaxKind::TokenDotDotEq if grandparent_kind(db, self) == Some(SyntaxKind::StructArgTail) => { true @@ -761,7 +761,7 @@ impl SyntaxNodeFormat for SyntaxNode { true, )) } - SyntaxKind::TerminalDotDot + SyntaxKind::TerminalDotDot | SyntaxKind::TerminalDotDotEq if matches!(parent_kind(db, self), Some(SyntaxKind::ExprBinary)) => { BreakLinePointsPositions::Leading(BreakLinePointProperties::new( diff --git a/crates/cairo-lang-parser/src/colored_printer.rs b/crates/cairo-lang-parser/src/colored_printer.rs index 4fdfcc3328f..a584b313a82 100644 --- a/crates/cairo-lang-parser/src/colored_printer.rs +++ b/crates/cairo-lang-parser/src/colored_printer.rs @@ -94,6 +94,7 @@ fn set_color(text: SmolStr, kind: SyntaxKind) -> ColoredString { | SyntaxKind::TokenColon | SyntaxKind::TokenColonColon | SyntaxKind::TokenDotDot + | SyntaxKind::TokenDotDotEq | SyntaxKind::TokenSemicolon | SyntaxKind::TokenAnd | SyntaxKind::TokenAndAnd diff --git a/crates/cairo-lang-parser/src/lexer.rs b/crates/cairo-lang-parser/src/lexer.rs index a90c6367c2f..d95eb389a51 100644 --- a/crates/cairo-lang-parser/src/lexer.rs +++ b/crates/cairo-lang-parser/src/lexer.rs @@ -270,7 +270,13 @@ impl<'a> Lexer<'a> { ']' => self.take_token_of_kind(TokenKind::RBrack), '(' => self.take_token_of_kind(TokenKind::LParen), ')' => self.take_token_of_kind(TokenKind::RParen), - '.' => self.pick_kind('.', TokenKind::DotDot, TokenKind::Dot), + '.' => { + self.take(); + match self.peek() { + Some('.') => self.pick_kind('=', TokenKind::DotDotEq, TokenKind::DotDot), + _ => TokenKind::Dot, + } + } '*' => self.pick_kind('=', TokenKind::MulEq, TokenKind::Mul), '/' => self.pick_kind('=', TokenKind::DivEq, TokenKind::Div), '%' => self.pick_kind('=', TokenKind::ModEq, TokenKind::Mod), @@ -422,6 +428,7 @@ enum TokenKind { Comma, Dot, DotDot, + DotDotEq, Eq, Hash, Semicolon, @@ -503,6 +510,7 @@ fn token_kind_to_terminal_syntax_kind(kind: TokenKind) -> SyntaxKind { TokenKind::Comma => SyntaxKind::TerminalComma, TokenKind::Dot => SyntaxKind::TerminalDot, TokenKind::DotDot => SyntaxKind::TerminalDotDot, + TokenKind::DotDotEq => SyntaxKind::TerminalDotDotEq, TokenKind::Eq => SyntaxKind::TerminalEq, TokenKind::Hash => SyntaxKind::TerminalHash, TokenKind::Semicolon => SyntaxKind::TerminalSemicolon, diff --git a/crates/cairo-lang-parser/src/lexer_test.rs b/crates/cairo-lang-parser/src/lexer_test.rs index f55101ebfd3..a374a3d67f0 100644 --- a/crates/cairo-lang-parser/src/lexer_test.rs +++ b/crates/cairo-lang-parser/src/lexer_test.rs @@ -71,6 +71,7 @@ fn terminal_kind_to_text(kind: SyntaxKind) -> Vec<&'static str> { SyntaxKind::TerminalModEq => vec!["%="], SyntaxKind::TerminalDot => vec!["."], SyntaxKind::TerminalDotDot => vec![".."], + SyntaxKind::TerminalDotDotEq => vec!["..="], SyntaxKind::TerminalEq => vec!["="], SyntaxKind::TerminalEqEq => vec!["=="], SyntaxKind::TerminalGE => vec![">="], @@ -162,6 +163,7 @@ fn terminal_kinds() -> Vec { SyntaxKind::TerminalComma, SyntaxKind::TerminalDot, SyntaxKind::TerminalDotDot, + SyntaxKind::TerminalDotDotEq, SyntaxKind::TerminalEq, SyntaxKind::TerminalSemicolon, SyntaxKind::TerminalQuestionMark, @@ -218,7 +220,7 @@ fn need_separator( || (text0 == "." && text1.starts_with('.')) || (text0 == "-" && (text1.starts_with('>') || text1.starts_with('='))) || ((text0 == "+" || text0 == "*" || text0 == "/" || text0 == "%") - && text1.starts_with('=')) + || (text0 == "..") && text1.starts_with('=')) || (kind0 == SyntaxKind::TerminalLiteralNumber && kind0 == kind1) { return true; @@ -295,7 +297,6 @@ fn test_lex_double_token() { for separator in separators { let text = format!("{text0}{separator}{text1}"); let mut lexer = Lexer::from_text(db, text.as_str()); - let terminal = lexer.next().unwrap(); let token_text = terminal.text; assert_eq!( diff --git a/crates/cairo-lang-parser/src/operators.rs b/crates/cairo-lang-parser/src/operators.rs index 723d8c57944..85000a15fab 100644 --- a/crates/cairo-lang-parser/src/operators.rs +++ b/crates/cairo-lang-parser/src/operators.rs @@ -29,7 +29,7 @@ pub fn get_post_operator_precedence(kind: SyntaxKind) -> Option { | SyntaxKind::TerminalGE => Some(7), SyntaxKind::TerminalAndAnd => Some(8), SyntaxKind::TerminalOrOr => Some(9), - SyntaxKind::TerminalDotDot => Some(10), + SyntaxKind::TerminalDotDot | SyntaxKind::TerminalDotDotEq => Some(10), SyntaxKind::TerminalEq | SyntaxKind::TerminalPlusEq | SyntaxKind::TerminalMinusEq diff --git a/crates/cairo-lang-parser/src/parser.rs b/crates/cairo-lang-parser/src/parser.rs index 5aeb4c57d96..efdc006a62f 100644 --- a/crates/cairo-lang-parser/src/parser.rs +++ b/crates/cairo-lang-parser/src/parser.rs @@ -1183,6 +1183,7 @@ impl<'a> Parser<'a> { SyntaxKind::TerminalOr => self.take::().into(), SyntaxKind::TerminalXor => self.take::().into(), SyntaxKind::TerminalDotDot => self.take::().into(), + SyntaxKind::TerminalDotDotEq => self.take::().into(), _ => unreachable!(), } } diff --git a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/range_inclusive b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/range_inclusive new file mode 100644 index 00000000000..7756a315164 --- /dev/null +++ b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/range_inclusive @@ -0,0 +1,68 @@ +//! > test_runner_name +test_partial_parser_tree(expect_diagnostics: false) + +//! > cairo_code +fn f() { + for i in 1..=x {} +} + +//! > top_level_kind +ExprFor + +//! > ignored_kinds + +//! > expected_diagnostics + +//! > expected_tree +└── Top level kind: ExprFor + ├── for_kw (kind: TokenFor): 'for' + ├── pattern (kind: ExprPath) + │ └── item #0 (kind: PathSegmentSimple) + │ └── ident (kind: TokenIdentifier): 'i' + ├── identifier (kind: TokenIdentifier): 'in' + ├── expr (kind: ExprBinary) + │ ├── lhs (kind: TokenLiteralNumber): '1' + │ ├── op (kind: TokenDotDotEq): '..=' + │ └── rhs (kind: ExprPath) + │ └── item #0 (kind: PathSegmentSimple) + │ └── ident (kind: TokenIdentifier): 'x' + └── body (kind: ExprBlock) + ├── lbrace (kind: TokenLBrace): '{' + ├── statements (kind: StatementList) [] + └── rbrace (kind: TokenRBrace): '}' + +//! > ========================================================================== + +//! > Test range inclusive operator precedence + +//! > test_runner_name +test_partial_parser_tree(expect_diagnostics: false) + +//! > cairo_code +fn f() { + x += false && true..=1 + 2 +} + +//! > top_level_kind +ExprBinary + +//! > ignored_kinds + +//! > expected_diagnostics + +//! > expected_tree +└── Top level kind: ExprBinary + ├── lhs (kind: ExprPath) + │ └── item #0 (kind: PathSegmentSimple) + │ └── ident (kind: TokenIdentifier): 'x' + ├── op (kind: TokenPlusEq): '+=' + └── rhs (kind: ExprBinary) + ├── lhs (kind: ExprBinary) + │ ├── lhs (kind: TokenFalse): 'false' + │ ├── op (kind: TokenAndAnd): '&&' + │ └── rhs (kind: TokenTrue): 'true' + ├── op (kind: TokenDotDotEq): '..=' + └── rhs (kind: ExprBinary) + ├── lhs (kind: TokenLiteralNumber): '1' + ├── op (kind: TokenPlus): '+' + └── rhs (kind: TokenLiteralNumber): '2' diff --git a/crates/cairo-lang-semantic/src/corelib.rs b/crates/cairo-lang-semantic/src/corelib.rs index fd996d065a0..f1a5c18379c 100644 --- a/crates/cairo-lang-semantic/src/corelib.rs +++ b/crates/cairo-lang-semantic/src/corelib.rs @@ -523,6 +523,9 @@ pub fn core_binary_operator( BinaryOperator::Or(_) => ("BitOr", "bitor", false, CoreTraitContext::TopLevel), BinaryOperator::Xor(_) => ("BitXor", "bitxor", false, CoreTraitContext::TopLevel), BinaryOperator::DotDot(_) => ("RangeOp", "range", false, CoreTraitContext::Ops), + BinaryOperator::DotDotEq(_) => { + ("RangeInclusiveOp", "range_inclusive", false, CoreTraitContext::Ops) + } _ => return Ok(Err(SemanticDiagnosticKind::UnknownBinaryOperator)), }; Ok(Ok(( diff --git a/crates/cairo-lang-semantic/src/expr/semantic_test_data/range_inclusive b/crates/cairo-lang-semantic/src/expr/semantic_test_data/range_inclusive new file mode 100644 index 00000000000..f81c041accd --- /dev/null +++ b/crates/cairo-lang-semantic/src/expr/semantic_test_data/range_inclusive @@ -0,0 +1,40 @@ +//! > Test range + +//! > test_runner_name +test_expr_semantics(expect_diagnostics: false) + +//! > function_body + +//! > expr_code +1..=10_u8 + +//! > module_code + +//! > expected_semantics +FunctionCall( + ExprFunctionCall { + function: core::ops::range::RangeInclusiveOpImpl::::range_inclusive, + args: [ + Value( + Literal( + ExprLiteral { + value: 1, + ty: core::integer::u8, + }, + ), + ), + Value( + Literal( + ExprLiteral { + value: 10, + ty: core::integer::u8, + }, + ), + ), + ], + coupon_arg: None, + ty: core::ops::range::RangeInclusive::, + }, +) + +//! > expected_diagnostics diff --git a/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs b/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs index 9f71ddd6535..8a8fe3b2c72 100644 --- a/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs +++ b/crates/cairo-lang-syntax-codegen/src/cairo_spec.rs @@ -122,6 +122,7 @@ pub fn get_spec() -> Vec { .node_with_explicit_kind("LT", "TerminalLT") .node_with_explicit_kind("GT", "TerminalGT") .node_with_explicit_kind("DotDot", "TerminalDotDot") + .node_with_explicit_kind("DotDotEq", "TerminalDotDotEq") ) .add_struct(StructBuilder::new("ExprListParenthesized") .node("lparen", "TerminalLParen") @@ -870,6 +871,7 @@ pub fn get_spec() -> Vec { .add_token_and_terminal("DivEq") .add_token_and_terminal("Dot") .add_token_and_terminal("DotDot") + .add_token_and_terminal("DotDotEq") .add_token_and_terminal("EndOfFile") .add_token_and_terminal("Eq") .add_token_and_terminal("EqEq") diff --git a/crates/cairo-lang-syntax/src/node/ast.rs b/crates/cairo-lang-syntax/src/node/ast.rs index ea4aca9380b..4886be1c05c 100644 --- a/crates/cairo-lang-syntax/src/node/ast.rs +++ b/crates/cairo-lang-syntax/src/node/ast.rs @@ -2714,6 +2714,7 @@ pub enum BinaryOperator { LT(TerminalLT), GT(TerminalGT), DotDot(TerminalDotDot), + DotDotEq(TerminalDotDotEq), } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct BinaryOperatorPtr(pub SyntaxStablePtrId); @@ -2856,6 +2857,11 @@ impl From for BinaryOperatorPtr { Self(value.0) } } +impl From for BinaryOperatorPtr { + fn from(value: TerminalDotDotEqPtr) -> Self { + Self(value.0) + } +} impl From for BinaryOperatorGreen { fn from(value: TerminalDotGreen) -> Self { Self(value.0) @@ -2981,6 +2987,11 @@ impl From for BinaryOperatorGreen { Self(value.0) } } +impl From for BinaryOperatorGreen { + fn from(value: TerminalDotDotEqGreen) -> Self { + Self(value.0) + } +} #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct BinaryOperatorGreen(pub GreenId); impl TypedSyntaxNode for BinaryOperator { @@ -3040,6 +3051,9 @@ impl TypedSyntaxNode for BinaryOperator { SyntaxKind::TerminalDotDot => { BinaryOperator::DotDot(TerminalDotDot::from_syntax_node(db, node)) } + SyntaxKind::TerminalDotDotEq => { + BinaryOperator::DotDotEq(TerminalDotDotEq::from_syntax_node(db, node)) + } _ => { panic!("Unexpected syntax kind {:?} when constructing {}.", kind, "BinaryOperator") } @@ -3123,6 +3137,9 @@ impl TypedSyntaxNode for BinaryOperator { SyntaxKind::TerminalDotDot => { Some(BinaryOperator::DotDot(TerminalDotDot::from_syntax_node(db, node))) } + SyntaxKind::TerminalDotDotEq => { + Some(BinaryOperator::DotDotEq(TerminalDotDotEq::from_syntax_node(db, node))) + } _ => None, } } @@ -3153,6 +3170,7 @@ impl TypedSyntaxNode for BinaryOperator { BinaryOperator::LT(x) => x.as_syntax_node(), BinaryOperator::GT(x) => x.as_syntax_node(), BinaryOperator::DotDot(x) => x.as_syntax_node(), + BinaryOperator::DotDotEq(x) => x.as_syntax_node(), } } fn stable_ptr(&self) -> Self::StablePtr { @@ -3194,6 +3212,7 @@ impl BinaryOperator { | SyntaxKind::TerminalLT | SyntaxKind::TerminalGT | SyntaxKind::TerminalDotDot + | SyntaxKind::TerminalDotDotEq ) } } @@ -30151,6 +30170,197 @@ impl From<&TerminalDotDot> for SyntaxStablePtrId { } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct TokenDotDotEq { + node: SyntaxNode, +} +impl Token for TokenDotDotEq { + fn new_green(db: &dyn SyntaxGroup, text: SmolStr) -> Self::Green { + TokenDotDotEqGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TokenDotDotEq, + details: GreenNodeDetails::Token(text), + }) + .intern(db), + ) + } + fn text(&self, db: &dyn SyntaxGroup) -> SmolStr { + extract_matches!(&self.node.0.green.lookup_intern(db).details, GreenNodeDetails::Token) + .clone() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TokenDotDotEqPtr(pub SyntaxStablePtrId); +impl TypedStablePtr for TokenDotDotEqPtr { + type SyntaxNode = TokenDotDotEq; + fn untyped(&self) -> SyntaxStablePtrId { + self.0 + } + fn lookup(&self, db: &dyn SyntaxGroup) -> TokenDotDotEq { + TokenDotDotEq::from_syntax_node(db, self.0.lookup(db)) + } +} +impl From for SyntaxStablePtrId { + fn from(ptr: TokenDotDotEqPtr) -> Self { + ptr.untyped() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TokenDotDotEqGreen(pub GreenId); +impl TokenDotDotEqGreen { + pub fn text(&self, db: &dyn SyntaxGroup) -> SmolStr { + extract_matches!(&self.0.lookup_intern(db).details, GreenNodeDetails::Token).clone() + } +} +impl TypedSyntaxNode for TokenDotDotEq { + const OPTIONAL_KIND: Option = Some(SyntaxKind::TokenDotDotEq); + type StablePtr = TokenDotDotEqPtr; + type Green = TokenDotDotEqGreen; + fn missing(db: &dyn SyntaxGroup) -> Self::Green { + TokenDotDotEqGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TokenMissing, + details: GreenNodeDetails::Token("".into()), + }) + .intern(db), + ) + } + fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self { + match node.0.green.lookup_intern(db).details { + GreenNodeDetails::Token(_) => Self { node }, + GreenNodeDetails::Node { .. } => { + panic!("Expected a token {:?}, not an internal node", SyntaxKind::TokenDotDotEq) + } + } + } + fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option { + match node.0.green.lookup_intern(db).details { + GreenNodeDetails::Token(_) => Some(Self { node }), + GreenNodeDetails::Node { .. } => None, + } + } + fn as_syntax_node(&self) -> SyntaxNode { + self.node.clone() + } + fn stable_ptr(&self) -> Self::StablePtr { + TokenDotDotEqPtr(self.node.0.stable_ptr) + } +} +impl From<&TokenDotDotEq> for SyntaxStablePtrId { + fn from(node: &TokenDotDotEq) -> Self { + node.stable_ptr().untyped() + } +} +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct TerminalDotDotEq { + node: SyntaxNode, + children: Arc<[SyntaxNode]>, +} +impl Terminal for TerminalDotDotEq { + const KIND: SyntaxKind = SyntaxKind::TerminalDotDotEq; + type TokenType = TokenDotDotEq; + fn new_green( + db: &dyn SyntaxGroup, + leading_trivia: TriviaGreen, + token: <::TokenType as TypedSyntaxNode>::Green, + trailing_trivia: TriviaGreen, + ) -> Self::Green { + let children: Vec = vec![leading_trivia.0, token.0, trailing_trivia.0]; + let width = children.iter().copied().map(|id| id.lookup_intern(db).width()).sum(); + TerminalDotDotEqGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TerminalDotDotEq, + details: GreenNodeDetails::Node { children, width }, + }) + .intern(db), + ) + } + fn text(&self, db: &dyn SyntaxGroup) -> SmolStr { + self.token(db).text(db) + } +} +impl TerminalDotDotEq { + pub fn leading_trivia(&self, db: &dyn SyntaxGroup) -> Trivia { + Trivia::from_syntax_node(db, self.children[0].clone()) + } + pub fn token(&self, db: &dyn SyntaxGroup) -> TokenDotDotEq { + TokenDotDotEq::from_syntax_node(db, self.children[1].clone()) + } + pub fn trailing_trivia(&self, db: &dyn SyntaxGroup) -> Trivia { + Trivia::from_syntax_node(db, self.children[2].clone()) + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TerminalDotDotEqPtr(pub SyntaxStablePtrId); +impl TerminalDotDotEqPtr {} +impl TypedStablePtr for TerminalDotDotEqPtr { + type SyntaxNode = TerminalDotDotEq; + fn untyped(&self) -> SyntaxStablePtrId { + self.0 + } + fn lookup(&self, db: &dyn SyntaxGroup) -> TerminalDotDotEq { + TerminalDotDotEq::from_syntax_node(db, self.0.lookup(db)) + } +} +impl From for SyntaxStablePtrId { + fn from(ptr: TerminalDotDotEqPtr) -> Self { + ptr.untyped() + } +} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TerminalDotDotEqGreen(pub GreenId); +impl TypedSyntaxNode for TerminalDotDotEq { + const OPTIONAL_KIND: Option = Some(SyntaxKind::TerminalDotDotEq); + type StablePtr = TerminalDotDotEqPtr; + type Green = TerminalDotDotEqGreen; + fn missing(db: &dyn SyntaxGroup) -> Self::Green { + TerminalDotDotEqGreen( + Arc::new(GreenNode { + kind: SyntaxKind::TerminalDotDotEq, + details: GreenNodeDetails::Node { + children: vec![ + Trivia::missing(db).0, + TokenDotDotEq::missing(db).0, + Trivia::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::TerminalDotDotEq, + "Unexpected SyntaxKind {:?}. Expected {:?}.", + kind, + SyntaxKind::TerminalDotDotEq + ); + let children = db.get_children(node.clone()); + Self { node, children } + } + fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option { + let kind = node.kind(db); + if kind == SyntaxKind::TerminalDotDotEq { + Some(Self::from_syntax_node(db, node)) + } else { + None + } + } + fn as_syntax_node(&self) -> SyntaxNode { + self.node.clone() + } + fn stable_ptr(&self) -> Self::StablePtr { + TerminalDotDotEqPtr(self.node.0.stable_ptr) + } +} +impl From<&TerminalDotDotEq> for SyntaxStablePtrId { + fn from(node: &TerminalDotDotEq) -> Self { + node.stable_ptr().untyped() + } +} +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct TokenEndOfFile { node: SyntaxNode, } @@ -37105,6 +37315,7 @@ pub enum TokenNode { TerminalDivEq(TerminalDivEq), TerminalDot(TerminalDot), TerminalDotDot(TerminalDotDot), + TerminalDotDotEq(TerminalDotDotEq), TerminalEndOfFile(TerminalEndOfFile), TerminalEq(TerminalEq), TerminalEqEq(TerminalEqEq), @@ -37380,6 +37591,11 @@ impl From for TokenNodePtr { Self(value.0) } } +impl From for TokenNodePtr { + fn from(value: TerminalDotDotEqPtr) -> Self { + Self(value.0) + } +} impl From for TokenNodePtr { fn from(value: TerminalEndOfFilePtr) -> Self { Self(value.0) @@ -37770,6 +37986,11 @@ impl From for TokenNodeGreen { Self(value.0) } } +impl From for TokenNodeGreen { + fn from(value: TerminalDotDotEqGreen) -> Self { + Self(value.0) + } +} impl From for TokenNodeGreen { fn from(value: TerminalEndOfFileGreen) -> Self { Self(value.0) @@ -38074,6 +38295,9 @@ impl TypedSyntaxNode for TokenNode { SyntaxKind::TerminalDotDot => { TokenNode::TerminalDotDot(TerminalDotDot::from_syntax_node(db, node)) } + SyntaxKind::TerminalDotDotEq => { + TokenNode::TerminalDotDotEq(TerminalDotDotEq::from_syntax_node(db, node)) + } SyntaxKind::TerminalEndOfFile => { TokenNode::TerminalEndOfFile(TerminalEndOfFile::from_syntax_node(db, node)) } @@ -38302,6 +38526,9 @@ impl TypedSyntaxNode for TokenNode { SyntaxKind::TerminalDotDot => { Some(TokenNode::TerminalDotDot(TerminalDotDot::from_syntax_node(db, node))) } + SyntaxKind::TerminalDotDotEq => { + Some(TokenNode::TerminalDotDotEq(TerminalDotDotEq::from_syntax_node(db, node))) + } SyntaxKind::TerminalEndOfFile => { Some(TokenNode::TerminalEndOfFile(TerminalEndOfFile::from_syntax_node(db, node))) } @@ -38451,6 +38678,7 @@ impl TypedSyntaxNode for TokenNode { TokenNode::TerminalDivEq(x) => x.as_syntax_node(), TokenNode::TerminalDot(x) => x.as_syntax_node(), TokenNode::TerminalDotDot(x) => x.as_syntax_node(), + TokenNode::TerminalDotDotEq(x) => x.as_syntax_node(), TokenNode::TerminalEndOfFile(x) => x.as_syntax_node(), TokenNode::TerminalEq(x) => x.as_syntax_node(), TokenNode::TerminalEqEq(x) => x.as_syntax_node(), @@ -38545,6 +38773,7 @@ impl TokenNode { | SyntaxKind::TerminalDivEq | SyntaxKind::TerminalDot | SyntaxKind::TerminalDotDot + | SyntaxKind::TerminalDotDotEq | SyntaxKind::TerminalEndOfFile | SyntaxKind::TerminalEq | SyntaxKind::TerminalEqEq diff --git a/crates/cairo-lang-syntax/src/node/key_fields.rs b/crates/cairo-lang-syntax/src/node/key_fields.rs index b870015ea47..025ad081e3d 100644 --- a/crates/cairo-lang-syntax/src/node/key_fields.rs +++ b/crates/cairo-lang-syntax/src/node/key_fields.rs @@ -585,6 +585,10 @@ pub fn get_key_fields(kind: SyntaxKind, children: &[GreenId]) -> Vec { SyntaxKind::TerminalDotDot => { vec![] } + SyntaxKind::TokenDotDotEq => vec![], + SyntaxKind::TerminalDotDotEq => { + vec![] + } SyntaxKind::TokenEndOfFile => vec![], SyntaxKind::TerminalEndOfFile => { vec![] diff --git a/crates/cairo-lang-syntax/src/node/kind.rs b/crates/cairo-lang-syntax/src/node/kind.rs index 4614e8977a4..de170ed12a9 100644 --- a/crates/cairo-lang-syntax/src/node/kind.rs +++ b/crates/cairo-lang-syntax/src/node/kind.rs @@ -240,6 +240,8 @@ pub enum SyntaxKind { TerminalDot, TokenDotDot, TerminalDotDot, + TokenDotDotEq, + TerminalDotDotEq, TokenEndOfFile, TerminalEndOfFile, TokenEq, @@ -364,6 +366,7 @@ impl SyntaxKind { | SyntaxKind::TokenDivEq | SyntaxKind::TokenDot | SyntaxKind::TokenDotDot + | SyntaxKind::TokenDotDotEq | SyntaxKind::TokenEndOfFile | SyntaxKind::TokenEq | SyntaxKind::TokenEqEq @@ -454,6 +457,7 @@ impl SyntaxKind { | SyntaxKind::TerminalDivEq | SyntaxKind::TerminalDot | SyntaxKind::TerminalDotDot + | SyntaxKind::TerminalDotDotEq | SyntaxKind::TerminalEndOfFile | SyntaxKind::TerminalEq | SyntaxKind::TerminalEqEq