Natools

Check-in [d9a7acb07a]
Login
Overview
Comment:s_expressions-dynamic_interpreter: backup of the current Interpreter interface before making it read-only
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d9a7acb07a4bb4eed7c797a303b1efe9a5a97d8c
User & Date: nat on 2014-05-13 20:33:54
Other Links: manifest | tags
Context
2014-05-14
18:33
s_expressions-interpreters: make commands and interpreters read-only during execution check-in: 07db27cc2f user: nat tags: trunk
2014-05-13
20:33
s_expressions-dynamic_interpreter: backup of the current Interpreter interface before making it read-only check-in: d9a7acb07a user: nat tags: trunk
2014-05-12
17:22
s_expressions-interpreter_tests: use the new Add procedure, to keep complete coverage check-in: db048daa0f user: nat tags: trunk
Changes

Added src/natools-s_expressions-dynamic_interpreters.adb version [c05be98464].

































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
------------------------------------------------------------------------------
-- Copyright (c) 2013-2014, Natacha Porté                                   --
--                                                                          --
-- Permission to use, copy, modify, and distribute this software for any    --
-- purpose with or without fee is hereby granted, provided that the above   --
-- copyright notice and this permission notice appear in all copies.        --
--                                                                          --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           --
------------------------------------------------------------------------------

