diff --git a/highlighter.d b/highlighter.d index cbd861f..205799b 100644 --- a/highlighter.d +++ b/highlighter.d @@ -17,13 +17,15 @@ void writeSpan(string cssClass, string value) // http://ethanschoonover.com/solarized -void highlight(R)(R tokens) +void highlight(R)(TokenRange!R tokens, string fileName) { - stdout.writeln(q"EOS + stdout.writeln(q"[
- +]"); + stdout.writeln("-EOS"); +]"); foreach (Token t; tokens) { diff --git a/main.d b/main.d index 5b0b679..a863893 100644 --- a/main.d +++ b/main.d @@ -140,6 +140,7 @@ int main(string[] args) if (tokenCount) { + import core.memory; /+if (args.length == 1) { writeln((cast (ubyte[]) stdin.byLine(KeepTerminator.yes).join()).byToken().walkLength()); @@ -151,11 +152,12 @@ int main(string[] args) { config.fileName = arg; uint count; + //GC.disable(); foreach(t; byToken(cast(ubyte[]) File(arg).byLine(KeepTerminator.yes).join(), config)) { - writeln(t); ++count; } + //GC.enable(); writefln("%s: %d", arg, count); } /+}+/ @@ -193,7 +195,8 @@ int main(string[] args) config.iterStyle = IterationStyle.everything; config.tokenStyle = TokenStyle.source; File f = args.length == 1 ? stdin : File(args[1]); - highlighter.highlight((cast(ubyte[]) f.byLine(KeepTerminator.yes).join()).byToken(config)); + highlighter.highlight((cast(ubyte[]) f.byLine(KeepTerminator.yes).join()).byToken(config), + args.length == 1 ? "stdin" : args[1]); return 0; } diff --git a/std/d/lexer.d b/std/d/lexer.d index 44896d1..74decd5 100644 --- a/std/d/lexer.d +++ b/std/d/lexer.d @@ -119,8 +119,7 @@ import std.traits; import std.uni; import std.utf; import std.regex; - -import std.stdio; +import std.container; public: @@ -268,7 +267,7 @@ struct LexerConfig /** * Replacement for the ___VERSION__ token. Defaults to 1. */ - uint versionNumber = 1; + uint versionNumber = 100; /** * Replacement for the ___VENDOR__ token. Defaults to $(D_STRING "std.d.lexer") @@ -415,6 +414,7 @@ private: { this.range = range; buffer = new ubyte[config.bufferSize]; + cache.initialize(); } /* @@ -631,7 +631,7 @@ private: current.type = lookupTokenType(cast(char[]) buffer[0 .. bufferIndex]); current.value = getTokenValue(current.type); if (current.value is null) - current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + setTokenValue(); if (!(config.iterStyle & IterationStyle.ignoreEOF) && current.type == TokenType.eof) { @@ -693,7 +693,7 @@ private: keepChar(); } if (config.iterStyle & IterationStyle.includeWhitespace) - current.value = (cast(char[]) buffer[0..bufferIndex]).idup; + setTokenValue(); } void lexComment() @@ -759,7 +759,7 @@ private: assert(false); } if (config.iterStyle & IterationStyle.includeComments) - current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + setTokenValue(); } void lexHexString() @@ -770,20 +770,13 @@ private: body { current.type = TokenType.stringLiteral; - size_t i; - if (config.tokenStyle & TokenStyle.includeQuotes) + keepChar(); + keepChar(); + while (true) { - buffer[i++] = 'x'; - buffer[i++] = '"'; - } - range.popFront(); - range.popFront(); - index += 2; - while (!range.isEoF()) - { - if (i >= buffer.length) + if (range.isEoF()) { - errorMessage("Hex string constant exceeded buffer size"); + errorMessage("Unterminated hex string literal"); return; } else if (isHexDigit(range.front)) @@ -796,44 +789,28 @@ private: } else if (range.front == '"') { - if (config.tokenStyle & TokenStyle.includeQuotes) - buffer[i++] = '"'; - range.popFront(); - ++index; + keepChar(); break; } else { errorMessage(format("Invalid character '%s' in hex string literal", cast(char) range.front)); + return; } } - if (!range.isEoF()) - { - switch (range.front) - { - case 'w': - current.type = TokenType.wstringLiteral; - goto case 'c'; - case 'd': - current.type = TokenType.dstringLiteral; - goto case 'c'; - case 'c': - if (config.tokenStyle & TokenStyle.includeQuotes) - buffer[i++] = range.front; - range.popFront(); - ++index; - break; - default: - break; - } - } + lexStringSuffix(); if (config.tokenStyle & TokenStyle.notEscaped) - current.value = (cast(char[]) buffer[0 .. i]).idup; + { + if (config.tokenStyle & TokenStyle.includeQuotes) + setTokenValue(); + else + setTokenValue(bufferIndex - 1, 2); + } else { auto a = appender!(ubyte[])(); - foreach (b; std.range.chunks(buffer[0 .. i], 2)) + foreach (b; std.range.chunks(buffer[2 .. bufferIndex - 1], 2)) { string s = to!string(cast(char[]) b); a.put(cast(ubyte[]) to!string(cast(dchar) parse!uint(s, 16))); @@ -999,7 +976,7 @@ private: { bool foundDot = false; current.type = TokenType.intLiteral; - scope(exit) current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + scope(exit) setTokenValue(); decimalLoop: while (!range.isEoF()) { switch (range.front) @@ -1049,7 +1026,7 @@ private: void lexBinary() { current.type = TokenType.intLiteral; - scope(exit) current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + scope(exit) setTokenValue(); binaryLoop: while (!range.isEoF()) { switch (range.front) @@ -1073,7 +1050,7 @@ private: void lexHex() { current.type = TokenType.intLiteral; - scope(exit) current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + scope(exit) setTokenValue(); bool foundDot; hexLoop: while (!range.isEoF()) { @@ -1155,13 +1132,13 @@ private: scope (exit) { if (config.tokenStyle & TokenStyle.includeQuotes) - current.value = (cast(char[]) buffer[0..bufferIndex]).idup; + setTokenValue(); else { if (buffer[0] == 'r') - current.value = (cast(char[]) buffer[2..bufferIndex - 1]).idup; + setTokenValue(bufferIndex - 1, 2); else - current.value = (cast(char[]) buffer[1..bufferIndex - 1]).idup; + setTokenValue(bufferIndex - 1, 1); } } @@ -1250,9 +1227,9 @@ private: scope (exit) { if (config.tokenStyle & TokenStyle.includeQuotes) - current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + setTokenValue(); else - current.value = (cast(char[]) buffer[3 .. bufferIndex - 2]).idup; + setTokenValue(bufferIndex - 2, 3); } while (true) { @@ -1323,7 +1300,7 @@ private: scope(exit) { if (config.tokenStyle & TokenStyle.includeQuotes) - current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + setTokenValue(); else { size_t b = 2 + ident.length; @@ -1332,8 +1309,7 @@ private: size_t e = bufferIndex; if (buffer[e - 1] == 'c' || buffer[e - 1] == 'd' || buffer[e - 1] == 'w') --e; - stderr.writeln("b = ", b, " e = ", e); - current.value = (cast(char[]) buffer[b .. e]).idup; + setTokenValue(e, b); } } @@ -1376,9 +1352,9 @@ private: scope (exit) { if (config.tokenStyle & TokenStyle.includeQuotes) - current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; + setTokenValue(); else - current.value = (cast(char[]) buffer[2 .. bufferIndex - 1]).idup; + setTokenValue(bufferIndex - 1, 2); } keepChar(); @@ -1514,6 +1490,13 @@ private: } } + void setTokenValue(size_t endIndex = 0, size_t startIndex = 0) + { + if (endIndex == 0) + endIndex = bufferIndex; + current.value = cache.get(buffer[startIndex .. endIndex]); + } + Token current; uint lineNumber; uint index; @@ -1523,6 +1506,7 @@ private: ubyte[] buffer; size_t bufferIndex; LexerConfig config; + StringCache cache; } /** @@ -1822,207 +1806,207 @@ private: * To avoid memory allocations Token.value is set to a slice of this string * for operators and keywords. */ -immutable string opKwdValues = - "#/=*=+=++-=--^^=~=<<=%==>>>=||=&&=,;:!<=!<>=!=!>=?...()[]{}@$" - ~ "boolcdoublecentcfloatcrealdchardstringfunctionidoubleifloatirealubyte" - ~ "ucentuintulongushortvoidwcharwstringaligndeprecatedexternpragmaexport" - ~ "packageprivateprotectedpublicabstractautoconstfinal__gsharedimmutable" - ~ "inoutscopesharedstaticsynchronizedaliasasmassertbodybreakcasecastcatch" - ~ "classcontinuedebugdefaultdelegatedeleteelseenumfalsefinally" - ~ "foreach_reversegotoimportinterfaceinvariantlazymacromixinmodule" - ~ "newnothrownulloverridepurerefreturnstructsuperswitchtemplatethistruetry" - ~ "typedeftypeidtypeofunionunittestversionvolatilewhilewith__traits" - ~ "__vector__parameters__DATE__EOF__TIME__TIMESTAMP__VENDOR__VERSION__" - ~ "FILE__LINE__"; +//immutable string opKwdValues = +// "#/=*=+=++-=--^^=~=<<=%==>>>=||=&&=,;:!<=!<>=!=!>=?...()[]{}@$" +// ~ "boolcdoublecentcfloatcrealdchardstringfunctionidoubleifloatirealubyte" +// ~ "ucentuintulongushortvoidwcharwstringaligndeprecatedexternpragmaexport" +// ~ "packageprivateprotectedpublicabstractautoconstfinal__gsharedimmutable" +// ~ "inoutscopesharedstaticsynchronizedaliasasmassertbodybreakcasecastcatch" +// ~ "classcontinuedebugdefaultdelegatedeleteelseenumfalsefinally" +// ~ "foreach_reversegotoimportinterfaceinvariantlazymacromixinmodule" +// ~ "newnothrownulloverridepurerefreturnstructsuperswitchtemplatethistruetry" +// ~ "typedeftypeidtypeofunionunittestversionvolatilewhilewith__traits" +// ~ "__vector__parameters__DATE__EOF__TIME__TIMESTAMP__VENDOR__VERSION__" +// ~ "FILE__LINE__"; /* * Slices of the above string to save memory. This array is automatically * generated. */ -immutable(string[]) tokenValues = [ - opKwdValues[2 .. 3], // = - opKwdValues[59 .. 60], // @ - opKwdValues[31 .. 32], // & - opKwdValues[32 .. 34], // &= - opKwdValues[28 .. 29], // | - opKwdValues[29 .. 31], // |= - opKwdValues[16 .. 18], // ~= - opKwdValues[36 .. 37], // : - opKwdValues[34 .. 35], // , - opKwdValues[11 .. 13], // -- - opKwdValues[1 .. 2], // / - opKwdValues[1 .. 3], // /= - opKwdValues[60 .. 61], // $ - opKwdValues[50 .. 51], // . - opKwdValues[22 .. 24], // == - opKwdValues[23 .. 25], // => - opKwdValues[24 .. 25], // > - opKwdValues[26 .. 28], // >= - opKwdValues[0 .. 1], // # - opKwdValues[7 .. 9], // ++ - opKwdValues[57 .. 58], // { - opKwdValues[55 .. 56], // [ - opKwdValues[18 .. 19], // < - opKwdValues[19 .. 21], // <= - opKwdValues[41 .. 44], // <>= - opKwdValues[41 .. 43], // <> - opKwdValues[31 .. 33], // && - opKwdValues[28 .. 30], // || - opKwdValues[53 .. 54], // ( - opKwdValues[9 .. 10], // - - opKwdValues[9 .. 11], // -= - opKwdValues[21 .. 22], // % - opKwdValues[21 .. 23], // %= - opKwdValues[3 .. 5], // *= - opKwdValues[37 .. 38], // ! - opKwdValues[44 .. 46], // != - opKwdValues[46 .. 48], // !> - opKwdValues[46 .. 49], // !>= - opKwdValues[37 .. 39], // !< - opKwdValues[37 .. 40], // !<= - opKwdValues[40 .. 43], // !<> - opKwdValues[5 .. 6], // + - opKwdValues[5 .. 7], // += - opKwdValues[13 .. 15], // ^^ - opKwdValues[13 .. 16], // ^^= - opKwdValues[58 .. 59], // } - opKwdValues[56 .. 57], // ] - opKwdValues[54 .. 55], // ) - opKwdValues[35 .. 36], // ; - opKwdValues[18 .. 20], // << - opKwdValues[18 .. 21], // <<= - opKwdValues[24 .. 26], // >> - opKwdValues[25 .. 28], // >>= - opKwdValues[50 .. 52], // .. - opKwdValues[3 .. 4], // * - opKwdValues[49 .. 50], // ? - opKwdValues[16 .. 17], // ~ - opKwdValues[40 .. 44], // !<>= - opKwdValues[24 .. 27], // >>> - opKwdValues[24 .. 28], // >>>= - opKwdValues[50 .. 53], // ... - opKwdValues[13 .. 14], // ^ - opKwdValues[14 .. 16], // ^= - opKwdValues[61 .. 65], // bool - opKwdValues[126 .. 130], // byte - opKwdValues[65 .. 72], // cdouble - opKwdValues[72 .. 76], // cent - opKwdValues[76 .. 82], // cfloat - opKwdValues[88 .. 92], // char - opKwdValues[82 .. 87], // creal - opKwdValues[87 .. 92], // dchar - opKwdValues[66 .. 72], // double - opKwdValues[92 .. 99], // dstring - opKwdValues[77 .. 82], // float - opKwdValues[99 .. 107], // function - opKwdValues[107 .. 114], // idouble - opKwdValues[114 .. 120], // ifloat - opKwdValues[136 .. 139], // int - opKwdValues[120 .. 125], // ireal - opKwdValues[140 .. 144], // long - opKwdValues[83 .. 87], // real - opKwdValues[145 .. 150], // short - opKwdValues[93 .. 99], // string - opKwdValues[125 .. 130], // ubyte - opKwdValues[130 .. 135], // ucent - opKwdValues[135 .. 139], // uint - opKwdValues[139 .. 144], // ulong - opKwdValues[144 .. 150], // ushort - opKwdValues[150 .. 154], // void - opKwdValues[154 .. 159], // wchar - opKwdValues[159 .. 166], // wstring - opKwdValues[166 .. 171], // align - opKwdValues[171 .. 181], // deprecated - opKwdValues[181 .. 187], // extern - opKwdValues[187 .. 193], // pragma - opKwdValues[193 .. 199], // export - opKwdValues[199 .. 206], // package - opKwdValues[206 .. 213], // private - opKwdValues[213 .. 222], // protected - opKwdValues[222 .. 228], // public - opKwdValues[228 .. 236], // abstract - opKwdValues[236 .. 240], // auto - opKwdValues[240 .. 245], // const - opKwdValues[245 .. 250], // final - opKwdValues[250 .. 259], // __gshared - opKwdValues[259 .. 268], // immutable - opKwdValues[268 .. 273], // inout - opKwdValues[273 .. 278], // scope - opKwdValues[253 .. 259], // shared - opKwdValues[284 .. 290], // static - opKwdValues[290 .. 302], // synchronized - opKwdValues[302 .. 307], // alias - opKwdValues[307 .. 310], // asm - opKwdValues[310 .. 316], // assert - opKwdValues[316 .. 320], // body - opKwdValues[320 .. 325], // break - opKwdValues[325 .. 329], // case - opKwdValues[329 .. 333], // cast - opKwdValues[333 .. 338], // catch - opKwdValues[338 .. 343], // class - opKwdValues[343 .. 351], // continue - opKwdValues[351 .. 356], // debug - opKwdValues[356 .. 363], // default - opKwdValues[363 .. 371], // delegate - opKwdValues[371 .. 377], // delete - opKwdValues[66 .. 68], // do - opKwdValues[377 .. 381], // else - opKwdValues[381 .. 385], // enum - opKwdValues[385 .. 390], // false - opKwdValues[390 .. 397], // finally - opKwdValues[397 .. 404], // foreach - opKwdValues[397 .. 412], // foreach_reverse - opKwdValues[397 .. 400], // for - opKwdValues[412 .. 416], // goto - opKwdValues[114 .. 116], // if - opKwdValues[416 .. 422], // import - opKwdValues[96 .. 98], // in - opKwdValues[422 .. 431], // interface - opKwdValues[431 .. 440], // invariant - opKwdValues[522 .. 524], // is - opKwdValues[440 .. 444], // lazy - opKwdValues[444 .. 449], // macro - opKwdValues[449 .. 454], // mixin - opKwdValues[454 .. 460], // module - opKwdValues[460 .. 463], // new - opKwdValues[463 .. 470], // nothrow - opKwdValues[470 .. 474], // null - opKwdValues[270 .. 273], // out - opKwdValues[474 .. 482], // override - opKwdValues[482 .. 486], // pure - opKwdValues[486 .. 489], // ref - opKwdValues[489 .. 495], // return - opKwdValues[495 .. 501], // struct - opKwdValues[501 .. 506], // super - opKwdValues[506 .. 512], // switch - opKwdValues[512 .. 520], // template - opKwdValues[520 .. 524], // this - opKwdValues[465 .. 470], // throw - opKwdValues[524 .. 528], // true - opKwdValues[528 .. 531], // try - opKwdValues[531 .. 538], // typedef - opKwdValues[538 .. 544], // typeid - opKwdValues[544 .. 550], // typeof - opKwdValues[550 .. 555], // union - opKwdValues[555 .. 563], // unittest - opKwdValues[563 .. 570], // version - opKwdValues[570 .. 578], // volatile - opKwdValues[578 .. 583], // while - opKwdValues[583 .. 587], // with - opKwdValues[615 .. 623], // __DATE__ - opKwdValues[621 .. 628], // __EOF__ - opKwdValues[626 .. 634], // __TIME__ - opKwdValues[632 .. 645], // __TIMESTAMP__ - opKwdValues[643 .. 653], // __VENDOR__ - opKwdValues[651 .. 662], // __VERSION__ - opKwdValues[660 .. 668], // __FILE__ - opKwdValues[666 .. 674], // __LINE__ +immutable(string[TokenType.max + 1]) tokenValues = [ + "=", + "@", + "&", + "&=", + "|", + "|=", + "~=", + ":", + ",", + "--", + "/", + "/=", + "$", + ".", + "==", + "=>", + ">", + ">=", + "#", + "++", + "{", + "[", + "<", + "<=", + "<>=", + "<>", + "&&", + "||", + "(", + "-", + "-=", + "%", + "%=", + "*=", + "!", + "!=", + "!>", + "!>=", + "!<", + "!<=", + "!<>", + "+", + "+=", + "^^", + "^^=", + "}", + "]", + ")", + ";", + "<<", + "<<=", + ">>", + ">>=", + "..", + "*", + "?", + "~", + "!<>=", + ">>>", + ">>>=", + "...", + "^", + "^=", + "bool", + "byte", + "cdouble", + "cent", + "cfloat", + "char", + "creal", + "dchar", + "double", + "dstring", + "float", + "function", + "idouble", + "ifloat", + "int", + "ireal", + "long", + "real", + "short", + "string", + "ubyte", + "ucent", + "uint", + "ulong", + "ushort", + "void", + "wchar", + "wstring", + "align", + "deprecated", + "extern", + "pragma", + "export", + "package", + "private", + "protected", + "public", + "abstract", + "auto", + "const", + "final", + "__gshared", + "immutable", + "inout", + "scope", + "shared", + "static", + "synchronized", + "alias", + "asm", + "assert", + "body", + "break", + "case", + "cast", + "catch", + "class", + "continue", + "debug", + "default", + "delegate", + "delete", + "do", + "else", + "enum", + "false", + "finally", + "foreach", + "foreach_reverse", + "for", + "goto", + "if", + "import", + "in", + "interface", + "invariant", + "is", + "lazy", + "macro", + "mixin", + "module", + "new", + "nothrow", + "null", + "out", + "override", + "pure", + "ref", + "return", + "struct", + "super", + "switch", + "template", + "this", + "throw", + "true", + "try", + "typedef", + "typeid", + "typeof", + "union", + "unittest", + "version", + "volatile", + "while", + "with", + "__DATE__", + "__EOF__", + "__TIME__", + "__TIMESTAMP__", + "__VENDOR__", + "__VERSION__", + "__FILE__", + "__LINE__", null, null, null, - opKwdValues[587 .. 595], // __traits - opKwdValues[603 .. 615], // __parameters - opKwdValues[595 .. 603], // __vector + "__traits", + "__parameters", + "__vector", null, null, null, @@ -2477,4 +2461,64 @@ string generateCaseTrie(string[] args ...) return printCaseStatements(t, ""); } +struct StringCache +{ + + void initialize() + { + pages.length = 1; + } + + string get(ubyte[] bytes) + { + + import std.stdio; + string* val = (cast(string) bytes) in index; + if (val !is null) + { + return *val; + } + else + { + auto s = insert(bytes); + index[s] = s; + return s; + } + } + +private: + + immutable pageSize = 1024 * 1024; + + string insert(ubyte[] bytes) + { + if (bytes.length >= pageSize) + assert(false); + size_t last = pages.length - 1; + Page* p = &(pages[last]); + size_t free = p.data.length - p.lastUsed; + if (free >= bytes.length) + { + p.data[p.lastUsed .. (p.lastUsed + bytes.length)] = bytes; + p.lastUsed += bytes.length; + return cast(immutable(char)[]) p.data[p.lastUsed - bytes.length .. p.lastUsed]; + } + else + { + pages.length++; + pages[pages.length - 1].data[0 .. bytes.length] = bytes; + pages[pages.length - 1].lastUsed = bytes.length; + return cast(immutable(char)[]) pages[pages.length - 1].data[0 .. bytes.length]; + } + } + + struct Page + { + ubyte[pageSize] data; + size_t lastUsed; + } + Page[] pages; + string[string] index; +} + //void main(string[] args) {}