Skip to content

Commit

Permalink
Merge branch 'topic/opt_parse_more' into 'master'
Browse files Browse the repository at this point in the history
More enhancements to Opt_Parse, for GNATcheck

See merge request eng/toolchain/gnatcoll-core!109
  • Loading branch information
raph-amiard committed Jun 13, 2024
2 parents 14ec587 + 6c21f91 commit 4ebe169
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 41 deletions.
95 changes: 59 additions & 36 deletions src/gnatcoll-opt_parse.adb
Original file line number Diff line number Diff line change
Expand Up @@ -490,12 +490,20 @@ package body GNATCOLL.Opt_Parse is
end Handle_Failure;

function Internal return Boolean is
use type Parsed_Arguments_Shared_Ptrs.Element_Access;
begin
Result.Ref.Set
(Parsed_Arguments_Type'
(Raw_Args => new XString_Array'(Cmd_Line_Args),
Results => new Parser_Result_Array
(1 .. Self.Data.All_Parsers.Last_Index)));
-- If we're not in incremental mode, then reset the results.
if not
(Self.Data.Incremental
and then Result.Ref.Unchecked_Get /= null)
then
Result.Ref.Set
(Parsed_Arguments_Type'
(Raw_Args => new XString_Array'(Cmd_Line_Args),
Results =>
new Parser_Result_Array
(1 .. Self.Data.All_Parsers.Last_Index)));
end if;

while Current_Arg <= Cmd_Line_Args'Last loop

Expand Down Expand Up @@ -529,7 +537,8 @@ package body GNATCOLL.Opt_Parse is
begin
declare
P_Return : constant Parser_Return :=
Pos_Parser.Parse (Cmd_Line_Args, Current_Arg, Result);
Pos_Parser.Parse
(Cmd_Line_Args, Current_Arg, Result);
begin
if P_Return /= Error_Return then
Current_Arg := Positive (P_Return);
Expand All @@ -539,8 +548,8 @@ package body GNATCOLL.Opt_Parse is
exception
when E : Opt_Parse_Error =>
Handle_Failure
("for parser " & (+Pos_Parser.Name) & " - "
& Ada.Exceptions.Exception_Message (E));
("for parser " & (+Pos_Parser.Name) & " - " &
Ada.Exceptions.Exception_Message (E));
return False;
end;
end loop;
Expand All @@ -550,7 +559,8 @@ package body GNATCOLL.Opt_Parse is
-- we encounter an unknown argument.
if Unknown_Args = null then
Handle_Failure
("Unrecognized argument " & (+Cmd_Line_Args (Current_Arg)));
("Unrecognized argument " &
(+Cmd_Line_Args (Current_Arg)));
return False;
else
Unknown_Args.Append (Cmd_Line_Args (Current_Arg));
Expand All @@ -561,7 +571,8 @@ package body GNATCOLL.Opt_Parse is
end loop;

for Parser of Self.Data.All_Parsers loop
if not Parser.Opt and then not Parser.Has_Result (Result) then
if not Parser.Opt and then not Parser.Has_Result (Result)
then
Handle_Failure ("Missing value for " & (+Parser.Name));
return False;
end if;
Expand All @@ -579,13 +590,6 @@ package body GNATCOLL.Opt_Parse is
end Internal;

begin
-- Reset the default result if we're using it
if Arguments = No_Arguments
and then Self.Data.Default_Result /= No_Parsed_Arguments
then
Self.Data.Default_Result := No_Parsed_Arguments;
end if;

return Ret : constant Boolean := Internal do
-- Print help if parsing has failed
if not Ret then
Expand All @@ -605,7 +609,9 @@ package body GNATCOLL.Opt_Parse is
Result : in out Parsed_Arguments) return Parser_Return
is
begin
if Self.Has_Result (Result) and then not Self.Does_Accumulate then
if Self.Has_Result (Result) and then not
(Self.Does_Accumulate or else Self.Parser.Incremental)
then
return Error_Return;
end if;

Expand Down Expand Up @@ -1215,13 +1221,12 @@ package body GNATCOLL.Opt_Parse is
Result : in out Parsed_Arguments) return Parser_Return
is
Res : Parser_Result_Access
renames Result.Ref.Get.Results (Self.Position);
renames Result.Ref.Unchecked_Get.Results (Self.Position);

Tmp : Internal_Result_Access := null;

Converted_Arg : Arg_Type;
Arg_Count : Natural := 0;

begin
if Accumulate then
declare
Expand Down Expand Up @@ -1288,9 +1293,11 @@ package body GNATCOLL.Opt_Parse is
----------------------------

