diff --git a/crates/cairo-lang-defs/src/patcher.rs b/crates/cairo-lang-defs/src/patcher.rs index 933c841c834..79b21b3fd9c 100644 --- a/crates/cairo-lang-defs/src/patcher.rs +++ b/crates/cairo-lang-defs/src/patcher.rs @@ -268,13 +268,8 @@ impl<'a> PatchBuilder<'a> { /// Builds the resulting code and code mappings. pub fn build(mut self) -> (String, Vec) { // Adds the mapping to the original node from all code not previously mapped. - self.code_mappings.push(CodeMapping { - span: TextSpan { - start: TextOffset::default(), - end: TextOffset::default().add_width(TextWidth::from_str(&self.code)), - }, - origin: self.origin, - }); + self.code_mappings + .push(CodeMapping { span: TextSpan::from_str(&self.code), origin: self.origin }); (self.code, self.code_mappings) } @@ -320,7 +315,7 @@ impl<'a> PatchBuilder<'a> { } pub fn add_node(&mut self, node: SyntaxNode) { - let start = TextOffset::default().add_width(TextWidth::from_str(&self.code)); + let start = TextOffset::from_str(&self.code); let orig_span = node.span(self.db); self.code_mappings.push(CodeMapping { span: TextSpan { start, end: start.add_width(orig_span.width()) }, @@ -330,9 +325,9 @@ impl<'a> PatchBuilder<'a> { } fn add_mapped(&mut self, node: RewriteNode, origin: TextSpan) { - let start = TextOffset::default().add_width(TextWidth::from_str(&self.code)); + let start = TextOffset::from_str(&self.code); self.add_modified(node); - let end = TextOffset::default().add_width(TextWidth::from_str(&self.code)); + let end = TextOffset::from_str(&self.code); self.code_mappings .push(CodeMapping { span: TextSpan { start, end }, origin: CodeOrigin::Span(origin) }); } @@ -344,7 +339,7 @@ impl<'a> PatchBuilder<'a> { let origin_span = TextSpan { start: orig_start, end: orig_end }; let text = node.get_text_of_span(self.db, origin_span); - let start = TextOffset::default().add_width(TextWidth::from_str(&self.code)); + let start = TextOffset::from_str(&self.code); self.code += &text; diff --git a/crates/cairo-lang-diagnostics/src/diagnostics_test.rs b/crates/cairo-lang-diagnostics/src/diagnostics_test.rs index c9c41baf27b..662db1768c5 100644 --- a/crates/cairo-lang-diagnostics/src/diagnostics_test.rs +++ b/crates/cairo-lang-diagnostics/src/diagnostics_test.rs @@ -24,8 +24,8 @@ impl DiagnosticEntry for SimpleDiag { DiagnosticLocation { file_id: self.file_id, span: TextSpan { - start: TextOffset::default().add_width(TextWidth::new_for_testing(0)), - end: TextOffset::default().add_width(TextWidth::new_for_testing(6)), + start: TextOffset::START, + end: TextWidth::new_for_testing(6).as_offset(), }, } } diff --git a/crates/cairo-lang-filesystem/src/db.rs b/crates/cairo-lang-filesystem/src/db.rs index 94b5e8eca1c..41197aba63c 100644 --- a/crates/cairo-lang-filesystem/src/db.rs +++ b/crates/cairo-lang-filesystem/src/db.rs @@ -334,8 +334,8 @@ fn file_content(db: &dyn FilesGroup, file: FileId) -> Option> { } fn file_summary(db: &dyn FilesGroup, file: FileId) -> Option> { let content = db.file_content(file)?; - let mut line_offsets = vec![TextOffset::default()]; - let mut offset = TextOffset::default(); + let mut line_offsets = vec![TextOffset::START]; + let mut offset = TextOffset::START; for ch in content.chars() { offset = offset.add_width(TextWidth::from_char(ch)); if ch == '\n' { diff --git a/crates/cairo-lang-filesystem/src/span.rs b/crates/cairo-lang-filesystem/src/span.rs index 9386fe681e9..2d8f87062b6 100644 --- a/crates/cairo-lang-filesystem/src/span.rs +++ b/crates/cairo-lang-filesystem/src/span.rs @@ -17,6 +17,8 @@ mod test; )] pub struct TextWidth(u32); impl TextWidth { + pub const ZERO: Self = Self(0); + pub fn from_char(c: char) -> Self { Self(c.len_utf8() as u32) } @@ -27,9 +29,24 @@ impl TextWidth { pub fn new_for_testing(value: u32) -> Self { Self(value) } + /// Creates a `TextWidth` at the given index of a string. + /// + /// The index is required to be a char boundary. + /// This function runs a debug assertion to verify this, + /// while retains performance on release builds. + pub fn at(s: &str, index: usize) -> Self { + debug_assert!( + s.is_char_boundary(index), + "cannot create a TextWidth outside of a char boundary" + ); + Self(index as u32) + } pub fn as_u32(self) -> u32 { self.0 } + pub fn as_offset(self) -> TextOffset { + TextOffset(self) + } } impl Add for TextWidth { type Output = Self; @@ -57,6 +74,13 @@ impl Sum for TextWidth { )] pub struct TextOffset(TextWidth); impl TextOffset { + pub const START: Self = Self(TextWidth::ZERO); + + /// Creates a `TextOffset` at the end of a given string. + #[allow(clippy::should_implement_trait)] + pub fn from_str(content: &str) -> Self { + Self(TextWidth::from_str(content)) + } pub fn add_width(self, width: TextWidth) -> Self { TextOffset(self.0 + width) } @@ -87,6 +111,11 @@ pub struct TextSpan { pub end: TextOffset, } impl TextSpan { + /// Creates a `TextSpan` for the entirety of a given string. + #[allow(clippy::should_implement_trait)] + pub fn from_str(content: &str) -> Self { + Self { start: TextOffset::START, end: TextOffset::from_str(content) } + } pub fn width(self) -> TextWidth { self.end - self.start } diff --git a/crates/cairo-lang-parser/src/db_test.rs b/crates/cairo-lang-parser/src/db_test.rs index abc1452000d..c6f1192e242 100644 --- a/crates/cairo-lang-parser/src/db_test.rs +++ b/crates/cairo-lang-parser/src/db_test.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use cairo_lang_filesystem::ids::FileId; -use cairo_lang_filesystem::span::{TextOffset, TextSpan, TextWidth}; +use cairo_lang_filesystem::span::TextSpan; use cairo_lang_syntax::node::ast::{ ModuleItemList, SyntaxFile, TerminalEndOfFile, TokenEndOfFile, Trivia, }; @@ -9,7 +9,6 @@ use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::{SyntaxNode, Terminal, Token as SyntaxToken, TypedSyntaxNode}; use cairo_lang_utils::Upcast; use indoc::indoc; -use num_traits::ToPrimitive; use pretty_assertions::assert_eq; use smol_str::SmolStr; use test_log::test; @@ -96,11 +95,7 @@ fn test_token_stream_expr_parser() { let token_stream = MockTokenStream { tokens: vec![MockToken { content: expr_code.to_string(), - span: TextSpan { - start: TextOffset::default(), - end: TextOffset::default() - .add_width(TextWidth::new_for_testing(expr_code.len().to_u32().unwrap())), - }, + span: TextSpan::from_str(expr_code), }], content_string: expr_code.to_string(), }; diff --git a/crates/cairo-lang-parser/src/lexer.rs b/crates/cairo-lang-parser/src/lexer.rs index f729e5c4ff8..a90c6367c2f 100644 --- a/crates/cairo-lang-parser/src/lexer.rs +++ b/crates/cairo-lang-parser/src/lexer.rs @@ -27,8 +27,8 @@ impl<'a> Lexer<'a> { Lexer { db, text, - previous_position: TextOffset::default(), - current_position: TextOffset::default(), + previous_position: TextOffset::START, + current_position: TextOffset::START, done: false, } } diff --git a/crates/cairo-lang-plugins/src/test.rs b/crates/cairo-lang-plugins/src/test.rs index d860baf6e0d..92e488aaf5e 100644 --- a/crates/cairo-lang-plugins/src/test.rs +++ b/crates/cairo-lang-plugins/src/test.rs @@ -14,7 +14,7 @@ use cairo_lang_filesystem::db::{ use cairo_lang_filesystem::ids::{ CodeMapping, CodeOrigin, CrateId, Directory, FileLongId, VirtualFile, }; -use cairo_lang_filesystem::span::{TextOffset, TextSpan, TextWidth}; +use cairo_lang_filesystem::span::TextSpan; use cairo_lang_parser::db::ParserDatabase; use cairo_lang_syntax::node::db::{SyntaxDatabase, SyntaxGroup}; use cairo_lang_syntax::node::helpers::QueryAttrs; @@ -160,10 +160,7 @@ impl MacroPlugin for DoubleIndirectionPlugin { let orig_span = node.span(db); let code_mappings = |content: &str| { vec![CodeMapping { - span: TextSpan { - start: TextOffset::default(), - end: TextOffset::default().add_width(TextWidth::from_str(content)), - }, + span: TextSpan::from_str(content), origin: CodeOrigin::Start(orig_span.start), }] }; diff --git a/crates/cairo-lang-semantic/src/inline_macros/consteval_int.rs b/crates/cairo-lang-semantic/src/inline_macros/consteval_int.rs index 447a9bd3323..8a9062a4464 100644 --- a/crates/cairo-lang-semantic/src/inline_macros/consteval_int.rs +++ b/crates/cairo-lang-semantic/src/inline_macros/consteval_int.rs @@ -4,7 +4,7 @@ use cairo_lang_defs::plugin::{ PluginGeneratedFile, }; use cairo_lang_filesystem::ids::{CodeMapping, CodeOrigin}; -use cairo_lang_filesystem::span::{TextOffset, TextSpan, TextWidth}; +use cairo_lang_filesystem::span::TextSpan; use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode, ast}; use indoc::indoc; @@ -45,10 +45,7 @@ impl InlineMacroExprPlugin for ConstevalIntMacro { InlinePluginResult { code: code.map(|x| { let content = x.to_string(); - let span = TextSpan { - start: TextOffset::default(), - end: TextOffset::default().add_width(TextWidth::from_str(&content)), - }; + let span = TextSpan::from_str(&content); PluginGeneratedFile { name: "consteval_int_inline_macro".into(), content, diff --git a/crates/cairo-lang-starknet/src/plugin/test.rs b/crates/cairo-lang-starknet/src/plugin/test.rs index d68c79a7f75..a8b9f6d61c3 100644 --- a/crates/cairo-lang-starknet/src/plugin/test.rs +++ b/crates/cairo-lang-starknet/src/plugin/test.rs @@ -7,7 +7,7 @@ use cairo_lang_defs::ids::ModuleId; use cairo_lang_diagnostics::DiagnosticLocation; use cairo_lang_filesystem::db::FilesGroup; use cairo_lang_filesystem::ids::FileLongId; -use cairo_lang_filesystem::span::{TextOffset, TextSpan, TextWidth}; +use cairo_lang_filesystem::span::TextSpan; use cairo_lang_plugins::test_utils::expand_module_text; use cairo_lang_semantic::test_utils::setup_test_module; use cairo_lang_test_utils::parse_test_file::{TestFileRunner, TestRunnerResult}; @@ -49,9 +49,8 @@ impl TestFileRunner for ExpandContractTestRunner { for file_id in files { let content = db.file_content(file_id).unwrap(); - let start = TextOffset::default(); - let end = start.add_width(TextWidth::from_str(&content)); - let content_location = DiagnosticLocation { file_id, span: TextSpan { start, end } }; + let content_location = + DiagnosticLocation { file_id, span: TextSpan::from_str(&content) }; let original_location = content_location.user_location(db.upcast()); let origin = (content_location != original_location) .then(|| format!("{:?}\n", original_location.debug(db.upcast()))) diff --git a/crates/cairo-lang-syntax/src/node/ast_test.rs b/crates/cairo-lang-syntax/src/node/ast_test.rs index 62382776d46..7dc74ab2b41 100644 --- a/crates/cairo-lang-syntax/src/node/ast_test.rs +++ b/crates/cairo-lang-syntax/src/node/ast_test.rs @@ -26,106 +26,86 @@ fn test_ast() { .map(|node| (node.kind(db), node.text(db), node.offset(), node.width(db))) .collect::>(), vec![ - ( - SyntaxKind::ExprBinary, - None, - TextOffset::default().add_width(TextWidth::new_for_testing(0)), - TextWidth::new_for_testing(7) - ), - ( - SyntaxKind::ExprPath, - None, - TextOffset::default().add_width(TextWidth::new_for_testing(0)), - TextWidth::new_for_testing(4) - ), - ( - SyntaxKind::PathSegmentSimple, - None, - TextOffset::default().add_width(TextWidth::new_for_testing(0)), - TextWidth::new_for_testing(4) - ), + (SyntaxKind::ExprBinary, None, TextOffset::START, TextWidth::new_for_testing(7)), + (SyntaxKind::ExprPath, None, TextOffset::START, TextWidth::new_for_testing(4)), + (SyntaxKind::PathSegmentSimple, None, TextOffset::START, TextWidth::new_for_testing(4)), ( SyntaxKind::TerminalIdentifier, None, - TextOffset::default().add_width(TextWidth::new_for_testing(0)), + TextOffset::START, TextWidth::new_for_testing(4) ), - ( - SyntaxKind::Trivia, - None, - TextOffset::default().add_width(TextWidth::new_for_testing(0)), - TextWidth::new_for_testing(0) - ), + (SyntaxKind::Trivia, None, TextOffset::START, TextWidth::new_for_testing(0)), ( SyntaxKind::TokenIdentifier, Some("foo".into()), - TextOffset::default().add_width(TextWidth::new_for_testing(0)), + TextOffset::START, TextWidth::new_for_testing(3) ), ( SyntaxKind::Trivia, None, - TextOffset::default().add_width(TextWidth::new_for_testing(3)), + TextWidth::new_for_testing(3).as_offset(), TextWidth::new_for_testing(1) ), ( SyntaxKind::TokenWhitespace, Some(" ".into()), - TextOffset::default().add_width(TextWidth::new_for_testing(3)), + TextWidth::new_for_testing(3).as_offset(), TextWidth::new_for_testing(1) ), ( SyntaxKind::TerminalPlus, None, - TextOffset::default().add_width(TextWidth::new_for_testing(4)), + TextWidth::new_for_testing(4).as_offset(), TextWidth::new_for_testing(2) ), ( SyntaxKind::Trivia, None, - TextOffset::default().add_width(TextWidth::new_for_testing(4)), + TextWidth::new_for_testing(4).as_offset(), TextWidth::new_for_testing(0) ), ( SyntaxKind::TokenPlus, Some("+".into()), - TextOffset::default().add_width(TextWidth::new_for_testing(4)), + TextWidth::new_for_testing(4).as_offset(), TextWidth::new_for_testing(1) ), ( SyntaxKind::Trivia, None, - TextOffset::default().add_width(TextWidth::new_for_testing(5)), + TextWidth::new_for_testing(5).as_offset(), TextWidth::new_for_testing(1) ), ( SyntaxKind::TokenWhitespace, Some(" ".into()), - TextOffset::default().add_width(TextWidth::new_for_testing(5)), + TextWidth::new_for_testing(5).as_offset(), TextWidth::new_for_testing(1) ), ( SyntaxKind::TerminalLiteralNumber, None, - TextOffset::default().add_width(TextWidth::new_for_testing(6)), + TextWidth::new_for_testing(6).as_offset(), TextWidth::new_for_testing(1) ), ( SyntaxKind::Trivia, None, - TextOffset::default().add_width(TextWidth::new_for_testing(6)), + TextWidth::new_for_testing(6).as_offset(), TextWidth::new_for_testing(0) ), ( SyntaxKind::TokenLiteralNumber, Some("5".into()), - TextOffset::default().add_width(TextWidth::new_for_testing(6)), + TextWidth::new_for_testing(6).as_offset(), TextWidth::new_for_testing(1) ), ( SyntaxKind::Trivia, None, - TextOffset::default().add_width(TextWidth::new_for_testing(7)), + TextWidth::new_for_testing(7).as_offset(), TextWidth::new_for_testing(0) ) ] diff --git a/crates/cairo-lang-syntax/src/node/mod.rs b/crates/cairo-lang-syntax/src/node/mod.rs index 6758ac0e7a5..620aa112614 100644 --- a/crates/cairo-lang-syntax/src/node/mod.rs +++ b/crates/cairo-lang-syntax/src/node/mod.rs @@ -49,7 +49,7 @@ impl SyntaxNode { pub fn new_root(db: &dyn SyntaxGroup, file_id: FileId, green: GreenId) -> Self { let inner = SyntaxNodeInner { green, - offset: TextOffset::default(), + offset: TextOffset::START, parent: None, stable_ptr: SyntaxStablePtr::Root(file_id, green).intern(db), }; @@ -272,11 +272,10 @@ impl SyntaxNode { let orig_span = self.span(db); assert!(orig_span.contains(span)); let full_text = self.get_text(db); - let zero_offset = TextOffset::default(); let span_in_span = TextSpan { - start: zero_offset.add_width(span.start - orig_span.start), - end: zero_offset.add_width(span.end - orig_span.start), + start: (span.start - orig_span.start).as_offset(), + end: (span.end - orig_span.start).as_offset(), }; span_in_span.take(&full_text).to_string() }