From 30d59f09f6908aa0de2ec3a58a0736c8030ffda5 Mon Sep 17 00:00:00 2001
From: Jed Barber <jjbarber@y7mail.com>
Date: Thu, 21 Jan 2021 16:33:47 +1100
Subject: Piecewise parsing fixed, unit tested

---
 src/packrat-errors.adb  | 24 +++++++++++++
 src/packrat-errors.ads  |  5 +++
 src/packrat-parsers.adb | 94 ++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 103 insertions(+), 20 deletions(-)

(limited to 'src')

diff --git a/src/packrat-errors.adb b/src/packrat-errors.adb
index 3f7c38f..0122b7d 100644
--- a/src/packrat-errors.adb
+++ b/src/packrat-errors.adb
@@ -313,6 +313,30 @@ package body Packrat.Errors is
     end Decode;
 
 
+
+
+
+    function Equivalent
+           (Left, Right : in Error_Info_Array)
+        return Boolean
+    is
+        Marked : array (Left'Range) of Boolean := (others => False);
+    begin
+        if Left'Length /= Right'Length then
+            return False;
+        end if;
+        for L_Index in Left'Range loop
+            for R of Right loop
+                if Left (L_Index) = R and not Marked (L_Index) then
+                    Marked (L_Index) := True;
+                    exit;
+                end if;
+            end loop;
+        end loop;
+        return (for all M of Marked => M = True);
+    end Equivalent;
+
+
 end Packrat.Errors;
 
 
diff --git a/src/packrat-errors.ads b/src/packrat-errors.ads
index 50fa966..d3b38c3 100644
--- a/src/packrat-errors.ads
+++ b/src/packrat-errors.ads
@@ -79,6 +79,11 @@ package Packrat.Errors is
         return Error_Info_Array;
 
 
+    function Equivalent
+           (Left, Right : in Error_Info_Array)
+        return Boolean;
+
+
 end Packrat.Errors;
 
 
diff --git a/src/packrat-parsers.adb b/src/packrat-parsers.adb
index abb2736..26d5343 100644
--- a/src/packrat-parsers.adb
+++ b/src/packrat-parsers.adb
@@ -313,7 +313,6 @@ package body Packrat.Parsers is
                         Target.Results.Union (Add.Results);
                         Target.Status := Add.Status;
                     when Needs_More =>
-                        null;
                         Target.Status := Add.Status;
                     when Failure =>
                         null;
@@ -343,6 +342,9 @@ package body Packrat.Parsers is
         Salt, Temp : Combinator_Result;
         Adjust : Result_Sets.Set;
     begin
+        if From.Status = Failure or From.Status = Needs_More then
+            return From;
+        end if;
         Salt.Curtails := From.Curtails;
         for R of From.Results loop
             Temp := Next (Input, Context, R.Finish + 1);
@@ -356,6 +358,9 @@ package body Packrat.Parsers is
             Temp.Results := Adjust;
             Merge (Salt, Temp);
         end loop;
+        if Salt.Status = Failure and From.Status = Optional_More then
+            Salt.Status := Needs_More;
+        end if;
         return Salt;
     end Continue;
 
@@ -739,7 +744,8 @@ package body Packrat.Parsers is
             end if;
             Salt := Params (Params'First) (Input, Context, Start);
             for I in Integer range Params'First + 1 .. Params'Last loop
-                exit when Salt.Status = Failure;
+                exit when Salt.Status = Failure or
+                    (Context.Allow_Incomplete and Salt.Status = Needs_More);
                 declare
                     function Cont_Param is new Continue (Params (I).all);
                 begin
@@ -773,6 +779,7 @@ package body Packrat.Parsers is
         begin
             Salt := Part_One (Input, Context, Start);
             Salt := Cont_Param (Salt, Input, Context);
+            Complete_Status (Salt, Context.Allow_Incomplete);
             return Salt;
         end Actual;
         function Memo is new Memoize (To_Key (Start, Sequence_2'Access), Actual);
@@ -816,11 +823,14 @@ package body Packrat.Parsers is
     is
         function Actual
                (Context : in out Parser_Context)
-            return Combinator_Result is
+            return Combinator_Result
+        is
+            Salt : Combinator_Result;
         begin
-            return Merge
-               (Choice_One (Input, Context, Start),
-                Choice_Two (Input, Context, Start));
+            Merge (Salt, Choice_One (Input, Context, Start));
+            Merge (Salt, Choice_Two (Input, Context, Start));
+            Complete_Status (Salt, Context.Allow_Incomplete);
+            return Salt;
         end Actual;
         function Memo is new Memoize (To_Key (Start, Choice_2'Access), Actual);
         function Curt is new Curtailment (To_Key (Start, Choice_2'Access), Input, Memo);
@@ -1128,7 +1138,11 @@ package body Packrat.Parsers is
             Part : Combo_Result_Part;
             Salt : Combinator_Result;
         begin
-            if Start <= Input'Last and then Test (Input (Start)) then
+            if Start > Input'Last then
+                if Context.Allow_Incomplete then
+                    Salt.Status := Needs_More;
+                end if;
+            elsif Test (Input (Start)) then
                 Part.Finish := Start;
                 Part.Value := Elem_Holds.To_Holder (Input (Start .. Start));
                 Salt.Results.Include (Part);
@@ -1155,7 +1169,11 @@ package body Packrat.Parsers is
             Part : Combo_Result_Part;
             Salt : Combinator_Result;
         begin
-            if Start <= Input'Last and then Test (Change (Input (Start))) then
+            if Start > Input'Last then
+                if Context.Allow_Incomplete then
+                    Salt.Status := Needs_More;
+                end if;
+            elsif Test (Change (Input (Start))) then
                 Part.Finish := Start;
                 Part.Value := Elem_Holds.To_Holder (Input (Start .. Start));
                 Salt.Results.Include (Part);
@@ -1183,7 +1201,11 @@ package body Packrat.Parsers is
             Part : Combo_Result_Part;
             Salt : Combinator_Result;
         begin
-            if Start <= Input'Last and then Input (Start) = Item then
+            if Start > Input'Last then
+                if Context.Allow_Incomplete then
+                    Salt.Status := Needs_More;
+                end if;
+            elsif Input (Start) = Item then
                 Part.Finish := Start;
                 Part.Value := Elem_Holds.To_Holder (Input (Start .. Start));
                 Salt.Results.Include (Part);
@@ -1211,7 +1233,11 @@ package body Packrat.Parsers is
             Part : Combo_Result_Part;
             Salt : Combinator_Result;
         begin
-            if Start <= Input'Last and then Change (Input (Start)) = Item then
+            if Start > Input'Last then
+                if Context.Allow_Incomplete then
+                    Salt.Status := Needs_More;
+                end if;
+            elsif Change (Input (Start)) = Item then
                 Part.Finish := Start;
                 Part.Value := Elem_Holds.To_Holder (Input (Start .. Start));
                 Salt.Results.Include (Part);
@@ -1239,7 +1265,11 @@ package body Packrat.Parsers is
             Part : Combo_Result_Part;
         begin
             if Start > Input'Last then
-                return Salt : Combinator_Result;
+                return Salt : Combinator_Result do
+                    if Context.Allow_Incomplete then
+                        Salt.Status := Needs_More;
+                    end if;
+                end return;
             elsif Items'Length = 0 then
                 return Empty (Input, Context, Start);
             end if;
@@ -1280,10 +1310,9 @@ package body Packrat.Parsers is
         is
             Part : Combo_Result_Part;
         begin
-            if Start > Input'Last then
-                return Salt : Combinator_Result;
-            end if;
-            if Input'Last - Start < Number - 1 then
+            if Start > Input'Last or else
+                Input'Last - Start < Number - 1
+            then
                 return Salt : Combinator_Result do
                     if Context.Allow_Incomplete then
                         Salt.Status := Needs_More;
@@ -1316,8 +1345,14 @@ package body Packrat.Parsers is
             Part : Combo_Result_Part;
             My_Finish : Positive := Start;
         begin
-            if Start > Input'Last or else not Test (Input (Start)) then
-                return Empty_Fail;
+            if Start > Input'Last then
+                return Salt : Combinator_Result do
+                    if Context.Allow_Incomplete then
+                        Salt.Status := Needs_More;
+                    end if;
+                end return;
+            elsif not Test (Input (Start)) then
+                return Salt : Combinator_Result;
             end if;
             while My_Finish <= Input'Last and then Test (Input (My_Finish)) loop
                 My_Finish := My_Finish + 1;
@@ -1350,8 +1385,14 @@ package body Packrat.Parsers is
             Part : Combo_Result_Part;
             My_Finish : Positive := Start;
         begin
-            if Start > Input'Last or else Test (Input (Start)) then
-                return Empty_Fail;
+            if Start > Input'Last then
+                return Salt : Combinator_Result do
+                    if Context.Allow_Incomplete then
+                        Salt.Status := Needs_More;
+                    end if;
+                end return;
+            elsif Test (Input (Start)) then
+                return Salt : Combinator_Result;
             end if;
             while My_Finish <= Input'Last and then not Test (Input (My_Finish)) loop
                 My_Finish := My_Finish + 1;
@@ -1405,6 +1446,13 @@ package body Packrat.Parsers is
             end if;
         end loop;
         Salt.Results.Assign (Adjust);
+        if Salt.Results.Is_Empty then
+            if Salt.Status = Success then
+                Salt.Status := Failure;
+            elsif Salt.Status = Optional_More then
+                Salt.Status := Needs_More;
+            end if;
+        end if;
         return Salt;
     end Not_Empty;
 
@@ -1416,7 +1464,13 @@ package body Packrat.Parsers is
         return Combinator_Result is
     begin
         if Start > Input'Last then
-            return Empty (Input, Context, Start);
+            if Context.Allow_Incomplete then
+                return Salt : Combinator_Result do
+                    Salt.Status := Needs_More;
+                end return;
+            else
+                return Empty (Input, Context, Start);
+            end if;
         else
             return Salt : Combinator_Result;
         end if;
-- 
cgit