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 }