1 
2 /* This version of microEmacs is based on the public domain C
3  * version written by Dave G. Conroy.
4  * The D programming language version is written by Walter Bright.
5  * http://www.digitalmars.com/d/
6  * This program is in the public domain.
7  */
8 
9 /* This is the C++ syntax highligher.
10  */
11 
12 module syntaxcpp;
13 
14 import core.stdc.stdio;
15 import core.stdc.ctype;
16 
17 import std.utf;
18 
19 import ed;
20 import buffer;
21 import window;
22 import main;
23 import display;
24 import random;
25 
26 /********************************
27  * Returns:
28  *	starting syntax state of next line
29  */
30 SyntaxState syntaxHighlightCPP(SyntaxState syntaxState, const(char)[] text, attr_t[] attr)
31 {
32     size_t i = 0;
33 
34     switch (syntaxState.syntax)
35     {
36 	case Syntax..string:
37 	case Syntax.singleString:
38 	{
39 	    const quote = (syntaxState.syntax == Syntax..string)       ? '"' :
40 			                                                '\'';
41 	    const istart = i;
42 	    bool escape;
43 	    while (i < text.length)
44 	    {
45 		if (text[i] == quote && !escape)
46 		{
47 		    ++i;
48 		    attr[istart .. i] = config..string;
49 		    goto Loop;
50 		}
51 		else if (text[i] == '\\')
52 		    escape ^= true;
53 		else
54 		    escape = false;
55 		++i;
56 	    }
57 	    attr[istart .. i] = config..string;
58 	    return SyntaxState(syntaxState.syntax);
59 	}
60 
61 	case Syntax.comment:
62 	{
63 	    // it's /* */ comment
64 	    const istart = i;
65 	    while (i < text.length)
66 	    {
67 		if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
68 		{
69 		    i += 2;
70 		    attr[istart .. i] = config.comment;
71 		    goto Loop;
72 		}
73 		++i;
74 	    }
75 	    attr[istart .. i] = config.comment;
76 	    return SyntaxState(Syntax.comment);
77 	}
78 
79 	default:
80 	    break;
81     }
82 
83   Loop:
84     while (i < text.length)
85     {
86 	const c = text[i];
87 	switch (c)
88 	{
89 	    case 'a': .. case 'z':
90 	    case 'A': .. case 'Z':
91 	    case '_':
92 	    Idstart:
93 	    {
94 		const istart = i;
95 		++i;
96 		while (i < text.length)
97 		{
98 		    const ci = text[i];
99 		    if (isalnum(ci) || ci == '_' || ci & 0x80)
100 		    {
101 			++i;
102 			continue;
103 		    }
104 		    break;
105 		}
106 		const id = text[istart .. i];
107 		attr[istart .. i] = isCPPKeyword(id) ? config.keyword : config.normattr;
108 		continue;
109 	    }
110 
111 	    case '/':
112 	    {
113 		const istart = i;
114 		++i;
115 		if (i < text.length)
116 		{
117 		    if (text[i] == '/')
118 		    {
119 			attr[istart .. text.length] = config.comment;
120 			return SyntaxState(Syntax.normal);
121 		    }
122 
123 		    if (text[i] == '*')
124 		    {
125 			++i;
126 			while (i < text.length)
127 			{
128 			    if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
129 			    {
130 				i += 2;
131 				attr[istart .. i] = config.comment;
132 				continue Loop;
133 			    }
134 			    ++i;
135 			}
136 			attr[istart .. i] = config.comment;
137 			return SyntaxState(Syntax.comment);
138 		    }
139 		}
140 		continue;
141 	    }
142 
143 	    case '"':
144 	    case '\'':
145 	    {
146 		const istart = i;
147 		bool escape;
148 		++i;
149 		while (i < text.length)
150 		{
151 		    if (text[i] == c && !escape)
152 		    {
153 			++i;
154 			attr[istart .. i] = config..string;
155 			continue Loop;
156 		    }
157 		    else if (text[i] == '\\')
158 			escape ^= true;
159 		    else
160 			escape = false;
161 		    ++i;
162 		}
163 		attr[istart .. i] = config..string;
164 		return SyntaxState(c == '"'  ? Syntax..string :
165 				               Syntax.singleString);
166 	    }
167 
168 	    default:
169 		if (text[i] & 0x80)
170 		    goto Idstart;
171 		attr[i] = config.normattr;
172 		++i;
173 		continue;
174 	}
175 /*
176 	switch (syntaxState.syntax)
177 	{
178 	    case Syntax.normal:
179 		break;
180 
181 	    case Syntax.string:
182 	    case Syntax.singleString:
183 		break;
184 
185 	    case Syntax.comment:
186 		break;
187 
188 	    default:
189 		assert(0);
190 	}
191 */
192     }
193     return SyntaxState(Syntax.normal);
194 }
195 
196 private bool isCPPKeyword(const(char)[] s)
197 {
198     switch (s)
199     {
200         case "alignas":
201         case "const_cast":
202         case "for":
203         case "public":
204         case "thread_local ":
205         case "alignof":
206         case "continue":
207         case "friend":
208         case "register":
209         case "throw":
210         case "asm":
211         case "decltype":
212         case "goto":
213         case "reinterpret_cast":
214         case "true ":
215         case "auto":
216         case "default":
217         case "if":
218         case "requires":
219         case "try ":
220         case "bool":
221         case "delete":
222         case "inline":
223         case "return":
224         case "typedef ":
225         case "break":
226         case "do":
227         case "int":
228         case "short":
229         case "typeid ":
230         case "case":
231         case "double":
232         case "long":
233         case "signed":
234         case "typename ":
235         case "catch":
236         case "dynamic_cast":
237         case "mutable":
238         case "sizeof":
239         case "union ":
240         case "char":
241         case "else":
242         case "namespace":
243         case "static":
244         case "unsigned ":
245         case "char16_t":
246         case "enum":
247         case "new":
248         case "static_assert":
249         case "using ":
250         case "char32_t":
251         case "explicit":
252         case "noexcept":
253         case "static_cast":
254         case "virtual ":
255         case "class":
256         case "export":
257         case "nullptr":
258         case "struct":
259         case "void ":
260         case "concept":
261         case "extern":
262         case "operator":
263         case "switch":
264         case "volatile ":
265         case "const":
266         case "false":
267         case "private":
268         case "template":
269         case "wchar_t ":
270         case "constexpr":
271         case "float":
272         case "protected":
273         case "this":
274         case "while":
275 
276         case "and":
277         case "and_eq":
278         case "bitand":
279         case "bitor":
280         case "compl":
281         case "not ":
282         case "not_eq":
283         case "or":
284         case "or_eq":
285         case "xor":
286         case "xor_eq ":
287 
288         case "__FILE__":
289         case "__LINE__":
290 	    return true;
291 
292 	default:
293 	    return false;
294     }
295 }