function Create_Argument_Parser
(Help : String;
Command_Name : String := "";
Help_Column_Limit : Col_Type := 80) return Argument_Parser
(Help : String;
Command_Name : String := "";
Help_Column_Limit : Col_Type := 80;
Incremental : Boolean := False;
Generate_Help_Flag : Boolean := True) return Argument_Parser
is
XCommand_Name : constant XString :=
+(if Command_Name = ""
Expand All @@ -1302,19 +1309,26 @@ package body GNATCOLL.Opt_Parse is
begin
return Parser : Argument_Parser do
Parser.Data :=
new Argument_Parser_Data'(+Help, XCommand_Name, others => <>);
Parser.Data.Help_Flag := new Help_Flag_Parser'
(Name => +"help",
Help => +"Show this help message",
Position => <>,
Opt => True,
Parser => Parser.Data,
Short => +"-h",
Long => +"--help");
Parser.Data.Opts_Parsers.Append (Parser.Data.Help_Flag);
Parser.Data.All_Parsers.Append (Parser.Data.Help_Flag);
Parser.Data.Help_Flag.Position := Parser.Data.All_Parsers.Last_Index;
Parser.Data.Help_Column_Limit := Help_Column_Limit;
new Argument_Parser_Data'
(+Help, XCommand_Name,
Incremental => Incremental,
others => <>);

if Generate_Help_Flag then
Parser.Data.Help_Flag := new Help_Flag_Parser'
(Name => +"help",
Help => +"Show this help message",
Position => <>,
Opt => True,
Parser => Parser.Data,
Short => +"-h",
Long => +"--help");
Parser.Data.Opts_Parsers.Append (Parser.Data.Help_Flag);
Parser.Data.All_Parsers.Append (Parser.Data.Help_Flag);
Parser.Data.Help_Flag.Position
:= Parser.Data.All_Parsers.Last_Index;
Parser.Data.Help_Column_Limit := Help_Column_Limit;
end if;
end return;
end Create_Argument_Parser;

Expand All @@ -1327,6 +1341,15 @@ package body GNATCOLL.Opt_Parse is
return Self.Data.Last_Error.To_String;
end Last_Error;

-----------
-- Reset --
-----------

procedure Reset (Self : Argument_Parser) is
begin
Self.Data.Default_Result := No_Parsed_Arguments;
end Reset;

----------
-- Help --
----------
Expand Down
38 changes: 33 additions & 5 deletions src/gnatcoll-opt_parse.ads
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,29 @@ package GNATCOLL.Opt_Parse is
-------------------------------

function Create_Argument_Parser
(Help : String;
Command_Name : String := "";
Help_Column_Limit : Col_Type := 80) return Argument_Parser;
(Help : String;
Command_Name : String := "";
Help_Column_Limit : Col_Type := 80;
Incremental : Boolean := False;
Generate_Help_Flag : Boolean := True) return Argument_Parser;
-- Create an argument parser with the provided help string.
--
-- ``Command_Name`` refers to the name of your command/executable. This
-- will be used when generating the help string.
--
-- ``Help_Column_Limit`` is the number of columns you want the help string
-- to be formatted to.
--
-- ``Incremental`` activates the incremental mode. In this mode, you can
-- call ``Parse`` several times on your parser, with a given set of
-- ``Parsed_Arguments``, without those results being resetted every time.
-- Instead, results will be accumulated. The consequence is also that a
-- given argument can be passed several times without triggering an
-- error in ``Parse``. This is useful in the context of GNAT's tools,
-- where you often need to process arguments in several passes.
--
-- ``Generate_Help_Flag`` will condition the generation of the ``--help``
-- flag. Some tools might wish to deactivate it to handle it manually.

function Help (Self : Argument_Parser) return String;
-- Return the help for this parser as a String.
Expand All @@ -169,6 +188,11 @@ package GNATCOLL.Opt_Parse is
-- Return the last error produced by this parser if there is one, the empty
-- string otherwise.

procedure Reset (Self : Argument_Parser);
-- Reset the implicit default results for this parser. This is useful for
-- users who use the incremental mode, in conjunction with the implicit
-- default results.

------------------------
-- Parse entry points --
------------------------
Expand Down Expand Up @@ -591,7 +615,7 @@ private
subtype Parser_Vector is Parsers_Vectors.Vector;

type Argument_Parser_Data is record
Help, Command_Name : XString;
Help, Command_Name : XString;

Last_Error : XString;
-- Last error that was generated by the parser
Expand All @@ -604,8 +628,12 @@ private

Mutex : aliased Mutual_Exclusion;
-- Mutex used to make Get_Result thread safe
Help_Column_Limit : Col_Type := 80;

Help_Column_Limit : Col_Type := 80;

Incremental : Boolean := False;
-- Whether this parse is in incremental or normal mode. See the
-- documentation in `Create_Argument_Parser`.
end record;

type Parser_Result is abstract tagged record
Expand Down
33 changes: 33 additions & 0 deletions testsuite/tests/opt_parse/custom_help/test.adb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
with GNATCOLL.Opt_Parse; use GNATCOLL.Opt_Parse;
with GNATCOLL.Strings; use GNATCOLL.Strings;

with Test_Assert;

function Test return Integer is
package A renames Test_Assert;

function "+"
(Self : String) return XString renames To_XString;

package Arg is
Parser : Argument_Parser := Create_Argument_Parser
(Help => "Empty parser", Generate_Help_Flag => False);

package Help is new Parse_Flag
(Parser => Parser,
Short => "-h",
Long => "--help",
Help => "Custom help");

end Arg;
begin

if Arg.Parser.Parse ((1 => +"--help"))
then
A.Assert (Arg.Help.Get, "Custom help flag not triggered");
else
A.Assert (False, "Arg parsing failed, should have succeeded");
end if;

return A.Report;
end Test;
2 changes: 2 additions & 0 deletions testsuite/tests/opt_parse/custom_help/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
description:
Test the preservation of unknown arguments mechanism in Opt_Parse
103 changes: 103 additions & 0 deletions testsuite/tests/opt_parse/incremental/test.adb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
------------------------------------------------------------------------------
-- G N A T C O L L --
-- --
-- Copyright (C) 2010-2018, AdaCore --
-- --
-- This library is free software; you can redistribute it and/or modify it --
-- under terms of the GNU General Public License as published by the Free --
-- Software Foundation; either version 3, or (at your option) any later --
-- version. This library is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
-- --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception, --
-- version 3.1, as published by the Free Software Foundation. --
-- --
-- You should have received a copy of the GNU General Public License and --
-- a copy of the GCC Runtime Library Exception along with this program; --
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
-- <http://www.gnu.org/licenses/>. --
-- --
------------------------------------------------------------------------------

with GNATCOLL.Opt_Parse; use GNATCOLL.Opt_Parse;
with GNATCOLL.Strings; use GNATCOLL.Strings;

with Test_Assert;

function Test return Integer is
package A renames Test_Assert;

function "+"
(Self : String) return XString renames To_XString;

package Arg is
Parser : Argument_Parser := Create_Argument_Parser
(Help => "Test", Incremental => True);

package Numbers is new Parse_Option_List
(Parser => Parser,
Short => "-n",
Long => "--number",
Accumulate => True,
Arg_Type => Integer,
Help => "The numbers");

package Val is new Parse_Option
(Parser => Parser,
Short => "-v",
Long => "--value",
Arg_Type => Integer,
Default_Val => 0,
Help => "Value");

package Quiet is new Parse_Flag
(Parser => Parser,
Short => "-q",
Long => "--quiet",
Help => "Whether the tool should be quiet or not");

end Arg;

use type Arg.Numbers.Result_Array;

pragma Extensions_Allowed (On);
begin

if Arg.Parser.Parse
((+"-v", +"12", +"--number", +"219", +"-v",
+"15", +"-q", +"-q"))
then
A.Assert (Arg.Numbers.Get = (1 => 219), "Wrong num array");
A.Assert (Arg.Val.Get = 15, "Wrong value");
A.Assert (Arg.Quiet.Get, "Wrong value");
else
A.Assert (False, "Argument parsing failed");
end if;

if Arg.Parser.Parse
((+"-n", +"25", +"-n", +"28"))
then
A.Assert (Arg.Numbers.Get = (219, 25, 28),
"Wrong num array: " & Arg.Numbers.Get'Image);
A.Assert (Arg.Val.Get = 15, "Wrong value");
else
A.Assert (False, "Argument parsing failed");
end if;

-- After this call, the parser's defaut results should be reset
Arg.Parser.Reset;
if Arg.Parser.Parse
((+"-n", +"25", +"-n", +"28"))
then
A.Assert (Arg.Numbers.Get = (25, 28),
"Wrong num array: " & Arg.Numbers.Get'Image);
A.Assert (Arg.Val.Get = 0, "Wrong value");
else
A.Assert (False, "Argument parsing failed");
end if;

return A.Report;

end Test;
2 changes: 2 additions & 0 deletions testsuite/tests/opt_parse/incremental/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
description:
Test Opt_Parse's incremental mode

0 comments on commit 4ebe169

Please sign in to comment.