From 68aa746dbcbbbe529310ad0fa0f8cebb9626140a Mon Sep 17 00:00:00 2001 From: zihang Date: Fri, 5 Dec 2025 15:15:52 +0800 Subject: [PATCH 1/3] Fix all deprecation warnings and syntax lint issues - Replace deprecated @hashmap.T with @hashmap.HashMap (8 warnings) - Replace deprecated is_empty() with is None pattern (6 warnings) - Replace deprecated substring with str[:] syntax (1 warning) - Fix duplicate test name (1 warning) - Fix syntax lint warning by rewriting match (try? expr) to try-catch pattern (1 warning) All changes are minimal and focused on fixing deprecation warnings. moon check now passes with 0 warnings, and all 70 tests pass. Co-authored-by: openhands --- src/ini_file.mbt | 36 +++++++++++++++++++----------------- src/parser.mbt | 29 ++++++++++++++++++----------- src/parser_test.mbt | 7 ++++--- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/ini_file.mbt b/src/ini_file.mbt index c303397..a6d4aca 100644 --- a/src/ini_file.mbt +++ b/src/ini_file.mbt @@ -12,20 +12,20 @@ priv struct Value(String) derive(Show) ///| struct IniFile { - sections : @hashmap.T[Section, @hashmap.T[Key, Value]] + sections : @hashmap.HashMap[Section, @hashmap.HashMap[Key, Value]] // default not case sensitive is_case_sensitive : Bool } ///| -pub fn IniFile::new(is_case_sensitive~ : Bool = false) -> IniFile { +pub fn IniFile::new(is_case_sensitive? : Bool = false) -> IniFile { IniFile::{ sections: @hashmap.new(), is_case_sensitive } } ///| fn IniFile::new_with_sections( - sections : @hashmap.T[Section, @hashmap.T[Key, Value]], - is_case_sensitive~ : Bool = false, + sections : @hashmap.HashMap[Section, @hashmap.HashMap[Key, Value]], + is_case_sensitive? : Bool = false, ) -> IniFile { IniFile::{ sections, is_case_sensitive } } @@ -39,10 +39,11 @@ fn IniFile::lower_if_needed(self : IniFile, s : String) -> String { } } -///| get is a alias for get_string +///| +/// get is a alias for get_string pub fn IniFile::get( self : IniFile, - section~ : String = "", + section? : String = "", key : String, ) -> String? { self.get_string(section~, key) @@ -51,7 +52,7 @@ pub fn IniFile::get( ///| pub fn IniFile::get_string( self : IniFile, - section~ : String = "", + section? : String = "", key : String, ) -> String? { let section_map = self.get_section( @@ -61,10 +62,10 @@ pub fn IniFile::get_string( }, create_if_not_exists=false, ) - guard not(section_map.is_empty()) else { None } + guard section_map is Some(_) else { None } let section_map = section_map.unwrap() let value = section_map.get(self.lower_if_needed(key)) - guard not(value.is_empty()) else { None } + guard value is Some(_) else { None } let value = value.unwrap() let Value(v) = value Some(v) @@ -73,11 +74,11 @@ pub fn IniFile::get_string( ///| pub fn IniFile::get_bool( self : IniFile, - section~ : String = "", + section? : String = "", key : String, ) -> Bool? { let value = self.get_string(section~, key) - guard not(value.is_empty()) else { None } + guard value is Some(_) else { None } let value = value.unwrap() match value.to_lower() { "true" | "yes" | "on" => Some(true) @@ -92,8 +93,8 @@ pub fn IniFile::get_bool( fn IniFile::get_section( self : IniFile, section : Section, - create_if_not_exists~ : Bool = false, -) -> @hashmap.T[Key, Value]? { + create_if_not_exists? : Bool = false, +) -> @hashmap.HashMap[Key, Value]? { let section_map = self.sections.get(section) match section_map { None => @@ -112,7 +113,7 @@ fn IniFile::get_section( fn IniFile::get_section_or_create( self : IniFile, section : Section, -) -> @hashmap.T[Key, Value] { +) -> @hashmap.HashMap[Key, Value] { let section_map = self.get_section(section, create_if_not_exists=true) section_map.unwrap() } @@ -120,7 +121,7 @@ fn IniFile::get_section_or_create( ///| pub fn IniFile::set( self : IniFile, - section~ : String = "", + section? : String = "", key : String, value : String, ) -> Unit { @@ -133,7 +134,8 @@ pub fn IniFile::set( section_map.set(self.lower_if_needed(key), Value(value)) } -///| Converts the IniFile to a standard INI format string +///| +/// Converts the IniFile to a standard INI format string pub fn IniFile::to_string(self : IniFile) -> String { fn escape_char(c : Char) -> String { match c { @@ -176,7 +178,7 @@ pub fn IniFile::to_string(self : IniFile) -> String { let buf = StringBuilder::new() // Global section first let global_section = self.sections.get(Section::Global) - if not(global_section.is_empty()) { + if global_section is Some(_) { global_section .unwrap() .iter() diff --git a/src/parser.mbt b/src/parser.mbt index 4e14fe1..a5730a5 100644 --- a/src/parser.mbt +++ b/src/parser.mbt @@ -11,7 +11,7 @@ pub suberror IniParseError { ///| priv struct ParseContext { mut current_section : Section - sections : @hashmap.T[Section, @hashmap.T[Key, Value]] + sections : @hashmap.HashMap[Section, @hashmap.HashMap[Key, Value]] mut line : Int mut col : Int mut key : String @@ -66,7 +66,7 @@ fn IniParseState::lower_if_needed(self : IniParseState, s : String) -> String { } ///| -pub fn IniParseState::new(is_case_sensitive~ : Bool = false) -> IniParseState { +pub fn IniParseState::new(is_case_sensitive? : Bool = false) -> IniParseState { IniParseState::{ ctx: ParseContext::{ current_section: Section::Global, @@ -86,7 +86,7 @@ pub fn IniParseState::new(is_case_sensitive~ : Bool = false) -> IniParseState { ///| pub fn parse( str : String, - is_case_sensitive~ : Bool = false, + is_case_sensitive? : Bool = false, ) -> IniFile raise IniParseError { IniParseState::new(is_case_sensitive~).parse(str).finish() } @@ -405,11 +405,18 @@ fn IniParseState::commit_value( self : IniParseState, // If true, drop the last space in the value // this is used to handle the case when a comment is at the end of the line - drop_last_one_space~ : Bool = false, + drop_last_one_space? : Bool = false, ) -> IniParseState raise IniParseError { let mut value = self.ctx.buffer.to_string() if drop_last_one_space && value.rev_iter().nth(0).unwrap().is_whitespace() { - value = value.substring(end=value.length() - 1) + let len = value.length() + if len > 0 { + try { + value = value[:len - 1].to_string() + } catch { + _ => () + } + } } let section = self.ctx.sections.get(self.ctx.current_section).unwrap() let key = self.ctx.key @@ -500,7 +507,7 @@ test "IniParseState::process_char/global_section_edge_cases" { } ///| -test "panic IniParseState::process_char/unclosed_section" { +test "panic IniParseState::process_char/unclosed_section_newline" { let state = IniParseState::new() ignore(state.process_char('[')) ignore(state.process_char('\n')) @@ -649,7 +656,7 @@ test "IniParseState::handle_key_char/valueless_key" { inspect(state.ctx.key, content="key") inspect(state.phase, content="Start") let section = state.ctx.sections.get(state.ctx.current_section) - inspect(section.is_empty(), content="false") + inspect(section is Some(_), content="true") let value = section.unwrap().get("key") inspect(value, content="Some(Value(\"\"))") } @@ -732,10 +739,10 @@ test "IniParseState::commit_value/basic" { inspect(state.ctx.buffer.is_empty(), content="true") // Verify the section exists let section = state.ctx.sections.get(Section::NamedSection("section")) - inspect(section.is_empty(), content="false") + inspect(section is Some(_), content="true") // Verify the key exists in the section let value = section.unwrap().get("key") - inspect(value.is_empty(), content="false") + inspect(value is Some(_), content="true") } ///| @@ -752,8 +759,8 @@ test "IniParseState::commit_value/empty_value" { let state = state.commit_value() // Verify the section exists let section = state.ctx.sections.get(Section::NamedSection("section")) - inspect(section.is_empty(), content="false") + inspect(section is Some(_), content="true") // Verify the key exists in the section with empty value let value = section.unwrap().get("key") - inspect(value.is_empty(), content="false") + inspect(value is Some(_), content="true") } diff --git a/src/parser_test.mbt b/src/parser_test.mbt index cf4cb54..858da8b 100644 --- a/src/parser_test.mbt +++ b/src/parser_test.mbt @@ -128,9 +128,10 @@ test "parse/error_value_without_section_or_key" { // This case is tricky because the parser might interpret 'value' as a key // Let's test assignment without a preceding key let input = "[section]\n=value" - match (try? parse(input)) { - Ok(_) => assert_true(false) - Err(_) => assert_true(true) + try parse(input) catch { + _ => assert_true(true) + } noraise { + _ => assert_true(false) } // The ValueWithoutSection error is harder to trigger directly with current logic, // as '=' is required to start reading a value, which implies a key was being read. From 9d23d270c96bad7826d13764efd95d65b74a335d Mon Sep 17 00:00:00 2001 From: zihang Date: Fri, 5 Dec 2025 15:16:05 +0800 Subject: [PATCH 2/3] AI work on: Try to eliminate all the warnings with minimal changes possible. The bottom line is that moon check works. It would be better if moon test works. The package may not need fix. In this case, do nothing. One major change is that the string[i] used to return Int, but now it needs to return UInt16. Try to fix it by using the correct type conversion. --- src/pkg.generated.mbti | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/pkg.generated.mbti diff --git a/src/pkg.generated.mbti b/src/pkg.generated.mbti new file mode 100644 index 0000000..5d653c3 --- /dev/null +++ b/src/pkg.generated.mbti @@ -0,0 +1,34 @@ +// Generated using `moon info`, DON'T EDIT IT +package "ShellWen/sw_ini" + +// Values +pub fn parse(String, is_case_sensitive? : Bool) -> IniFile raise IniParseError + +// Errors +pub suberror IniParseError { + UnexpectedEqualSign(line~ : Int, col~ : Int) + EmptySection(line~ : Int, col~ : Int) + UnclosedSection(line~ : Int, col~ : Int) + ValueWithoutSection(line~ : Int, col~ : Int) + QuoteMismatch(line~ : Int, col~ : Int) + QuoteNotClosed(line~ : Int, col~ : Int) +} + +// Types and methods +type IniFile +pub fn IniFile::get(Self, section? : String, String) -> String? +pub fn IniFile::get_bool(Self, section? : String, String) -> Bool? +pub fn IniFile::get_string(Self, section? : String, String) -> String? +pub fn IniFile::new(is_case_sensitive? : Bool) -> Self +pub fn IniFile::set(Self, section? : String, String, String) -> Unit +pub fn IniFile::to_string(Self) -> String + +type IniParseState +pub fn IniParseState::finish(Self) -> IniFile raise IniParseError +pub fn IniParseState::new(is_case_sensitive? : Bool) -> Self +pub fn IniParseState::parse(Self, String) -> Self raise IniParseError + +// Type aliases + +// Traits + From 7aa931e1ae43e3c60172bc3be163e0edab54a2ac Mon Sep 17 00:00:00 2001 From: zihang Date: Tue, 9 Dec 2025 15:18:32 +0800 Subject: [PATCH 3/3] fix: make the code more idomatic --- src/parser.mbt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/parser.mbt b/src/parser.mbt index a5730a5..a3a587c 100644 --- a/src/parser.mbt +++ b/src/parser.mbt @@ -408,15 +408,8 @@ fn IniParseState::commit_value( drop_last_one_space? : Bool = false, ) -> IniParseState raise IniParseError { let mut value = self.ctx.buffer.to_string() - if drop_last_one_space && value.rev_iter().nth(0).unwrap().is_whitespace() { - let len = value.length() - if len > 0 { - try { - value = value[:len - 1].to_string() - } catch { - _ => () - } - } + if drop_last_one_space && value is [.. rest, ch] && ch.is_whitespace() { + value = rest.to_string() } let section = self.ctx.sections.get(self.ctx.current_section).unwrap() let key = self.ctx.key