summaryrefslogtreecommitdiff
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
parent63f9f901a3c2345411b201c86dceceb4807fb974 (diff)
Bugfixes and extra parser combinators
-rw-r--r--src/packrat-parse_graphs.adb1
-rw-r--r--src/packrat-parsers.adb295
-rw-r--r--src/packrat-parsers.ads137
3 files changed, 375 insertions, 58 deletions
diff --git a/src/packrat-parse_graphs.adb b/src/packrat-parse_graphs.adb
index 99ce360..434c0a0 100644
--- a/src/packrat-parse_graphs.adb
+++ b/src/packrat-parse_graphs.adb
@@ -246,6 +246,7 @@ package body Packrat.Parse_Graphs is
SU.Append (Result, Latin.LF & Latin.LF);
end loop;
SU.Delete (Result, SU.Length (Result) - 1, SU.Length (Result));
+ SU.Append (Result, Latin.LF);
return SU.To_String (Result);
end Debug_String;
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;
diff --git a/src/packrat-parsers.ads b/src/packrat-parsers.ads
index 03b262c..a98170f 100644
--- a/src/packrat-parsers.ads
+++ b/src/packrat-parsers.ads
@@ -113,7 +113,6 @@ package Packrat.Parsers is
return Combinator_Result;
generic
- Label : in Traits.Label_Enum;
with function Combo
(Input : in Traits.Element_Array;
Context : in out Parser_Context;
@@ -154,6 +153,23 @@ package Packrat.Parsers is
return Combinator_Result;
generic
+ with function Part_One
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ with function Part_Two
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ function Sequence_2
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
+ generic
Params : in Combinator_Array;
function Choice
(Input : in Traits.Element_Array;
@@ -162,6 +178,23 @@ package Packrat.Parsers is
return Combinator_Result;
generic
+ with function Choice_One
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ with function Choice_Two
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ function Choice_2
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
+ generic
with function Param
(Input : in Traits.Element_Array;
Context : in out Parser_Context;
@@ -193,9 +226,38 @@ package Packrat.Parsers is
Context : in out Parser_Context;
Start : in Positive)
return Combinator_Result;
+ function Followed_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
+ generic
+ with function Param
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ function Not_Followed_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
+
+
+
+ generic
+ with function Param
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
with function Test
- (Item : in Traits.Element_Type)
- return Boolean;
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
Minimum : in Natural := 0;
function Many_Until
(Input : in Traits.Element_Array;
@@ -215,6 +277,69 @@ package Packrat.Parsers is
Start : in Positive)
return Combinator_Result;
+ generic
+ with function Item
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ with function Separator
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ Minimum : in Natural := 0;
+ function Separate_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
+ generic
+ with function Item
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ with function Separator
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ with function Ender
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ Minimum : in Natural := 0;
+ function Separate_End_By
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
+ generic
+ with function Starter
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ with function Item
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ with function Ender
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+ function Between
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
@@ -317,6 +442,12 @@ package Packrat.Parsers is
Start : in Positive)
return Combinator_Result;
+ function End_Of_Input
+ (Input : in Traits.Element_Array;
+ Context : in out Parser_Context;
+ Start : in Positive)
+ return Combinator_Result;
+
private