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 D syntax highligher.
10  */
11 
12 module syntaxd;
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 syntaxHighlightD(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 	case Syntax.backtickString:
39 	{
40 	    const quote = (syntaxState.syntax == Syntax..string)       ? '"' :
41 			  (syntaxState.syntax == Syntax.singleString) ? '\'' :
42 			                                                '`';
43 	    const istart = i;
44 	    bool escape;
45 	    while (i < text.length)
46 	    {
47 		if (text[i] == quote && !escape)
48 		{
49 		    ++i;
50 		    attr[istart .. i] = config..string;
51 		    goto Loop;
52 		}
53 		else if (text[i] == '\\')
54 		    escape ^= true;
55 		else
56 		    escape = false;
57 		++i;
58 	    }
59 	    attr[istart .. i] = config..string;
60 	    return SyntaxState(syntaxState.syntax);
61 	}
62 
63 	case Syntax.comment:
64 	{
65 	    if (syntaxState.nest)	// it's /+ +/ nested comment
66 	    {
67 		const istart = i;
68 		uint nest = syntaxState.nest;
69 		while (i < text.length)
70 		{
71 		    if (text[i] == '+' && i + 1 < text.length && text[i + 1] == '/')
72 		    {
73 			i += 2;
74 			--nest;
75 			if (nest == 0)
76 			{
77 			    attr[istart .. i] = config.comment;
78 			    goto Loop;
79 			}
80 			continue;
81 		    }
82 		    if (text[i] == '/' && i + 1 < text.length && text[i + 1] == '+')
83 		    {
84 			i += 2;
85 			++nest;
86 			continue;
87 		    }
88 		    ++i;
89 		}
90 		attr[istart .. i] = config.comment;
91 		return SyntaxState(Syntax.comment, nest);
92 	    }
93 	    else			// it's /* */ comment
94 	    {
95 		const istart = i;
96 		while (i < text.length)
97 		{
98 		    if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
99 		    {
100 			i += 2;
101 			attr[istart .. i] = config.comment;
102 			goto Loop;
103 		    }
104 		    ++i;
105 		}
106 		attr[istart .. i] = config.comment;
107 		return SyntaxState(Syntax.comment);
108 	    }
109 	}
110 
111 	default:
112 	    break;
113     }
114 
115   Loop:
116     while (i < text.length)
117     {
118 	const c = text[i];
119 	switch (c)
120 	{
121 	    case 'a': .. case 'z':
122 	    case 'A': .. case 'Z':
123 	    case '_':
124 	    Idstart:
125 	    {
126 		const istart = i;
127 		++i;
128 		while (i < text.length)
129 		{
130 		    const ci = text[i];
131 		    if (isalnum(ci) || ci == '_' || ci & 0x80)
132 		    {
133 			++i;
134 			continue;
135 		    }
136 		    break;
137 		}
138 		const id = text[istart .. i];
139 		attr[istart .. i] = isDKeyword(id) ? config.keyword : config.normattr;
140 		continue;
141 	    }
142 
143 	    case '/':
144 	    {
145 		const istart = i;
146 		++i;
147 		if (i < text.length)
148 		{
149 		    if (text[i] == '/')
150 		    {
151 			attr[istart .. text.length] = config.comment;
152 			return SyntaxState(Syntax.normal);
153 		    }
154 
155 		    if (text[i] == '*')
156 		    {
157 			++i;
158 			while (i < text.length)
159 			{
160 			    if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
161 			    {
162 				i += 2;
163 				attr[istart .. i] = config.comment;
164 				continue Loop;
165 			    }
166 			    ++i;
167 			}
168 			attr[istart .. i] = config.comment;
169 			return SyntaxState(Syntax.comment);
170 		    }
171 
172 		    if (text[i] == '+')
173 		    {
174 			uint nest = 1;
175 			++i;
176 			while (i < text.length)
177 			{
178 			    if (text[i] == '+' && i + 1 < text.length && text[i + 1] == '/')
179 			    {
180 				i += 2;
181 				--nest;
182 				if (nest == 0)
183 				{
184 				    attr[istart .. i] = config.comment;
185 				    continue Loop;
186 				}
187 				continue;
188 			    }
189 			    if (text[i] == '/' && i + 1 < text.length && text[i + 1] == '+')
190 			    {
191 				i += 2;
192 				++nest;
193 				continue;
194 			    }
195 			    ++i;
196 			}
197 			attr[istart .. i] = config.comment;
198 			return SyntaxState(Syntax.comment, nest);
199 		    }
200 		}
201 		continue;
202 	    }
203 
204 	    case '"':
205 	    case '\'':
206 	    case '`':
207 	    {
208 		const istart = i;
209 		bool escape;
210 		++i;
211 		while (i < text.length)
212 		{
213 		    if (text[i] == c && !escape)
214 		    {
215 			++i;
216 			attr[istart .. i] = config..string;
217 			continue Loop;
218 		    }
219 		    else if (text[i] == '\\')
220 			escape ^= true;
221 		    else
222 			escape = false;
223 		    ++i;
224 		}
225 		attr[istart .. i] = config..string;
226 		return SyntaxState(c == '"'  ? Syntax..string :
227 				   c == '\'' ? Syntax.singleString :
228 				               Syntax.backtickString);
229 	    }
230 
231 	    default:
232 		if (text[i] & 0x80)
233 		    goto Idstart;
234 		attr[i] = config.normattr;
235 		++i;
236 		continue;
237 	}
238 /*
239 	switch (syntaxState.syntax)
240 	{
241 	    case Syntax.normal:
242 		break;
243 
244 	    case Syntax.string:
245 	    case Syntax.singleString:
246 		break;
247 
248 	    case Syntax.comment:
249 		break;
250 
251 	    default:
252 		assert(0);
253 	}
254 */
255     }
256     return SyntaxState(Syntax.normal);
257 }
258 
259 private bool isDKeyword(const(char)[] s)
260 {
261     switch (s)
262     {
263         case "this":
264         case "super":
265         case "assert":
266         case "null":
267         case "true":
268         case "false":
269         case "cast":
270         case "new":
271         case "delete":
272         case "throw":
273         case "module":
274         case "pragma":
275         case "typeof":
276         case "typeid":
277         case "template":
278         case "void":
279         case "byte":
280         case "ubyte":
281         case "short":
282         case "ushort":
283         case "int":
284         case "uint":
285         case "long":
286         case "ulong":
287         case "cent":
288         case "ucent":
289         case "float":
290         case "double":
291         case "real":
292         case "bool":
293         case "char":
294         case "wchar":
295         case "dchar":
296         case "ifloat":
297         case "idouble":
298         case "ireal":
299         case "cfloat":
300         case "cdouble":
301         case "creal":
302         case "delegate":
303         case "function":
304         case "is":
305         case "if":
306         case "else":
307         case "while":
308         case "for":
309         case "do":
310         case "switch":
311         case "case":
312         case "default":
313         case "break":
314         case "continue":
315         case "synchronized":
316         case "return":
317         case "goto":
318         case "try":
319         case "catch":
320         case "finally":
321         case "with":
322         case "asm":
323         case "foreach":
324         case "foreach_reverse":
325         case "scope":
326         case "struct":
327         case "class":
328         case "interface":
329         case "union":
330         case "enum":
331         case "import":
332         case "mixin":
333         case "static":
334         case "final":
335         case "const":
336         case "alias":
337         case "override":
338         case "abstract":
339         case "debug":
340         case "deprecated":
341         case "in":
342         case "out":
343         case "inout":
344         case "lazy":
345         case "auto":
346         case "align":
347         case "extern":
348         case "private":
349         case "package":
350         case "protected":
351         case "public":
352         case "export":
353         case "invariant":
354         case "unittest":
355         case "version":
356         case "__argTypes":
357         case "__parameters":
358         case "ref":
359         case "macro":
360         case "pure":
361         case "nothrow":
362         case "__gshared":
363         case "__traits":
364         case "__vector":
365         case "__overloadset":
366         case "__FILE__":
367         case "__FILE_FULL_PATH__":
368         case "__LINE__":
369         case "__MODULE__":
370         case "__FUNCTION__":
371         case "__PRETTY_FUNCTION__":
372         case "shared":
373         case "immutable":
374 	    return true;
375 
376 	default:
377 	    return false;
378     }
379 }