------------------------------------------------------------------------------
-- 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. --
------------------------------------------------------------------------------
package body Natools.S_Expressions.Lockable is
----------------
-- Lock Stack --
----------------
procedure Push_Level
(Stack : in out Lock_Stack;
Level : in Natural;
State : out Lock_State) is
begin
State := (Depth => Stack.Depth, Level => Stack.Level);
Stack := (Depth => Stack.Depth + 1, Level => Level);
end Push_Level;
procedure Pop_Level
(Stack : in out Lock_Stack;
State : in Lock_State;
Allow_Gap : in Boolean := False) is
begin
if State.Depth = 0 then
raise Constraint_Error with "Invalid stack state";
elsif State.Depth >= Stack.Depth then
raise Constraint_Error with "Trying to Pop a state outside of Stack";
elsif not Allow_Gap and then State.Depth < Stack.Depth - 1 then
raise Constraint_Error
with "Trying to Pop several items without Allow_Gap";
end if;
Stack := (Depth => State.Depth, Level => State.Level);
end Pop_Level;
function Current_Level (Stack : Lock_Stack) return Natural is
begin
return Stack.Level;
end Current_Level;
function Null_State return Lock_State is
begin
return (0, 0);
end Null_State;
-------------------------------------
-- Lockable Wrapper Implementation --
-------------------------------------
function Current_Event (Object : in Wrapper) return Events.Event is
begin
if Object.Finished then
return Events.End_Of_Input;
else
return Object.Backend.Current_Event;
end if;
end Current_Event;
function Current_Atom (Object : in Wrapper) return Atom is
begin
if Object.Finished then
raise Program_Error with "Current_Atom on finished wrapper";
else
return Object.Backend.Current_Atom;
end if;
end Current_Atom;
function Current_Level (Object : in Wrapper) return Natural is
begin
if Object.Finished then
return 0;
else
return Object.Backend.Current_Level - Current_Level (Object.Stack);
end if;
end Current_Level;
procedure Query_Atom
(Object : in Wrapper;
Process : not null access procedure (Data : in Atom)) is
begin
if Object.Finished then
raise Program_Error with "Query_Atom on finished wrapper";
else
Object.Backend.Query_Atom (Process);
end if;
end Query_Atom;
procedure Read_Atom
(Object : in Wrapper;
Data : out Atom;
Length : out Count) is
begin
if Object.Finished then
raise Program_Error with "Read_Atom on finished wrapper";
else
Object.Backend.Read_Atom (Data, Length);
end if;
end Read_Atom;
procedure Next
(Object : in out Wrapper;
Event : out Events.Event) is
begin
if Object.Finished then
Event := Events.Error;
return;
end if;
Object.Backend.Next (Event);
if Event = Events.Close_List
and then Object.Backend.Current_Level < Current_Level (Object.Stack)
then
Object.Finished := True;
Event := Events.End_Of_Input;
end if;
end Next;
procedure Lock
(Object : in out Wrapper;
State : out Lock_State) is
begin
Push_Level (Object.Stack, Object.Backend.Current_Level, State);
end Lock;
procedure Unlock
(Object : in out Wrapper;
State : in out Lock_State;
Finish : in Boolean := True)
is
Previous_Level : constant Natural := Current_Level (Object.Stack);
begin
Pop_Level (Object.Stack, State);
State := (0, 0);
if Finish then
declare
Event : Events.Event;
begin
Event := Object.Backend.Current_Event;
loop
case Event is
when Events.Open_List | Events.Add_Atom =>
null;
when Events.Close_List =>
exit when Object.Backend.Current_Level < Previous_Level;
when Events.Error | Events.End_Of_Input =>
exit;
end case;
Object.Backend.Next (Event);
end loop;
end;
end if;
Object.Finished := Object.Backend.Current_Level
< Current_Level (Object.Stack);
end Unlock;
end Natools.S_Expressions.Lockable;