diff --git a/grammar.txt b/grammar.txt index 1e5fbc0..178fcfd 100644 --- a/grammar.txt +++ b/grammar.txt @@ -18,4 +18,4 @@ list_or ::= ('|' | 'or') EVS_or EVS_and ::= (EVS_Nested | VS) [and_list] EVS_or ::= (EVS_Nested | VS) [or_list] OP ::= '<' | '>' etc -NEG ::= '!' | 'not' +NEG ::= '!' | '¬' | 'not' diff --git a/src/semantic_versioning-extended.adb b/src/semantic_versioning-extended.adb index 10224f1..6902ff4 100644 --- a/src/semantic_versioning-extended.adb +++ b/src/semantic_versioning-extended.adb @@ -333,7 +333,8 @@ package body Semantic_Versioning.Extended is return List_Img; when Negated => - return "!(" & Img (Trees.First_Child (Pos)) & ")"; + return (if Opts.Unicode then U ("¬") else "!") + & "(" & Img (Trees.First_Child (Pos)) & ")"; end case; end Img; @@ -378,6 +379,8 @@ package body Semantic_Versioning.Extended is VS, End_Of_Input); + Not_UChar : constant String := U ("¬"); + I : Integer := Str'First; -- Next char to process Err : Unbounded_String; @@ -519,6 +522,14 @@ package body Semantic_Versioning.Extended is return VS; end if; + if Begins_With (Str (I .. Str'Last), Not_UChar) then + if not Opts.Unicode then + Error (U ("Unicode operator '¬' not allowed " & + "(Unicode option is disabled)")); + end if; + return Negation; + end if; + case Str (I) is when '&' => return Ampersand; when '(' => return Lparen; @@ -531,6 +542,7 @@ package body Semantic_Versioning.Extended is when others => return Unknown; end case; end Internal; + begin return T : constant Tokens := Internal do Trace ("Next token: " & T'Img); @@ -561,6 +573,8 @@ package body Semantic_Versioning.Extended is when Negation => if Is_Keyword ("not") then Match ("not"); + elsif Begins_With (Str (I .. Str'Last), Not_UChar) then + Match (Not_UChar); else Match ('!'); end if; @@ -760,7 +774,9 @@ package body Semantic_Versioning.Extended is ------------- function Value_U (Str : Wide_Wide_String; - Relaxed : Boolean := False) return Version_Set - is (Value (U (Str), Relaxed)); + Relaxed : Boolean := False; + Opts : Basic.Options := Basic.Default_Options) + return Version_Set + is (Value (U (Str), Relaxed, Opts)); end Semantic_Versioning.Extended; diff --git a/src/semantic_versioning-extended.ads b/src/semantic_versioning-extended.ads index e124806..d8df0ce 100644 --- a/src/semantic_versioning-extended.ads +++ b/src/semantic_versioning-extended.ads @@ -67,7 +67,9 @@ package Semantic_Versioning.Extended with Preelaborate is -- Options control parsing (Unicode for accepting Unicode operators) function Value_U (Str : Wide_Wide_String; - Relaxed : Boolean := False) return Version_Set; + Relaxed : Boolean := False; + Opts : Basic.Options := Basic.Default_Options) + return Version_Set; function Image (VS : Version_Set) return String; -- Original image, as given to Value diff --git a/tests/alire.toml b/tests/alire.toml index 94b8bbb..e0b0771 100644 --- a/tests/alire.toml +++ b/tests/alire.toml @@ -10,3 +10,4 @@ semantic_versioning = { path = '..' } [build-profiles] semantic_versioning = 'validation' +semver_tests = 'validation' diff --git a/tests/src/semver_tests-negation.adb b/tests/src/semver_tests-negation.adb index cba0d4e..3b6a357 100644 --- a/tests/src/semver_tests-negation.adb +++ b/tests/src/semver_tests-negation.adb @@ -15,4 +15,7 @@ begin Assert (X.Value ("!^1").Synthetic_Image = X.Value ("!(^1)").Synthetic_Image); -- Equivalent + + -- Alternate symbol + Assert (X.Is_In (V ("1.1"), X.Value_U ("¬1"))); end Semver_Tests.Negation; diff --git a/tests/src/semver_tests-options.adb b/tests/src/semver_tests-options.adb index 7de54fa..d39e61e 100644 --- a/tests/src/semver_tests-options.adb +++ b/tests/src/semver_tests-options.adb @@ -92,6 +92,12 @@ begin XVS1 := X.Value (U ("≥1.2.0"), Opts => Unicode_Opts); Assert (X.Is_In (V1_2, XVS1), "Extended Unicode parsing failed"); + XVS1 := X.Value_U ("¬1.2.0", Opts => Unicode_Opts); + Assert (not X.Is_In (V1_2, XVS1), "Extended Unicode negation parsing failed"); + + Assert (not X.Parse (U ("¬1.2.0"), Opts => No_Unicode_Opts).Valid, + "Parse should fail for Unicode negation when disabled"); + -- Test Synthetic_Image with different options XVS1 := X.Value (">=1.2.0 & /=1.2.5"); Assert (X.Synthetic_Image (XVS1, Opts => Unicode_Opts) = @@ -104,6 +110,16 @@ begin "Extended ASCII output failed: " & X.Synthetic_Image (XVS1, Opts => No_Unicode_Opts)); + XVS1 := X.Value ("!1.2.0"); + Assert (X.Synthetic_Image (XVS1, Opts => Unicode_Opts) = + U ("¬(=1.2.0)"), + "Extended Unicode negation output failed: " & + X.Synthetic_Image (XVS1, Opts => Unicode_Opts)); + Assert (X.Synthetic_Image (XVS1, Opts => No_Unicode_Opts) = + "!(=1.2.0)", + "Extended ASCII negation output failed: " & + X.Synthetic_Image (XVS1, Opts => No_Unicode_Opts)); + -- Test Implicit_Equal with Extended XVS1 := X.Value ("=1.2.0"); Assert (X.Synthetic_Image (XVS1, Opts => With_Implicit) = "1.2.0", diff --git a/tests/src/semver_tests-with_unicode.adb b/tests/src/semver_tests-with_unicode.adb index 9cbe73a..9a6a32a 100644 --- a/tests/src/semver_tests-with_unicode.adb +++ b/tests/src/semver_tests-with_unicode.adb @@ -1,6 +1,19 @@ procedure Semver_Tests.With_Unicode is + + Unicode_Opts : constant Basic.Options := + (Unicode => True, + Word_Operators => False, + Implicit_Equal => False); + begin Assert (X.Is_In (V ("1.1"), X.Value_U ("≠1"))); Assert (X.Is_In (V ("1.1"), X.Value_U ("≥1"))); Assert (X.Is_In (V ("1.1"), X.Value_U ("≤1.1"))); + + declare + XVS : constant X.Version_Set := X.Value_U ("¬1", Opts => Unicode_Opts); + begin + Assert (not X.Is_In (V ("1.0.0"), XVS)); + Assert (X.Synthetic_Image (XVS, Opts => Unicode_Opts) = U ("¬(=1.0.0)")); + end; end Semver_Tests.With_Unicode;