1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity high)
4 module dil.lexer.Tables;
5 
6 import dil.lexer.Token,
7        dil.lexer.IdTable;
8 import dil.Float;
9 import dil.String;
10 import common;
11 
12 /// Tables used by the $(MODLINK2 dil.lexer.Lexer, Lexer).
13 ///
14 /// The purpose is to keep common Token values
15 /// stored in a single place, with the added benefit of saving memory.
16 /// Most importantly, it provides access to unique Identifiers.
17 /// TODO: Inserting and reading needs to be thread-safe.
18 class LexerTables
19 {
20   alias StringValue = Token.StringValue;
21   alias IntegerValue = Token.IntegerValue;
22   alias NewlineValue = Token.NewlineValue;
23 
24   IdTable idents; /// Maps id strings to unique Identifier objects.
25   cbinstr[hash_t] strings; /// Maps hashes to binary string values.
26   StringValue*[hash_t] strvals; /// Maps string+postfix to StringValues.
27   Float[hash_t] floats; /// Maps float strings to Float values.
28   IntegerValue*[ulong] ulongs; /// Maps a ulong to an IntegerValue.
29   /// A list of newline values.
30   /// Only instances where the 'hlinfo' member is null are kept here.
31   NewlineValue*[] newlines;
32 
33   /// Contructs a LexerTables object.
34   this()
35   {
36     idents = new IdTable();
37   }
38 
39   /// Looks up a StringValue in the table.
40   /// Params:
41   ///   str = The string to be looked up.
42   ///   pf = The postfix character.
43   ///   dup = True if str should be copied.
44   /// Returns: A stored or new StringValue.
45   StringValue* lookupString(cstring str, char postfix, bool dup = true)
46   {
47     auto hash = hashOf(str);
48     if (auto psv = (hash + postfix) in strvals)
49       return *psv;
50     // Insert a new StringValue into the table.
51     auto sv = new StringValue;
52     sv.str = lookupString(hash, str, dup);
53     sv.pf = postfix;
54     strvals[hash + postfix] = sv;
55     return sv;
56   }
57 
58   /// Looks up a string in the table.
59   /// Params:
60   ///   hash = The hash of str.
61   ///   str = The string to be looked up.
62   ///   dup = True if str should be copied.
63   /// Returns: A stored or new string.
64   cbinstr lookupString(hash_t hash, cstring str, bool dup = true)
65   {
66     assert(hash == hashOf(str));
67     auto bstr = cast(cbinstr)str;
68     if (auto pstr = hash in strings)
69       bstr = *pstr;
70     else // Insert a new string into the table.
71       bstr = strings[hash] = dup ? bstr.dup : bstr;
72     return bstr;
73   }
74 
75   /// Looks up an identifier.
76   Identifier* lookupIdentifier(cstring str)
77   {
78     return idents.lookup(str);
79   }
80 
81   /// Looks up a ulong in the table.
82   /// Params:
83   ///   num = The number value.
84   IntegerValue* lookupUlong(ulong num)
85   {
86     if (auto pintval = num in ulongs)
87       return *pintval;
88     // Insert a new IntegerValue into the table.
89     auto iv = new IntegerValue;
90     iv.ulong_ = num;
91     ulongs[num] = iv;
92     return iv;
93   }
94 
95   /// Looks up a newline value that can be shared among Lexer instances.
96   NewlineValue* lookupNewline(uint_t lineNum)
97   {
98     assert(lineNum != 0);
99     auto i = lineNum - 1;
100     if (i >= newlines.length)
101       newlines.length = lineNum;
102     auto nl = newlines[i];
103     if (!nl)
104     { // Insert a new NewlineValue.
105       newlines[i] = nl = new NewlineValue;
106       nl.lineNum = lineNum;
107     }
108     return nl;
109   }
110 }