summaryrefslogtreecommitdiff
path: root/src/ortho/llvm/ortho_ident.adb
blob: e7b650539984b6e0b81fab6c28b08de236ace85f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
--  LLVM back-end for ortho.
--  Copyright (C) 2014 Tristan Gingold
--
--  GHDL is free software; you can redistribute it and/or modify it under
--  the terms of the GNU General Public License as published by the Free
--  Software Foundation; either version 2, or (at your option) any later
--  version.
--
--  GHDL is distributed in the hope that it will be useful, but WITHOUT ANY
--  WARRANTY; without even the implied warranty of MERCHANTABILITY or
--  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
--  for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with GCC; see the file COPYING.  If not, write to the Free
--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
--  02111-1307, USA.

package body Ortho_Ident is
   type Chunk (Max : Positive);
   type Chunk_Acc is access Chunk;

   type Chunk (Max : Positive) is record
      Prev : Chunk_Acc;
      Len : Natural := 0;
      S : String (1 .. Max);
   end record;

   Cur_Chunk : Chunk_Acc := null;

   subtype Fat_String is String (Positive);

   function Get_Identifier (Str : String) return O_Ident
   is
      Len : constant Natural := Str'Length;
      Max : Positive;
      Org : Positive;
   begin
      if Cur_Chunk = null or else Cur_Chunk.Len + Len >= Cur_Chunk.Max then
         if Cur_Chunk = null then
            Max := 32 * 1024;
         else
            Max := 2 * Cur_Chunk.Max;
         end if;
         if Len + 2 > Max then
            Max := 2 * (Len + 2);
         end if;
         declare
            New_Chunk : Chunk_Acc;
         begin
            --  Do not use allocator by expression, as we don't want to
            --  initialize S.
            New_Chunk := new Chunk (Max);
            New_Chunk.Len := 0;
            New_Chunk.Prev := Cur_Chunk;
            Cur_Chunk := New_Chunk;
         end;
      end if;

      Org := Cur_Chunk.Len + 1;
      Cur_Chunk.S (Org .. Org + Len - 1) := Str;
      Cur_Chunk.S (Org + Len) := ASCII.NUL;
      Cur_Chunk.Len := Org + Len;

      return (Addr => Cur_Chunk.S (Org)'Address);
   end Get_Identifier;

   function Is_Equal (L, R : O_Ident) return Boolean
   is
   begin
      return L = R;
   end Is_Equal;

   function Get_String_Length (Id : O_Ident) return Natural
   is
      Str : Fat_String;
      pragma Import (Ada, Str);
      for Str'Address use Id.Addr;
   begin
      for I in Str'Range loop
         if Str (I) = ASCII.NUL then
            return I - 1;
         end if;
      end loop;
      raise Program_Error;
   end Get_String_Length;

   function Get_String (Id : O_Ident) return String
   is
      Str : Fat_String;
      pragma Import (Ada, Str);
      for Str'Address use Id.Addr;
   begin
      for I in Str'Range loop
         if Str (I) = ASCII.NUL then
            return Str (1 .. I - 1);
         end if;
      end loop;
      raise Program_Error;
   end Get_String;

   function Get_Cstring (Id : O_Ident) return System.Address is
   begin
      return Id.Addr;
   end Get_Cstring;

   function Is_Equal (Id : O_Ident; Str : String) return Boolean
   is
      Istr : Fat_String;
      pragma Import (Ada, Istr);
      for Istr'Address use Id.Addr;

      Str_Len : constant Natural := Str'Length;
   begin
      for I in Istr'Range loop
         if Istr (I) = ASCII.NUL then
            return I - 1 = Str_Len;
         end if;
         if I > Str_Len then
            return False;
         end if;
         if Istr (I) /= Str (Str'First + I - 1) then
            return False;
         end if;
      end loop;
      raise Program_Error;
   end Is_Equal;

   function Is_Nul (Id : O_Ident) return Boolean is
   begin
      return Id = O_Ident_Nul;
   end Is_Nul;

end Ortho_Ident;