taste-backend-skeletons.adb 15.7 KB
Newer Older
Maxime Perrotin's avatar
Maxime Perrotin committed
1
with Text_IO; use Text_IO;
2
with Ada.Strings.Unbounded,
3
     Ada.Characters.Handling,
4
     Ada.Containers.Ordered_Sets,
Maxime Perrotin's avatar
Maxime Perrotin committed
5
     Ada.Exceptions,
6
7
     Ada.Directories,
     TASTE.Parser_Utils;
8

9
use Ada.Characters.Handling,
Maxime Perrotin's avatar
Maxime Perrotin committed
10
    Ada.Exceptions,
11
12
    Ada.Directories,
    TASTE.Parser_Utils;
Maxime Perrotin's avatar
Maxime Perrotin committed
13

Maxime Perrotin's avatar
Maxime Perrotin committed
14
15
16
17
18
19
--  This package covers the generation of skeletons for all supported languages
--  There is no code that is specific to one particular language. The package
--  looks for a sub-directory with the name of the language and checks that all
--  skeleton-related template files are present. Then it fills the Template
--  mappings and generate the corresponding code.

Maxime Perrotin's avatar
Maxime Perrotin committed
20
21
package body TASTE.Backend.Skeletons is
   procedure Generate (Model : TASTE_Model) is
22
23
      Output_File : File_Type;
      Template    : constant IV_As_Template :=
Maxime Perrotin's avatar
Maxime Perrotin committed
24
        Interface_View_Template (Model.Interface_View);
Maxime Perrotin's avatar
Maxime Perrotin committed
25

26
27
      Prefix : constant String := Model.Configuration.Binary_Path.all
        & "templates/skeletons/";
Maxime Perrotin's avatar
Maxime Perrotin committed
28

29
      use Ada.Strings.Unbounded;
Maxime Perrotin's avatar
Maxime Perrotin committed
30
      type Output is (Header, Code);
Maxime Perrotin's avatar
Maxime Perrotin committed
31
32
33
34
35

      --  Function checking that all templates files are available to support
      --  a given language (based on the directory name).
      function Is_Template_Present (Path : String) return Boolean is
        (Exists (Path) and then Kind (Path) = Directory and then
Maxime Perrotin's avatar
Maxime Perrotin committed
36
37
38
39
         Exists (Path & "interface-header.tmplt")       and then
         Exists (Path & "interface-body.tmplt")         and then
         Exists (Path & "header.tmplt")                 and then
         Exists (Path & "body.tmplt")                   and then
40
         Exists (Path & "makefile.tmplt")               and then
Maxime Perrotin's avatar
Maxime Perrotin committed
41
42
         Exists (Path & "body-filename.tmplt")          and then
         Exists (Path & "header-filename.tmplt"));
Maxime Perrotin's avatar
Maxime Perrotin committed
43

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
      --  Return a Tag list of ASN.1 Modules for the skeleton headers
      function Get_Module_List return Tag is
         Result : Tag;
      begin
         for Each of Model.Data_View.ASN1_Files loop
            for Module of Each.Modules loop
               Result := Result & Module.Name;
            end loop;
         end loop;
         return Result;
      end Get_Module_List;

      --  Return a Tag list of ASN.1 Files
      function Get_ASN1_File_List return Tag is
         Result : Tag;
      begin
         for Each of Model.Data_View.ASN1_Files loop
            Result := Result & Each.Path;
         end loop;
         return Result;
      end Get_ASN1_File_List;

66
      --  Generate the content of the Makefile per function
67
      function Function_Makefile (Path    : String;
68
69
70
71
                                 Content : Translate_Set) return String is
         Tmplt_Makefile : constant String := Path & "makefile.tmplt";
      begin
         return Parse (Tmplt_Makefile, Content);
72
73
74
      end Function_Makefile;

      --  Generate string for a global Makefile (processing all functions)
75
76
      --  The template contains a set of languages, and a list of
      --  combined function name/language
77
      function Global_Makefile return String is
78
79
80
81
82
83
84
         package Languages_Set is new Ordered_Sets (Unbounded_String);
         use Languages_Set;
         Languages        : Set;
         Unique_Languages : Tag;
         Functions_Tag    : Vector_Tag;
         Language_Tag     : Vector_Tag;
         Content_Set      : Translate_Set;
