diff options
author | Tristan Gingold <tgingold@free.fr> | 2018-11-23 19:33:55 +0100 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2018-11-23 19:33:55 +0100 |
commit | 021f946659b84a9803ae9148cc1315059f5dfc15 (patch) | |
tree | 86424ff98028e5755e5b384dbb10f33097fe2489 | |
parent | 1830a66709ad88f74832c6e92fc68f8e75d00089 (diff) | |
download | ghdl-021f946659b84a9803ae9148cc1315059f5dfc15.tar.gz ghdl-021f946659b84a9803ae9148cc1315059f5dfc15.tar.bz2 ghdl-021f946659b84a9803ae9148cc1315059f5dfc15.zip |
Add files_map-editor for libghdl.
-rw-r--r-- | src/files_map-editor.adb | 175 | ||||
-rw-r--r-- | src/files_map-editor.ads | 21 | ||||
-rw-r--r-- | src/vhdl/python/libghdl.adb | 2 | ||||
-rw-r--r-- | src/vhdl/python/libghdl/thin.py | 4 |
4 files changed, 202 insertions, 0 deletions
diff --git a/src/files_map-editor.adb b/src/files_map-editor.adb new file mode 100644 index 000000000..a1f673e83 --- /dev/null +++ b/src/files_map-editor.adb @@ -0,0 +1,175 @@ +package body Files_Map.Editor is + -- Compute the number of character in FILE between [START_POS; END_POS) + function Get_Range_Length (File : Source_File_Entry; + Start_Pos : Source_Ptr; + End_Pos : Source_Ptr) return Source_Ptr + is + pragma Assert (File <= Source_Files.Last); + F : Source_File_Record renames Source_Files.Table (File); + Res : Source_Ptr; + begin + pragma Assert (End_Pos >= Start_Pos); + pragma Assert (End_Pos <= F.File_Length); + Res := End_Pos - Start_Pos; + + -- Returns now if the gap is outside the range. + if F.Gap_Last < Start_Pos or else F.Gap_Start >= End_Pos then + return Res; + end if; + + -- Check the gap is completly within the range. + if F.Gap_Last > End_Pos or else F.Gap_Start <= Start_Pos then + raise Internal_Error; + end if; + + return Res - (F.Gap_Last - F.Gap_Start + 1); + end Get_Range_Length; + + -- Move the gap to the end of LINE. + procedure Move_Gap (File : Source_File_Entry; + Line : Positive) + is + use Lines_Tables; + + F : Source_File_Record renames Source_Files.Table (File); + New_Start : Source_Ptr; + Gap_Len : Source_Ptr; + 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. + return; + end if; + else + New_Start := Line_To_Position (File, Line + 1); + if New_Start = F.Gap_Last + 1 then + -- No move (the gap is already at end of LINE). + return; + end if; + end if; + + Gap_Len := F.Gap_Last - F.Gap_Start + 1; + + if New_Start < F.Gap_Start then + -- The gap is moved toward the start of the file by DIFF bytes: + -- | [A][XXXX] | + -- => | [XXXX][B] | + Diff := F.Gap_Start - New_Start; + -- Move [A] to [B]. + F.Source (F.Gap_Last - Diff + 1 .. F.Gap_Last) := + F.Source (New_Start .. New_Start + Diff - 1); + -- Renumber + -- Lines starting from line + 1 until location < Gap_Start should + -- have their location added by gap_len. + for L in Line + 1 .. Last (F.Lines) loop + exit when F.Lines.Table (L) >= F.Gap_Start; + F.Lines.Table (L) := F.Lines.Table (L) + Gap_Len; + end loop; + else + -- The gap is moved toward the end of the file by DIFF bytes. + -- | [XXXX][A] | + -- => | [B][XXXX] | + Diff := New_Start - F.Gap_Start; + -- 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); + -- Renumber + -- Lines starting from LINE downto location > Gap_Start should have + -- their location substracted by gap_len. + for L in reverse 1 .. Line loop + exit when F.Lines.Table (L) <= F.Gap_Start; + F.Lines.Table (L) := F.Lines.Table (L) - Gap_Len; + end loop; + end if; + + -- Adjust gap. + F.Gap_Start := New_Start; + F.Gap_Last := New_Start + Gap_Len - 1; + end Move_Gap; + + procedure Replace_Text (File : Source_File_Entry; + Start_Line : Positive; + Start_Off : Natural; + End_Line : Positive; + End_Off : Natural; + Text : String) + 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 (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 + declare + Move_Len : constant Source_Ptr := F.Gap_Start - End_Pos; + New_Pos : constant Source_Ptr := Start_Pos + Text_Size; + 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; + + -- Renumber. + if Start_Line /= End_Line then + -- Not handled. + -- FIXME: also handle newlines in TEXT. + raise Internal_Error; + end if; + end Replace_Text; + + procedure Replace_Text_Ptr (File : Source_File_Entry; + Start_Line : Positive; + Start_Off : Natural; + End_Line : Positive; + End_Off : Natural; + Str : Thin_String_Ptr; + Str_Len : Natural) is + begin + Replace_Text (File, Start_Line, Start_Off, End_Line, End_Off, + Str (1 .. Str_Len)); + end Replace_Text_Ptr; + + procedure Set_Gap (File : Source_File_Entry; + First : Source_Ptr; + Last : Source_Ptr) + is + pragma Assert (File <= Source_Files.Last); + F : Source_File_Record renames Source_Files.Table (File); + begin + F.Gap_Start := First; + F.Gap_Last := Last; + end Set_Gap; +end Files_Map.Editor; diff --git a/src/files_map-editor.ads b/src/files_map-editor.ads new file mode 100644 index 000000000..b5e9deb0f --- /dev/null +++ b/src/files_map-editor.ads @@ -0,0 +1,21 @@ +package Files_Map.Editor is + procedure Replace_Text (File : Source_File_Entry; + Start_Line : Positive; + Start_Off : Natural; + End_Line : Positive; + End_Off : Natural; + Text : String); + + procedure Replace_Text_Ptr (File : Source_File_Entry; + Start_Line : Positive; + Start_Off : Natural; + End_Line : Positive; + End_Off : Natural; + Str : Thin_String_Ptr; + Str_Len : Natural); + + -- Set the position of the GAP in FILE. + procedure Set_Gap (File : Source_File_Entry; + First : Source_Ptr; + Last : Source_Ptr); +end Files_Map.Editor; diff --git a/src/vhdl/python/libghdl.adb b/src/vhdl/python/libghdl.adb index 0267ccec7..cf87cb158 100644 --- a/src/vhdl/python/libghdl.adb +++ b/src/vhdl/python/libghdl.adb @@ -20,7 +20,9 @@ with GNAT.OS_Lib; use GNAT.OS_Lib; with Ghdllocal; with Ghdlcomp; with Errorout.Memory; +with Files_Map.Editor; pragma Unreferenced (Errorout.Memory); -- At least from Ada code. +pragma Unreferenced (Files_Map.Editor); package body Libghdl is function Set_Option (Opt : Thin_String_Ptr; Len : Natural) return Integer is diff --git a/src/vhdl/python/libghdl/thin.py b/src/vhdl/python/libghdl/thin.py index 25e03809c..758ab26ab 100644 --- a/src/vhdl/python/libghdl/thin.py +++ b/src/vhdl/python/libghdl/thin.py @@ -108,6 +108,10 @@ EOT = b'\x04' No_Location = 0 +class Files_Map_Editor: + Set_Gap = libghdl.files_map__editor__set_gap + Replace_Text = libghdl.files_map__editor__replace_text_ptr + # Names Get_Name_Length = libghdl.name_table__get_name_length |