summaryrefslogtreecommitdiff
path: root/src/packrat-parsers.adb
diff options
context:
space:
mode:
authorJed Barber <jjbarber@y7mail.com>2020-12-10 23:21:56 +1100
committerJed Barber <jjbarber@y7mail.com>2020-12-10 23:21:56 +1100
commitfb29719b1ce83fca511c1f310b388e0af65da257 (patch)
treefefae45466cc2e4e3f48c24b22b1ae1723942219 /src/packrat-parsers.adb
parent63f9f901a3c2345411b201c86dceceb4807fb974 (diff)
Bugfixes and extra parser combinators
Diffstat (limited to 'src/packrat-parsers.adb')
-rw-r--r--src/packrat-parsers.adb295
1 files changed, 240 insertions, 55 deletions
diff --git a/src/packrat-parsers.adb b/src/packrat-parsers.adb
index 60102f4..875a765 100644
--- a/src/packrat-parsers.adb
+++ b/src/packrat-parsers.adb
@@ -324,7 +324,7 @@ package body Packrat.Parsers is
Adjust.Clear;
for N of Temp.Results loop
Adjust.Include
- ((Finish => N.Finish,
+ ((Finish => Integer'Max (R.Finish, N.Finish),
Value => Elem_Holds.To_Holder (Element (R.Value) & Element (N.Value)),
Tokens => Tok_Holds.To_Holder (Element (R.Tokens) & Element (N.Tokens))));
end loop;
@@ -431,6 +431,9 @@ package body Packrat.Parsers is
end Finish_Root;
+
+
+
package body Parse_Parts is
Context : Parser_Context := Empty_Context;
@@ -601,13 +604,6 @@ package body Packrat.Parsers is
Salt : Combinator_Result := Combo (Input, Context, Start);
Processed : Result_Sets.Set;
begin
- if Salt.Status = Failure then
- Ada.Strings.Unbounded.Append
- (Context.Error_String,
- Packrat.Errors.Encode (Traits.Label_Enum'Image (Label), Start));
- else
- Context.Error_String := +"";
- end if;
for R of Salt.Results loop
Processed.Include
((Finish => R.Finish,
@@ -691,6 +687,32 @@ package body Packrat.Parsers is
end Sequence;
+ -- This exists purely to get around errors that would otherwise
+ -- result from using Sequence internally due to the access types.
+ function Sequence_2
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result
+ is
+ function Actual
+ (Context : in out Parser_Context)
+ return Combinator_Result
+ is
+ function Cont_Param is new Continue (Part_Two);
+ Salt : Combinator_Result;
+ begin
+ Salt := Part_One (Input, Context, Start);
+ Salt := Cont_Param (Salt, Input, Context);
+ return Salt;
+ end Actual;
+ function Curt is new Curtailment (To_Key (Start, Sequence_2'Access), Input, Actual);
+ function Memo is new Memoize (To_Key (Start, Sequence_2'Access), Curt);
+ begin
+ return Memo (Context);
+ end Sequence_2;
+
+
function Choice
(Input : in Traits.Element_Array;
Context : in out Parser_Context;
@@ -721,6 +743,28 @@ package body Packrat.Parsers is
end Choice;
+ -- This exists because otherwise Sequence_2 would look weird.
+ function Choice_2
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result
+ is
+ function Actual
+ (Context : in out Parser_Context)
+ return Combinator_Result is
+ begin
+ return Merge
+ (Choice_One (Input, Context, Start),
+ Choice_Two (Input, Context, Start));
+ end Actual;
+ function Curt is new Curtailment (To_Key (Start, Choice_2'Access), Input, Actual);
+ function Memo is new Memoize (To_Key (Start, Choice_2'Access), Curt);
+ begin
+ return Memo (Context);
+ end Choice_2;
+
+
function Count
(Input : in Traits.Element_Array;
Context : in out Parser_Context;
@@ -742,6 +786,13 @@ package body Packrat.Parsers is
while Salt.Status /= Failure loop
Counter := Counter + 1;
exit when Counter = Number;
+ if Salt.Status = Optional_More or Salt.Status = Needs_More or
+ (for some P of Salt.Results => P.Finish = Input'Last)
+ then
+ Salt.Results.Clear;
+ Salt.Status := Needs_More;
+ exit;
+ end if;
Salt := Cont_Param (Salt, Input, Context);
end loop;
Complete_Status (Salt, Context.Allow_Incomplete);
@@ -770,7 +821,7 @@ package body Packrat.Parsers is
Counter : Natural := 0;
begin
if Start > Input'Last then
- return Empty_Fail;
+ return Salt;
end if;
if Minimum = 0 then
Merge (Salt, Empty (Input, Context, Start));
@@ -780,7 +831,15 @@ package body Packrat.Parsers is
Counter := Counter + 1;
if Counter >= Minimum then
Merge (Salt, Temp);
- elsif Temp.Status = Optional_More or Temp.Status = Needs_More then
+ if Temp.Status = Optional_More or Temp.Status = Needs_More or
+ (for some P of Temp.Results => P.Finish = Input'Last)
+ then
+ Salt.Status := Optional_More;
+ exit;
+ end if;
+ elsif Temp.Status = Optional_More or Temp.Status = Needs_More or
+ (for some P of Temp.Results => P.Finish = Input'Last)
+ then
Salt.Status := Needs_More;
exit;
end if;
@@ -796,6 +855,75 @@ package body Packrat.Parsers is
end Many;
+ function Followed_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result
+ is
+ function Actual
+ (Context : in out Parser_Context)
+ return Combinator_Result is
+ begin
+ case Param (Input, Context, Start).Status is
+ when Success | Optional_More =>
+ return Empty (Input, Context, Start);
+ when Needs_More =>
+ return Salt : Combinator_Result do
+ if Context.Allow_Incomplete then
+ Salt.Status := Needs_More;
+ end if;
+ end return;
+ when Failure =>
+ return Salt : Combinator_Result do
+ if Context.Allow_Incomplete and Start > Input'Last then
+ Salt.Status := Needs_More;
+ end if;
+ end return;
+ end case;
+ end Actual;
+ function Curt is new Curtailment (To_Key (Start, Followed_By'Access), Input, Actual);
+ function Memo is new Memoize (To_Key (Start, Followed_By'Access), Curt);
+ begin
+ return Memo (Context);
+ end Followed_By;
+
+
+ function Not_Followed_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result
+ is
+ function Actual
+ (Context : in out Parser_Context)
+ return Combinator_Result is
+ begin
+ case Param (Input, Context, Start).Status is
+ when Success | Optional_More =>
+ return Salt : Combinator_Result;
+ when Needs_More =>
+ if Context.Allow_Incomplete then
+ return Salt : Combinator_Result do
+ Salt.Status := Needs_More;
+ end return;
+ else
+ return Empty (Input, Context, Start);
+ end if;
+ when Failure =>
+ return Empty (Input, Context, Start);
+ end case;
+ end Actual;
+ function Curt is new Curtailment (To_Key (Start, Not_Followed_By'Access), Input, Actual);
+ function Memo is new Memoize (To_Key (Start, Not_Followed_By'Access), Curt);
+ begin
+ return Memo (Context);
+ end Not_Followed_By;
+
+
+
+
+
function Many_Until
(Input : in Traits.Element_Array;
Context : in out Parser_Context;
@@ -806,41 +934,11 @@ package body Packrat.Parsers is
(Context : in out Parser_Context)
return Combinator_Result
is
- function Not_Empty_Param is new Not_Empty (Param);
- function Cont_Param is new Continue (Not_Empty_Param);
- Salt, Temp : Combinator_Result;
- Adjust : Result_Sets.Set;
- Counter : Natural := 0;
+ function Not_Till is new Not_Followed_By (Test);
+ function Till is new Followed_By (Test);
+ function Sep_End_By is new Separate_End_By (Param, Not_Till, Till, Minimum);
begin
- if Start > Input'Last then
- return Empty_Fail;
- end if;
- if Minimum = 0 then
- Merge (Salt, Empty (Input, Context, Start));
- end if;
- if Test (Input (Start)) then
- return Salt;
- end if;
- Temp := Not_Empty_Param (Input, Context, Start);
- while Temp.Status /= Failure loop
- Counter := Counter + 1;
- if Counter >= Minimum then
- Merge (Salt, Temp);
- elsif Temp.Status = Optional_More or Temp.Status = Needs_More then
- Salt.Status := Needs_More;
- exit;
- end if;
- Adjust.Clear;
- for R of Temp.Results loop
- if R.Finish = Input'Last or else not Test (Input (R.Finish + 1)) then
- Adjust.Include (R);
- end if;
- end loop;
- Temp.Results.Assign (Adjust);
- Temp := Cont_Param (Temp, Input, Context);
- end loop;
- Complete_Status (Salt, Context.Allow_Incomplete);
- return Salt;
+ return Sep_End_By (Input, Context, Start);
end Actual;
function Curt is new Curtailment (To_Key (Start, Many_Until'Access), Input, Actual);
function Memo is new Memoize (To_Key (Start, Many_Until'Access), Curt);
@@ -876,6 +974,81 @@ package body Packrat.Parsers is
end Optional;
+ function Separate_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result
+ is
+ function Actual
+ (Context : in out Parser_Context)
+ return Combinator_Result
+ is
+ function Not_Empty_Item is new Not_Empty (Item);
+ function Sep_Seq is new Sequence_2 (Separator, Not_Empty_Item);
+ function Many_Sep_Seq is new Many
+ (Sep_Seq, (if Minimum = 0 then Minimum else Minimum - 1));
+ function Full_Seq is new Sequence_2 (Not_Empty_Item, Many_Sep_Seq);
+ begin
+ if Minimum = 0 then
+ return Merge (Empty (Input, Context, Start), Full_Seq (Input, Context, Start));
+ else
+ return Full_Seq (Input, Context, Start);
+ end if;
+ end Actual;
+ function Curt is new Curtailment (To_Key (Start, Separate_By'Access), Input, Actual);
+ function Memo is new Memoize (To_Key (Start, Separate_By'Access), Curt);
+ begin
+ return Memo (Context);
+ end Separate_By;
+
+
+ function Separate_End_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result
+ is
+ function Actual
+ (Context : in out Parser_Context)
+ return Combinator_Result
+ is
+ function Sep_By is new Separate_By (Item, Separator, Minimum);
+ function End_Seq is new Sequence_2 (Sep_By, Ender);
+ begin
+ return End_Seq (Input, Context, Start);
+ end Actual;
+ function Curt is new Curtailment (To_Key (Start, Separate_End_By'Access), Input, Actual);
+ function Memo is new Memoize (To_Key (Start, Separate_End_By'Access), Curt);
+ begin
+ return Memo (Context);
+ end Separate_End_By;
+
+
+ function Between
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result
+ is
+ function Actual
+ (Context : in out Parser_Context)
+ return Combinator_Result
+ is
+ function Ignore_Start is new Ignore (Starter);
+ function Ignore_End is new Ignore (Ender);
+ function Part_Seq is new Sequence_2 (Ignore_Start, Item);
+ function Full_Seq is new Sequence_2 (Part_Seq, Ignore_End);
+ begin
+ return Full_Seq (Input, Context, Start);
+ end Actual;
+ function Curt is new Curtailment (To_Key (Start, Between'Access), Input, Actual);
+ function Memo is new Memoize (To_Key (Start, Between'Access), Curt);
+ begin
+ return Memo (Context);
+ end Between;
+
+
@@ -1045,24 +1218,22 @@ package body Packrat.Parsers is
return Combinator_Result
is
Part : Combo_Result_Part;
- My_Offset : Natural;
begin
if Start > Input'Last then
- return Empty_Fail;
+ return Salt : Combinator_Result;
end if;
if Input'Last - Start < Number - 1 then
- if not Context.Allow_Incomplete then
- return Empty_Fail;
- end if;
- My_Offset := Input'Last - Start;
- else
- My_Offset := Number - 1;
+ return Salt : Combinator_Result do
+ if Context.Allow_Incomplete then
+ Salt.Status := Needs_More;
+ end if;
+ end return;
end if;
return Salt : Combinator_Result do
- Part.Finish := Start + My_Offset;
- Part.Value := Elem_Holds.To_Holder (Input (Start .. Start + My_Offset));
+ Part.Finish := Start + Number - 1;
+ Part.Value := Elem_Holds.To_Holder (Input (Start .. Start + Number - 1));
Salt.Results.Include (Part);
- Salt.Status := (if My_Offset < Number - 1 then Needs_More else Success);
+ Salt.Status := Success;
end return;
end Actual;
function Call is new Memoize (To_Key (Start, Take'Access), Actual);
@@ -1177,6 +1348,20 @@ package body Packrat.Parsers is
end Not_Empty;
+ function End_Of_Input
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result is
+ begin
+ if Start > Input'Last then
+ return Empty (Input, Context, Start);
+ else
+ return Salt : Combinator_Result;
+ end if;
+ end End_Of_Input;
+
+
end Packrat.Parsers;