85
86
87
88
89
         Tmplt   : constant String := Prefix & "makefile.tmplt";
      begin
         if not Exists (Tmplt) then
            raise Skeleton_Error with "Missing makefile.tmplt";
         end if;
90
91
         for Each of Model.Interface_View.Flat_Functions loop
            Languages := Languages or To_Set (US (Language_Spelling (Each)));
92
93
94
            Functions_Tag := Functions_Tag & Each.Name;
            Language_Tag  := Language_Tag & Language_Spelling (Each);
         end loop;
95
96
97
98
99
         for Each of Languages loop
            Unique_Languages := Unique_Languages & To_String (Each);
         end loop;
         Content_Set := +Assoc  ("Function_Names",   Functions_Tag)
                        & Assoc ("Language",         Language_Tag)
100
101
102
                        & Assoc ("Unique_Languages", Unique_Languages)
                        & Assoc ("ASN1_Files",       Get_ASN1_File_List)
                        & Assoc ("ASN1_Modules",     Get_Module_List);
103
104
         return Parse (Tmplt, Content_Set);
      end Global_Makefile;
105

Maxime Perrotin's avatar
Maxime Perrotin committed
106
107
108
109
      function Process_Interfaces (Interfaces : Interface_Vectors.Vector;
                                   Path       : String;
                                   Target     : Output) return Tag
      is
Maxime Perrotin's avatar
Maxime Perrotin committed
110
111
112
113
         Result : Tag;
         Tmplt_Sign  : constant String :=
            Path & "interface-" & (if Target = Header then "header"
                                                      else "body") & ".tmplt";
Maxime Perrotin's avatar
Maxime Perrotin committed
114
115
      begin
         for Each of Interfaces loop
Maxime Perrotin's avatar
Maxime Perrotin committed
116
            Result := Result & String'(Parse (Tmplt_Sign, Each.Header));
Maxime Perrotin's avatar
Maxime Perrotin committed
117
         end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
118
         return Result;
Maxime Perrotin's avatar
Maxime Perrotin committed
119
120
      end Process_Interfaces;
   begin
121
      Put_Info ("=== Generate skeletons ===");
Maxime Perrotin's avatar
Maxime Perrotin committed
122
123
124
125
      for Each of Model.Interface_View.Flat_Functions loop
         declare
            Language   : constant String := Language_Spelling (Each);
            Path       : constant String := Prefix & To_Lower (Language) & "/";
Maxime Perrotin's avatar
Maxime Perrotin committed
126
            Proceed    : constant Boolean := Is_Template_Present (Path);
127
128
129
130
            Hdr_Tmpl   : constant Translate_Set :=
                +Assoc ("Name", Each.Name)
                & Assoc ("Is_Type", Each.Is_Type)
                & Assoc ("Instance_Of", Each.Instance_Of.Value_Or (US ("")));
131
            Make_Tmpl  : constant Translate_Set := Function_Makefile_Template
132
133
134
                                        (F       => Each,
                                         Modules => Get_Module_List,
                                         Files   => Get_ASN1_File_List);
135
136
            Make_Text  : constant String := (if Proceed
                             then Function_Makefile (Path, Make_Tmpl) else "");
Maxime Perrotin's avatar
Maxime Perrotin committed
137

Maxime Perrotin's avatar
Maxime Perrotin committed
138
139
            Func_Tmpl  : constant Func_As_Template :=
              Template.Funcs.Element (To_String (Each.Name));
Maxime Perrotin's avatar
Maxime Perrotin committed
140
141
142

            Func_Hdr   : constant Translate_Set :=
              (if Proceed then Func_Tmpl.Header
143
144
145
146
147
               & Assoc ("Provided_Interfaces",
                 Process_Interfaces (Func_Tmpl.Provided, Path, Header))
               & Assoc ("Required_Interfaces",
                 Process_Interfaces (Func_Tmpl.Required, Path, Header))
               & Assoc ("ASN1_Modules", Get_Module_List)
Maxime Perrotin's avatar
Maxime Perrotin committed
148
               & Assoc ("ASN1_Files", Get_ASN1_File_List)
Maxime Perrotin's avatar
Maxime Perrotin committed
149
150
151
152
153
154
155
156
157
158
               else Null_Set);

            Header_Text : constant String :=
             (if Proceed then Parse (Path & "header.tmplt", Func_Hdr) else "");

            Func_Body  : constant Translate_Set :=
              (if Proceed then Func_Tmpl.Header
              & Assoc ("Provided_Interfaces",
                       Process_Interfaces (Func_Tmpl.Provided, Path, Code))
              & Assoc ("Required_Interfaces",
Maxime Perrotin's avatar
Maxime Perrotin committed
159
                       Process_Interfaces (Func_Tmpl.Required, Path, Code))
Maxime Perrotin's avatar
Maxime Perrotin committed
160
161
               else Null_Set);
            Body_Text   : constant String :=