package body Natools.S_Expressions.Dynamic_Interpreters is

   -----------------
   -- Interpreter --
   -----------------

   procedure Add_Command
     (Self : in out Interpreter;
      Name : in Atom;
      Cmd : in Command'Class) is
   begin
      Self.Commands.Insert (Name, Cmd);
      Self.Max_Length := Count'Max (Self.Max_Length, Name'Length);
   end Add_Command;


   procedure Add
     (Self : in out Interpreter;
      Name : in String;
      Cmd : in Command'Class) is
   begin
      Self.Add_Command (To_Atom (Name), Cmd);
   end Add;


   function Has_Command (Self : Interpreter; Name : Atom) return Boolean is
   begin
      return Self.Commands.Contains (Name);
   end Has_Command;


   function Is_Empty (Self : Interpreter) return Boolean is
   begin
      return Self.Commands.Is_Empty;
   end Is_Empty;


   procedure Set_Fallback
     (Self : in out Interpreter;
      Name : in Atom)
   is
      function Create return Atom;

      function Create return Atom is
      begin
         return Name;
      end Create;
   begin
      Self.Fallback_Name.Replace (Create'Access);
   end Set_Fallback;


   procedure Reset_Fallback (Self : in out Interpreter) is
   begin
      Self.Fallback_Name.Reset;
   end Reset_Fallback;


   not overriding procedure Execute
     (Self : in out Interpreter;
      Expression : in out Lockable.Descriptor'Class;
      State : in out Shared_State;
      Context : in Shared_Context)
   is
      Event : Events.Event := Expression.Current_Event;
      Lock_State : Lockable.Lock_State;
   begin
      loop
         case Event is
            when Events.Add_Atom =>
               Self.Execute (State, Context, Expression.Current_Atom);
            when Events.Open_List =>
               Expression.Lock (Lock_State);
               begin
                  Expression.Next (Event);
                  if Event = Events.Add_Atom then
                     Self.Execute (State, Context, Expression);
                  end if;
               exception
                  when others =>
                     Expression.Unlock (Lock_State, False);
                     raise;
               end;
               Expression.Unlock (Lock_State);
            when Events.Close_List | Events.End_Of_Input | Events.Error =>
               exit;
         end case;

         Expression.Next (Event);
      end loop;
   end Execute;


   not overriding procedure Execute
     (Self : in out Interpreter;
      Fallback : in out Command'Class;
      Expression : in out Lockable.Descriptor'Class;
      State : in out Shared_State;
      Context : in Shared_Context)
   is
      procedure Dispatch (Process : not null access procedure
                            (Name : in Atom; Cmd : in out Command'Class));
      procedure Process_Atom (Name : in Atom; Cmd : in out Command'Class);
      procedure Process_Exp (Name : in Atom; Cmd : in out Command'Class);

      procedure Dispatch (Process : not null access procedure
                            (Name : in Atom; Cmd : in out Command'Class))
      is
         procedure Process_Fallback (Name : in Atom);

         procedure Process_Fallback (Name : in Atom) is
         begin
            Process (Name, Fallback);
         end Process_Fallback;

         Buffer : Atom (1 .. Self.Max_Length);
         Length : Count;
         Cursor : Command_Maps.Cursor;
      begin
         Expression.Read_Atom (Buffer, Length);
         if Length > Self.Max_Length then
            Expression.Query_Atom (Process_Fallback'Access);
         else
            Cursor := Self.Commands.Find (Buffer (1 .. Length));
            if Command_Maps.Has_Element (Cursor) then
               Self.Commands.Update_Element (Cursor, Process);
            else
               Process (Buffer (1 .. Length), Fallback);
            end if;
         end if;
      end Dispatch;

      procedure Process_Atom (Name : in Atom; Cmd : in out Command'Class) is
      begin
         Cmd.Execute (State, Context, Name);
      end Process_Atom;

      procedure Process_Exp (Name : in Atom; Cmd : in out Command'Class) is
         pragma Unreferenced (Name);
      begin
         Cmd.Execute (State, Context, Expression);
      end Process_Exp;

      Event : Events.Event := Expression.Current_Event;
      Lock_State : Lockable.Lock_State;
   begin
      loop
         case Event is
            when Events.Add_Atom =>
               Dispatch (Process_Atom'Access);

            when Events.Open_List =>
               Expression.Lock (Lock_State);
               begin
                  Expression.Next (Event);
                  if Event = Events.Add_Atom then
                     Dispatch (Process_Exp'Access);
                  end if;
               exception
                  when others =>
                     Expression.Unlock (Lock_State, False);
                     raise;
               end;
               Expression.Unlock (Lock_State);

            when Events.Close_List | Events.End_Of_Input | Events.Error =>
               exit;
         end case;

         Expression.Next (Event);
      end loop;
   end Execute;


   overriding procedure Execute
     (Self : in out Interpreter;
      State : in out Shared_State;
      Context : in Shared_Context;
      Name : in Atom)
   is
      procedure Process_Atom (Key : in Atom; Cmd : in out Command'Class);

      procedure Process_Atom (Key : in Atom; Cmd : in out Command'Class) is
         pragma Unreferenced (Key);
      begin
         Cmd.Execute (State, Context, Name);
      end Process_Atom;

      Cursor : Command_Maps.Cursor;
   begin
      if Name'Length <= Self.Max_Length then
         Cursor := Self.Commands.Find (Name);
         if Command_Maps.Has_Element (Cursor) then
            Self.Commands.Update_Element (Cursor, Process_Atom'Access);
            return;
         end if;
      end if;

      if not Self.Fallback_Name.Is_Empty then
         Cursor := Self.Commands.Find (Self.Fallback_Name.Query.Data.all);
         if Command_Maps.Has_Element (Cursor) then
            Self.Commands.Update_Element (Cursor, Process_Atom'Access);
            return;
         end if;
      end if;

      raise Command_Not_Found
        with "Unknown command """ & To_String (Name) & '"';
   end Execute;


   overriding procedure Execute
     (Self : in out Interpreter;
      State : in out Shared_State;
      Context : in Shared_Context;
      Cmd : in out Lockable.Descriptor'Class)
   is
      procedure Process_Exp (Name : in Atom; Actual : in out Command'Class);

      procedure Process_Exp (Name : in Atom; Actual : in out Command'Class) is
         pragma Unreferenced (Name);
      begin
         Actual.Execute (State, Context, Cmd);
      end Process_Exp;

      Buffer : Atom (1 .. Self.Max_Length);
      Length : Count;
      Cursor : Command_Maps.Cursor;
   begin
      if Cmd.Current_Event /= Events.Add_Atom then
         return;
      end if;

      Cmd.Read_Atom (Buffer, Length);

      if Length <= Self.Max_Length then
         Cursor := Self.Commands.Find (Buffer (1 .. Length));
         if Command_Maps.Has_Element (Cursor) then
            Self.Commands.Update_Element (Cursor, Process_Exp'Access);
            return;
         end if;
      end if;

      if not Self.Fallback_Name.Is_Empty then
         Cursor := Self.Commands.Find (Self.Fallback_Name.Query.Data.all);
         if Command_Maps.Has_Element (Cursor) then
            Self.Commands.Update_Element (Cursor, Process_Exp'Access);
            return;
         end if;
      end if;

      raise Command_Not_Found
        with "Unknown command """ & To_String (Cmd.Current_Atom) & '"';
   end Execute;

end Natools.S_Expressions.Dynamic_Interpreters;

Added src/natools-s_expressions-dynamic_interpreters.ads version [39f192a56d].









































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
------------------------------------------------------------------------------
-- Copyright (c) 2013-2014, Natacha Porté                                   --
--                                                                          --
-- Permission to use, copy, modify, and distribute this software for any    --
-- purpose with or without fee is hereby granted, provided that the above   --
-- copyright notice and this permission notice appear in all copies.        --
--                                                                          --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           --
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Natools.S_Expressions.Dynamic_Interpreters provides an implemntation of  --
-- a dispatching command interpreter. The base list of a given S-expression --
-- is considered as list of command, either argumentless (atoms) or with a  --
-- S-expression argument (sublist). Sublists that don't start with an atom  --
-- are silently ignored and can be used as comments.                        --
--                                                                          --
-- Formal types represent common objets for all the command, Shared_State   --
-- begin read/write while Shared_Context is read-only.                      --
------------------------------------------------------------------------------

with Natools.S_Expressions.Lockable;

private with Ada.Containers.Indefinite_Ordered_Maps;
private with Natools.S_Expressions.Atom_Refs;

generic
   type Shared_State (<>) is limited private;
   type Shared_Context (<>) is limited private;

package Natools.S_Expressions.Dynamic_Interpreters is
   pragma Preelaborate (Dynamic_Interpreters);

   Command_Not_Found : exception;


   type Command is interface;

   procedure Execute
     (Self : in out Command;
      State : in out Shared_State;
      Context : in Shared_Context;
      Name : in Atom)
     is null;
      --  Execute a single argumentless command

   procedure Execute
     (Self : in out Command;
      State : in out Shared_State;
      Context : in Shared_Context;
      Cmd : in out Lockable.Descriptor'Class)
     is null;
      --  Execute a single command with arguments


   type Null_Command is new Command with null record;

   Do_Nothing : Null_Command := Null_Command'(null record);


   type Interpreter is new Command with private;

   procedure Add_Command
     (Self : in out Interpreter;
      Name : in Atom;
      Cmd : in Command'Class);

   procedure Add
     (Self : in out Interpreter;
      Name : in String;
      Cmd : in Command'Class);

   function Has_Command (Self : Interpreter; Name : Atom) return Boolean;

   function Is_Empty (Self : Interpreter) return Boolean;

   procedure Set_Fallback
     (Self : in out Interpreter;
      Name : in Atom);

   procedure Reset_Fallback (Self : in out Interpreter);

   not overriding procedure Execute
     (Self : in out Interpreter;
      Expression : in out Lockable.Descriptor'Class;
      State : in out Shared_State;
      Context : in Shared_Context);
      --  Execute an expression, raising Command_Not_Found on unknown commands

   not overriding procedure Execute
     (Self : in out Interpreter;
      Fallback : in out Command'Class;
      Expression : in out Lockable.Descriptor'Class;
      State : in out Shared_State;
      Context : in Shared_Context);
      --  Execute an expression with temporary fallback for unknown commands

   overriding procedure Execute
     (Self : in out Interpreter;
      State : in out Shared_State;
      Context : in Shared_Context;
      Name : in Atom);
      --  Execute a single argumentless command

   overriding procedure Execute
     (Self : in out Interpreter;
      State : in out Shared_State;
      Context : in Shared_Context;
      Cmd : in out Lockable.Descriptor'Class);
      --  Execute a single command with arguments


private

   type Exception_Command is new Command with null record;

   package Command_Maps is new Ada.Containers.Indefinite_Ordered_Maps
     (Atom, Command'Class, Less_Than);

   type Interpreter is new Command with record
      Commands : Command_Maps.Map;
      Max_Length : Count := 0;
      Fallback_Name : Atom_Refs.Reference;
   end record;

end Natools.S_Expressions.Dynamic_Interpreters;

Added tests/natools-s_expressions-dynamic_interpreter_tests.adb version [e5de2d8275].































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
------------------------------------------------------------------------------
-- Copyright (c) 2014, Natacha Porté                                        --
--                                                                          --
-- Permission to use, copy, modify, and distribute this software for any    --
-- purpose with or without fee is hereby granted, provided that the above   --
-- copyright notice and this permission notice appear in all copies.        --
--                                                                          --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           --
------------------------------------------------------------------------------

with Natools.S_Expressions.Caches;
with Natools.S_Expressions.Test_Tools;

package body Natools.S_Expressions.Dynamic_Interpreter_Tests is

   function Test_Interpreter return Test_Interpreters.Interpreter;

   function Invalid_Commands return Caches.Reference;


   ------------------------
   -- Helper Subprograms --
   ------------------------

   function Invalid_Commands return Caches.Reference is
      Cache : Caches.Reference;
      Short : constant Atom := To_Atom ("not-cmd");
      Long : constant Atom := To_Atom ("not-a-command");
   begin
      Cache.Append_Atom (Short);
      Cache.Open_List;
      Cache.Append_Atom (Short);
      Cache.Append_Atom (To_Atom ("arg"));
      Cache.Close_List;
      Cache.Append_Atom (Long);
      Cache.Open_List;
      Cache.Append_Atom (Long);
      Cache.Open_List;
      Cache.Close_List;
      Cache.Close_List;
      return Cache;
   end Invalid_Commands;


   function Test_Interpreter return Test_Interpreters.Interpreter is
      Template : Recorder;
   begin
      return Inter : Test_Interpreters.Interpreter do
         Inter.Add_Command (To_Atom ("cmd"), Template);
         Inter.Add_Command (To_Atom ("command"), Template);
      end return;
   end Test_Interpreter;



   ----------------------
   -- Recorder Command --
   ----------------------

   overriding procedure Execute
     (Self : in out Recorder;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Self);
   begin
      if Context then
         State.Append_Atom (Name);
      end if;
   end Execute;


   overriding procedure Execute
     (Self : in out Recorder;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class)
   is
      pragma Unreferenced (Self);
   begin
      if not Context then
         return;
      end if;

      declare
         Buffer : aliased Test_Tools.Memory_Stream;
         Serializer : Printers.Canonical (Buffer'Access);
      begin
         Printers.Transfer (Cmd, Serializer);
         State.Open_List;
         State.Append_Atom (Buffer.Get_Data);
         State.Close_List;
      end;
   end Execute;



   --------------------
   -- Raiser Command --
   --------------------

   overriding procedure Execute
     (Self : in out Raiser;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Name : in Atom)
   is
      pragma Unreferenced (Self, State, Context, Name);
   begin
      raise Special_Exception;
   end Execute;


   overriding procedure Execute
     (Self : in out Raiser;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class)
   is
      pragma Unreferenced (Self, State, Context, Cmd);
   begin
      raise Special_Exception;
   end Execute;



   -------------------------
   -- Complete Test Suite --
   -------------------------

   procedure All_Tests (Report : in out NT.Reporter'Class) is
   begin
      Test_Basic_Usage (Report);
      Test_Unknown_Commands (Report);
      Test_Premanent_Fallback (Report);
      Test_Local_Fallback (Report);
      Test_Exception_Fallback (Report);
      Test_Inspection (Report);
   end All_Tests;



   ----------------------
   -- Individual Tests --
   ----------------------

   procedure Test_Basic_Usage (Report : in out NT.Reporter'Class) is
      Test : NT.Test := Report.Item ("Basic usage");
   begin
      declare
         Inter : Test_Interpreters.Interpreter := Test_Interpreter;
         Buffer : aliased Test_Tools.Memory_Stream;
         Printer : Printers.Canonical (Buffer'Access);
         Input : Caches.Reference;
         Cursor : Caches.Cursor;
      begin
         Input.Append_Atom (To_Atom ("cmd"));
         Input.Open_List;
         Input.Append_Atom (To_Atom ("cmd"));
         Input.Append_Atom (To_Atom ("foo"));
         Input.Append_Atom (To_Atom ("bar"));
         Input.Close_List;
         Input.Append_Atom (To_Atom ("command"));
         Input.Open_List;
         Input.Open_List;
         Input.Append_Atom (To_Atom ("comment"));
         Input.Close_List;
         Input.Close_List;
         Input.Open_List;
         Input.Append_Atom (To_Atom ("command"));
         Input.Open_List;
         Input.Close_List;
         Input.Close_List;

         Cursor := Input.First;

         Buffer.Set_Expected (To_Atom
           ("3:cmd(15:3:cmd3:foo3:bar)7:command(11:7:command())"));

         Inter.Execute (Cursor, Printer, True);
         Buffer.Check_Stream (Test);
      end;
   exception
      when Error : others => Test.Report_Exception (Error);
   end Test_Basic_Usage;


   procedure Test_Exception_Fallback (Report : in out NT.Reporter'Class) is
      Test : NT.Test := Report.Item ("Local fallback raising an exception");
   begin
      declare
         Inter : Test_Interpreters.Interpreter := Test_Interpreter;
         Buffer : aliased Test_Tools.Memory_Stream;
         Printer : Printers.Canonical (Buffer'Access);
         Input : Caches.Reference;
         Cursor : Caches.Cursor;
         Fallback : Raiser;
      begin
         Input.Append_Atom (To_Atom ("cmd"));
         Input.Open_List;
         Input.Append_Atom (To_Atom ("unknown"));
         Input.Append_Atom (To_Atom ("argument"));
         Input.Close_List;
         Input.Close_List;
         Input.Open_List;
         Input.Append_Atom (To_Atom ("command"));
         Input.Close_List;
         Cursor := Input.First;

         Buffer.Set_Expected (To_Atom ("3:cmd"));

         begin
            Inter.Execute (Fallback, Cursor, Printer, True);
            Test.Fail ("No exception raised");
         exception
            when Special_Exception => null;
            when Error : others =>
               Test.Fail ("Wrong exception raised:");
               Test.Report_Exception (Error, NT.Fail);
         end;

         Buffer.Check_Stream (Test);

         Test_Tools.Next_And_Check (Test, Cursor, To_Atom ("argument"), 1);
         Test_Tools.Next_And_Check (Test, Cursor, Events.Close_List, 0);
         Test_Tools.Next_And_Check (Test, Cursor, Events.Open_List, 1);
         Test_Tools.Next_And_Check (Test, Cursor, To_Atom ("command"), 1);
         Test_Tools.Next_And_Check (Test, Cursor, Events.Close_List, 0);
         Test_Tools.Next_And_Check (Test, Cursor, Events.End_Of_Input, 0);
      end;
   exception
      when Error : others => Test.Report_Exception (Error);
   end Test_Exception_Fallback;


   procedure Test_Inspection (Report : in out NT.Reporter'Class) is
      Test : NT.Test := Report.Item ("Inspection");
   begin
      declare
         Inter : Test_Interpreters.Interpreter;
      begin
         if not Inter.Is_Empty then
            Test.Fail ("Default interpreter is not empty");
         end if;

         if Inter.Has_Command (To_Atom ("cmd")) then
            Test.Fail ("Default interpreter has command ""cmd""");
         end if;

         Inter := Test_Interpreter;

         if Inter.Is_Empty then
            Test.Fail ("Test interpreter is empty");
         end if;

         if not Inter.Has_Command (To_Atom ("cmd")) then
            Test.Fail ("Test interpreter has not command ""cmd""");
         end if;

         if Inter.Has_Command (To_Atom ("not-a-cmd")) then
            Test.Fail ("Test interpreter has command ""not-a-cmd""");
         end if;

      end;
   exception
      when Error : others => Test.Report_Exception (Error);
   end Test_Inspection;


   procedure Test_Local_Fallback (Report : in out NT.Reporter'Class) is
      Test : NT.Test := Report.Item ("Local fallback");
   begin
      declare
         Inter : Test_Interpreters.Interpreter := Test_Interpreter;
         Buffer : aliased Test_Tools.Memory_Stream;
         Printer : Printers.Canonical (Buffer'Access);
         Input : Caches.Reference := Invalid_Commands;
         Cursor : Caches.Cursor := Input.First;
         Fallback : Recorder;
      begin
         Input.Append_Atom (To_Atom ("cmd"));
         Buffer.Set_Expected (To_Atom
           ("7:not-cmd(14:7:not-cmd3:arg)13:not-a-command"
            & "(18:13:not-a-command())3:cmd"));

         Inter.Execute (Fallback, Cursor, Printer, True);

         Buffer.Check_Stream (Test);
      end;
   exception
      when Error : others => Test.Report_Exception (Error);
   end Test_Local_Fallback;


   procedure Test_Premanent_Fallback (Report : in out NT.Reporter'Class) is
      Test : NT.Test := Report.Item ("Permanent fallback");
   begin
      declare
         Inter : Test_Interpreters.Interpreter := Test_Interpreter;
         Buffer : aliased Test_Tools.Memory_Stream;
         Printer : Printers.Canonical (Buffer'Access);
         Input : constant Caches.Reference := Invalid_Commands;
         Cursor : Caches.Cursor := Input.First;
      begin
         Buffer.Set_Expected (To_Atom
           ("7:not-cmd(14:7:not-cmd3:arg)13:not-a-command"
            & "(18:13:not-a-command())"));

         Inter.Set_Fallback (To_Atom ("cmd"));
         Inter.Execute (Cursor, Printer, True);

         Buffer.Check_Stream (Test);
      end;
   exception
      when Error : others => Test.Report_Exception (Error);
   end Test_Premanent_Fallback;


   procedure Test_Unknown_Commands (Report : in out NT.Reporter'Class) is
      Test : NT.Test := Report.Item ("Unknown commands");
   begin
      declare
         Inter : Test_Interpreters.Interpreter := Test_Interpreter;
         Buffer : aliased Test_Tools.Memory_Stream;
         Printer : Printers.Canonical (Buffer'Access);
         Input : constant Caches.Reference := Invalid_Commands;
         Cursor : Caches.Cursor := Input.First;
      begin
         Inter.Set_Fallback (To_Atom ("cmd"));
         Inter.Reset_Fallback;

         begin
            Inter.Execute (Cursor, Printer, True);
            Test.Fail ("No exception raised after not-cmd");
         exception
            when Test_Interpreters.Command_Not_Found => null;
            when Error : others =>
               Test.Fail ("Unexpected exception raised after not-cmd");
               Test.Report_Exception (Error, NT.Fail);
         end;

         Test_Tools.Next_And_Check (Test, Cursor, Events.Open_List, 1);

         begin
            Inter.Execute (Cursor, Printer, True);
            Test.Fail ("No exception raised after (not-cmd)");
         exception
            when Test_Interpreters.Command_Not_Found => null;
            when Error : others =>
               Test.Fail ("Unexpected exception raised after (not-cmd)");
               Test.Report_Exception (Error, NT.Fail);
         end;

         Test_Tools.Next_And_Check (Test, Cursor, To_Atom ("arg"), 1);
         Test_Tools.Next_And_Check (Test, Cursor, Events.Close_List, 0);
         Test_Tools.Next_And_Check
           (Test, Cursor, To_Atom ("not-a-command"), 0);

         begin
            Inter.Execute (Cursor, Printer, True);
            Test.Fail ("No exception raised after not-a-command");
         exception
            when Test_Interpreters.Command_Not_Found => null;
            when Error : others =>
               Test.Fail ("Unexpected exception raised after not-a-command");
               Test.Report_Exception (Error, NT.Fail);
         end;

         Test_Tools.Next_And_Check (Test, Cursor, Events.Open_List, 1);

         begin
            Inter.Execute (Cursor, Printer, True);
            Test.Fail ("No exception raised after not-a-command");
         exception
            when Test_Interpreters.Command_Not_Found => null;
            when Error : others =>
               Test.Fail ("Unexpected exception raised after not-a-command");
               Test.Report_Exception (Error, NT.Fail);
         end;

         Test_Tools.Next_And_Check (Test, Cursor, Events.Open_List, 2);
         Test_Tools.Next_And_Check (Test, Cursor, Events.Close_List, 1);
         Test_Tools.Next_And_Check (Test, Cursor, Events.Close_List, 0);
         Test_Tools.Next_And_Check (Test, Cursor, Events.End_Of_Input, 0);

         Buffer.Check_Stream (Test);
      end;
   exception
      when Error : others => Test.Report_Exception (Error);
   end Test_Unknown_Commands;

end Natools.S_Expressions.Dynamic_Interpreter_Tests;

Added tests/natools-s_expressions-dynamic_interpreter_tests.ads version [b1da921500].



























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
------------------------------------------------------------------------------
-- Copyright (c) 2014, Natacha Porté                                        --
--                                                                          --
-- Permission to use, copy, modify, and distribute this software for any    --
-- purpose with or without fee is hereby granted, provided that the above   --
-- copyright notice and this permission notice appear in all copies.        --
--                                                                          --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           --
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Natools.S_Expressions.Dynamic_Interpreter_Tests provides a test suite    --
-- for the dyamic version of S-expression interpreters.                     --
------------------------------------------------------------------------------

with Natools.Tests;

private with Natools.S_Expressions.Dynamic_Interpreters;
private with Natools.S_Expressions.Lockable;
private with Natools.S_Expressions.Printers;

package Natools.S_Expressions.Dynamic_Interpreter_Tests is
   pragma Preelaborate (Dynamic_Interpreter_Tests);

   package NT renames Natools.Tests;

   procedure All_Tests (Report : in out NT.Reporter'Class);

   procedure Test_Basic_Usage (Report : in out NT.Reporter'Class);
   procedure Test_Exception_Fallback (Report : in out NT.Reporter'Class);
   procedure Test_Inspection (Report : in out NT.Reporter'Class);
   procedure Test_Local_Fallback (Report : in out NT.Reporter'Class);
   procedure Test_Premanent_Fallback (Report : in out NT.Reporter'Class);
   procedure Test_Unknown_Commands (Report : in out NT.Reporter'Class);

private

   package Test_Interpreters is new Natools.S_Expressions.Dynamic_Interpreters
     (Printers.Printer'Class, Boolean);

   type Recorder is new Test_Interpreters.Command with null record;

   overriding procedure Execute
     (Self : in out Recorder;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Name : in Atom);

   overriding procedure Execute
     (Self : in out Recorder;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class);

   Special_Exception : exception;

   type Raiser is new Test_Interpreters.Command with null record;

   overriding procedure Execute
     (Self : in out Raiser;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Name : in Atom);

   overriding procedure Execute
     (Self : in out Raiser;
      State : in out Printers.Printer'Class;
      Context : in Boolean;
      Cmd : in out Lockable.Descriptor'Class);

end Natools.S_Expressions.Dynamic_Interpreter_Tests;

Modified tests/test_all.adb from [cf090ebe77] to [f858f83fe4].

22
23
24
25
26
27
28

29
30
31
32
33
34
35
with Ada.Text_IO;
with Natools.Chunked_Strings.Tests;
with Natools.Getopt_Long_Tests;
with Natools.HMAC_Tests;
with Natools.Reference_Tests;
with Natools.S_Expressions.Atom_Buffers.Tests;
with Natools.S_Expressions.Cache_Tests;

with Natools.S_Expressions.Encodings.Tests;
with Natools.S_Expressions.Interpreter_Tests;
with Natools.S_Expressions.Lockable.Tests;
with Natools.S_Expressions.Parsers.Tests;
with Natools.S_Expressions.Printers.Tests;
with Natools.S_Expressions.Printers.Pretty.Tests;
with Natools.S_Expressions.Printers.Pretty.Config.Tests;







>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
with Ada.Text_IO;
with Natools.Chunked_Strings.Tests;
with Natools.Getopt_Long_Tests;
with Natools.HMAC_Tests;
with Natools.Reference_Tests;
with Natools.S_Expressions.Atom_Buffers.Tests;
with Natools.S_Expressions.Cache_Tests;
with Natools.S_Expressions.Dynamic_Interpreter_Tests;
with Natools.S_Expressions.Encodings.Tests;
with Natools.S_Expressions.Interpreter_Tests;
with Natools.S_Expressions.Lockable.Tests;
with Natools.S_Expressions.Parsers.Tests;
with Natools.S_Expressions.Printers.Tests;
with Natools.S_Expressions.Printers.Pretty.Tests;
with Natools.S_Expressions.Printers.Pretty.Config.Tests;
85
86
87
88
89
90
91




92
93
94
95
96
97
98
   Report.Section ("S_Expressions.Atom_Buffers");
   Natools.S_Expressions.Atom_Buffers.Tests.All_Tests (Report);
   Report.End_Section;

   Report.Section ("S_Expressions.Caches");
   Natools.S_Expressions.Cache_Tests.All_Tests (Report);
   Report.End_Section;





   Report.Section ("S_Expressions.Encodings");
   Natools.S_Expressions.Encodings.Tests.All_Tests (Report);
   Report.End_Section;

   Report.Section ("S_Expressions.Interpreters");
   Natools.S_Expressions.Interpreter_Tests.All_Tests (Report);







>
>
>
>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
   Report.Section ("S_Expressions.Atom_Buffers");
   Natools.S_Expressions.Atom_Buffers.Tests.All_Tests (Report);
   Report.End_Section;

   Report.Section ("S_Expressions.Caches");
   Natools.S_Expressions.Cache_Tests.All_Tests (Report);
   Report.End_Section;

   Report.Section ("S_Expressions.Dynamic_Interpreters");
   Natools.S_Expressions.Dynamic_Interpreter_Tests.All_Tests (Report);
   Report.End_Section;

   Report.Section ("S_Expressions.Encodings");
   Natools.S_Expressions.Encodings.Tests.All_Tests (Report);
   Report.End_Section;

   Report.Section ("S_Expressions.Interpreters");
   Natools.S_Expressions.Interpreter_Tests.All_Tests (Report);