]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Plugins/ExpressionParser/Go/GoLexer.cpp
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / source / Plugins / ExpressionParser / Go / GoLexer.cpp
1 //===-- GoLexer.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include <string.h>
11
12 #include "GoLexer.h"
13
14 using namespace lldb_private;
15
16 llvm::StringMap<GoLexer::TokenType> *GoLexer::m_keywords;
17
18 GoLexer::GoLexer(const char *src)
19     : m_src(src), m_end(src + strlen(src)), m_last_token(TOK_INVALID, "") {}
20
21 bool GoLexer::SkipWhitespace() {
22   bool saw_newline = false;
23   for (; m_src < m_end; ++m_src) {
24     if (*m_src == '\n')
25       saw_newline = true;
26     if (*m_src == '/' && !SkipComment())
27       return saw_newline;
28     else if (!IsWhitespace(*m_src))
29       return saw_newline;
30   }
31   return saw_newline;
32 }
33
34 bool GoLexer::SkipComment() {
35   if (m_src[0] == '/' && m_src[1] == '/') {
36     for (const char *c = m_src + 2; c < m_end; ++c) {
37       if (*c == '\n') {
38         m_src = c - 1;
39         return true;
40       }
41     }
42     return true;
43   } else if (m_src[0] == '/' && m_src[1] == '*') {
44     for (const char *c = m_src + 2; c < m_end; ++c) {
45       if (c[0] == '*' && c[1] == '/') {
46         m_src = c + 1;
47         return true;
48       }
49     }
50   }
51   return false;
52 }
53
54 const GoLexer::Token &GoLexer::Lex() {
55   bool newline = SkipWhitespace();
56   const char *start = m_src;
57   m_last_token.m_type = InternalLex(newline);
58   m_last_token.m_value = llvm::StringRef(start, m_src - start);
59   return m_last_token;
60 }
61
62 GoLexer::TokenType GoLexer::InternalLex(bool newline) {
63   if (m_src >= m_end) {
64     return TOK_EOF;
65   }
66   if (newline) {
67     switch (m_last_token.m_type) {
68     case TOK_IDENTIFIER:
69     case LIT_FLOAT:
70     case LIT_IMAGINARY:
71     case LIT_INTEGER:
72     case LIT_RUNE:
73     case LIT_STRING:
74     case KEYWORD_BREAK:
75     case KEYWORD_CONTINUE:
76     case KEYWORD_FALLTHROUGH:
77     case KEYWORD_RETURN:
78     case OP_PLUS_PLUS:
79     case OP_MINUS_MINUS:
80     case OP_RPAREN:
81     case OP_RBRACK:
82     case OP_RBRACE:
83       return OP_SEMICOLON;
84     default:
85       break;
86     }
87   }
88   char c = *m_src;
89   switch (c) {
90   case '0':
91   case '1':
92   case '2':
93   case '3':
94   case '4':
95   case '5':
96   case '6':
97   case '7':
98   case '8':
99   case '9':
100     return DoNumber();
101   case '+':
102   case '-':
103   case '*':
104   case '/':
105   case '%':
106   case '&':
107   case '|':
108   case '^':
109   case '<':
110   case '>':
111   case '!':
112   case ':':
113   case ';':
114   case '(':
115   case ')':
116   case '[':
117   case ']':
118   case '{':
119   case '}':
120   case ',':
121   case '=':
122     return DoOperator();
123   case '.':
124     if (IsDecimal(m_src[1]))
125       return DoNumber();
126     return DoOperator();
127   case '$':
128     // For lldb persistent vars.
129     return DoIdent();
130   case '"':
131   case '`':
132     return DoString();
133   case '\'':
134     return DoRune();
135   default:
136     break;
137   }
138   if (IsLetterOrDigit(c))
139     return DoIdent();
140   ++m_src;
141   return TOK_INVALID;
142 }
143
144 GoLexer::TokenType GoLexer::DoOperator() {
145   TokenType t = TOK_INVALID;
146   if (m_end - m_src > 2) {
147     t = LookupKeyword(llvm::StringRef(m_src, 3));
148     if (t != TOK_INVALID)
149       m_src += 3;
150   }
151   if (t == TOK_INVALID && m_end - m_src > 1) {
152     t = LookupKeyword(llvm::StringRef(m_src, 2));
153     if (t != TOK_INVALID)
154       m_src += 2;
155   }
156   if (t == TOK_INVALID) {
157     t = LookupKeyword(llvm::StringRef(m_src, 1));
158     ++m_src;
159   }
160   return t;
161 }
162
163 GoLexer::TokenType GoLexer::DoIdent() {
164   const char *start = m_src++;
165   while (m_src < m_end && IsLetterOrDigit(*m_src)) {
166     ++m_src;
167   }
168   TokenType kw = LookupKeyword(llvm::StringRef(start, m_src - start));
169   if (kw != TOK_INVALID)
170     return kw;
171   return TOK_IDENTIFIER;
172 }
173
174 GoLexer::TokenType GoLexer::DoNumber() {
175   if (m_src[0] == '0' && (m_src[1] == 'x' || m_src[1] == 'X')) {
176     m_src += 2;
177     while (IsHexChar(*m_src))
178       ++m_src;
179     return LIT_INTEGER;
180   }
181   bool dot_ok = true;
182   bool e_ok = true;
183   while (true) {
184     while (IsDecimal(*m_src))
185       ++m_src;
186     switch (*m_src) {
187     case 'i':
188       ++m_src;
189       return LIT_IMAGINARY;
190     case '.':
191       if (!dot_ok)
192         return LIT_FLOAT;
193       ++m_src;
194       dot_ok = false;
195       break;
196     case 'e':
197     case 'E':
198       if (!e_ok)
199         return LIT_FLOAT;
200       dot_ok = e_ok = false;
201       ++m_src;
202       if (*m_src == '+' || *m_src == '-')
203         ++m_src;
204       break;
205     default:
206       if (dot_ok)
207         return LIT_INTEGER;
208       return LIT_FLOAT;
209     }
210   }
211 }
212
213 GoLexer::TokenType GoLexer::DoRune() {
214   while (++m_src < m_end) {
215     switch (*m_src) {
216     case '\'':
217       ++m_src;
218       return LIT_RUNE;
219     case '\n':
220       return TOK_INVALID;
221     case '\\':
222       if (m_src[1] == '\n')
223         return TOK_INVALID;
224       ++m_src;
225     }
226   }
227   return TOK_INVALID;
228 }
229
230 GoLexer::TokenType GoLexer::DoString() {
231   if (*m_src == '`') {
232     while (++m_src < m_end) {
233       if (*m_src == '`') {
234         ++m_src;
235         return LIT_STRING;
236       }
237     }
238     return TOK_INVALID;
239   }
240   while (++m_src < m_end) {
241     switch (*m_src) {
242     case '"':
243       ++m_src;
244       return LIT_STRING;
245     case '\n':
246       return TOK_INVALID;
247     case '\\':
248       if (m_src[1] == '\n')
249         return TOK_INVALID;
250       ++m_src;
251     }
252   }
253   return TOK_INVALID;
254 }
255
256 GoLexer::TokenType GoLexer::LookupKeyword(llvm::StringRef id) {
257   if (m_keywords == nullptr)
258     m_keywords = InitKeywords();
259   const auto &it = m_keywords->find(id);
260   if (it == m_keywords->end())
261     return TOK_INVALID;
262   return it->second;
263 }
264
265 llvm::StringRef GoLexer::LookupToken(TokenType t) {
266   if (m_keywords == nullptr)
267     m_keywords = InitKeywords();
268   for (const auto &e : *m_keywords) {
269     if (e.getValue() == t)
270       return e.getKey();
271   }
272   return "";
273 }
274
275 llvm::StringMap<GoLexer::TokenType> *GoLexer::InitKeywords() {
276   auto &result = *new llvm::StringMap<TokenType>(128);
277   result["break"] = KEYWORD_BREAK;
278   result["default"] = KEYWORD_DEFAULT;
279   result["func"] = KEYWORD_FUNC;
280   result["interface"] = KEYWORD_INTERFACE;
281   result["select"] = KEYWORD_SELECT;
282   result["case"] = KEYWORD_CASE;
283   result["defer"] = KEYWORD_DEFER;
284   result["go"] = KEYWORD_GO;
285   result["map"] = KEYWORD_MAP;
286   result["struct"] = KEYWORD_STRUCT;
287   result["chan"] = KEYWORD_CHAN;
288   result["else"] = KEYWORD_ELSE;
289   result["goto"] = KEYWORD_GOTO;
290   result["package"] = KEYWORD_PACKAGE;
291   result["switch"] = KEYWORD_SWITCH;
292   result["const"] = KEYWORD_CONST;
293   result["fallthrough"] = KEYWORD_FALLTHROUGH;
294   result["if"] = KEYWORD_IF;
295   result["range"] = KEYWORD_RANGE;
296   result["type"] = KEYWORD_TYPE;
297   result["continue"] = KEYWORD_CONTINUE;
298   result["for"] = KEYWORD_FOR;
299   result["import"] = KEYWORD_IMPORT;
300   result["return"] = KEYWORD_RETURN;
301   result["var"] = KEYWORD_VAR;
302   result["+"] = OP_PLUS;
303   result["-"] = OP_MINUS;
304   result["*"] = OP_STAR;
305   result["/"] = OP_SLASH;
306   result["%"] = OP_PERCENT;
307   result["&"] = OP_AMP;
308   result["|"] = OP_PIPE;
309   result["^"] = OP_CARET;
310   result["<<"] = OP_LSHIFT;
311   result[">>"] = OP_RSHIFT;
312   result["&^"] = OP_AMP_CARET;
313   result["+="] = OP_PLUS_EQ;
314   result["-="] = OP_MINUS_EQ;
315   result["*="] = OP_STAR_EQ;
316   result["/="] = OP_SLASH_EQ;
317   result["%="] = OP_PERCENT_EQ;
318   result["&="] = OP_AMP_EQ;
319   result["|="] = OP_PIPE_EQ;
320   result["^="] = OP_CARET_EQ;
321   result["<<="] = OP_LSHIFT_EQ;
322   result[">>="] = OP_RSHIFT_EQ;
323   result["&^="] = OP_AMP_CARET_EQ;
324   result["&&"] = OP_AMP_AMP;
325   result["||"] = OP_PIPE_PIPE;
326   result["<-"] = OP_LT_MINUS;
327   result["++"] = OP_PLUS_PLUS;
328   result["--"] = OP_MINUS_MINUS;
329   result["=="] = OP_EQ_EQ;
330   result["<"] = OP_LT;
331   result[">"] = OP_GT;
332   result["="] = OP_EQ;
333   result["!"] = OP_BANG;
334   result["!="] = OP_BANG_EQ;
335   result["<="] = OP_LT_EQ;
336   result[">="] = OP_GT_EQ;
337   result[":="] = OP_COLON_EQ;
338   result["..."] = OP_DOTS;
339   result["("] = OP_LPAREN;
340   result["["] = OP_LBRACK;
341   result["{"] = OP_LBRACE;
342   result[","] = OP_COMMA;
343   result["."] = OP_DOT;
344   result[")"] = OP_RPAREN;
345   result["]"] = OP_RBRACK;
346   result["}"] = OP_RBRACE;
347   result[";"] = OP_SEMICOLON;
348   result[":"] = OP_COLON;
349   return &result;
350 }