162
163
164
165
166
                            (if Proceed
                             then Parse (Path & "body.tmplt", Func_Body)
                             else "");
            Output_Src  : constant String :=
                            Model.Configuration.Output_Dir.all
Maxime Perrotin's avatar
Maxime Perrotin committed
167
                            & "/" & To_Lower (To_String (Each.Name))
168
                            & "/" & Language
Maxime Perrotin's avatar
Maxime Perrotin committed
169
170
                            & "/" & "src" & "/";
            --  Get header and body filenames from templates
171
            Header_File : constant String := Strip_String
Maxime Perrotin's avatar
Maxime Perrotin committed
172
173
174
                            (if Proceed then Parse
                               (Path & "header-filename.tmplt", Hdr_Tmpl)
                             else "");
175
            Body_File   : constant String := Strip_String
Maxime Perrotin's avatar
Maxime Perrotin committed
176
177
178
                            (if Proceed then Parse
                               (Path & "body-filename.tmplt", Hdr_Tmpl)
                             else "");
179
            Make_File   : constant String := "Makefile";
Maxime Perrotin's avatar
Maxime Perrotin committed
180
         begin
Maxime Perrotin's avatar
Maxime Perrotin committed
181
            if Proceed then
Maxime Perrotin's avatar
Maxime Perrotin committed
182
               --  Create directory tree (output/function/language/src)
183
               Create_Path (Output_Src);
184
185
186
187
188
189
190
191
192
193
194
195
196
               if Header_File /= "" then
                  Put_Info ("Generating " & Output_Src & Header_File);
                  Create (File => Output_File,
                          Mode => Out_File,
                          Name => Output_Src & Header_File);
                  Put_Line (Output_File, Header_Text);
                  Close (Output_File);
               else
                  Put_Info ("No header file needed for function "
                             & To_String (Each.Name));
               end if;
               if Body_File /= "" and then not Exists (Output_Src & Body_File)
               then
197
                  Put_Info ("Generating " & Body_File);
198
                  Create (File => Output_File,
Maxime Perrotin's avatar
Maxime Perrotin committed
199
200
                          Mode => Out_File,
                          Name => Output_Src & Body_File);
201
202
                  Put_Line (Output_File, Body_Text);
                  Close (Output_File);
203
               else
204
205
                  Put_Info ("No body file generated for function "
                            & To_String (Each.Name));
Maxime Perrotin's avatar
Maxime Perrotin committed
206
               end if;
207
208
               Put_Info ("Generating " & Make_File & " for function "
                         & To_String (Each.Name));
209
               Create (File => Output_File,
210
211
                       Mode => Out_File,
                       Name => Output_Src & Make_File);
212
213
               Put_Line (Output_File, Make_Text);
               Close (Output_File);
Maxime Perrotin's avatar
Maxime Perrotin committed
214
            else
215
               Put_Info ("Ignoring function " & To_String (Each.Name));
Maxime Perrotin's avatar
Maxime Perrotin committed
216
            end if;
Maxime Perrotin's avatar
Maxime Perrotin committed
217
         exception
218
219
            when E : End_Error
               | Text_IO.Use_Error =>
220
221
               if Is_Open (Output_File) then
                  Close (Output_File);
Maxime Perrotin's avatar
Maxime Perrotin committed
222
223
224
225
               end if;
               raise Skeleton_Error with "Generation of skeleton for function "
                 & To_String (Each.Name) & " failed : "
                 & Exception_Message (E);
226
227
         end;
      end loop;
228
229
230
231
232
233
      Put_Info ("Generating global Makefile");
      Create (File => Output_File,
              Mode => Out_File,
              Name => Model.Configuration.Output_Dir.all & "/" & "Makefile");
      Put_Line (Output_File, Global_Makefile);
      Close (Output_File);
