mirror of https://github.com/briot/gnatbdd
320 lines
12 KiB
Ada
320 lines
12 KiB
Ada
-----------------------------------------------------------------------------
|
|
-- G N A T C O L L --
|
|
-- --
|
|
-- Copyright (C) 2014, 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.Traces; use GNATCOLL.Traces;
|
|
with GNATCOLL.Utils; use GNATCOLL.Utils;
|
|
|
|
package body BDD.Parser is
|
|
Me : constant Trace_Handle := Create ("BDD.PARSER");
|
|
|
|
-----------
|
|
-- Parse --
|
|
-----------
|
|
|
|
procedure Parse
|
|
(Self : Feature_Parser;
|
|
File : GNATCOLL.VFS.Virtual_File;
|
|
Runner : in out Abstract_Feature_Runner'Class)
|
|
is
|
|
pragma Unreferenced (Self);
|
|
|
|
type State_Type is (None, In_Feature,
|
|
In_Scenario,
|
|
In_String,
|
|
In_Outline, In_Examples);
|
|
State : State_Type := None;
|
|
F : Feature;
|
|
Scenar : Scenario;
|
|
Buffer : GNAT.Strings.String_Access := File.Read_File;
|
|
Seen_Scenar : Boolean := False; -- Whether we have one scenario in F
|
|
Index : Integer := Buffer'First;
|
|
Line : Natural := 0;
|
|
Index_In_Feature : Natural := 0;
|
|
String_Indent : Natural := 0; -- indentation of the mutli-line string
|
|
Line_S, Line_E : Integer; -- extents of the current line
|
|
First_Char : Integer; -- first non-blank character in line
|
|
String_Line_Start : Integer; -- first line of multi-line string
|
|
|
|
procedure Finish_Scenario;
|
|
procedure Finish_Feature;
|
|
-- Called when the end of a scenario or a feature are seen
|
|
|
|
function Get_Line_End (After : Positive) return String;
|
|
-- Return the line text after the given character
|
|
|
|
---------------------
|
|
-- Finish_Scenario --
|
|
---------------------
|
|
|
|
procedure Finish_Scenario is
|
|
begin
|
|
case State is
|
|
when In_Scenario | In_Outline | In_Examples =>
|
|
Runner.Scenario_End (F, Scenar);
|
|
Free (Scenar);
|
|
State := In_Feature;
|
|
Seen_Scenar := True;
|
|
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end Finish_Scenario;
|
|
|
|
--------------------
|
|
-- Finish_Feature --
|
|
--------------------
|
|
|
|
procedure Finish_Feature is
|
|
begin
|
|
Finish_Scenario;
|
|
if State /= None then
|
|
Runner.Feature_End (F);
|
|
Free (F);
|
|
end if;
|
|
|
|
State := None;
|
|
Seen_Scenar := False;
|
|
end Finish_Feature;
|
|
|
|
------------------
|
|
-- Get_Line_End --
|
|
------------------
|
|
|
|
function Get_Line_End (After : Positive) return String is
|
|
begin
|
|
if After <= Line_E then
|
|
return Buffer (After .. Line_E);
|
|
else
|
|
return "";
|
|
end if;
|
|
end Get_Line_End;
|
|
|
|
begin
|
|
Trace (Me, "Parsing " & File.Display_Full_Name);
|
|
|
|
while Index < Buffer'Last loop
|
|
Line_S := Index;
|
|
Line_E := Line_End (Buffer.all, Line_S);
|
|
|
|
Index := Line_E + 1;
|
|
if Buffer (Index) = ASCII.CR then
|
|
Index := Index + 1;
|
|
end if;
|
|
if Buffer (Index) = ASCII.LF then
|
|
Index := Index + 1;
|
|
end if;
|
|
|
|
Line := Line + 1;
|
|
|
|
if Active (Me) then
|
|
Trace (Me, "Line " & Image (Line, 3, Padding => ' ')
|
|
& " " & Buffer (Line_S .. Line_E));
|
|
end if;
|
|
|
|
First_Char := Line_S;
|
|
Skip_Blanks (Buffer (Line_S .. Line_E), First_Char);
|
|
|
|
if Starts_With (Buffer (First_Char .. Line_E), """""""") then
|
|
if State = In_String then
|
|
State := In_Scenario;
|
|
elsif State = In_Scenario then
|
|
State := In_String;
|
|
String_Indent := First_Char - Line_S;
|
|
String_Line_Start := Line;
|
|
else
|
|
raise Syntax_Error with "Multi-line strings only allowed in"
|
|
& " steps, at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
end if;
|
|
|
|
elsif State = In_String then
|
|
if First_Char < Line_S + String_Indent - 1 then
|
|
Trace (Me, "MANU String="
|
|
& Buffer (First_Char .. Line_E));
|
|
elsif Line_S + String_Indent - 1 <= Line_E then
|
|
Trace (Me, "MANU String="
|
|
& Buffer (Line_S + String_Indent - 1 .. Line_E));
|
|
else
|
|
Trace (Me, "MANU String=");
|
|
end if;
|
|
|
|
elsif First_Char > Line_E then
|
|
-- ignore blank lines
|
|
null;
|
|
|
|
elsif Buffer (First_Char) = '|' then
|
|
case State is
|
|
when In_Scenario | In_Outline =>
|
|
Trace (Me, "MANU Table=" & Buffer (First_Char .. Line_E));
|
|
|
|
when In_Examples =>
|
|
Trace (Me, "MANU Example=" & Buffer (First_Char .. Line_E));
|
|
|
|
when others =>
|
|
raise Syntax_Error with "Tables only allowed in"
|
|
& " steps, at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
end case;
|
|
|
|
elsif Buffer (First_Char) = '@' then
|
|
-- ??? parse tags
|
|
null;
|
|
|
|
elsif Buffer (First_Char) = '#' then
|
|
-- Ignore comment lines
|
|
null;
|
|
|
|
elsif Starts_With (Buffer (First_Char .. Line_E), Cst_Features) then
|
|
Finish_Feature;
|
|
F.Set_File (File);
|
|
F.Set_Name (Buffer (First_Char + Cst_Features'Length .. Line_E));
|
|
Runner.Feature_Start (F);
|
|
Index_In_Feature := 0;
|
|
State := In_Feature;
|
|
|
|
elsif Starts_With (Buffer (First_Char .. Line_E), Cst_Background) then
|
|
if State = None then
|
|
raise Syntax_Error with "Background must be defined within a"
|
|
& " Feature at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
end if;
|
|
|
|
if Seen_Scenar then
|
|
raise Syntax_Error with "Background must be defined before all"
|
|
& " Scenario, at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
end if;
|
|
|
|
Finish_Scenario;
|
|
Scenar.Set_Attributes
|
|
(Name => Get_Line_End (First_Char + Cst_Background'Length),
|
|
Kind => Kind_Background,
|
|
Line => Line,
|
|
Index => Positive'Last);
|
|
Runner.Scenario_Start (F, Scenar);
|
|
State := In_Scenario;
|
|
|
|
elsif Starts_With (Buffer (First_Char .. Line_E), Cst_Scenario) then
|
|
if State = None then
|
|
raise Syntax_Error with "Scenario must be defined within a"
|
|
& " Feature at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
end if;
|
|
|
|
Finish_Scenario;
|
|
Index_In_Feature := Index_In_Feature + 1;
|
|
Scenar.Set_Attributes
|
|
(Name => Get_Line_End (First_Char + Cst_Scenario'Length),
|
|
Kind => Kind_Scenario,
|
|
Line => Line,
|
|
Index => Index_In_Feature);
|
|
Runner.Scenario_Start (F, Scenar);
|
|
State := In_Scenario;
|
|
|
|
elsif Starts_With (Buffer (First_Char .. Line_E),
|
|
Cst_Scenario_Outline)
|
|
then
|
|
if State = None then
|
|
raise Syntax_Error with
|
|
"Scenario Outline must be defined within a Feature at "
|
|
& File.Display_Full_Name & ":" & Image (Line, 1);
|
|
end if;
|
|
|
|
Finish_Scenario;
|
|
Index_In_Feature := Index_In_Feature + 1;
|
|
Scenar.Set_Attributes
|
|
(Name => Get_Line_End (First_Char + Cst_Scenario_Outline'Length),
|
|
Kind => Kind_Outline,
|
|
Line => Line,
|
|
Index => Index_In_Feature);
|
|
Runner.Scenario_Start (F, Scenar);
|
|
State := In_Outline;
|
|
|
|
elsif Starts_With (Buffer (First_Char .. Line_E), Cst_Scenarios) then
|
|
if State /= In_Outline then
|
|
raise Syntax_Error with
|
|
"Scenarios must be defined within a Scenario Outline, at "
|
|
& File.Display_Full_Name & ":" & Image (Line, 1);
|
|
end if;
|
|
State := In_Examples;
|
|
|
|
elsif Starts_With (Buffer (First_Char .. Line_E), Cst_Examples) then
|
|
if State /= In_Outline then
|
|
raise Syntax_Error with
|
|
"Examples must be defined within a Scenario Outline, at "
|
|
& File.Display_Full_Name & ":" & Image (Line, 1);
|
|
end if;
|
|
State := In_Examples;
|
|
|
|
elsif Starts_With (Buffer (First_Char .. Line_E), Cst_Given)
|
|
or else Starts_With (Buffer (First_Char .. Line_E), Cst_And)
|
|
or else Starts_With (Buffer (First_Char .. Line_E), Cst_Then)
|
|
or else Starts_With (Buffer (First_Char .. Line_E), Cst_But)
|
|
or else Starts_With (Buffer (First_Char .. Line_E), Cst_When)
|
|
then
|
|
if State /= In_Scenario
|
|
and then State /= In_Outline
|
|
then
|
|
raise Syntax_Error with "Step must be defined with in a"
|
|
& " Scenario at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
end if;
|
|
|
|
-- ??? Should handle the step
|
|
null;
|
|
|
|
else
|
|
if State = None then
|
|
raise Syntax_Error with "Expected line starting with "
|
|
& Cst_Features & " at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
|
|
elsif State = In_Feature then
|
|
F.Add_Description (Buffer (First_Char .. Line_E));
|
|
|
|
elsif State = In_Scenario
|
|
or else State = In_Outline
|
|
then
|
|
raise Syntax_Error with
|
|
"Expected line starting with "
|
|
& Cst_Given & "/"
|
|
& Cst_When & "/"
|
|
& Cst_Then & "/"
|
|
& Cst_And & "/"
|
|
& Cst_But & ", at " & File.Display_Full_Name & ":"
|
|
& Image (Line, 1);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
if State = In_String then
|
|
raise Syntax_Error with "Multi-line string must end with """""" at "
|
|
& File.Display_Full_Name & ":" & Image (String_Line_Start, 1);
|
|
end if;
|
|
|
|
Finish_Feature;
|
|
Free (Buffer);
|
|
end Parse;
|
|
|
|
end BDD.Parser;
|