aboutsummaryrefslogtreecommitdiffstats
path: root/src/files_map-editor.adb
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2018-11-28 20:13:50 +0100
committerTristan Gingold <tgingold@free.fr>2018-11-28 20:13:50 +0100
commit873fb32cbfe91241c186af0aaa6f029b30c37896 (patch)
tree7e9d4fc37ba42793f3b9275c9b49ad813490bbda /src/files_map-editor.adb
parent1b6ba4e94ce97cd1be347bfcb32508da535d7c64 (diff)
downloadghdl-873fb32cbfe91241c186af0aaa6f029b30c37896.tar.gz
ghdl-873fb32cbfe91241c186af0aaa6f029b30c37896.tar.bz2
ghdl-873fb32cbfe91241c186af0aaa6f029b30c37896.zip
files_map-editor: fixes - WIP.
Diffstat (limited to 'src/files_map-editor.adb')
-rw-r--r--src/files_map-editor.adb385
1 files changed, 231 insertions, 154 deletions
diff --git a/src/files_map-editor.adb b/src/files_map-editor.adb
index 885bc1bc1..54e0c044f 100644
--- a/src/files_map-editor.adb
+++ b/src/files_map-editor.adb
@@ -16,9 +16,104 @@
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
-with Ada.Text_IO;
+with Logging; use Logging;
package body Files_Map.Editor is
+ -- Count the length of newlines at position P in TEXT.
+ -- Result can be:
+ -- 1 for (LF, CR)
+ -- 2 for (LF+CR or CR+LF),
+ -- 0 for non-newlines.
+ function Is_Newline (Text : File_Buffer; P : Source_Ptr) return Natural is
+ begin
+ if Text (P) = ASCII.CR then
+ if P < Text'Last and then Text (P + 1) = ASCII.LF then
+ return 2;
+ else
+ return 1;
+ end if;
+ elsif Text (P) = ASCII.LF then
+ if P < Text'Last and then Text (P + 1) = ASCII.CR then
+ return 2;
+ else
+ return 1;
+ end if;
+ else
+ return 0;
+ end if;
+ end Is_Newline;
+
+ procedure Compute_Lines (File : Source_File_Entry)
+ is
+ pragma Assert (File <= Source_Files.Last);
+ F : Source_File_Record renames Source_Files.Table (File);
+ L : Positive;
+ P : Source_Ptr;
+ Nl : Natural;
+ begin
+ Lines_Tables.Init (F.Lines);
+
+ L := 1;
+ P := Source_Ptr_Org;
+ loop
+ File_Add_Line_Number (File, L, P);
+ L := L + 1;
+
+ loop
+ Nl := Is_Newline (F.Source.all, P);
+ if Nl = 0 then
+ P := P + 1;
+ else
+ P := P + Source_Ptr (Nl);
+ exit;
+ end if;
+ exit when P = F.Source'Last;
+ end loop;
+
+ Skip_Gap (File, P);
+ exit when P = F.Source'Last;
+ end loop;
+ end Compute_Lines;
+
+ procedure Check_Buffer_Lines (File : Source_File_Entry)
+ is
+ pragma Assert (File <= Source_Files.Last);
+ F : Source_File_Record renames Source_Files.Table (File);
+ L : Positive;
+ P : Source_Ptr;
+ Nl : Natural;
+ begin
+ L := 1;
+ P := Source_Ptr_Org;
+ Main_Loop: loop
+ if F.Lines.Table (L) /= P then
+ Log_Line ("offset mismatch for line" & Natural'Image (L));
+ end if;
+
+ exit Main_Loop when P = F.File_Length;
+
+ -- Skip until eol.
+ loop
+ Nl := Is_Newline (F.Source.all, P);
+ if Nl = 0 then
+ P := P + 1;
+ else
+ P := P + Source_Ptr (Nl);
+ exit;
+ end if;
+ exit Main_Loop when P = F.File_Length;
+ end loop;
+
+ Skip_Gap (File, P);
+
+ L := L + 1;
+ end loop Main_Loop;
+
+ if Lines_Tables.Last (F.Lines) /= L then
+ Log_Line ("incorrect number of lines");
+ end if;
+ end Check_Buffer_Lines;
+
-- Compute the number of character in FILE between [START_POS; END_POS)
function Get_Range_Length (File : Source_File_Entry;
Start_Pos : Source_Ptr;
@@ -57,11 +152,13 @@ package body Files_Map.Editor is
Diff : Source_Ptr;
begin
if Line = Lines_Tables.Last (F.Lines) then
- New_Start := F.File_Length;
- if New_Start = F.Gap_Start then
- -- No move.
+ -- Moved to the end of the buffer.
+ if F.Gap_Start >= F.File_Length then
+ pragma Assert (F.Gap_Start = F.File_Length + 2);
+ -- Already there.
return;
end if;
+ New_Start := F.Source'Last - F.Gap_Last + F.Gap_Start;
else
New_Start := Line_To_Position (File, Line + 1);
if New_Start = F.Gap_Last + 1 then
@@ -80,6 +177,11 @@ package body Files_Map.Editor is
-- Move [A] to [B].
F.Source (F.Gap_Last - Diff + 1 .. F.Gap_Last) :=
F.Source (New_Start .. New_Start + Diff - 1);
+
+ if F.Gap_Start >= F.File_Length then
+ F.File_Length := F.File_Length + Gap_Len;
+ end if;
+
-- Renumber
-- Lines starting from line + 1 until location < Gap_Start should
-- have their location added by gap_len.
@@ -95,6 +197,11 @@ package body Files_Map.Editor is
-- Move [A] to [B].
F.Source (F.Gap_Start .. F.Gap_Start + Diff - 1) :=
F.Source (F.Gap_Last + 1 .. F.Gap_Last + 1 + Diff - 1);
+
+ if New_Start + Gap_Len >= F.File_Length then
+ F.File_Length := F.File_Length - Gap_Len;
+ end if;
+
-- Renumber
-- Lines starting from LINE downto location > Gap_Start should have
-- their location substracted by gap_len.
@@ -109,34 +216,10 @@ package body Files_Map.Editor is
F.Gap_Last := New_Start + Gap_Len - 1;
end Move_Gap;
- -- Count the length of newlines at position P in TEXT.
- -- Result can be:
- -- 1 for (LF, CR)
- -- 2 for (LF+CR or CR+LF),
- -- 0 for non-newlines.
- function Is_Newline (Text : String; P : Positive) return Natural is
- begin
- if Text (P) = ASCII.CR then
- if P < Text'Last and then Text (P + 1) = ASCII.LF then
- return 2;
- else
- return 1;
- end if;
- elsif Text (P) = ASCII.LF then
- if P < Text'Last and then Text (P + 1) = ASCII.CR then
- return 2;
- else
- return 1;
- end if;
- else
- return 0;
- end if;
- end Is_Newline;
-
-- Count the number of newlines (LF, CR, LF+CR or CR+LF) in TEXT.
- function Count_Newlines (Text : String) return Natural
+ function Count_Newlines (Text : File_Buffer) return Natural
is
- P : Positive;
+ P : Source_Ptr;
Res : Natural;
R : Natural;
begin
@@ -145,7 +228,7 @@ package body Files_Map.Editor is
while P <= Text'Last loop
R := Is_Newline (Text, P);
if R > 0 then
- P := P + R;
+ P := P + Source_Ptr (R);
Res := Res + 1;
else
P := P + 1;
@@ -160,94 +243,106 @@ package body Files_Map.Editor is
Start_Off : Natural;
End_Line : Positive;
End_Off : Natural;
- Text : String)
+ Text : File_Buffer)
is
pragma Assert (File <= Source_Files.Last);
F : Source_File_Record renames Source_Files.Table (File);
- Start_Pos : constant Source_Ptr :=
- Line_To_Position (File, Start_Line) + Source_Ptr (Start_Off);
- End_Pos : constant Source_Ptr :=
- Line_To_Position (File, End_Line) + Source_Ptr (End_Off);
- Text_Size : constant Source_Ptr := Text'Length;
- Gap_Size : Source_Ptr;
- Range_Size : Source_Ptr;
begin
- Gap_Size := F.Gap_Last - F.Gap_Start + 1;
- Range_Size := Get_Range_Length (File, Start_Pos, End_Pos);
-
- -- Check there is enough space.
- if Text_Size > Gap_Size + Range_Size then
- raise Constraint_Error;
- end if;
-
- -- Move gap
+ -- Move gap to the end of end_line. At least a part of End_Line
+ -- remains as the end position is exclusive but valid.
Move_Gap (File, End_Line);
- -- Replace text, handle new lines.
- -- Deletion.
- -- End_Pos --| |---- Gap_Start
- -- | [ABCDEFGHn][XXX] |
- -- => | [ABRGHn][XXXXXX] |
- -- |-- Start_Pos
- --
- -- Insertion
- -- End_Pos --| |---- Gap_Start
- -- | [ABCDn][XXXXX] |
- -- => | [ABRRRDn][XXX] |
- -- |-- Start_Pos
+ -- The gap has moved, so every offset may have changed...
declare
- Move_Len : constant Source_Ptr := F.Gap_Start - End_Pos;
- New_Pos : constant Source_Ptr := Start_Pos + Text_Size;
+ Start_Pos : constant Source_Ptr :=
+ Line_To_Position (File, Start_Line) + Source_Ptr (Start_Off);
+ End_Pos : constant Source_Ptr :=
+ Line_To_Position (File, End_Line) + Source_Ptr (End_Off);
+ Text_Len : constant Source_Ptr := Text'Length;
+ Gap_Size : constant Source_Ptr := F.Gap_Last - F.Gap_Start + 1;
+ Range_Size : Source_Ptr;
begin
- F.Source (New_Pos .. New_Pos + Move_Len - 1) :=
- F.Source (End_Pos .. End_Pos + Move_Len - 1);
- -- FIXME: clear gap when extended.
- F.Gap_Start := New_Pos + Move_Len;
- -- Copy.
- F.Source (Start_Pos .. Start_Pos + Text_Size - 1) :=
- File_Buffer (Text);
- end;
+ Range_Size := Get_Range_Length (File, Start_Pos, End_Pos);
- -- Renumber.
- declare
- use Lines_Tables;
- Text_Lines : constant Natural := Count_Newlines (Text);
- Orig_Lines : constant Natural := End_Line - Start_Line;
- Diff : constant Integer := Text_Lines - Orig_Lines;
- Orig_Last : constant Natural := Last (F.Lines);
- P : Positive;
- Nl_Len : Natural;
- L : Natural;
- begin
- -- No change in newlines.
- if Text_Lines = 0 and then Orig_Lines = 0 then
- return;
+ -- Check there is enough space.
+ if Text_Len > Gap_Size + Range_Size then
+ raise Constraint_Error;
end if;
- -- Make room for lines table.
- if Diff /= 0 then
- if Diff > 0 then
- Set_Last (F.Lines, Orig_Last + Diff);
- end if;
- F.Lines.Table (End_Line + Diff .. Orig_Last + Diff) :=
- F.Lines.Table (End_Line .. Orig_Last);
- if Diff < 0 then
- Set_Last (F.Lines, Orig_Last + Diff);
+ -- Replace text, handle new lines.
+ -- Deletion.
+ -- End_Pos --| |---- Gap_Start
+ -- | [ABCDEFGHn][XXX] |
+ -- => | [ABRGHn][XXXXXX] |
+ -- |-- Start_Pos
+ --
+ -- Insertion
+ -- End_Pos --| |---- Gap_Start
+ -- | [ABCDn][XXXXX] |
+ -- => | [ABRRRDn][XXX] |
+ -- |-- Start_Pos
+ declare
+ Move_Len : constant Source_Ptr := F.Gap_Start - End_Pos;
+ New_Pos : constant Source_Ptr := Start_Pos + Text_Len;
+ begin
+ F.Source (New_Pos .. New_Pos + Move_Len - 1) :=
+ F.Source (End_Pos .. End_Pos + Move_Len - 1);
+ -- Copy.
+ F.Source (Start_Pos .. Start_Pos + Text_Len - 1) := Text;
+
+ -- If the gap was after the end of the file, then adjust end of
+ -- file.
+ if F.Gap_Start > F.File_Length then
+ F.File_Length := F.File_Length + Text_Len - Range_Size;
end if;
- end if;
+
+ -- FIXME: clear gap when extended.
+ F.Gap_Start := New_Pos + Move_Len;
+ end;
-- Renumber.
- P := Text'First;
- L := Start_Line + 1;
- while P <= Text'Last loop
- Nl_Len := Is_Newline (Text, P);
- if Nl_Len = 0 then
- P := P + 1;
- else
- P := P + Nl_Len;
- F.Lines.Table (L) := Start_Pos + Source_Ptr (P - Text'First);
+ declare
+ use Lines_Tables;
+ Text_Lines : constant Natural := Count_Newlines (Text);
+ Orig_Lines : constant Natural := End_Line - Start_Line;
+ Diff : constant Integer := Text_Lines - Orig_Lines;
+ Orig_Last : constant Natural := Last (F.Lines);
+ P : Source_Ptr;
+ Nl_Len : Natural;
+ L : Natural;
+ begin
+ -- No change in newlines.
+ if Text_Lines = 0 and then Orig_Lines = 0 then
+ return;
end if;
- end loop;
+
+ -- Make room for lines table.
+ if Diff /= 0 then
+ if Diff > 0 then
+ Set_Last (F.Lines, Orig_Last + Diff);
+ end if;
+ F.Lines.Table (End_Line + 1 + Diff .. Orig_Last + Diff) :=
+ F.Lines.Table (End_Line + 1 .. Orig_Last);
+ if Diff < 0 then
+ Set_Last (F.Lines, Orig_Last + Diff);
+ end if;
+ end if;
+
+ -- Renumber.
+ P := Text'First;
+ L := Start_Line + 1;
+ while P <= Text'Last loop
+ Nl_Len := Is_Newline (Text, P);
+ if Nl_Len = 0 then
+ P := P + 1;
+ else
+ P := P + Source_Ptr (Nl_Len);
+ F.Lines.Table (L) := Start_Pos + (P - Text'First);
+ end if;
+ end loop;
+
+ Check_Buffer_Lines (File);
+ end;
end;
end Replace_Text;
@@ -256,11 +351,11 @@ package body Files_Map.Editor is
Start_Off : Natural;
End_Line : Positive;
End_Off : Natural;
- Str : Thin_String_Ptr;
- Str_Len : Natural) is
+ Text_Ptr : File_Buffer_Ptr;
+ Text_Len : Source_Ptr) is
begin
Replace_Text (File, Start_Line, Start_Off, End_Line, End_Off,
- Str (1 .. Str_Len));
+ Text_Ptr (0 .. Text_Len - 1));
end Replace_Text_Ptr;
procedure Set_Gap (File : Source_File_Entry;
@@ -275,36 +370,51 @@ package body Files_Map.Editor is
end Set_Gap;
procedure Check_Buffer_Content (File : Source_File_Entry;
- Str : Thin_String_Ptr;
- Str_Len : Natural)
+ Str : File_Buffer_Ptr;
+ Str_Len : Source_Ptr)
is
- use Ada.Text_IO;
pragma Assert (File <= Source_Files.Last);
F : Source_File_Record renames Source_Files.Table (File);
begin
-- Check length.
declare
- Buf_Len : constant Source_Ptr :=
- F.File_Length - (F.Gap_Last - F.Gap_Start);
+ Buf_Len : Source_Ptr;
begin
- if Str_Len /= Natural (Buf_Len) then
- Put_Line (Standard_Error,
- "length mismatch (text:" & Natural'Image (Str_Len)
+ Buf_Len := F.File_Length;
+ if F.Gap_Start < F.File_Length then
+ Buf_Len := F.File_Length - (F.Gap_Last + 1 - F.Gap_Start);
+ if F.File_Length + 1 /= F.Source'Last then
+ Log_Line ("bad file length");
+ end if;
+ else
+ if F.Gap_Start /= F.File_Length + 2 then
+ Log_Line ("bad position of gap at end of file");
+ end if;
+ end if;
+ if Str_Len /= Buf_Len then
+ Log_Line ("length mismatch - text:" & Source_Ptr'Image (Str_Len)
& ", buffer:" & Source_Ptr'Image (Buf_Len));
end if;
end;
+ -- Check presence of EOT.
+ if F.Source (F.File_Length) /= EOT then
+ Log_Line ("missing first EOT");
+ end if;
+ if F.Source (F.File_Length + 1) /= EOT then
+ Log_Line ("missing second EOT");
+ end if;
+
-- Check content.
declare
- T_Pos : Natural;
+ T_Pos : Source_Ptr;
S_Pos : Source_Ptr;
begin
- T_Pos := Str'First;
+ T_Pos := Source_Ptr_Org;
S_Pos := Source_Ptr_Org;
- while T_Pos <= Str_Len loop
+ while T_Pos < Str_Len loop
if F.Source (S_Pos) /= Str (T_Pos) then
- Put_Line (Standard_Error,
- "difference at offset" & Natural'Image (T_Pos));
+ Log_Line ("difference at offset" & Source_Ptr'Image (T_Pos));
exit;
end if;
T_Pos := T_Pos + 1;
@@ -316,40 +426,7 @@ package body Files_Map.Editor is
end;
-- Check lines.
- declare
- L : Positive;
- P : Source_Ptr;
- Nl : Natural;
- subtype Buf_Subtype is String (1 .. Natural (F.File_Length));
- begin
- L := 1;
- P := Source_Ptr_Org;
- loop
- if F.Lines.Table (L) /= P then
- Put_Line (Standard_Error,
- "offset mismatch for line" & Natural'Image (L));
- end if;
- L := L + 1;
-
- loop
- Nl := Is_Newline
- (Buf_Subtype (F.Source (Source_Ptr_Org
- .. F.File_Length - 1)),
- Positive (1 + P));
- if Nl = 0 then
- P := P + 1;
- else
- P := P + Source_Ptr (Nl);
- exit;
- end if;
- end loop;
-
- if P = F.Gap_Start then
- P := F.Gap_Last + 1;
- end if;
- exit when P = F.File_Length;
- end loop;
- end;
+ Check_Buffer_Lines (File);
end Check_Buffer_Content;
end Files_Map.Editor;