-- 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 — Generic text transformation body
--
-- UTF-8 decode loop. Calls On_Codepoint for each decoded codepoint,
-- then On_Finish at end of input. Output position tracking and error
-- propagation are handled here; the module callbacks do the real work.
-------------------------------------------------------------------------------
with Lingenic_Text.UTF8;
procedure Lingenic_Text.Text_Transform
(Input : Byte_Array;
State : in out State_Type;
Output : in out Byte_Array;
Last : out Natural;
OK : out Boolean)
with SPARK_Mode
is
Pos : Positive := Input'First;
CP : Codepoint;
Len : Positive;
Valid : Boolean;
Out_Pos : Natural := Output'First;
begin
Last := Output'First - 1;
OK := True;
while Pos <= Input'Last loop
pragma Loop_Invariant (Pos >= Input'First);
pragma Loop_Invariant (Out_Pos >= Output'First);
pragma Loop_Invariant (Out_Pos <= Output'Last + 1);
pragma Loop_Invariant (OK);
pragma Loop_Invariant (Partial_Valid (State, Output, Out_Pos));
pragma Loop_Variant (Increases => Pos);
UTF8.Decode (Input, Pos, CP, Len, Valid);
if not Valid then
OK := False;
return;
end if;
On_Codepoint (State, CP, Output, Out_Pos, OK);
if not OK then
return;
end if;
-- Advance past decoded UTF-8 sequence
if Pos > Input'Last - Len + 1 then
Pos := Input'Last + 1;
else
Pos := Pos + Len;
end if;
end loop;
On_Finish (State, Output, Out_Pos, OK);
if not OK then
return;
end if;
if Out_Pos = Output'First then
-- No output produced. Postcondition requires Last in range on
-- success, so report failure.
OK := False;
else
Last := Out_Pos - 1;
end if;
end Lingenic_Text.Text_Transform;