ASIS Applications may take on many forms. This section is intended to present a notional ASIS Application using the example of a restrictions checker. A restrictions checker is intended to visit every element in an ASIS context to determine if a violation of a safety-critical check has been made. The ASIS context could include all compilation units in the Ada application. Such a restrictions checker might contain a large number of restrictions to check. The example restrictions checker looks for violations of two safety-critical guidelines:
a) Short circuit operators are always used (i.e., OR ELSE and AND THEN are used and OR and AND are not used). b) Tasks are declared at the library level.
A procedure, named Process_Element, is created which contains calls to procedures Check_Short_Circuit and Check_Library_Level_Task, which performs a restrictions check for each of our safety-critical guidelines above.
procedure Process_Element (Elem : in Asis.Element; -- 3.6 Control : in out Asis.Traverse_Control; -- 3.13 Dummy : in out boolean) is begin Check_Short_Circuit (Elem); Check_Library_Level_Task (Elem); -- Additional guidelines can be checked here. end Process_Element;
This procedure will process each element in the Context as controlled by an instantiation to Traverse_Element. The body of the Check_Short_Circuit and Check_Library_Level_Task identify the processing to be performed on each Element.
The Check_Short_Circuit procedure is passed the current Element to be evaluated. The Operator_Kinds function identifies the operator kind. If the Element happens to be An_And_Operator or An_Or_Operator, then a violation exists and must be reported by identifying the line number of the violation. Otherwise, there is no processing for this Element.
procedure Check_Short_Circuit( Elem : in Asis.Element) is -- 3.6 Op_Kind : Asis.Operator_Kinds := -- 3.9.18 Asis.Elements.Operator_Kind (Elem); -- 13.22 begin case Op_Kind is when Asis.An_And_Operator => -- 3.9.18 Put_Line ("Violation of Short Circuit Operator guideline:"); Put ("-- Use of AND Operator at line "); Put (Asis.Text.Line_Number'Wide_Image -- 20.2 (Asis.Text.First_Line_Number (Elem))); -- 20.8 New_Line; when Asis.An_Or_Operator => -- 3.9.18 Put_Line ("Violation of Short Circuit Operator guideline:"); Put ("-- Use of OR Operator at line "); Put (Asis.Text.Line_Number'Wide_Image -- 20.2 (Asis.Text.First_Line_Number (Elem))); -- 20.8 New_Line; when others => null; end case; end Check_Short_Circuit;
The Check_Library_Level_Task checks to see if the Element parameter is a Declaration_Kind of A_Task_Type_Declaration, A_Protected_Type_Declaration, A_Single_Task_Declaration, or A_Single_Protected_Declaration. If the Element is such a declaration, then a test Is_Library_Level is performed. If the task is not at the Library level, then a violation is reported along with its line number.
procedure Check_Library_Level_Task (Elem : Asis.Element) is -- 3.6 begin case Asis.Elements.Declaration_Kind (Elem) is -- 13.9 when Asis.A_Task_Type_Declaration | -- 3.94 Asis.A_Protected_Type_Declaration | -- 3.94 Asis.A_Single_Task_Declaration | -- 3.94 Asis.A_Single_Protected_Declaration => -- 3.94 If not Is_Library_Level (Asis.Elements.Enclosing_Compilation_Unit(Elem)) then -- 13.2 Put_Line ("Violation of Tasking guideline:"); Put ("-- Non-Library Level Task at Line:"); Put (Asis.Text.Line_Number'Wide_Image -- 20.2 (Asis.Text.First_Line_Number (Elem))); -- 20.8 New_Line; end if; when others => null; end case; end Check_Library_Level_Task;
The function Is_Library_Level returns true when the Unit_Class of the Compilation_Unit is A_Public_Declaration.
function Is_Library_Level ( CU : Asis.Compilation_Unit ) -- 3.10 return boolean is begin Case Asis.Compilation_Units.Unit_Class (CU) is -- 10.2 when Asis.A_Public_Declaration => -- 3.12.2 return true; when others => return false; end case; end Is_Library_Level;
So far the procedure Process_Element has been created to check restrictions on an Element in a Compilation_Unit. The next step is to traverse all the Elements in a Compilation_Unit with this check. The following package, called Check_Compilation_Unit, does this with its procedure Find_Violations. Find_Violations prints the name of the Unit_Kind and name of each Compilation_Unit as it checks each element in the Compilation_Unit for restrictions using the procedure Check. Procedure Check is an instantiation of ASIS's Traverse_Element with Process_Element, containing the restriction checks. Traverse_Element provides a traversal of each element in a Compilation_Unit's logical syntax tree. The generic is instantiated with a state, a pre-operation, and a post-operation. In this example, Process_Element is the pre-operation which is executed when we land on each Element in the logical syntax tree. In this example, no processing is needed as we leave the Element, so the third generic parameter is the procedure No_Op. The state is not needed by the application. The package Check_Compilation_Unit provides the procedure Find_Violations for the selected Compilation_Unit. It traverses the logical syntax tree, finding and reporting the short circuit violations and task library level violations.
with Asis; package Check_Compilation_Unit is procedure Find_Violations (CU : in Asis.Compilation_Unit); -- 3.10 end Check_Compilation_Unit; with Asis; with Asis.Elements; with Asis.Iterator; with Asis.Text; with Ada.Wide_Text_Io; use Ada.Wide_Text_Io; package body Check_Compilation_Unit is procedure Process_Element (Elem : in Asis.Element; -- 3.6 Control : in out Asis.Traverse_Control; -- 3.13 Dummy : in out boolean); procedure No_Op (Elem : in Asis.Element; -- 3.6 Control : in out Asis.Traverse_Control; -- 3.13 Dummy : in out boolean); procedure Check is new Asis.Iterator.Traverse_Element -- 14.1 (boolean, Process_Element, No_Op); Procedure Find_Violations (CU : Asis.Compilation_Unit) is -- 3.10 Control : Asis.Traverse_Control := Asis.Continue; -- 3.13 Dummy : boolean; begin Put_Line ("Processing " & Asis.Unit_Kinds'Wide_Image -- 3.12.1 (Asis.Compilation_Units.Unit_Kind (CU)) -- 10.1 & ": " & (Asis.Compilation_Units.Unit_Full_Name (CU))); -- 10.19 Check (Asis.Elements.Unit_Declaration (CU), Control, Dummy); end Check_Compilation_Unit;
The ASIS application is almost complete. A main program is needed which contains the required sequencing of calls to initialize the ASIS interface, name the Ada environment, access the Ada environment, loop through all Compilation_Units in the ASIS Context with the Find_Violations procedure, and closing/releasing all ASIS resources. The Compilation_Units in the Context are placed into the Unit_List. This is achieved with the following main program, called My_Application.
procedure My_Application is My_Context : Asis.Context; -- 3.5 begin Asis.Implementation.Initialize; -- 6.6 Asis.Ada_Environments.Associate (My_Context, "My Context"); -- 8.3 Asis.Ada_Environments.Open (My_Context); -- 8.4 declare Unit_List : Asis.Compilation_Unit_List := -- 3.11 Asis.Compilation_Units.Compilation_Units (My_Context); -- 10.10 begin for I in Unit_List'Range loop case Asis.Compilation_Units.Unit_Origin (Unit_List (I)) is -- 10.3 when Asis.An_Application_Unit => -- 3.12.3 Check_Compilation_Unit.Find_Violations (Unit_List (I)); when others => null; end case; end loop; end; Asis.Ada_Environments.Close (My_Context); -- 8.5 Asis.Ada_Environments.Dissociate (My_Context); -- 8.6 Asis.Implementation.Finalize; -- 6.8 end My_Application;
Last update 29 May 1998. Questions, comments to Clyde Roby (CRoby@IDA.Org)