summaryrefslogtreecommitdiff
path: root/src/packrat-parse_graphs.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/packrat-parse_graphs.adb')
-rw-r--r--src/packrat-parse_graphs.adb1062
1 files changed, 937 insertions, 125 deletions
diff --git a/src/packrat-parse_graphs.adb b/src/packrat-parse_graphs.adb
index c911fb4..c9171c6 100644
--- a/src/packrat-parse_graphs.adb
+++ b/src/packrat-parse_graphs.adb
@@ -1,20 +1,17 @@
-package body Packrat.Parse_Graphs is
+with
+ -- Ada.Strings.Fixed,
+ Ada.Characters.Latin_1;
- function "<"
- (Left, Right : in Edge_Label_Type)
- return Boolean is
- begin
- if Left.Finish = Right.Finish then
- return Left.Order < Right.Order;
- else
- return Left.Finish < Right.Finish;
- end if;
- end "<";
+
+package body Packrat.Parse_Graphs is
+ package SU renames Ada.Strings.Unbounded;
+ package Latin renames Ada.Characters.Latin_1;
+
@@ -23,47 +20,90 @@ package body Packrat.Parse_Graphs is
return Boolean
is
use type Base.Graph;
+ use type Finish_Vectors.Vector;
+ use type Node_Label_Maps.Map;
begin
- return Base.Graph (Left) = Base.Graph (Right) and
- Left.Root_Node = Right.Root_Node;
+ return Left.Internal_Graph = Right.Internal_Graph and
+ Left.Root_Node = Right.Root_Node and
+ Left.Root_Finishes = Right.Root_Finishes and
+ Left.Label_Map = Right.Label_Map;
end "=";
+ function "<"
+ (Left, Right : Finished_Token)
+ return Boolean
+ is
+ Left_Index, Right_Index : Positive;
+ begin
+ if Gen_Tokens.Start (Left.Token) = Gen_Tokens.Start (Right.Token) then
+ if Left.Finish = Right.Finish then
+ if Gen_Tokens.Label (Left.Token) = Gen_Tokens.Label (Right.Token) then
+ Left_Index := Gen_Tokens.Value (Left.Token)'First;
+ Right_Index := Gen_Tokens.Value (Right.Token)'First;
+ while Left_Index <= Gen_Tokens.Value (Left.Token)'Last and
+ Right_Index <= Gen_Tokens.Value (Right.Token)'Last
+ loop
+ if Gen_Tokens.Value (Left.Token) (Left_Index) <
+ Gen_Tokens.Value (Right.Token) (Right_Index)
+ then
+ return True;
+ elsif Gen_Tokens.Value (Left.Token) (Left_Index) /=
+ Gen_Tokens.Value (Right.Token) (Right_Index)
+ then
+ return False;
+ end if;
+ Left_Index := Left_Index + 1;
+ Right_Index := Right_Index + 1;
+ end loop;
+ return Gen_Tokens.Value (Left.Token)'Length <
+ Gen_Tokens.Value (Right.Token)'Length;
+ else
+ return Gen_Tokens.Label (Left.Token) < Gen_Tokens.Label (Right.Token);
+ end if;
+ else
+ return Left.Finish < Right.Finish;
+ end if;
+ else
+ return Gen_Tokens.Start (Left.Token) < Gen_Tokens.Start (Right.Token);
+ end if;
+ end "<";
-
- function To_Graph
- (Nodes : in Node_Array;
- Edges : in Edge_Array)
- return Parse_Graph is
+ function "<"
+ (Left, Right : in Finished_Token_Array)
+ return Boolean
+ is
+ Left_Index : Positive := Left'First;
+ Right_Index : Positive := Right'First;
begin
- return G : Parse_Graph :=
- (Base.To_Graph (Nodes, Edges) with Root_Node => No_Node);
- end To_Graph;
+ while Left_Index <= Left'Last and Right_Index <= Right'Last loop
+ if Left (Left_Index) < Right (Right_Index) then
+ return True;
+ elsif Left (Left_Index) /= Right (Right_Index) then
+ return False;
+ end if;
+ Left_Index := Left_Index + 1;
+ Right_Index := Right_Index + 1;
+ end loop;
+ return Left'Length < Right'Length;
+ end "<";
- function To_Graph
- (Nodes : in Node_Array;
- Edges : in Edge_Array;
- Root : in Extended_Node_ID_Type)
- return Parse_Graph
- is
- Valid : Boolean := False;
+ function "<"
+ (Left, Right : in Token_Group)
+ return Boolean is
begin
- if Root /= No_Node then
- for N of Nodes loop
- if Root = N then
- Valid := True;
- exit;
- end if;
- end loop;
- if not Valid then
- raise Constraint_Error with "Root node not in graph";
+ if Gen_Tokens.Start (Left.Parent.Token) = Gen_Tokens.Start (Right.Parent.Token) then
+ if Finish (Left) = Finish (Right) then
+ return Left.Elems.Element < Right.Elems.Element;
+ else
+ return Finish (Left) < Finish (Right);
end if;
+ else
+ return Gen_Tokens.Start (Left.Parent.Token) < Gen_Tokens.Start (Right.Parent.Token);
end if;
- return G : Parse_Graph :=
- (Base.To_Graph (Nodes, Edges) with Root_Node => Root);
- end To_Graph;
+ end "<";
@@ -73,8 +113,10 @@ package body Packrat.Parse_Graphs is
(Target : in out Parse_Graph;
Source : in Parse_Graph) is
begin
- Base.Assign (Base.Graph (Target), Base.Graph (Source));
+ Target.Internal_Graph.Assign (Source.Internal_Graph);
Target.Root_Node := Source.Root_Node;
+ Target.Root_Finishes.Assign (Source.Root_Finishes);
+ Target.Label_Map.Assign (Source.Label_Map);
end Assign;
@@ -83,170 +125,940 @@ package body Packrat.Parse_Graphs is
return Parse_Graph is
begin
return G : Parse_Graph :=
- (Base.Copy (Base.Graph (Source)) with Root_Node => Source.Root_Node);
+ (Internal_Graph => Source.Internal_Graph.Copy,
+ Root_Node => Source.Root_Node,
+ Root_Finishes => Source.Root_Finishes.Copy,
+ Label_Map => Source.Label_Map.Copy);
end Copy;
procedure Move
(Target, Source : in out Parse_Graph) is
begin
- Base.Move (Base.Graph (Target), Base.Graph (Source));
+ Target.Internal_Graph.Move (Source.Internal_Graph);
Target.Root_Node := Source.Root_Node;
- Source.Root_Node := No_Node;
+ Source.Root_Node := Base.No_Node;
+ Target.Root_Finishes.Move (Source.Root_Finishes);
+ Target.Label_Map.Move (Source.Label_Map);
end Move;
- function Root
+ function Is_Empty
(Container : in Parse_Graph)
- return Cursor is
+ return Boolean is
begin
- if not Container.Contains (Container.Root_Node) then
- return No_Element;
- else
- return Container.To_Cursor (Container.Root_Node);
- end if;
- end Root;
+ return Container.Label_Map.Is_Empty;
+ end Is_Empty;
- procedure Set_Root
- (Container : in out Parse_Graph;
- Node : in Extended_Node_ID_Type) is
+ procedure Clear
+ (Container : in out Parse_Graph) is
begin
- Container.Root_Node := Node;
- end Set_Root;
+ Container.Internal_Graph.Clear;
+ Container.Root_Node := Base.No_Node;
+ Container.Root_Finishes.Clear;
+ Container.Label_Map.Clear;
+ end Clear;
- function Finish_List
+ function In_Finishes
(Container : in Parse_Graph;
Node : in Node_ID_Type)
- return Finish_Array is
+ return Finish_Vectors.Vector
+ is
+ Result : Finish_Vectors.Vector;
+ Current : Finish_Type;
begin
- return Finish_List (Container.To_Cursor (Node));
- end Finish_List;
+ if Node = Container.Root_Node then
+ Result := Container.Root_Finishes;
+ end if;
+ for Edge of Container.Internal_Graph.Inbound (Node) loop
+ Current := Container.Internal_Graph.Label (Edge).Subnode_Finish;
+ if not Result.Contains (Current) then
+ Result.Append (Current);
+ end if;
+ end loop;
+ return Result;
+ end In_Finishes;
- function Finish_List
- (Position : in Cursor)
- return Finish_Array
+ function Out_Finishes
+ (Container : in Parse_Graph;
+ Node : in Node_ID_Type)
+ return Finish_Vectors.Vector
is
- function V2A is new Vector_To_Array (Finish_Type, Finish_Array, Finish_Vectors);
- Fins : Finish_Vectors.Vector;
- Current : Edge_Label_Type;
- begin
- for E of Outbound (Position) loop
- if Has_Label (Position, E) then
- Current := Label (Position, E);
- if not Fins.Contains (Current.Finish) then
- Fins.Append (Current.Finish);
- end if;
+ Result : Finish_Vectors.Vector;
+ Current : Finish_Type;
+ begin
+ for Edge of Container.Internal_Graph.Outbound (Node) loop
+ Current := Container.Internal_Graph.Label (Edge).Group_Finish;
+ if not Result.Contains (Current) then
+ Result.Append (Current);
end if;
end loop;
- Finsort.Sort (Fins);
- return V2A (Fins);
- end Finish_List;
+ return Result;
+ end Out_Finishes;
+
+
+
+
+
+ function Debug_String
+ (Container : in Parse_Graph)
+ return String
+ is
+ Mapping : Enum_Node_Maps.Map;
+ Current : Gen_Tokens.Token;
+ Result : SU.Unbounded_String;
+ begin
+ for Node of Container.Internal_Graph.Nodes loop
+ declare
+ Current : Label_Enum :=
+ Gen_Tokens.Label (Container.Internal_Graph.Label (Node));
+ begin
+ if not Mapping.Contains (Current) then
+ Mapping.Insert (Current, Node_Vectors.Empty_Vector);
+ end if;
+ Mapping.Reference (Current).Append (Node);
+ end;
+ end loop;
+ for Iter in Mapping.Iterate loop
+ SU.Append (Result, Label_Enum'Image (Enum_Node_Maps.Key (Iter)) & Latin.HT);
+ for Node of Enum_Node_Maps.Element (Iter) loop
+ Current := Container.Internal_Graph.Label (Node);
+ SU.Append (Result, Positive'Image (Gen_Tokens.Start (Current)) & " ->" & Latin.HT);
+ for Fin of In_Finishes (Container, Node) loop
+ SU.Append (Result, Finish_Type'Image (Fin) & " ->" & Latin.HT);
+ declare
+ Groupings : Token_Group_Array := Container.Subgroups ((Current, Fin));
+ begin
+ if Groupings'Length = 0 then
+ SU.Append (Result, "Leaf");
+ else
+ for Grouping of Groupings loop
+ for Fin_Token of Elements (Grouping) loop
+ SU.Append (Result, "Subnode " &
+ Label_Enum'Image (Gen_Tokens.Label (Fin_Token.Token)) &
+ " (" & Positive'Image (Gen_Tokens.Start (Fin_Token.Token)) &
+ "," & Finish_Type'Image (Fin_Token.Finish) & "), ");
+ end loop;
+ SU.Delete (Result, SU.Length (Result) - 1, SU.Length (Result));
+ SU.Append (Result, Latin.HT);
+ SU.Append (Result, SU."*" (3, Latin.HT));
+ end loop;
+ end if;
+ end;
+ SU.Delete (Result, SU.Length (Result), SU.Length (Result));
+ end loop;
+ SU.Delete (Result, SU.Length (Result), SU.Length (Result));
+ end loop;
+ -- what delete goes here?
+ end loop;
+ return SU.To_String (Result);
+ end Debug_String;
+
- function Sub_Nodes
+
+
+ function Contains
(Container : in Parse_Graph;
- Node : in Node_ID_Type;
- Finish_At : in Finish_Type)
- return Node_Array is
+ Token : in Gen_Tokens.Token)
+ return Boolean is
begin
- return Sub_Nodes (Container.To_Cursor (Node), Finish_At);
- end Sub_Nodes;
+ return Container.Label_Map.Contains (Token);
+ end Contains;
- function Sub_Nodes
- (Position : in Cursor;
- Finish_At : in Finish_Type)
- return Node_Array
+ function Contains
+ (Container : in Parse_Graph;
+ Position : in Finished_Token)
+ return Boolean
is
- function V2A is new Vector_To_Array (Node_ID_Type, Node_Array, Node_Vectors);
- Nodes : Node_Vectors.Vector;
- Current_Label : Edge_Label_Type;
- begin
- for E of Outbound (Position) loop
- if Has_Label (Position, E) then
- Current_Label := Label (Position, E);
- if Current_Label.Finish = Finish_At then
- Nodes.Reference (Current_Label.Order) := E.To;
+ Node : Node_ID_Type;
+ begin
+ if not Container.Contains (Position.Token) then
+ return False;
+ end if;
+ Node := Container.Label_Map.Element (Position.Token);
+ if Node = Container.Root_Node then
+ for F of Container.Root_Finish_List loop
+ if F = Position.Finish then
+ return True;
end if;
+ end loop;
+ end if;
+ return (for some Edge of Container.Internal_Graph.Inbound (Node) =>
+ Container.Internal_Graph.Label (Edge).Subnode_Finish = Position.Finish);
+ end Contains;
+
+
+ function Contains
+ (Container : in Parse_Graph;
+ Grouping : in Token_Group)
+ return Boolean
+ is
+ Groups : Group_ID_Vectors.Vector;
+ Next_ID : Group_ID_Type;
+ Parent_Node : Node_ID_Type;
+ begin
+ if not Container.Contains (Grouping.Parent) then
+ return False;
+ end if;
+ for Fin_Token of Elements (Grouping) loop
+ if not Container.Contains (Fin_Token) then
+ return False;
+ end if;
+ end loop;
+ Parent_Node := Container.Label_Map.Element (Grouping.Parent.Token);
+ for Edge of Container.Internal_Graph.Outbound (Parent_Node) loop
+ Next_ID := Container.Internal_Graph.Label (Edge).Group_ID;
+ if not Groups.Contains (Next_ID) then
+ Groups.Append (Next_ID);
end if;
end loop;
- return V2A (Nodes);
- end Sub_Nodes;
+ return (for some ID of Groups =>
+ (for all Sub of Elements (Grouping) =>
+ (for some Edge of Container.Internal_Graph.Between
+ (Parent_Node, Container.Label_Map.Element (Sub.Token)) =>
+ Container.Internal_Graph.Label (Edge) =
+ (Group_ID => ID,
+ Group_Finish => Finish (Grouping),
+ Subnode_Finish => Sub.Finish))));
+ end Contains;
+
+
+ function Reachable
+ (Container : in Parse_Graph;
+ Position : in Finished_Token)
+ return Boolean
+ is
+ -- This is basically a depth first search function.
+ function Finder
+ (Current : in Finished_Token)
+ return Boolean is
+ begin
+ return Current = Position or else
+ (for some Grouping of Container.Subgroups (Current) =>
+ (for some Fin_Token of Elements (Grouping) => Finder (Fin_Token)));
+ end Finder;
+ begin
+ return (for some Finish of Container.Root_Finish_List =>
+ Finder (Container.Root_Element (Finish)));
+ end Reachable;
+
+
+ function Locally_Reachable
+ (Container : in Parse_Graph;
+ Node : in Node_ID_Type)
+ return Boolean
+ is
+ use type Ada.Containers.Count_Type;
+ In_Subnodes, Out_Groups : Finish_Vectors.Vector;
+ In_Pos, Out_Pos : Positive := 1;
+ begin
+ In_Subnodes := In_Finishes (Container, Node);
+ if In_Subnodes.Length = 0 then
+ return False;
+ end if;
+ Out_Groups := Out_Finishes (Container, Node);
+ Finish_Sort.Sort (In_Subnodes);
+ Finish_Sort.Sort (Out_Groups);
+ while Out_Pos <= Out_Groups.Last_Index loop
+ if In_Pos > In_Subnodes.Last_Index or else
+ In_Subnodes.Element (In_Pos) > Out_Groups.Element (Out_Pos)
+ then
+ return False;
+ elsif In_Subnodes.Element (In_Pos) = Out_Groups.Element (Out_Pos) then
+ Out_Pos := Out_Pos + 1;
+ end if;
+ In_Pos := In_Pos + 1;
+ end loop;
+ return True;
+ end Locally_Reachable;
+
+
+ function All_Reachable
+ (Container : in Parse_Graph)
+ return Boolean is
+ begin
+ return (for all Node of Container.Internal_Graph.Nodes =>
+ Container.Locally_Reachable (Node));
+ end All_Reachable;
+
+
+ function Valid_Starts_Finishes
+ (Parent : in Finished_Token;
+ Subtokens : in Finished_Token_Array)
+ return Boolean
+ is
+ Subvec : Finished_Token_Vectors.Vector;
+ begin
+ for Sub of Subtokens loop
+ if Gen_Tokens.Start (Sub.Token) > Sub.Finish + 1 then
+ return False;
+ end if;
+ Subvec.Append (Sub);
+ end loop;
+ Finished_Token_Sort.Sort (Subvec);
+ for Index in Subvec.First_Index .. Subvec.Last_Index - 1 loop
+ if Subvec (Index).Finish >= Gen_Tokens.Start (Subvec (Index + 1).Token) then
+ return False;
+ end if;
+ end loop;
+ if Parent.Finish < Subvec.Last_Element.Finish or else
+ Gen_Tokens.Start (Parent.Token) > Gen_Tokens.Start (Subvec.First_Element.Token)
+ then
+ return False;
+ end if;
+ return True;
+ end Valid_Starts_Finishes;
+
+
+ function No_Loops_Introduced
+ (Container : in Parse_Graph;
+ Parent : in Finished_Token;
+ Subtokens : in Finished_Token_Array)
+ return Boolean
+ is
+ function Looper
+ (Current : in Finished_Token)
+ return Boolean is
+ begin
+ if not Container.Contains (Current.Token) then
+ return False;
+ elsif Current = Parent then
+ return True;
+ elsif Gen_Tokens.Start (Current.Token) > Gen_Tokens.Start (Parent.Token) then
+ return False;
+ else
+ return (for some Grouping of Container.Subgroups (Current) =>
+ (for some Sub of Elements (Grouping) => Looper (Sub)));
+ end if;
+ end Looper;
+ begin
+ return not Container.Contains (Parent.Token) or else
+ (for all Sub of Subtokens => not Looper (Sub));
+ end No_Loops_Introduced;
+
+
+ function Is_Sorted
+ (Finishes : in Finish_Array)
+ return Boolean
+ is
+ function Actual is new Sorted (Finish_Type, Finish_Array);
+ begin
+ return Actual (Finishes);
+ end Is_Sorted;
+
+
+ function Is_Sorted
+ (Positions : in Finished_Token_Array)
+ return Boolean
+ is
+ function Actual is new Sorted (Finished_Token, Finished_Token_Array);
+ begin
+ return Actual (Positions);
+ end Is_Sorted;
+
+
+ function Is_Sorted
+ (Groupings : in Token_Group_Array)
+ return Boolean
+ is
+ function Actual is new Sorted (Token_Group, Token_Group_Array);
+ begin
+ return Actual (Groupings);
+ end Is_Sorted;
+
+
+ function No_Duplicates
+ (Finishes : in Finish_Array)
+ return Boolean
+ is
+ function Actual is new No_Dups (Finish_Type, Finish_Array);
+ begin
+ return Actual (Finishes);
+ end No_Duplicates;
+
+
+ function No_Duplicates
+ (Positions : in Finished_Token_Array)
+ return Boolean
+ is
+ function Actual is new No_Dups (Finished_Token, Finished_Token_Array);
+ begin
+ return Actual (Positions);
+ end No_Duplicates;
+
+
+ function No_Duplicates
+ (Groupings : in Token_Group_Array)
+ return Boolean
+ is
+ function Actual is new No_Dups (Token_Group, Token_Group_Array);
+ begin
+ return Actual (Groupings);
+ end No_Duplicates;
+
+ procedure Include
+ (Container : in out Parse_Graph;
+ Token : in Gen_Tokens.Token)
+ is
+ Node_ID : Node_ID_Type;
+ begin
+ if not Container.Contains (Token) then
+ Node_ID := Container.Internal_Graph.Unused;
+ Container.Internal_Graph.Insert (Base.Labeled_Node_Type'(Node_ID, Token));
+ Container.Label_Map.Insert (Token, Node_ID);
+ end if;
+ end Include;
+
+
+ procedure Connect
+ (Container : in out Parse_Graph;
+ Parent : in Finished_Token;
+ Subtokens : in Finished_Token_Array)
+ is
+ Parent_ID : Node_ID_Type;
+ Use_GID : Group_ID_Type;
+ New_Edge : Base.Edge_Type;
+ New_Label : Edge_Label_Type;
+ begin
+ Container.Include (Parent.Token);
+ for Sub of Subtokens loop
+ Container.Include (Sub.Token);
+ end loop;
+ Parent_ID := Container.Label_Map.Element (Parent.Token);
+ declare
+ Outedges : Base.Edge_Array := Container.Internal_Graph.Outbound (Parent_ID);
+ begin
+ Use_GID := Group_ID_Type'First;
+ while (for some E of Outedges =>
+ Container.Internal_Graph.Label (E).Group_ID = Use_GID)
+ loop
+ Use_GID := Use_GID + 1;
+ end loop;
+ end;
+ for Sub of Subtokens loop
+ New_Edge :=
+ (ID => Container.Internal_Graph.Unused,
+ From => Parent_ID,
+ To => Container.Label_Map.Element (Sub.Token));
+ New_Label := (Use_GID, Parent.Finish, Sub.Finish);
+ Container.Internal_Graph.Insert (Base.Labeled_Edge_Type'(New_Edge, New_Label));
+ end loop;
+ end Connect;
+
procedure Prune
(Container : in out Parse_Graph;
- Node : in Node_ID_Type)
+ Token : in Gen_Tokens.Token) is
+ begin
+ if not Container.Contains (Token) then
+ return;
+ end if;
+ if Container.Label_Map (Token) = Container.Root_Node then
+ Container.Clear_Root;
+ end if;
+ Container.Internal_Graph.Delete (Container.Label_Map (Token));
+ Container.Label_Map.Delete (Token);
+ end Prune;
+
+
+ procedure Prune
+ (Container : in out Parse_Graph;
+ Position : in Finished_Token)
is
- My_Cursor : Cursor := Container.To_Cursor (Node);
+ Node : Node_ID_Type;
begin
- Prune (My_Cursor);
+ if not Container.Contains (Position.Token) then
+ return;
+ end if;
+ Node := Container.Label_Map.Element (Position.Token);
+ if Node = Container.Root_Node then
+ for I in reverse 1 .. Container.Root_Finishes.Last_Index loop
+ if Container.Root_Finishes.Element (I) = Position.Finish then
+ Container.Root_Finishes.Delete (I);
+ end if;
+ end loop;
+ end if;
+ for Edge of Container.Internal_Graph.Inbound (Node) loop
+ if Container.Internal_Graph.Label (Edge).Subnode_Finish = Position.Finish then
+ Container.Internal_Graph.Delete (Edge);
+ end if;
+ end loop;
end Prune;
procedure Prune
- (Position : in out Cursor)
+ (Container : in out Parse_Graph;
+ Grouping : in Token_Group)
is
- use type Ada.Containers.Count_Type;
- Active : Cursor_Vectors.Vector;
- Current : Cursor;
+ Group_IDs : Group_ID_Vectors.Vector;
+ Parent_Node : Node_ID_Type;
+ Current_ID : Group_ID_Type;
begin
- if not Has_Element (Position) then
+ -- Short circuit checks
+ if not Container.Contains (Grouping.Parent) then
return;
end if;
- for N of Children (Position) loop
- if N /= Element (Position) then
- Active.Append (Cursor_To (Position, N));
+ for Fin_Token of Elements (Grouping) loop
+ if not Container.Contains (Fin_Token) then
+ return;
end if;
end loop;
- Delete (Position);
- while not Active.Is_Empty loop
- for Index in reverse 1 .. Active.Last_Index loop
- Current := Active (Index);
- if Indegree (Current) = 0 then
- for N of Children (Current) loop
- if not Active.Contains (Cursor_To (Current, N)) then
- Active.Append (Cursor_To (Current, N));
- end if;
- end loop;
- Delete (Current);
+
+ Parent_Node := Container.To_Node (Grouping.Parent);
+
+ -- Gather up the IDs of groups for deletion
+ for Edge of Container.Internal_Graph.Between
+ (Parent_Node, Container.To_Node (Element (Grouping, 1)))
+ loop
+ Current_ID := Container.Internal_Graph.Label (Edge).Group_ID;
+ if not Group_IDs.Contains (Current_ID) and then
+ (for all Index in 2 .. Last_Index (Grouping) =>
+ (for some Other of Container.Internal_Graph.Between
+ (Parent_Node, Container.To_Node (Element (Grouping, Index))) =>
+ Container.Internal_Graph.Label (Other).Group_ID = Current_ID))
+ then
+ Group_IDs.Append (Current_ID);
+ end if;
+ end loop;
+
+ -- Delete all relevant edges
+ for Fin_Token of Elements (Grouping) loop
+ for Edge of Container.Internal_Graph.Between
+ (Parent_Node, Container.To_Node (Fin_Token))
+ loop
+ if Group_IDs.Contains (Container.Internal_Graph.Label (Edge).Group_ID) then
+ Container.Internal_Graph.Delete (Edge);
end if;
- Active.Delete (Index);
end loop;
end loop;
end Prune;
+ procedure Delete_Unreachable
+ (Container : in out Parse_Graph)
+ is
+ Examine, Next : Node_Vectors.Vector;
+ begin
+ if not Container.Has_Root then
+ Container.Clear;
+ return;
+ end if;
+ for Node of Container.Internal_Graph.Nodes loop
+ Examine.Append (Node);
+ end loop;
+ while not Examine.Is_Empty loop
+ for Node of Examine loop
+ if Container.Internal_Graph.Contains (Node) and then
+ not Locally_Reachable (Container, Node)
+ then
+ for Outnode of Container.Internal_Graph.Children (Node) loop
+ Next.Append (Outnode);
+ end loop;
+ Container.Internal_Graph.Delete (Node);
+ end if;
+ end loop;
+ Examine.Move (Next);
+ end loop;
+ end Delete_Unreachable;
- function Is_Ambiguous
+
+
+ function Has_Root
(Container : in Parse_Graph)
return Boolean is
begin
- for N of Container.Nodes loop
- if Finish_List (Container, N)'Length > 1 then
- return True;
+ return Container.Root_Node /= Base.No_Node;
+ end Has_Root;
+
+
+ procedure Set_Root
+ (Container : in out Parse_Graph;
+ Token : in Gen_Tokens.Token;
+ Finishes : in Finish_Array) is
+ begin
+ Container.Root_Node := Container.Label_Map.Element (Token);
+ Container.Root_Finishes.Clear;
+ for F of Finishes loop
+ if not Container.Root_Finishes.Contains (F) then
+ Container.Root_Finishes.Append (F);
+ end if;
+ end loop;
+ Finish_Sort.Sort (Container.Root_Finishes);
+ end Set_Root;
+
+
+ procedure Clear_Root
+ (Container : in out Parse_Graph) is
+ begin
+ Container.Root_Node := Base.No_Node;
+ Container.Root_Finishes.Clear;
+ end Clear_Root;
+
+
+ function Root_Token
+ (Container : in Parse_Graph)
+ return Gen_Tokens.Token is
+ begin
+ return Container.Internal_Graph.Label (Container.Root_Node);
+ end Root_Token;
+
+
+ function Root_Finish_List
+ (Container : in Parse_Graph)
+ return Finish_Array
+ is
+ function V2A is new Vector_To_Array (Finish_Type, Finish_Array, Finish_Vectors);
+ begin
+ return V2A (Container.Root_Finishes);
+ end Root_Finish_List;
+
+
+ function Root_Element
+ (Container : in Parse_Graph;
+ Finish_At : in Finish_Type)
+ return Finished_Token is
+ begin
+ return Root : Finished_Token :=
+ (Token => Container.Internal_Graph.Label (Container.Root_Node),
+ Finish => Finish_At);
+ end Root_Element;
+
+
+
+
+
+ function Finish_List
+ (Container : in Parse_Graph;
+ Token : in Gen_Tokens.Token)
+ return Finish_Array
+ is
+ function V2A is new Vector_To_Array (Finish_Type, Finish_Array, Finish_Vectors);
+ Result : Finish_Vectors.Vector;
+ begin
+ for Edge of Container.Internal_Graph.Outbound (Container.Label_Map.Element (Token)) loop
+ if not Result.Contains (Container.Internal_Graph.Label (Edge).Group_Finish) then
+ Result.Append (Container.Internal_Graph.Label (Edge).Group_Finish);
+ end if;
+ end loop;
+ Finish_Sort.Sort (Result);
+ return V2A (Result);
+ end Finish_List;
+
+
+ function Is_Leaf
+ (Container : in Parse_Graph;
+ Position : in Finished_Token)
+ return Boolean is
+ begin
+ for Edge of Container.Internal_Graph.Outbound
+ (Container.Label_Map.Element (Position.Token))
+ loop
+ if Container.Internal_Graph.Label (Edge).Group_Finish = Position.Finish then
+ return False;
+ end if;
+ end loop;
+ return True;
+ end Is_Leaf;
+
+
+ function Is_Branch
+ (Container : in Parse_Graph;
+ Position : in Finished_Token)
+ return Boolean is
+ begin
+ return not Container.Is_Leaf (Position);
+ end Is_Branch;
+
+
+
+
+
+ function Subgroups
+ (Container : in Parse_Graph;
+ Position : in Finished_Token)
+ return Token_Group_Array
+ is
+ function V2A is new Vector_To_Array
+ (Finished_Token, Finished_Token_Array, Finished_Token_Vectors);
+ function V2A is new Vector_To_Array
+ (Token_Group, Token_Group_Array, Token_Group_Vectors);
+ Groupings : Group_Finished_Token_Maps.Map;
+ Edge_Label : Edge_Label_Type;
+ Next_Token : Finished_Token;
+ Result : Token_Group_Vectors.Vector;
+ begin
+ for Edge of Container.Internal_Graph.Outbound
+ (Container.Label_Map.Element (Position.Token))
+ loop
+ Edge_Label := Container.Internal_Graph.Label (Edge);
+ if Edge_Label.Group_Finish = Position.Finish then
+ Next_Token :=
+ (Token => Container.Internal_Graph.Label (Edge.To),
+ Finish => Edge_Label.Subnode_Finish);
+ if not Groupings.Contains (Edge_Label.Group_ID) then
+ Groupings.Insert (Edge_Label.Group_ID, Finished_Token_Vectors.Empty_Vector);
+ end if;
+ Groupings.Reference (Edge_Label.Group_ID).Append (Next_Token);
+ end if;
+ end loop;
+ for Raw_Group of Groupings loop
+ Finished_Token_Sort.Sort (Raw_Group);
+ Result.Append
+ ((Parent => Position,
+ Elems => Finished_Token_Array_Holders.To_Holder (V2A (Raw_Group))));
+ end loop;
+ Token_Group_Sort.Sort (Result);
+ return V2A (Result);
+ end Subgroups;
+
+
+ function First_Index
+ (Grouping : in Token_Group)
+ return Positive is
+ begin
+ return Grouping.Elems.Constant_Reference.Element'First;
+ end First_Index;
+
+
+ function Last_Index
+ (Grouping : in Token_Group)
+ return Positive is
+ begin
+ return Grouping.Elems.Constant_Reference.Element'Last;
+ end Last_Index;
+
+
+ function Length
+ (Grouping : in Token_Group)
+ return Ada.Containers.Count_Type is
+ begin
+ return Ada.Containers.Count_Type
+ (Grouping.Elems.Constant_Reference.Element'Length);
+ end Length;
+
+
+ function Element
+ (Grouping : in Token_Group;
+ Index : in Positive)
+ return Finished_Token is
+ begin
+ return Grouping.Elems.Constant_Reference.Element (Index);
+ end Element;
+
+
+ function Elements
+ (Grouping : in Token_Group)
+ return Finished_Token_Array is
+ begin
+ return Grouping.Elems.Element;
+ end Elements;
+
+
+ function Parent
+ (Grouping : in Token_Group)
+ return Finished_Token is
+ begin
+ return Grouping.Parent;
+ end Parent;
+
+
+ function Finish
+ (Grouping : in Token_Group)
+ return Finish_Type is
+ begin
+ return Grouping.Parent.Finish;
+ end Finish;
+
+
+
+
+
+ function Is_Root_Ambiguous
+ (Container : in Parse_Graph)
+ return Boolean
+ is
+ use type Ada.Containers.Count_Type;
+ First_Group : Group_ID_Type;
+ Seen_Group : Boolean := False;
+ Check_Label : Edge_Label_Type;
+ begin
+ if Container.Root_Finishes.Length = 0 then
+ return False;
+ elsif Container.Root_Finishes.Length > 1 then
+ return True;
+ end if;
+ for Edge of Container.Internal_Graph.Outbound (Container.Root_Node) loop
+ Check_Label := Container.Internal_Graph.Label (Edge);
+ if Container.Root_Finishes.Contains (Check_Label.Group_Finish) then
+ if not Seen_Group then
+ Seen_Group := True;
+ First_Group := Check_Label.Group_ID;
+ elsif Check_Label.Group_ID /= First_Group then
+ return True;
+ end if;
end if;
end loop;
return False;
+ end Is_Root_Ambiguous;
+
+
+ function Is_Ambiguous
+ (Container : in Parse_Graph)
+ return Boolean
+ is
+ Seen_Finishes : Finish_Group_Maps.Map;
+ Edge_Label : Edge_Label_Type;
+ begin
+ if Container.Has_Root and then Is_Root_Ambiguous (Container) then
+ return True;
+ end if;
+ for Node of Container.Internal_Graph.Nodes loop
+ for Edge of Container.Internal_Graph.Outbound (Node) loop
+ Edge_Label := Container.Internal_Graph.Label (Edge);
+ if Seen_Finishes.Contains (Edge_Label.Group_Finish) then
+ if Seen_Finishes.Element (Edge_Label.Group_Finish) /= Edge_Label.Group_ID then
+ return True;
+ end if;
+ else
+ Seen_Finishes.Insert (Edge_Label.Group_Finish, Edge_Label.Group_ID);
+ end if;
+ end loop;
+ Seen_Finishes.Clear;
+ end loop;
+ return False;
end Is_Ambiguous;
+ function Ambiguities
+ (Container : in Parse_Graph;
+ Ambiguous_Root : out Boolean)
+ return Finished_Token_Array
+ is
+ function V2A is new Vector_To_Array
+ (Finished_Token, Finished_Token_Array, Finished_Token_Vectors);
+ Seen_Finishes : Finish_Group_Maps.Map;
+ Edge_Label : Edge_Label_Type;
+ Next_Token : Finished_Token;
+ Result : Finished_Token_Vectors.Vector;
+ begin
+ Ambiguous_Root := Container.Has_Root and then Container.Is_Root_Ambiguous;
+ for Node of Container.Internal_Graph.Nodes loop
+ for Edge of Container.Internal_Graph.Outbound (Node) loop
+ Edge_Label := Container.Internal_Graph.Label (Edge);
+ if Seen_Finishes.Contains (Edge_Label.Group_Finish) then
+ if Seen_Finishes.Element (Edge_Label.Group_Finish) /= Edge_Label.Group_ID then
+ Next_Token :=
+ (Token => Container.Internal_Graph.Label (Node),
+ Finish => Edge_Label.Group_Finish);
+ if not Result.Contains (Next_Token) then
+ Result.Append (Next_Token);
+ end if;
+ end if;
+ else
+ Seen_Finishes.Insert (Edge_Label.Group_Finish, Edge_Label.Group_ID);
+ end if;
+ end loop;
+ Seen_Finishes.Clear;
+ end loop;
+ Finished_Token_Sort.Sort (Result);
+ return V2A (Result);
+ end Ambiguities;
+
+
+
+
+
+ function Isomorphic
+ (Left, Right : in Parse_Graph)
+ return Boolean
+ is
+ begin
+ -- to-do
+ return False;
+ end Isomorphic;
+
+
+ function Isomorphic_Subgraph
+ (Left_Graph : in Parse_Graph;
+ Left_Position : in Finished_Token;
+ Right_Graph : in Parse_Graph;
+ Right_Position : in Finished_Token)
+ return Boolean
+ is
+ begin
+ -- to-do
+ return False;
+ end Isomorphic_Subgraph;
+
+
+
+ function To_Node
+ (Container : in Parse_Graph;
+ Token : in Gen_Tokens.Token)
+ return Node_ID_Type is
+ begin
+ return Container.Label_Map.Element (Token);
+ end To_Node;
+
+
+ function To_Node
+ (Container : in Parse_Graph;
+ Position : in Finished_Token)
+ return Node_ID_Type is
+ begin
+ return Container.Label_Map.Element (Position.Token);
+ end To_Node;
+
+
+
+
+
+ function Sorted
+ (Input : in Array_Type)
+ return Boolean is
+ begin
+ for Index in Input'First .. Input'Last - 1 loop
+ if Input (Index + 1) < Input (Index) then
+ return False;
+ end if;
+ end loop;
+ return True;
+ end Sorted;
+
+
+ function No_Dups
+ (Input : in Array_Type)
+ return Boolean is
+ begin
+ for X in Input'First .. Input'Last - 1 loop
+ for Y in X + 1 .. Input'Last loop
+ if Input (X) = Input (Y) then
+ return False;
+ end if;
+ end loop;
+ end loop;
+ return True;
+ end No_Dups;
+
function Vector_To_Array
(Input : in Type_Vectors.Vector)