「‍」 Lingenic

lingenic_text-case_mapping_spec

(⤓.ads ◇.ads); γ ≜ [2026-07-12T135427.513, 2026-07-12T135427.513] ∧ |γ| = 1

--  Copyright © 2026 Lingenic LLC. All rights reserved.
--  Licensed under the Lingenic Source-Available License v2.3.
--  Production use requires a separate license from Licensor.
--  See LICENSE.md and COPYRIGHT in the project root.
--

-------------------------------------------------------------------------------
--  Lingenic-Text
--  Formally Verified Unicode Text Processing Library
--
--  Case mapping ghost specification (Unicode Standard, Section 3.13).
--
--  Types and constants for case conversion operations.  Minimal ghost spec —
--  case mapping is table-driven.  The complexity is in initialization
--  (parsing UCD files) and the Final_Sigma state machine, not in ghost
--  predicates.
-------------------------------------------------------------------------------

package Lingenic_Text.Case_Mapping_Spec
   with SPARK_Mode, Pure
is

   ---------------------------------------------------------------------------
   --  Case operations
   ---------------------------------------------------------------------------

   type Case_Operation is (Op_Uppercase, Op_Lowercase, Op_Titlecase, Op_Casefold);

   ---------------------------------------------------------------------------
   --  Constants
   ---------------------------------------------------------------------------

   --  Max codepoints in a single full case mapping.
   --  SpecialCasing.txt mappings produce at most 3 codepoints.
   Max_Mapping_Len : constant := 3;

   --  Max pending codepoints for Final_Sigma buffering.
   --  During lowercase, when we see Greek capital sigma (U+03A3), we buffer
   --  it plus any trailing Case_Ignorable characters until we can determine
   --  whether Final_Sigma context applies.  32 is generous — in practice
   --  the run of Case_Ignorable characters between sigma and the next
   --  non-Case_Ignorable character is very short.
   Max_Pending : constant := 32;

   --  Greek sigma codepoints
   Greek_Capital_Sigma : constant Codepoint := 16#03A3#;
   Greek_Small_Sigma   : constant Codepoint := 16#03C3#;  --  medial
   Greek_Small_Final   : constant Codepoint := 16#03C2#;  --  final

   ---------------------------------------------------------------------------
   --  Is_Final_Sigma — ghost predicate for Final_Sigma context (Section 3.13)
   --
   --  A Greek capital sigma (U+03A3) maps to:
   --    ς (U+03C2, final)  when Preceded_By_Cased AND NOT Followed_By_Cased
   --    σ (U+03C3, medial) otherwise
   --
   --  Both conditions ignore intervening Case_Ignorable characters.
   --
   --  Parameters:
   --    Prev_Was_Cased  — True if the last non-Case_Ignorable before sigma
   --                      had the Cased property (Preceded_By_Cased).
   --    Followed_By_Cased — True if the next non-Case_Ignorable after sigma
   --                        has the Cased property.
   ---------------------------------------------------------------------------

   function Is_Final_Sigma
     (Prev_Was_Cased    : Boolean;
      Followed_By_Cased : Boolean) return Boolean
   is (Prev_Was_Cased and not Followed_By_Cased)
   with Ghost;

   function Final_Sigma_Result
     (Prev_Was_Cased    : Boolean;
      Followed_By_Cased : Boolean) return Codepoint
   is (if Is_Final_Sigma (Prev_Was_Cased, Followed_By_Cased)
       then Greek_Small_Final
       else Greek_Small_Sigma)
   with Ghost;

end Lingenic_Text.Case_Mapping_Spec;