diff options
Diffstat (limited to 'src/packrat-lexer.adb')
-rw-r--r-- | src/packrat-lexer.adb | 387 |
1 files changed, 338 insertions, 49 deletions
diff --git a/src/packrat-lexer.adb b/src/packrat-lexer.adb index 614452b..e1765d9 100644 --- a/src/packrat-lexer.adb +++ b/src/packrat-lexer.adb @@ -46,6 +46,33 @@ package body Packrat.Lexer is + function "=" + (Left, Right : in Combinator_Result) + return Boolean + is + Left_Valsize, Right_Valsize : Natural; + begin + if Left.Value = null then + Left_Valsize := 0; + else + Left_Valsize := Left.Value.all'Length; + end if; + if Right.Value = null then + Right_Valsize := 0; + else + Right_Valsize := Right.Value.all'Length; + end if; + + return Left.Length = Right.Length and + Left.Status = Right.Status and + Left_Valsize = Right_Valsize and + (Left_Valsize = 0 or else Left.Value.all = Right.Value.all); + end "="; + + + + + function Create_Result (Length : in Natural; Status : in Result_Status; @@ -104,55 +131,6 @@ package body Packrat.Lexer is end Join; - function "=" - (Left, Right : in Combinator_Result) - return Boolean - is - Left_Valsize, Right_Valsize : Natural; - begin - if Left.Value = null then - Left_Valsize := 0; - else - Left_Valsize := Left.Value.all'Length; - end if; - if Right.Value = null then - Right_Valsize := 0; - else - Right_Valsize := Right.Value.all'Length; - end if; - - return Left.Length = Right.Length and - Left.Status = Right.Status and - Left_Valsize = Right_Valsize and - (Left_Valsize = 0 or else Left.Value.all = Right.Value.all); - end "="; - - - function Status - (This : in Combinator_Result) - return Result_Status is - begin - return This.Status; - end Status; - - - function Debug_String - (This : in Combinator_Result) - return String - is - Value_Length : Natural; - begin - if This.Value = null then - Value_Length := 0; - else - Value_Length := This.Value.all'Length; - end if; - return Integer'Image (This.Length) - & " " & Result_Status'Image (This.Status) - & " " & Integer'Image (Value_Length); - end Debug_String; - - @@ -233,6 +211,317 @@ package body Packrat.Lexer is end Scan_Set_With; + + + + function Sequence + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result + is + Result : Combinator_Result := Create_Result (0, Success, Empty_Array); + Position : Positive := Start; + begin + if Start > Input'Last then + return Empty_Fail; + end if; + for C of Params loop + if Position > Input'Last then + Result.Status := Needs_More; + exit; + end if; + Result := Join (Result, C (Input, Position)); + exit when Result.Status = Failure; + Position := Start + Result.Length; + end loop; + return Result; + end Sequence; + + + function Count + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result + is + Result : Combinator_Result := Create_Result (0, Success, Empty_Array); + Position : Positive := Start; + begin + if Start > Input'Last then + return Empty_Fail; + end if; + for I in Integer range 1 .. Number loop + if Position > Input'Last then + Result.Status := Needs_More; + exit; + end if; + Result := Join (Result, Param (Input, Position)); + exit when Result.Status = Failure; + Position := Start + Result.Length; + end loop; + return Result; + end Count; + + + function Many + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result + is + Result : Combinator_Result := Create_Result (0, Success, Empty_Array); + Temp : Combinator_Result; + Position : Positive := Start; + Counter : Natural := 0; + begin + if Start > Input'Last then + return Empty_Fail; + end if; + loop + exit when Position > Input'Last; + Temp := Param (Input, Position); + exit when Temp.Status = Failure or Temp.Status = Needs_More; + Result := Join (Result, Temp); + Counter := Counter + 1; + Position := Start + Result.Length; + end loop; + if Counter < Minimum then + if Position > Input'Last or Temp.Status = Needs_More then + Result.Status := Needs_More; + else + Result.Status := Failure; + end if; + elsif Position > Input'Last or Temp.Status = Needs_More then + Result.Status := Optional_More; + else + Result.Status := Success; + end if; + return Result; + end Many; + + + function Many_Until + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result + is + Result : Combinator_Result := Create_Result (0, Success, Empty_Array); + Temp : Combinator_Result; + Position : Positive := Start; + Counter : Natural := 0; + begin + if Start > Input'Last then + return Empty_Fail; + end if; + loop + exit when Position > Input'Last; + Temp := Param (Input, Position); + exit when Temp.Status = Failure or Temp.Status = Needs_More or Test (Input (Position)); + Result := Join (Result, Temp); + Counter := Counter + 1; + Position := Start + Result.Length; + end loop; + if Counter < Minimum then + if Position > Input'Last or Temp.Status = Needs_More then + Result.Status := Needs_More; + else + Result.Status := Failure; + end if; + elsif Position > Input'Last then + Result.Status := Needs_More; + elsif Temp.Status = Needs_More and Test (Input (Position)) then + Result.Status := Optional_More; + elsif Test (Input (Position)) then + Result.Status := Success; + else + Result.Status := Failure; + end if; + return Result; + end Many_Until; + + + + + + function Satisfy + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result is + begin + if Start > Input'Last then + return Empty_Fail; + elsif Test (Input (Start)) then + return Create_Result (1, Success, (1 => Input (Start))); + else + return Empty_Fail; + end if; + end Satisfy; + + + function Satisfy_With + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result is + begin + if Start > Input'Last then + return Empty_Fail; + elsif Test (Change (Input (Start))) then + return Create_Result (1, Success, (1 => Input (Start))); + else + return Empty_Fail; + end if; + end Satisfy_With; + + + function Match + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result is + begin + if Start > Input'Last then + return Empty_Fail; + elsif Input (Start) = Item then + return Create_Result (1, Success, (1 => Item)); + else + return Empty_Fail; + end if; + end Match; + + + function Match_With + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result is + begin + if Start > Input'Last then + return Empty_Fail; + elsif Change (Input (Start)) = Item then + return Create_Result (1, Success, (1 => Input (Start))); + else + return Empty_Fail; + end if; + end Match_With; + + + function Multimatch + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result + is + Current_Offset : Natural := 0; + begin + if Items'Length = 0 then + return Create_Result (0, Success, Empty_Array); + end if; + + if Input'Last - Start + 1 <= 0 then + return Empty_Fail; + end if; + + while Input (Start + Current_Offset) = Items (Items'First + Current_Offset) loop + if Items'First + Current_Offset = Items'Last then + return Create_Result (Current_Offset + 1, Success, Items); + elsif Start + Current_Offset = Input'Last then + return Create_Result (Current_Offset + 1, Needs_More, Input (Start .. Input'Last)); + end if; + Current_Offset := Current_Offset + 1; + end loop; + return Create_Result (Current_Offset, Failure, Input (Start .. Start + Current_Offset - 1)); + end Multimatch; + + + function Take + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result is + begin + if Start > Input'Last then + return Empty_Fail; + elsif Start + Number - 1 > Input'Last then + return Create_Result (Input'Last - Start + 1, Needs_More, Input (Start .. Input'Last)); + else + return Create_Result (Number, Success, Input (Start .. Start + Number - 1)); + end if; + end Take; + + + function Take_While + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result + is + Finish : Positive := Start; + Status : Result_Status; + begin + if Start > Input'Last or else not Test (Input (Start)) then + return Empty_Fail; + end if; + while Finish <= Input'Last and then Test (Input (Finish)) loop + Finish := Finish + 1; + end loop; + if Finish > Input'Last then + Status := Optional_More; + else + Status := Success; + end if; + return Create_Result (Finish - Start, Status, Input (Start .. Finish - 1)); + end Take_While; + + + function Take_Until + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result + is + Finish : Positive := Start; + Status : Result_Status; + begin + if Start > Input'Last or else Test (Input (Start)) then + return Empty_Fail; + end if; + while Finish <= Input'Last and then not Test (Input (Finish)) loop + Finish := Finish + 1; + end loop; + if Finish > Input'Last then + Status := Optional_More; + else + Status := Success; + end if; + return Create_Result (Finish - Start, Status, Input (Start .. Finish - 1)); + end Take_Until; + + + + + + function Line_End + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result is + begin + if Start > Input'Last then + return Empty_Fail; + elsif Input (Start) = EOL_Item then + return Create_Result (1, Success, (1 => EOL_Item)); + else + return Empty_Fail; + end if; + end Line_End; + + + function Input_End + (Input : in Element_Array; + Start : in Positive) + return Combinator_Result is + begin + if Start > Input'Last then + return Empty_Fail; + elsif Input (Start) = EOF_Item then + return Create_Result (1, Success, (1 => EOF_Item)); + else + return Empty_Fail; + end if; + end Input_End; + + end Packrat.Lexer; |