Index: src/natools-s_expressions-generic_caches.adb ================================================================== --- src/natools-s_expressions-generic_caches.adb +++ src/natools-s_expressions-generic_caches.adb @@ -221,12 +221,15 @@ if Cache.Exp.Is_Empty then return Cursor'(others => <>); else N := Cache.Exp.Query.Data.Root; pragma Assert (N /= null); - return Cursor'(Exp => Cache.Exp, Position => N, - Opening => N.Kind = List_Node); + return Cursor'(Exp => Cache.Exp, + Position => N, + Opening => N.Kind = List_Node, + Stack => <>, + Locked => False); end if; end First; @@ -235,11 +238,11 @@ -------------------------- overriding function Current_Event (Object : in Cursor) return Events.Event is begin - if Object.Position = null then + if Object.Position = null or Object.Locked then return Events.End_Of_Input; end if; case Object.Position.Kind is when Atom_Node => @@ -254,43 +257,38 @@ end Current_Event; overriding function Current_Atom (Object : in Cursor) return Atom is begin - if Object.Position = null or else Object.Position.Kind /= Atom_Node then + if Object.Position = null or else Object.Position.Kind /= Atom_Node + or else Object.Locked + then raise Program_Error; end if; return Object.Position.Data.all; end Current_Atom; overriding function Current_Level (Object : in Cursor) return Natural is - Result : Natural := 0; - N : Node_Access := Object.Position; begin - if Object.Position /= null - and then Object.Position.Kind = List_Node - and then Object.Opening - then - Result := Result + 1; + if Object.Locked then + return 0; + else + return Absolute_Level (Object) + - Lockable.Current_Level (Object.Stack); end if; - - while N /= null loop - Result := Result + 1; - N := N.Parent; - end loop; - - return Natural'Max (Result, 1) - 1; end Current_Level; overriding procedure Query_Atom (Object : in Cursor; Process : not null access procedure (Data : in Atom)) is begin - if Object.Position = null or else Object.Position.Kind /= Atom_Node then + if Object.Position = null or else Object.Position.Kind /= Atom_Node + or else Object.Locked + then raise Program_Error; end if; Process.all (Object.Position.Data.all); end Query_Atom; @@ -301,11 +299,13 @@ Data : out Atom; Length : out Count) is Transferred : Count; begin - if Object.Position = null or else Object.Position.Kind /= Atom_Node then + if Object.Position = null or else Object.Position.Kind /= Atom_Node + or else Object.Locked + then raise Program_Error; end if; Length := Object.Position.Data'Length; Transferred := Count'Min (Data'Length, Length); @@ -317,11 +317,11 @@ overriding procedure Next (Object : in out Cursor; Event : out Events.Event) is begin - if Object.Position = null then + if Object.Position = null or Object.Locked then Event := Events.End_Of_Input; return; end if; if Object.Opening then @@ -344,9 +344,83 @@ else Object.Position := null; end if; Event := Object.Current_Event; + + if Event = Events.Close_List + and then Object.Absolute_Level < Lockable.Current_Level (Object.Stack) + then + Event := Events.End_Of_Input; + Object.Locked := True; + end if; end Next; -end Natools.S_Expressions.Generic_Caches; + + + ----------------------------------- + -- Lockable.Descriptor Interface -- + ----------------------------------- + + function Absolute_Level (Object : Cursor) return Natural is + Result : Natural := 0; + N : Node_Access := Object.Position; + begin + if Object.Position /= null + and then Object.Position.Kind = List_Node + and then Object.Opening + then + Result := Result + 1; + end if; + + while N /= null loop + Result := Result + 1; + N := N.Parent; + end loop; + + return Natural'Max (Result, 1) - 1; + end Absolute_Level; + + + overriding procedure Lock + (Object : in out Cursor; + State : out Lockable.Lock_State) is + begin + Lockable.Push_Level (Object.Stack, Object.Absolute_Level, State); + end Lock; + + + overriding procedure Unlock + (Object : in out Cursor; + State : in out Lockable.Lock_State; + Finish : in Boolean := True) + is + Previous_Level : constant Natural + := Lockable.Current_Level (Object.Stack); + begin + Lockable.Pop_Level (Object.Stack, State); + State := Lockable.Null_State; + Object.Locked := False; + + if Finish then + declare + Event : Events.Event := Object.Current_Event; + begin + loop + case Event is + when Events.Add_Atom | Events.Open_List => + null; + when Events.Close_List => + exit when Object.Absolute_Level < Previous_Level; + when Events.Error | Events.End_Of_Input => + exit; + end case; + Object.Next (Event); + end loop; + end; + end if; + + Object.Locked + := Object.Absolute_Level < Lockable.Current_Level (Object.Stack); + end Unlock; +end Natools.S_Expressions.Generic_Caches; Index: src/natools-s_expressions-generic_caches.ads ================================================================== --- src/natools-s_expressions-generic_caches.ads +++ src/natools-s_expressions-generic_caches.ads @@ -26,10 +26,11 @@ -- see Natools.S_Expressions.Holders. -- ------------------------------------------------------------------------------ with System.Storage_Pools; +with Natools.S_Expressions.Lockable; with Natools.S_Expressions.Printers; private with Ada.Finalization; private with Ada.Unchecked_Deallocation; private with Natools.References; @@ -50,11 +51,11 @@ function Duplicate (Cache : Reference) return Reference; -- Create a new copy of the S-expression held in Cache and return it - type Cursor is new Descriptor with private; + type Cursor is new Lockable.Descriptor with private; overriding function Current_Event (Object : in Cursor) return Events.Event; overriding function Current_Atom (Object : in Cursor) return Atom; overriding function Current_Level (Object : in Cursor) return Natural; overriding procedure Query_Atom @@ -66,10 +67,18 @@ Length : out Count); overriding procedure Next (Object : in out Cursor; Event : out Events.Event); + overriding procedure Lock + (Object : in out Cursor; + State : out Lockable.Lock_State); + overriding procedure Unlock + (Object : in out Cursor; + State : in out Lockable.Lock_State; + Finish : in Boolean := True); + function First (Cache : Reference'Class) return Cursor; -- Create a new Cursor pointing at the beginning of Cache private @@ -129,12 +138,16 @@ type Reference is new Printers.Printer with record Exp : Trees.Reference; end record; - type Cursor is new Descriptor with record + type Cursor is new Lockable.Descriptor with record Exp : Trees.Reference := Trees.Null_Reference; Position : Node_Access := null; Opening : Boolean := False; + Stack : Lockable.Lock_Stack; + Locked : Boolean := False; end record; + + function Absolute_Level (Object : Cursor) return Natural; end Natools.S_Expressions.Generic_Caches;