Maxime Perrotin's avatar
Maxime Perrotin committed
234
235
   end Generate;

236
   --  Makefiles need the function name and the list of ASN.1 files/modules
237
238
239
   function Function_Makefile_Template (F       : Taste_Terminal_Function;
                                        Modules : Tag;
                                        Files   : Tag) return Translate_Set
240
241
242
   is (Translate_Set'(+Assoc  ("Name",         F.Name)
                      & Assoc ("ASN1_Files",   Files)
                      & Assoc ("ASN1_Modules", Modules)));
Maxime Perrotin's avatar
Maxime Perrotin committed
243
244
245
246
247

   function Interface_Template (TI : Taste_Interface)
                                return Interface_As_Template
   is
      use Template_Vectors;
Maxime Perrotin's avatar
Maxime Perrotin committed
248
249
250
251
      Result           : Interface_As_Template;
      Param_Names      : Vector_Tag;
      Param_Types      : Vector_Tag;
      Param_Directions : Vector_Tag;
Maxime Perrotin's avatar
Maxime Perrotin committed
252
   begin
Maxime Perrotin's avatar
Maxime Perrotin committed
253
      Result.Header :=  +Assoc  ("Name",            TI.Name)
Maxime Perrotin's avatar
Maxime Perrotin committed
254
                        & Assoc ("Kind",            TI.RCM'Img)
Maxime Perrotin's avatar
Maxime Perrotin committed
255
256
                        & Assoc ("Parent_Function", TI.Parent_Function);
      for Each of TI.Params loop
257
         --  Result.Params    := Result.Params & Parameter_Template (Each, TI);
Maxime Perrotin's avatar
Maxime Perrotin committed
258
259
260
         Param_Names      := Param_Names & Each.Name;
         Param_Types      := Param_Types & Each.Sort;
         Param_Directions := Param_Directions & Each.Direction'Img;
Maxime Perrotin's avatar
Maxime Perrotin committed
261
      end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
262
263
264
265
      Result.Header := Result.Header
                       & Assoc ("Param_Names",      Param_Names)
                       & Assoc ("Param_Types",      Param_Types)
                       & Assoc ("Param_Directions", Param_Directions);
Maxime Perrotin's avatar
Maxime Perrotin committed
266
267
268
269
270
271
      return Result;
   end Interface_Template;

   function Func_Template (F : Taste_Terminal_Function) return Func_As_Template
   is
      use Interface_Vectors;
272
      use Ctxt_Params;
Maxime Perrotin's avatar
Maxime Perrotin committed
273
274
275
276
277
278
279
280
281
282
      Result             : Func_As_Template;
      List_Of_PIs        : Tag;
      List_Of_RIs        : Tag;
      List_Of_Sync_PIs   : Tag;
      List_Of_ASync_PIs  : Tag;
      List_Of_Sync_RIs   : Tag;
      List_Of_ASync_RIs  : Tag;
      Timers             : Tag;
      Property_Names     : Vector_Tag;
      Property_Values    : Vector_Tag;
283
284
      CP_Names           : Vector_Tag;   -- For Context Parameters
      CP_Types           : Vector_Tag;   -- For Context Parameters
Maxime Perrotin's avatar
Maxime Perrotin committed
285
      Interface_Tmplt    : Interface_As_Template;
Maxime Perrotin's avatar
Maxime Perrotin committed
286
287
   begin
      Result.Header := +Assoc ("Name", F.Name)
288
289
        & Assoc ("Language", Language_Spelling (F))
        & Assoc ("Has_Context", (Length (F.Context_Params) > 0));
290

291
292
293
294
295
296
      --  Add context parameters details
      for Each of F.Context_Params loop
         CP_Names := CP_Names & Each.Name;
         CP_Types := CP_Types & Each.Sort;
      end loop;

297
      --  Add list of all PI names (both synchronous and asynchronous)
Maxime Perrotin's avatar
Maxime Perrotin committed
298
      for Each of F.Provided loop
Maxime Perrotin's avatar
Maxime Perrotin committed
299
300
301
302
         Interface_Tmplt := Interface_Template (Each);
         Interface_Tmplt.Header := Interface_Tmplt.Header
                                   & Assoc ("Direction", "PI");
         Result.Provided := Result.Provided & Interface_Tmplt;
303
304
305
         List_Of_PIs     := List_Of_PIs & Each.Name;
         case Each.RCM is
            when Cyclic_Operation | Sporadic_Operation =>
Maxime Perrotin's avatar
Maxime Perrotin committed
306
               List_Of_ASync_PIs := List_Of_ASync_PIs & Each.Name;
307
            when others =>
Maxime Perrotin's avatar
Maxime Perrotin committed
308
               List_Of_Sync_PIs := List_Of_Sync_PIs & Each.Name;
309
         end case;
Maxime Perrotin's avatar
Maxime Perrotin committed
310
      end loop;
311

312
      --  Add list of all RI names (both synchronous and asynchronous)
Maxime Perrotin's avatar
Maxime Perrotin committed
313
      for Each of F.Required loop
Maxime Perrotin's avatar
Maxime Perrotin committed
314
315
316
317
         Interface_Tmplt := Interface_Template (Each);
         Interface_Tmplt.Header := Interface_Tmplt.Header
                                   & Assoc ("Direction", "RI");
         Result.Required := Result.Required & Interface_Tmplt;
318
319
320
         List_Of_RIs     := List_Of_RIs & Each.Name;
         case Each.RCM is
            when Cyclic_Operation | Sporadic_Operation =>
Maxime Perrotin's avatar
Maxime Perrotin committed
321
               List_Of_ASync_RIs := List_Of_ASync_RIs & Each.Name;
322
            when others =>
Maxime Perrotin's avatar
Maxime Perrotin committed
323
               List_Of_Sync_RIs := List_Of_Sync_RIs & Each.Name;
324
         end case;
Maxime Perrotin's avatar
Maxime Perrotin committed
325
      end loop;
326
327

      --  Add list of timers (names)
Maxime Perrotin's avatar
Maxime Perrotin committed
328
329
330
      for Each of F.Timers loop
         Timers := Timers & Each;
      end loop;
331
332
333
334
335
336
337
338

      --  Add all user-defined properties
      for Each of F.User_Properties loop
         Property_Names  := Property_Names & Each.Name;
         Property_Values := Property_Values & Each.Value;
      end loop;

      --  Setup the mapping for the template
Maxime Perrotin's avatar
Maxime Perrotin committed
339
      Result.Header := Result.Header
Maxime Perrotin's avatar
Maxime Perrotin committed
340
341
342
343
344
345
346
347
        & Assoc ("List_Of_PIs",       List_Of_PIs)
        & Assoc ("List_Of_RIs",       List_Of_RIs)
        & Assoc ("List_Of_Sync_PIs",  List_Of_Sync_PIs)
        & Assoc ("List_Of_Sync_RIs",  List_Of_Sync_RIs)
        & Assoc ("List_Of_ASync_PIs", List_Of_ASync_PIs)
        & Assoc ("List_Of_ASync_RIs", List_Of_ASync_RIs)
        & Assoc ("Property_Names",    Property_Names)
        & Assoc ("Property_Values",   Property_Values)
348
349
        & Assoc ("CP_Names",          CP_Names)
        & Assoc ("CP_Types",          CP_Types)
Maxime Perrotin's avatar
Maxime Perrotin committed
350
351
352
        & Assoc ("Is_Type",           F.Is_Type)
        & Assoc ("Instance_Of",       F.Instance_Of.Value_Or (US ("")))
        & Assoc ("Timers",            Timers);
Maxime Perrotin's avatar
Maxime Perrotin committed
353
354
355
356
357
      return Result;
   end Func_Template;

   function Interface_View_Template (IV : Complete_Interface_View)
                                     return IV_As_Template is
358
359
      use Func_Maps;
      use Ada.Strings.Unbounded;
Maxime Perrotin's avatar
Maxime Perrotin committed
360
361
362
      Result : IV_As_Template;
   begin
      for Each of IV.Flat_Functions loop
363
364
         Result.Funcs.Insert (Key      => To_String (Each.Name),
                              New_Item => Func_Template (Each));
Maxime Perrotin's avatar
Maxime Perrotin committed
365
366
367
      end loop;
      return Result;
   end Interface_View_Template;
368
end TASTE.Backend.Skeletons;