package body Packrat.Lexer.Combinators is 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 := Result.Join (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 := Result.Join (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 Temp := Param (Input, Position); exit when Temp.Status = Failure; if Temp.Status = Needs_More then Result.Status := Optional_More; exit; end if; Result := Result.Join (Temp); Counter := Counter + 1; Position := Start + Result.Length; if Position > Input'Last then Result.Status := Optional_More; exit; end if; end loop; if Counter < Minimum then if Result.Status = Optional_More then Result.Status := Needs_More; else Result.Status := Failure; end if; end if; return Result; end Many; function Many_Until (Input : in Element_Array; Start : in Positive) return Combinator_Result is begin return Empty_Fail; 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.Combinators;