Even faster
This commit is contained in:
parent
5a6477f2ee
commit
511c785675
378
autocomplete.d
378
autocomplete.d
|
@ -1,378 +0,0 @@
|
||||||
// Copyright Brian Schott (Sir Alaran) 2012.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module autocomplete;
|
|
||||||
|
|
||||||
import std.range;
|
|
||||||
import std.algorithm;
|
|
||||||
import std.array;
|
|
||||||
import std.conv;
|
|
||||||
import std.stdio;
|
|
||||||
import std.typecons;
|
|
||||||
import std.path;
|
|
||||||
import std.file;
|
|
||||||
import std.d.lexer;
|
|
||||||
|
|
||||||
import parser;
|
|
||||||
import langutils;
|
|
||||||
import types;
|
|
||||||
|
|
||||||
immutable string[] versions = ["AIX", "all", "Alpha", "ARM", "BigEndian", "BSD",
|
|
||||||
"Cygwin", "D_Coverage", "D_Ddoc", "DigitalMars", "D_InlineAsm_X86",
|
|
||||||
"D_InlineAsm_X86_64", "D_LP64", "D_NET", "D_PIC", "D_Version2",
|
|
||||||
"FreeBSD", "GNU", "HPPA", "HPPA64", "Hurd", "IA64", "LDC", "linux",
|
|
||||||
"LittleEndian", "MinGW", "MIPS", "MIPS64", "none", "OpenBSD", "OSX",
|
|
||||||
"Posix", "PPC", "PPC64", "S390", "S390X", "SDC", "SH", "SH64", "SkyOS",
|
|
||||||
"Solaris", "SPARC", "SPARC64", "SysV3", "SysV4", "unittest", "Win32",
|
|
||||||
"Win64", "Windows", "X86", "X86_64"
|
|
||||||
];
|
|
||||||
|
|
||||||
immutable string[] scopes = ["exit", "failure", "success"];
|
|
||||||
|
|
||||||
///**
|
|
||||||
// * Returns: indicies into the token array
|
|
||||||
// */
|
|
||||||
//size_t findEndOfExpression(const Token[] tokens, const size_t index)
|
|
||||||
//out (result)
|
|
||||||
//{
|
|
||||||
// assert (result < tokens.length);
|
|
||||||
// assert (result >= index);
|
|
||||||
//}
|
|
||||||
//body
|
|
||||||
//{
|
|
||||||
// size_t i = index;
|
|
||||||
// loop: while (i < tokens.length)
|
|
||||||
// {
|
|
||||||
// switch (tokens[i].type)
|
|
||||||
// {
|
|
||||||
// case TokenType.Return:
|
|
||||||
// case TokenType.New:
|
|
||||||
// case TokenType.Delete:
|
|
||||||
// case TokenType.Comma:
|
|
||||||
// case TokenType.RBrace:
|
|
||||||
// case TokenType.RParen:
|
|
||||||
// case TokenType.RBracket:
|
|
||||||
// case TokenType.Semicolon:
|
|
||||||
// break loop;
|
|
||||||
// case TokenType.LParen:
|
|
||||||
// skipParens(tokens, i);
|
|
||||||
// break;
|
|
||||||
// case TokenType.LBrace:
|
|
||||||
// skipBraces(tokens, i);
|
|
||||||
// break;
|
|
||||||
// case TokenType.LBracket:
|
|
||||||
// skipBrackets(tokens, i);
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// ++i;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return i;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//size_t findBeginningOfExpression(const Token[] tokens, const size_t index)
|
|
||||||
//in
|
|
||||||
//{
|
|
||||||
// assert (index < tokens.length);
|
|
||||||
// assert (tokens.length > 0);
|
|
||||||
//}
|
|
||||||
//out (result)
|
|
||||||
//{
|
|
||||||
// import std.string;
|
|
||||||
// assert (result < tokens.length);
|
|
||||||
// assert (result <= index, format("findBeginningOfExpression %d, %d", result, index));
|
|
||||||
//}
|
|
||||||
//body
|
|
||||||
//{
|
|
||||||
// size_t i = index;
|
|
||||||
// loop: while (i < tokens.length)
|
|
||||||
// {
|
|
||||||
// switch (tokens[i].type)
|
|
||||||
// {
|
|
||||||
// case TokenType.Assign: case TokenType.BitAnd: case TokenType.BitAndEquals:
|
|
||||||
// case TokenType.BitOr: case TokenType.BitOrEquals: case TokenType.CatEquals:
|
|
||||||
// case TokenType.Colon: case TokenType.Comma: case TokenType.Decrement:
|
|
||||||
// case TokenType.Div: case TokenType.DivEquals: case TokenType.Dollar:
|
|
||||||
// case TokenType.Equals: case TokenType.GoesTo:
|
|
||||||
// case TokenType.Greater: case TokenType.GreaterEqual: case TokenType.Hash:
|
|
||||||
// case TokenType.Increment: case TokenType.LBrace: case TokenType.LBracket:
|
|
||||||
// case TokenType.Less: case TokenType.LessEqual: case TokenType.LessEqualGreater:
|
|
||||||
// case TokenType.LessOrGreater: case TokenType.LogicAnd: case TokenType.LogicOr:
|
|
||||||
// case TokenType.LParen: case TokenType.Minus: case TokenType.MinusEquals:
|
|
||||||
// case TokenType.Mod: case TokenType.ModEquals: case TokenType.MulEquals:
|
|
||||||
// case TokenType.Not: case TokenType.NotEquals: case TokenType.NotGreater:
|
|
||||||
// case TokenType.NotGreaterEqual: case TokenType.NotLess: case TokenType.NotLessEqual:
|
|
||||||
// case TokenType.NotLessEqualGreater: case TokenType.Plus: case TokenType.PlusEquals:
|
|
||||||
// case TokenType.Pow: case TokenType.PowEquals: case TokenType.RBrace:
|
|
||||||
// case TokenType.Semicolon: case TokenType.ShiftLeft: case TokenType.ShiftLeftEqual:
|
|
||||||
// case TokenType.ShiftRight: case TokenType.ShiftRightEqual: case TokenType.Slice:
|
|
||||||
// case TokenType.Star: case TokenType.Ternary: case TokenType.Tilde:
|
|
||||||
// case TokenType.Unordered: case TokenType.UnsignedShiftRight: case TokenType.UnsignedShiftRightEqual:
|
|
||||||
// case TokenType.Vararg: case TokenType.Xor: case TokenType.XorEquals:
|
|
||||||
// case TokenType.KEYWORDS_BEGIN: .. case TokenType.KEYWORDS_END:
|
|
||||||
// return i + 1;
|
|
||||||
// case TokenType.RParen:
|
|
||||||
// if (i == 0)
|
|
||||||
// break loop;
|
|
||||||
// skipParens(tokens, i);
|
|
||||||
// break;
|
|
||||||
// case TokenType.RBracket:
|
|
||||||
// if (i == 0)
|
|
||||||
// break loop;
|
|
||||||
// skipBrackets(tokens, i);
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// if (i == 0)
|
|
||||||
// break loop;
|
|
||||||
// i--;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return i + 1;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//const(Token)[] splitCallChain(const(Token)[] tokens)
|
|
||||||
//{
|
|
||||||
// auto app = appender!(Token[])();
|
|
||||||
// size_t i = 0;
|
|
||||||
// while (i < tokens.length)
|
|
||||||
// {
|
|
||||||
// app.put(tokens[i++]);
|
|
||||||
// while (i < tokens.length && tokens[i] == TokenType.LParen) skipParens(tokens, i);
|
|
||||||
// while (i < tokens.length && tokens[i] == TokenType.LBracket) skipBrackets(tokens, i);
|
|
||||||
// while (i < tokens.length && tokens[i] == TokenType.Dot) ++i;
|
|
||||||
// }
|
|
||||||
// return app.data;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//unittest
|
|
||||||
//{
|
|
||||||
// auto code = `a.b[10].c("grcl").x`;
|
|
||||||
// auto tokens = tokenize(code);
|
|
||||||
// assert (splitCallChain(tokens) == ["a", "b", "c", "x"]);
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//struct AutoComplete
|
|
||||||
//{
|
|
||||||
// this(const (Token)[] tokens, CompletionContext context)
|
|
||||||
// {
|
|
||||||
// this.tokens = tokens;
|
|
||||||
// this.context = context;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// string getTypeOfExpression(const(Token)[] expression, const Token[] tokens, size_t cursor)
|
|
||||||
// {
|
|
||||||
// stderr.writeln("getting type of ", expression);
|
|
||||||
// if (expression.length == 0)
|
|
||||||
// return "void";
|
|
||||||
// auto type = typeOfVariable(expression[0], cursor);
|
|
||||||
// if (type is null)
|
|
||||||
// return "void";
|
|
||||||
// size_t index = 1;
|
|
||||||
// while (index < expression.length)
|
|
||||||
// {
|
|
||||||
// const Tuple!(string, string)[string] typeMap = context.getMembersOfType(
|
|
||||||
// type);
|
|
||||||
// const Tuple!(string, string)* memberType = expression[index].value in typeMap;
|
|
||||||
// if (memberType is null)
|
|
||||||
// return "void";
|
|
||||||
// else
|
|
||||||
// type = (*memberType)[0];
|
|
||||||
// index++;
|
|
||||||
// }
|
|
||||||
// return type;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// string typeOfVariable(Token symbol, size_t cursor)
|
|
||||||
// {
|
|
||||||
// // int is of type int, double of type double, and so on
|
|
||||||
// if (symbol.value in typeProperties)
|
|
||||||
// return symbol.value;
|
|
||||||
//
|
|
||||||
// string tokenType = getTypeFromToken(symbol);
|
|
||||||
// if (tokenType !is null)
|
|
||||||
// return tokenType;
|
|
||||||
//
|
|
||||||
// if (context.getMembersOfType(symbol.value))
|
|
||||||
// return symbol.value;
|
|
||||||
//
|
|
||||||
// // Arbitrarily define the depth of the cursor position as zero
|
|
||||||
// // iterate backwards through the code to try to find the variable
|
|
||||||
// int depth = 0;
|
|
||||||
// auto preceedingTokens = assumeSorted(tokens).lowerBound(cursor);
|
|
||||||
// auto index = preceedingTokens.length - 1;
|
|
||||||
// while (true)
|
|
||||||
// {
|
|
||||||
// if (preceedingTokens[index] == TokenType.LBrace)
|
|
||||||
// --depth;
|
|
||||||
// else if (preceedingTokens[index] == TokenType.RBrace)
|
|
||||||
// ++depth;
|
|
||||||
// else if (depth <= 0 && preceedingTokens[index].value == symbol)
|
|
||||||
// {
|
|
||||||
// // Found the symbol, now determine if it was declared here.
|
|
||||||
// auto p = preceedingTokens[index - 1];
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// if ((p == TokenType.Auto || p == TokenType.Immutable
|
|
||||||
// || p == TokenType.Const)
|
|
||||||
// && preceedingTokens[index + 1] == TokenType.Assign)
|
|
||||||
// {
|
|
||||||
// // Try to determine the type of a variable declared as "auto"
|
|
||||||
// return getTypeOfExpression(
|
|
||||||
// tokens[index + 2 .. findEndOfExpression(tokens, index + 2)],
|
|
||||||
// tokens, cursor);
|
|
||||||
// }
|
|
||||||
// else if (p == TokenType.Identifier
|
|
||||||
// || (p.type > TokenType.TYPES_BEGIN
|
|
||||||
// && p.type < TokenType.TYPES_END))
|
|
||||||
// {
|
|
||||||
// // Handle simple cases like "int a;" or "Someclass instance;"
|
|
||||||
// return p.value;
|
|
||||||
// }
|
|
||||||
// else if (p == TokenType.RBracket || p == TokenType.RParen)
|
|
||||||
// {
|
|
||||||
// return combineTokens(tokens[findBeginningOfExpression(tokens, index) .. index]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (index == 0)
|
|
||||||
// break;
|
|
||||||
// else
|
|
||||||
// --index;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Find all struct or class bodies that we're in.
|
|
||||||
// // Check for the symbol in those class/struct/interface bodies
|
|
||||||
// // if match is found, return it
|
|
||||||
// auto structs = context.getStructsContaining(cursor);
|
|
||||||
// if (symbol == "this" && structs.length > 0)
|
|
||||||
// {
|
|
||||||
// return minCount!("a.bodyStart > b.bodyStart")(structs)[0].name;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// foreach (s; structs)
|
|
||||||
// {
|
|
||||||
// auto t = s.getMemberType(symbol.value);
|
|
||||||
// if (t !is null)
|
|
||||||
// return t;
|
|
||||||
// }
|
|
||||||
// return "void";
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// string symbolAt(size_t cursor) const
|
|
||||||
// {
|
|
||||||
// auto r = assumeSorted(tokens).lowerBound(cursor)[$ - 1];
|
|
||||||
// if (r.value.length + r.startIndex > cursor)
|
|
||||||
// return r.value;
|
|
||||||
// else
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// string parenComplete(size_t cursor)
|
|
||||||
// {
|
|
||||||
// auto index = assumeSorted(tokens).lowerBound(cursor).length - 2;
|
|
||||||
// Token t = tokens[index];
|
|
||||||
// switch (tokens[index].type)
|
|
||||||
// {
|
|
||||||
// case TokenType.Version:
|
|
||||||
// return "completions\n" ~ to!string(join(map!`a ~ " k"`(versions), "\n").array());
|
|
||||||
// case TokenType.Scope:
|
|
||||||
// return "completions\n" ~ to!string(join(map!`a ~ " k"`(scopes), "\n").array());
|
|
||||||
// case TokenType.If:
|
|
||||||
// case TokenType.Cast:
|
|
||||||
// case TokenType.While:
|
|
||||||
// case TokenType.For:
|
|
||||||
// case TokenType.Foreach:
|
|
||||||
// case TokenType.Switch:
|
|
||||||
// return "";
|
|
||||||
// default:
|
|
||||||
// size_t startIndex = findBeginningOfExpression(tokens, index);
|
|
||||||
// auto callChain = splitCallChain(tokens[startIndex .. index + 1]);
|
|
||||||
// auto expressionType = getTypeOfExpression(
|
|
||||||
// callChain[0 .. $ - 1], tokens, cursor);
|
|
||||||
// return "calltips\n" ~ to!string(context.getCallTipsFor(expressionType,
|
|
||||||
// callChain[$ - 1].value, cursor).join("\n").array());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// string dotComplete(size_t cursor)
|
|
||||||
// {
|
|
||||||
// stderr.writeln("dotComplete");
|
|
||||||
// auto index = assumeSorted(tokens).lowerBound(cursor).length - 1;
|
|
||||||
// Token t = tokens[index];
|
|
||||||
//
|
|
||||||
// // If the last character entered before the cursor isn't a dot, give up.
|
|
||||||
// // The user was probably in the middle of typing the slice or vararg
|
|
||||||
// // operators
|
|
||||||
// if (t != TokenType.Dot)
|
|
||||||
// return null;
|
|
||||||
//
|
|
||||||
// size_t startIndex = findBeginningOfExpression(tokens, index);
|
|
||||||
// if (startIndex - 1 < tokens.length && tokens[startIndex - 1] == TokenType.Import)
|
|
||||||
// {
|
|
||||||
// return importComplete(splitCallChain(tokens[startIndex .. index]));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// auto expressionType = getTypeOfExpression(
|
|
||||||
// splitCallChain(tokens[startIndex .. index]), tokens, cursor);
|
|
||||||
//
|
|
||||||
// stderr.writeln("expression type is ", expressionType);
|
|
||||||
//
|
|
||||||
// // Complete pointers and references the same way
|
|
||||||
// if (expressionType[$ - 1] == '*')
|
|
||||||
// expressionType = expressionType[0 .. $ - 1];
|
|
||||||
//
|
|
||||||
// const Tuple!(string, string)[string] typeMap = context.getMembersOfType(
|
|
||||||
// expressionType);
|
|
||||||
// if (typeMap is null)
|
|
||||||
// return "";
|
|
||||||
// auto app = appender!(string[])();
|
|
||||||
// foreach (k, t; typeMap)
|
|
||||||
// app.put(k ~ " " ~ t[1]);
|
|
||||||
// return to!string(array(join(sort!("a.toLower() < b.toLower()")(app.data), "\n")));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// string importComplete(const(Token)[] tokens)
|
|
||||||
// {
|
|
||||||
// stderr.writeln("importComplete");
|
|
||||||
// auto app = appender!(string[])();
|
|
||||||
// string part = to!string(map!"a.value.dup"(tokens).join("/").array());
|
|
||||||
// foreach (path; context.importDirectories)
|
|
||||||
// {
|
|
||||||
// stderr.writeln("Searching for ", path, "/", part);
|
|
||||||
// if (!exists(buildPath(path, part)))
|
|
||||||
// continue;
|
|
||||||
// stderr.writeln("found it");
|
|
||||||
// foreach (DirEntry dirEntry; dirEntries(buildPath(path, part),
|
|
||||||
// SpanMode.shallow))
|
|
||||||
// {
|
|
||||||
// if (dirEntry.isDir)
|
|
||||||
// app.put(baseName(dirEntry.name) ~ " P");
|
|
||||||
// else if (dirEntry.name.endsWith(".d", ".di"))
|
|
||||||
// app.put(stripExtension(baseName(dirEntry.name)) ~ " M");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return to!string(sort!("a.toLower() < b.toLower()")(app.data).join("\n").array());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// const(Token)[] tokens;
|
|
||||||
// CompletionContext context;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//unittest
|
|
||||||
//{
|
|
||||||
// auto code = q{
|
|
||||||
//struct TestStruct { int a; int b; }
|
|
||||||
//TestStruct ts;
|
|
||||||
//ts.a.
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// auto tokens = tokenize(code);
|
|
||||||
// auto mod = parseModule(tokens);
|
|
||||||
// auto context = new CompletionContext(mod);
|
|
||||||
// auto completion = AutoComplete(tokens, context);
|
|
||||||
// assert (completion.getTypeOfExpression(splitCallChain(tokens[13 .. 16]),
|
|
||||||
// tokens, 56) == "int");
|
|
||||||
//}
|
|
2
build.sh
2
build.sh
|
@ -1,3 +1,3 @@
|
||||||
#dmd *.d std/d/*.d -release -inline -noboundscheck -O -w -wi -m64 -property -ofdscanner -L-lsqlite3 #-inline
|
#dmd *.d std/d/*.d -release -inline -noboundscheck -O -w -wi -m64 -property -ofdscanner -L-lsqlite3 #-inline
|
||||||
#dmd *.d std/d/*.d -g -m64 -w -wi -property -ofdscanner -L-lsqlite3 #-unittest
|
#dmd *.d std/d/*.d -g -m64 -w -wi -property -ofdscanner -L-lsqlite3 #-unittest
|
||||||
ldc2 -O4 *.d std/d/*.d -of=dscanner -release
|
ldc2 -O5 *.d std/d/*.d -of=dscanner -release -vectorize -m64
|
||||||
|
|
217
cache.d
217
cache.d
|
@ -1,217 +0,0 @@
|
||||||
// Copyright Brian Schott (Sir Alaran) 2012.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module cache;
|
|
||||||
|
|
||||||
import etc.c.sqlite3;
|
|
||||||
import std.c.stdlib;
|
|
||||||
import std.datetime;
|
|
||||||
import std.file;
|
|
||||||
import std.uuid;
|
|
||||||
import std.array;
|
|
||||||
import std.string;
|
|
||||||
import std.conv;
|
|
||||||
import std.d.lexer;
|
|
||||||
|
|
||||||
import location;
|
|
||||||
import parser;
|
|
||||||
import types;
|
|
||||||
|
|
||||||
private sqlite3* database;
|
|
||||||
|
|
||||||
version (Posix)
|
|
||||||
{
|
|
||||||
private immutable char* DB_PATH = "~/.dscanner/cache.db";
|
|
||||||
}
|
|
||||||
else version (Windows)
|
|
||||||
{
|
|
||||||
pragma(msg, "Caching not supported on Windows yet");
|
|
||||||
immutable string DB_PATH = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum Queries : string
|
|
||||||
{
|
|
||||||
getUpdateTime = "select mtime from files where filepath = ?",
|
|
||||||
insertContainer = "insert into containers values ()",
|
|
||||||
deleteContainer = "delete from containers where fileId = ?",
|
|
||||||
deleteSymbol = "delete from symbols where containerId = ?",
|
|
||||||
deleteFile = "delete from files where path = ?",
|
|
||||||
getPublicImports = "select importedId from publicImports where importerId = ?",
|
|
||||||
getModuleId = "select id from files where path = ?",
|
|
||||||
getContainersByModule = "select id from containers where fileId = ?"
|
|
||||||
}
|
|
||||||
|
|
||||||
private sqlite3* getDatabase()
|
|
||||||
{
|
|
||||||
if (database !is null)
|
|
||||||
return database;
|
|
||||||
int status = sqlite3_open(DB_PATH, &database);
|
|
||||||
if (status != SQLITE_OK)
|
|
||||||
{
|
|
||||||
throw new Exception("Could not open %s: %s".format(DB_PATH,
|
|
||||||
sqlite3_errmsg(database)));
|
|
||||||
}
|
|
||||||
return database;
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeDatabase()
|
|
||||||
{
|
|
||||||
if (database !is null)
|
|
||||||
{
|
|
||||||
sqlite3_close(database);
|
|
||||||
database = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getCachedModTime(sqlite3* db, sqlite3_stmt* statement, string filePath)
|
|
||||||
{
|
|
||||||
bindText(statement, 1, filePath);
|
|
||||||
if (sqlite3_step(statement) != SQLITE_ROW)
|
|
||||||
throw new Exception("%s".format(sqlite3_errmsg(db)));
|
|
||||||
return sqlite3_column_int64(statement, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the sqlite database with current autocomplete information for the
|
|
||||||
* given modules.
|
|
||||||
*/
|
|
||||||
void updateCache(string dirs[], string moduleNames[])
|
|
||||||
{
|
|
||||||
string[] filePaths;
|
|
||||||
foreach (moduleName; moduleNames)
|
|
||||||
{
|
|
||||||
string path = findAbsPath(dirs, moduleName);
|
|
||||||
if (path is null)
|
|
||||||
continue;
|
|
||||||
filePaths ~= path;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3* db = getDatabase();
|
|
||||||
sqlite3_stmt* statement;
|
|
||||||
scope(exit) { if (statement) sqlite3_finalize(statement); }
|
|
||||||
char* pzTail;
|
|
||||||
scope(exit) { if (pzTail) free(pzTail); }
|
|
||||||
sqlite3_prepare_v2(db, Queries.getUpdateTime.toStringz(),
|
|
||||||
cast(int) Queries.getUpdateTime.length + 1, &statement, &pzTail);
|
|
||||||
|
|
||||||
foreach (string filePath; filePaths)
|
|
||||||
{
|
|
||||||
immutable long mtime = getCachedModTime(db, statement, filePath);
|
|
||||||
SysTime timeLastModified = timeLastModified(filePath);
|
|
||||||
// if the times match, we don't need to update the cache.
|
|
||||||
if (timeLastModified.stdTime == mtime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// // re-parse the module
|
|
||||||
// Module m = parseModule(byToken(readText(filePath)).array());
|
|
||||||
//
|
|
||||||
// updateCache(m);
|
|
||||||
|
|
||||||
sqlite3_reset(statement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCache(const Module m)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(m !is null);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private string[] getImportedModules(string modulePath, sqlite3_stmt* statement = null)
|
|
||||||
{
|
|
||||||
auto app = appender!(string[])();
|
|
||||||
sqlite3* db = getDatabase();
|
|
||||||
bool statementAllocated = false;
|
|
||||||
scope(exit) { if (statementAllocated && statement !is null) sqlite3_finalize(statement); }
|
|
||||||
if (statement is null)
|
|
||||||
{
|
|
||||||
statementAllocated = true;
|
|
||||||
char* pzTail;
|
|
||||||
scope(exit) { if (pzTail) free(pzTail); }
|
|
||||||
sqlite3_prepare_v2(db, Queries.getPublicImports.toStringz(),
|
|
||||||
cast(int) Queries.getPublicImports.length + 1, &statement, &pzTail);
|
|
||||||
}
|
|
||||||
|
|
||||||
string moduleId = getModuleIdFromPath(modulePath);
|
|
||||||
bindText(statement, 1, moduleId);
|
|
||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
|
||||||
app.put(to!string(sqlite3_column_text(statement, 1)));
|
|
||||||
}
|
|
||||||
sqlite3_reset(statement);
|
|
||||||
foreach (string imported; app.data)
|
|
||||||
{
|
|
||||||
string[] r = getImportedModules(imported, statement);
|
|
||||||
}
|
|
||||||
return app.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getModuleIdFromPath(string filePath)
|
|
||||||
{
|
|
||||||
sqlite3* db = getDatabase();
|
|
||||||
sqlite3_stmt* statement;
|
|
||||||
char* pzTail;
|
|
||||||
scope(exit) if (pzTail) free(pzTail);
|
|
||||||
sqlite3_prepare_v2(db, Queries.getModuleId.toStringz(),
|
|
||||||
cast(int) Queries.getModuleId.length + 1, &statement,
|
|
||||||
&pzTail);
|
|
||||||
bindText(statement, 1, filePath);
|
|
||||||
if (sqlite3_step(statement) != SQLITE_ROW)
|
|
||||||
return null;
|
|
||||||
return to!string(sqlite3_column_text(statement, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: the container IDs of the containers that have
|
|
||||||
* been imported
|
|
||||||
*/
|
|
||||||
public string[] getContainersImported(string modulePath)
|
|
||||||
{
|
|
||||||
immutable string moduleId = getModuleIdFromPath(modulePath);
|
|
||||||
sqlite3* db = getDatabase();
|
|
||||||
sqlite3_stmt* statement;
|
|
||||||
char* pzTail;
|
|
||||||
scope(exit) if (pzTail) free(pzTail);
|
|
||||||
string[] moduleIds = getImportedModules(modulePath);
|
|
||||||
string[] containerIds;
|
|
||||||
foreach (string id; moduleIds)
|
|
||||||
{
|
|
||||||
containerIds ~= getContainersByModule(id);
|
|
||||||
}
|
|
||||||
return containerIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string[] getContainersByModule(string moduleId)
|
|
||||||
{
|
|
||||||
sqlite3* db = getDatabase();
|
|
||||||
sqlite3_stmt* statement;
|
|
||||||
scope(exit) if (statement !is null) sqlite3_finalize(statement);
|
|
||||||
char* pzTail;
|
|
||||||
prepareStatement(db, statement, Queries.getContainersByModule);
|
|
||||||
bindText(statement, 1, moduleId);
|
|
||||||
string[] rVal;
|
|
||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
|
||||||
rVal ~= to!string(sqlite3_column_text(statement, 1));
|
|
||||||
}
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareStatement(sqlite3* db, sqlite3_stmt* statement, string query)
|
|
||||||
{
|
|
||||||
char* pzTail;
|
|
||||||
scope(exit) if (pzTail) free(pzTail);
|
|
||||||
sqlite3_prepare_v2(db, query.toStringz(), cast(int) query.length + 1,
|
|
||||||
&statement, &pzTail);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindText(sqlite3_stmt* statement, int argPos, string text)
|
|
||||||
{
|
|
||||||
sqlite3_bind_text(statement, argPos, text.toStringz(),
|
|
||||||
cast(int) text.length + 1, SQLITE_TRANSIENT);
|
|
||||||
}
|
|
975
parser.d
975
parser.d
|
@ -1,975 +0,0 @@
|
||||||
|
|
||||||
// Copyright Brian Schott (Sir Alaran) 2012.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module parser;
|
|
||||||
|
|
||||||
import std.stream;
|
|
||||||
import std.array;
|
|
||||||
import std.stdio;
|
|
||||||
import std.algorithm;
|
|
||||||
import std.range;
|
|
||||||
import std.d.lexer;
|
|
||||||
|
|
||||||
import types;
|
|
||||||
import langutils;
|
|
||||||
import circularbuffer;
|
|
||||||
|
|
||||||
alias CircularBuffer!Token TokenBuffer;
|
|
||||||
|
|
||||||
class Balanced : TokenBuffer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
this(InputRange!Token tokens, TokenType open, TokenType close)
|
|
||||||
{
|
|
||||||
super(0, tokens);
|
|
||||||
this.range = tokens;
|
|
||||||
this.open = open;
|
|
||||||
this.close = close;
|
|
||||||
}
|
|
||||||
|
|
||||||
override bool empty() @property
|
|
||||||
{
|
|
||||||
return _empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
override Token front() @property
|
|
||||||
{
|
|
||||||
return range.front;
|
|
||||||
}
|
|
||||||
|
|
||||||
override void popFront()
|
|
||||||
{
|
|
||||||
range.popFront();
|
|
||||||
if (range.front == open)
|
|
||||||
++depth;
|
|
||||||
else if (range.front == close)
|
|
||||||
--depth;
|
|
||||||
_empty = depth == 0 || range.empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
invariant()
|
|
||||||
{
|
|
||||||
assert (range);
|
|
||||||
assert (depth >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int depth;
|
|
||||||
TokenType open;
|
|
||||||
TokenType close;
|
|
||||||
InputRange!(Token) range;
|
|
||||||
bool _empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Params:
|
|
||||||
* tokens = the array of tokens
|
|
||||||
* index = an index into tokens such that tokens.front.type == open
|
|
||||||
* open = the opening delimiter
|
|
||||||
* close = the closing delimiter
|
|
||||||
* Returns: all tokens that are between the balanced delimiters that start at
|
|
||||||
* tokens.front, not including the delimiters. If the delimiters in tokens
|
|
||||||
* are not balanced, this function will return tokens[index + 1 .. $];
|
|
||||||
*/
|
|
||||||
Balanced betweenBalanced(TokenBuffer tokens,
|
|
||||||
TokenType open, TokenType close)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert (tokens.front == open);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
return new Balanced(tokens, open, close);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See_also: betweenBalanced
|
|
||||||
*/
|
|
||||||
Balanced betweenBalancedBraces(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
return betweenBalanced(tokens, TokenType.lBrace, TokenType.rBrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See_also: betweenBalanced
|
|
||||||
*/
|
|
||||||
Balanced betweenBalancedParens(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
return betweenBalanced(tokens, TokenType.lParen, TokenType.rParen);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See_also: betweenBalanced
|
|
||||||
*/
|
|
||||||
Balanced betweenBalancedBrackets(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
return betweenBalanced(tokens, TokenType.lBracket, TokenType.rBracket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void skipBalanced(alias openToken, alias closeToken)(TokenBuffer tokens)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert (tokens.front == openToken);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
int depth = 1;
|
|
||||||
tokens.popFront();
|
|
||||||
while (!tokens.empty && depth != 0)
|
|
||||||
{
|
|
||||||
switch (tokens.front.type)
|
|
||||||
{
|
|
||||||
case openToken: ++depth; break;
|
|
||||||
case closeToken: --depth; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
tokens.popFront();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void skipParens(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
skipBalanced!(TokenType.lParen, TokenType.rParen)(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
void skipBrackets(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
skipBalanced!(TokenType.lBracket, TokenType.rBracket)(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
void skipBraces(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
skipBalanced!(TokenType.lBrace, TokenType.rBrace)(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Params:
|
|
||||||
* tokens = the token array to examine
|
|
||||||
* index = an indext into tokens such that tokens.front.type == open
|
|
||||||
* open = the opening delimiter
|
|
||||||
* close = the closing delimiter
|
|
||||||
* Returns: a string representing the contents of the two delimiters. This will
|
|
||||||
* not preserve whitespace, but it will place a single space character after
|
|
||||||
* a comma and between identifiers.
|
|
||||||
*/
|
|
||||||
string content(TokenBuffer tokens, TokenType open, TokenType close)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert (tokens.front == open);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
auto app = appender!string();
|
|
||||||
int depth = 1;
|
|
||||||
foreach (t; betweenBalanced(tokens, open, close))
|
|
||||||
{
|
|
||||||
if (t == TokenType.comma)
|
|
||||||
app.put(", ");
|
|
||||||
else
|
|
||||||
app.put(t.value);
|
|
||||||
}
|
|
||||||
return app.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See_also: content
|
|
||||||
*/
|
|
||||||
string parenContent(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
return "(" ~ content(tokens, TokenType.lParen, TokenType.rParen) ~ ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See_also: content
|
|
||||||
*/
|
|
||||||
string bracketContent(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
return "[" ~ content(tokens, TokenType.lBracket, TokenType.rBracket) ~ "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances index until it indexes a character in tokens after a right brace if
|
|
||||||
* index initially indexed a right brace, or advances index until it indexes a
|
|
||||||
* character after a simicolon otherwise.
|
|
||||||
*/
|
|
||||||
void skipBlockStatement(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
skipBraces(tokens);
|
|
||||||
else
|
|
||||||
skipPastNext(tokens, TokenType.semicolon);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances index until it indexes a character in tokens directly after a token
|
|
||||||
* of type type. This function handles nesting of braces, brackets, and
|
|
||||||
* parenthesis
|
|
||||||
*/
|
|
||||||
void skipPastNext(TokenBuffer tokens, TokenType type)
|
|
||||||
{
|
|
||||||
while (!tokens.empty)
|
|
||||||
{
|
|
||||||
if (tokens.front.type == TokenType.lBrace)
|
|
||||||
skipBraces(tokens);
|
|
||||||
else if (tokens.front.type == TokenType.lParen)
|
|
||||||
skipParens(tokens);
|
|
||||||
else if (tokens.front.type == TokenType.lBracket)
|
|
||||||
skipBrackets(tokens);
|
|
||||||
else if (tokens.front.type == type)
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tokens.popFront();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string parseTypeDeclaration(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
auto type = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
buildingType: while (!tokens.empty)
|
|
||||||
{
|
|
||||||
switch (tokens.front.type)
|
|
||||||
{
|
|
||||||
case TokenType.lBracket:
|
|
||||||
type ~= bracketContent(tokens);
|
|
||||||
break;
|
|
||||||
case TokenType.not:
|
|
||||||
type ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
type ~= parenContent(tokens);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
type ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.star:
|
|
||||||
case TokenType.bitAnd:
|
|
||||||
type ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
break;
|
|
||||||
case TokenType.function_:
|
|
||||||
type ~= " " ~ tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
type ~= parenContent(tokens);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break buildingType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a module from a token array.
|
|
||||||
* Params:
|
|
||||||
* protection = the default protection level for a block statement
|
|
||||||
* attributes = the default attributes for a block statement
|
|
||||||
* Returns: the parsed module
|
|
||||||
*/
|
|
||||||
Module parseModule(TokenBuffer tokens, string protection = "public", string[] attributes = [])
|
|
||||||
{
|
|
||||||
string type;
|
|
||||||
string name;
|
|
||||||
string localProtection = "";
|
|
||||||
string[] localAttributes = [];
|
|
||||||
|
|
||||||
void resetLocals()
|
|
||||||
{
|
|
||||||
type = "";
|
|
||||||
name = "";
|
|
||||||
localProtection = "";
|
|
||||||
localAttributes = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
Module mod = new Module;
|
|
||||||
size_t index = 0;
|
|
||||||
while(!tokens.empty)
|
|
||||||
{
|
|
||||||
switch(tokens.front.type)
|
|
||||||
{
|
|
||||||
case TokenType.pragma_:
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
skipParens(tokens);
|
|
||||||
break;
|
|
||||||
case TokenType.mixin_:
|
|
||||||
case TokenType.assert_:
|
|
||||||
tokens.popFront();
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
break;
|
|
||||||
case TokenType.alias_:
|
|
||||||
Alias a = parseAlias(tokens,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
attributes);
|
|
||||||
mod.aliases ~= a;
|
|
||||||
break;
|
|
||||||
case TokenType.import_:
|
|
||||||
mod.imports ~= parseImports(tokens);
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.version_:
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
{
|
|
||||||
tokens.betweenBalancedParens();
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
{
|
|
||||||
auto braceContent = tokens.betweenBalancedBraces();
|
|
||||||
mod.merge(parseModule(braceContent,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
attributes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tokens.front == TokenType.assign)
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
break;
|
|
||||||
case TokenType.deprecated_:
|
|
||||||
case TokenType.nothrow_:
|
|
||||||
case TokenType.override_:
|
|
||||||
case TokenType.synchronized_:
|
|
||||||
case TokenType.abstract_:
|
|
||||||
case TokenType.final_:
|
|
||||||
case TokenType.gshared:
|
|
||||||
case TokenType.static_:
|
|
||||||
localAttributes ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
break;
|
|
||||||
case TokenType.const_:
|
|
||||||
case TokenType.immutable_:
|
|
||||||
case TokenType.inout_:
|
|
||||||
case TokenType.pure_:
|
|
||||||
case TokenType.scope_:
|
|
||||||
case TokenType.shared_:
|
|
||||||
auto tmp = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
type = tmp ~ tokens.parenContent();
|
|
||||||
else if (tokens.front == TokenType.colon)
|
|
||||||
{
|
|
||||||
index++;
|
|
||||||
attributes ~= tmp;
|
|
||||||
}
|
|
||||||
localAttributes ~= tmp;
|
|
||||||
break;
|
|
||||||
case TokenType.align_:
|
|
||||||
case TokenType.extern_:
|
|
||||||
string attribute = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
attribute ~= parenContent(tokens);
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
mod.merge(parseModule(tokens.betweenBalancedBraces(),
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
attributes ~ attribute));
|
|
||||||
else if (tokens.front == TokenType.colon)
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
attributes ~= attribute;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
localAttributes ~= attribute;
|
|
||||||
break;
|
|
||||||
case TokenType.export_: .. case TokenType.public_:
|
|
||||||
string p = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.colon)
|
|
||||||
{
|
|
||||||
protection = p;
|
|
||||||
tokens.popFront();
|
|
||||||
}
|
|
||||||
else if (tokens.front == TokenType.lBrace)
|
|
||||||
mod.merge(parseModule(tokens.betweenBalancedBraces(),
|
|
||||||
p, attributes ~ localAttributes));
|
|
||||||
else
|
|
||||||
localProtection = p;
|
|
||||||
break;
|
|
||||||
case TokenType.module_:
|
|
||||||
tokens.popFront();
|
|
||||||
while (!tokens.empty && tokens.front != TokenType.semicolon)
|
|
||||||
{
|
|
||||||
mod.name ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
}
|
|
||||||
tokens.popFront();
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.union_:
|
|
||||||
mod.unions ~= parseUnion(tokens,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
localAttributes ~ attributes);
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.class_:
|
|
||||||
mod.classes ~= parseClass(tokens,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
localAttributes ~ attributes);
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.interface_:
|
|
||||||
mod.interfaces ~= parseInterface(tokens,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
localAttributes ~ attributes);
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.struct_:
|
|
||||||
mod.structs ~= parseStruct(tokens,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
localAttributes ~ attributes);
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.enum_:
|
|
||||||
mod.enums ~= parseEnum(tokens,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
localAttributes ~ attributes);
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.template_:
|
|
||||||
tokens.popFront(); // template
|
|
||||||
tokens.popFront(); // name
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
tokens.betweenBalancedParens(); // params
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
tokens.betweenBalancedBraces(); // body
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.bool_: .. case TokenType.wstring_:
|
|
||||||
case TokenType.auto_:
|
|
||||||
case TokenType.identifier:
|
|
||||||
if (type.empty())
|
|
||||||
{
|
|
||||||
type = tokens.parseTypeDeclaration();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.empty) break;
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
{
|
|
||||||
mod.functions ~= parseFunction(tokens, type, name,
|
|
||||||
tokens.front.line,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
attributes ~ localAttributes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Variable v = new Variable;
|
|
||||||
v.name = name;
|
|
||||||
v.type = type;
|
|
||||||
v.attributes = localAttributes ~ attributes;
|
|
||||||
v.protection = localProtection.empty() ? protection : localProtection;
|
|
||||||
v.line = tokens.front.line;
|
|
||||||
mod.variables ~= v;
|
|
||||||
}
|
|
||||||
resetLocals();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.unittest_:
|
|
||||||
tokens.popFront();
|
|
||||||
if (!tokens.empty() && tokens.front == TokenType.lBrace)
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
case TokenType.tilde:
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.this_)
|
|
||||||
{
|
|
||||||
name = "~";
|
|
||||||
goto case;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.this_:
|
|
||||||
name ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
if (!tokens.empty && tokens.front == TokenType.lParen)
|
|
||||||
{
|
|
||||||
mod.functions ~= parseFunction(tokens, "", name,
|
|
||||||
tokens.peek(-1).line,
|
|
||||||
localProtection.empty() ? protection : localProtection,
|
|
||||||
localAttributes ~ attributes);
|
|
||||||
}
|
|
||||||
resetLocals();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tokens.popFront();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an import statement
|
|
||||||
* Returns: only the module names that were imported, not which symbols were
|
|
||||||
* selectively improted.
|
|
||||||
*/
|
|
||||||
string[] parseImports(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
assert(tokens.front == TokenType.import_);
|
|
||||||
tokens.popFront();
|
|
||||||
auto app = appender!(string[])();
|
|
||||||
string im;
|
|
||||||
while (!tokens.empty)
|
|
||||||
{
|
|
||||||
switch(tokens.front.type)
|
|
||||||
{
|
|
||||||
case TokenType.comma:
|
|
||||||
tokens.popFront();
|
|
||||||
app.put(im);
|
|
||||||
im = "";
|
|
||||||
break;
|
|
||||||
case TokenType.assign:
|
|
||||||
case TokenType.semicolon:
|
|
||||||
app.put(im);
|
|
||||||
tokens.popFront();
|
|
||||||
return app.data;
|
|
||||||
case TokenType.colon:
|
|
||||||
app.put(im);
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
return app.data;
|
|
||||||
default:
|
|
||||||
im ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return app.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an enum declaration
|
|
||||||
*/
|
|
||||||
Enum parseEnum(TokenBuffer tokens, string protection, string[] attributes)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert (tokens.front == TokenType.enum_);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
Enum e = new Enum;
|
|
||||||
e.line = tokens.front.line;
|
|
||||||
tokens.popFront();
|
|
||||||
string enumType;
|
|
||||||
e.protection = protection;
|
|
||||||
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
goto enumBody;
|
|
||||||
|
|
||||||
if (isIdentifierOrType(tokens.front.type))
|
|
||||||
{
|
|
||||||
if (tokens.canPeek() && tokens.peek() == TokenType.identifier)
|
|
||||||
{
|
|
||||||
// enum long l = 4;
|
|
||||||
EnumMember m;
|
|
||||||
m.type = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
m.line = tokens.front.line;
|
|
||||||
e.name = m.name = tokens.front.value;
|
|
||||||
e.members ~= m;
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
else if (tokens.canPeek() && tokens.peek() == TokenType.assign)
|
|
||||||
{
|
|
||||||
// enum m = "abcd";
|
|
||||||
e.name = tokens.front.value;
|
|
||||||
EnumMember m;
|
|
||||||
m.name = e.name;
|
|
||||||
m.line = tokens.front.line;
|
|
||||||
m.type = getTypeFromToken(tokens.peek(2));
|
|
||||||
e.members ~= m;
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isIdentifierOrType(tokens.front.type))
|
|
||||||
{
|
|
||||||
e.name = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens.front == TokenType.colon)
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
if (!isIdentifierOrType(tokens.front.type))
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enumType = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enumBody:
|
|
||||||
//
|
|
||||||
// auto r = tokens.betweenBalancedBraces();
|
|
||||||
// while (!r.empty)
|
|
||||||
// {
|
|
||||||
// EnumMember m;
|
|
||||||
// if (isIdentifierOrType(r.front) && i + 1 < r.length && isIdentifierOrType(r[i + 1]))
|
|
||||||
// {
|
|
||||||
// m.line = r[i + 1].line;
|
|
||||||
// m.name = r[i + 1].value;
|
|
||||||
// m.type = r.front.value;
|
|
||||||
// }
|
|
||||||
// else if (isIdentifierOrType(r.front) && i + 1 < r.length && r[i + 1] == TokenType.Assign)
|
|
||||||
// {
|
|
||||||
// if (enumType == null && i + 2 < r.length)
|
|
||||||
// m.type = getTypeFromToken(r[i + 2]);
|
|
||||||
// else
|
|
||||||
// m.type = enumType;
|
|
||||||
// m.line = r.front.line;
|
|
||||||
// m.name = r.front.value;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// m.line = r.front.line;
|
|
||||||
// m.name = r.front.value;
|
|
||||||
// m.type = enumType == null ? "int" : enumType;
|
|
||||||
// }
|
|
||||||
// e.members ~= m;
|
|
||||||
// skipPastNext(r, TokenType.comma, i);
|
|
||||||
// }
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a function declaration
|
|
||||||
*/
|
|
||||||
Function parseFunction(TokenBuffer tokens, string type,
|
|
||||||
string name, uint line, string protection, string[] attributes)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert (tokens.front == TokenType.lParen);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
Function f = new Function;
|
|
||||||
f.name = name;
|
|
||||||
f.returnType = type;
|
|
||||||
f.line = line;
|
|
||||||
f.attributes.insertInPlace(f.attributes.length, attributes);
|
|
||||||
|
|
||||||
Variable[] vars1 = parseParameters(tokens);
|
|
||||||
if (!tokens.empty && tokens.front == TokenType.lParen)
|
|
||||||
{
|
|
||||||
f.templateParameters.insertInPlace(f.templateParameters.length,
|
|
||||||
map!("a.type")(vars1));
|
|
||||||
f.parameters.insertInPlace(f.parameters.length,
|
|
||||||
parseParameters(tokens));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
f.parameters.insertInPlace(f.parameters.length, vars1);
|
|
||||||
|
|
||||||
attributeLoop: while(!tokens.empty)
|
|
||||||
{
|
|
||||||
switch (tokens.front.type)
|
|
||||||
{
|
|
||||||
case TokenType.immutable_:
|
|
||||||
case TokenType.const_:
|
|
||||||
case TokenType.pure_:
|
|
||||||
case TokenType.nothrow_:
|
|
||||||
case TokenType.final_:
|
|
||||||
case TokenType.override_:
|
|
||||||
f.attributes ~= tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break attributeLoop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tokens.empty && tokens.front == TokenType.if_)
|
|
||||||
f.constraint = parseConstraint(tokens);
|
|
||||||
|
|
||||||
while (!tokens.empty &&
|
|
||||||
(tokens.front == TokenType.in_ || tokens.front == TokenType.out_
|
|
||||||
|| tokens.front == TokenType.body_))
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
if (!tokens.empty && tokens.front == TokenType.lParen
|
|
||||||
&& tokens.peek(-1) == TokenType.out_)
|
|
||||||
{
|
|
||||||
tokens.skipParens();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tokens.empty && tokens.front == TokenType.lBrace)
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
}
|
|
||||||
if (!tokens.empty)
|
|
||||||
return f;
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
else if (tokens.front == TokenType.semicolon)
|
|
||||||
tokens.popFront();
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
string parseConstraint(TokenBuffer tokens)
|
|
||||||
{
|
|
||||||
auto appender = appender!(string)();
|
|
||||||
assert(tokens.front == TokenType.if_);
|
|
||||||
appender.put(tokens.front.value);
|
|
||||||
tokens.popFront();
|
|
||||||
assert(tokens.front == TokenType.lParen);
|
|
||||||
return "if " ~ tokens.parenContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
Variable[] parseParameters(TokenBuffer tokens)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert (tokens.front == TokenType.lParen);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
auto appender = appender!(Variable[])();
|
|
||||||
Variable v = new Variable;
|
|
||||||
auto r = betweenBalancedParens(tokens);
|
|
||||||
size_t i = 0;
|
|
||||||
while (!r.empty)
|
|
||||||
{
|
|
||||||
switch(r.front.type)
|
|
||||||
{
|
|
||||||
case TokenType.alias_:
|
|
||||||
case TokenType.in_:
|
|
||||||
case TokenType.out_:
|
|
||||||
case TokenType.ref_:
|
|
||||||
case TokenType.scope_:
|
|
||||||
case TokenType.lazy_:
|
|
||||||
case TokenType.const_:
|
|
||||||
case TokenType.immutable_:
|
|
||||||
case TokenType.shared_:
|
|
||||||
case TokenType.inout_:
|
|
||||||
auto tmp = r.front.value;
|
|
||||||
r.popFront();
|
|
||||||
if (r.front == TokenType.lParen)
|
|
||||||
v.type ~= tmp ~ parenContent(r);
|
|
||||||
else
|
|
||||||
v.attributes ~= tmp;
|
|
||||||
break;
|
|
||||||
case TokenType.colon:
|
|
||||||
i++;
|
|
||||||
r.skipPastNext(TokenType.comma);
|
|
||||||
appender.put(v);
|
|
||||||
v = new Variable;
|
|
||||||
break;
|
|
||||||
case TokenType.comma:
|
|
||||||
++i;
|
|
||||||
appender.put(v);
|
|
||||||
v = new Variable;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (v.type.empty())
|
|
||||||
{
|
|
||||||
v.type = r.parseTypeDeclaration();
|
|
||||||
if (!r.empty)
|
|
||||||
appender.put(v);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v.line = r.front.line;
|
|
||||||
v.name = r.front.value;
|
|
||||||
r.popFront();
|
|
||||||
appender.put(v);
|
|
||||||
if (!r.empty && r.front == TokenType.vararg)
|
|
||||||
{
|
|
||||||
v.type ~= " ...";
|
|
||||||
}
|
|
||||||
v = new Variable;
|
|
||||||
r.skipPastNext(TokenType.comma);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return appender.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] parseBaseClassList(TokenBuffer tokens)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(tokens.front == TokenType.colon);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
auto appender = appender!(string[])();
|
|
||||||
tokens.popFront();
|
|
||||||
while (!tokens.empty)
|
|
||||||
{
|
|
||||||
if (tokens.front == TokenType.identifier)
|
|
||||||
{
|
|
||||||
string base = parseTypeDeclaration(tokens);
|
|
||||||
appender.put(base);
|
|
||||||
if (tokens.front == TokenType.comma)
|
|
||||||
tokens.popFront();
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return appender.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void parseStructBody(TokenBuffer tokens, Struct st)
|
|
||||||
{
|
|
||||||
st.bodyStart = tokens.front.startIndex;
|
|
||||||
Module m = parseModule(tokens.betweenBalancedBraces());
|
|
||||||
st.bodyEnd = tokens.peek(-1).startIndex;
|
|
||||||
st.functions.insertInPlace(0, m.functions);
|
|
||||||
st.variables.insertInPlace(0, m.variables);
|
|
||||||
st.aliases.insertInPlace(0, m.aliases);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Struct parseStructOrUnion(TokenBuffer tokens, string protection,
|
|
||||||
string[] attributes)
|
|
||||||
{
|
|
||||||
Struct s = new Struct;
|
|
||||||
s.line = tokens.front.line;
|
|
||||||
s.attributes = attributes;
|
|
||||||
s.protection = protection;
|
|
||||||
s.name = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
s.templateParameters.insertInPlace(s.templateParameters.length,
|
|
||||||
map!("a.type")(parseParameters(tokens)));
|
|
||||||
|
|
||||||
if (tokens.empty) return s;
|
|
||||||
|
|
||||||
if (tokens.front == TokenType.if_)
|
|
||||||
s.constraint = parseConstraint(tokens);
|
|
||||||
|
|
||||||
if (tokens.empty) return s;
|
|
||||||
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
parseStructBody(tokens, s);
|
|
||||||
else
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Struct parseStruct(TokenBuffer tokens, string protection,
|
|
||||||
string[] attributes)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(tokens.front == TokenType.struct_);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
return parseStructOrUnion(tokens, protection, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Struct parseUnion(TokenBuffer tokens, string protection, string[] attributes)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(tokens.front == TokenType.union_);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
return parseStructOrUnion(tokens, protection, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Inherits parseInherits(TokenBuffer tokens, string protection, string[] attributes)
|
|
||||||
{
|
|
||||||
auto i = new Inherits;
|
|
||||||
i.line = tokens.front.line;
|
|
||||||
i.name = tokens.front.value;
|
|
||||||
tokens.popFront();
|
|
||||||
i.protection = protection;
|
|
||||||
i.attributes.insertInPlace(i.attributes.length, attributes);
|
|
||||||
if (tokens.front == TokenType.lParen)
|
|
||||||
i.templateParameters.insertInPlace(i.templateParameters.length,
|
|
||||||
map!("a.type")(parseParameters(tokens)));
|
|
||||||
|
|
||||||
if (tokens.empty) return i;
|
|
||||||
|
|
||||||
if (tokens.front == TokenType.if_)
|
|
||||||
i.constraint = parseConstraint(tokens);
|
|
||||||
|
|
||||||
if (tokens.empty) return i;
|
|
||||||
|
|
||||||
if (tokens.front == TokenType.colon)
|
|
||||||
i.baseClasses = parseBaseClassList(tokens);
|
|
||||||
|
|
||||||
if (tokens.empty) return i;
|
|
||||||
|
|
||||||
if (tokens.front == TokenType.lBrace)
|
|
||||||
parseStructBody(tokens, i);
|
|
||||||
else
|
|
||||||
tokens.skipBlockStatement();
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
Inherits parseInterface(TokenBuffer tokens, string protection, string[] attributes)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert (tokens.front == TokenType.interface_);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
return parseInherits(tokens, protection, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Inherits parseClass(TokenBuffer tokens, string protection, string[] attributes)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(tokens.front == TokenType.class_);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
return parseInherits(tokens, protection, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an alias declaration.
|
|
||||||
* Note that the language spec mentions a "AliasInitializerList" in the grammar,
|
|
||||||
* but there seems to be no example of this being used, nor has the compiler
|
|
||||||
* accepted any of my attempts to create one. Therefore, it's not supported here
|
|
||||||
*/
|
|
||||||
Alias parseAlias(TokenBuffer tokens, string protection, string[] attributes)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(tokens.front == TokenType.alias_);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
tokens.popFront();
|
|
||||||
Alias a = new Alias;
|
|
||||||
a.aliasedType = parseTypeDeclaration(tokens);
|
|
||||||
a.attributes = attributes;
|
|
||||||
a.protection = protection;
|
|
||||||
if (tokens.front == TokenType.identifier)
|
|
||||||
{
|
|
||||||
a.name = tokens.front.value;
|
|
||||||
a.line = tokens.front.line;
|
|
||||||
skipBlockStatement(tokens);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
return a;
|
|
||||||
}
|
|
377
std/d/lexer.d
377
std/d/lexer.d
|
@ -412,8 +412,7 @@ private:
|
||||||
this(ref R range)
|
this(ref R range)
|
||||||
{
|
{
|
||||||
this.range = range;
|
this.range = range;
|
||||||
buffer = uninitializedArray!(ubyte[])(config.bufferSize);
|
buffer = uninitializedArray!(ubyte[])(bufferSize);
|
||||||
cache.initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -512,7 +511,7 @@ private:
|
||||||
current.type = TokenType.div;
|
current.type = TokenType.div;
|
||||||
current.value = "/";
|
current.value = "/";
|
||||||
advanceRange();
|
advanceRange();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
switch (r.front)
|
switch (r.front)
|
||||||
{
|
{
|
||||||
|
@ -544,12 +543,12 @@ private:
|
||||||
current.type = TokenType.dot;
|
current.type = TokenType.dot;
|
||||||
current.value = getTokenValue(TokenType.dot);
|
current.value = getTokenValue(TokenType.dot);
|
||||||
advanceRange();
|
advanceRange();
|
||||||
break outer;
|
return;
|
||||||
}
|
}
|
||||||
else if (r.front >= '0' && r.front <= '9')
|
else if (r.front >= '0' && r.front <= '9')
|
||||||
{
|
{
|
||||||
lexNumber();
|
lexNumber();
|
||||||
break outer;
|
return;
|
||||||
}
|
}
|
||||||
else if (r.front == '.')
|
else if (r.front == '.')
|
||||||
{
|
{
|
||||||
|
@ -568,22 +567,23 @@ private:
|
||||||
advanceRange();
|
advanceRange();
|
||||||
}
|
}
|
||||||
current.value = getTokenValue(current.type);
|
current.value = getTokenValue(current.type);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
advanceRange();
|
advanceRange();
|
||||||
current.type = TokenType.dot;
|
current.type = TokenType.dot;
|
||||||
current.value = getTokenValue(TokenType.dot);
|
current.value = getTokenValue(TokenType.dot);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case '0': .. case '9':
|
case '0': .. case '9':
|
||||||
lexNumber();
|
lexNumber();
|
||||||
break;
|
return;
|
||||||
case '\'':
|
case '\'':
|
||||||
case '"':
|
case '"':
|
||||||
case '`':
|
case '`':
|
||||||
lexString();
|
lexString();
|
||||||
break;
|
return;
|
||||||
case 'q':
|
case 'q':
|
||||||
static if (isArray!R)
|
static if (isArray!R)
|
||||||
auto r = range[index .. $];
|
auto r = range[index .. $];
|
||||||
|
@ -593,12 +593,12 @@ private:
|
||||||
if (!r.isRangeEoF() && r.front == '{')
|
if (!r.isRangeEoF() && r.front == '{')
|
||||||
{
|
{
|
||||||
lexTokenString();
|
lexTokenString();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
else if (!r.isRangeEoF() && r.front == '"')
|
else if (!r.isRangeEoF() && r.front == '"')
|
||||||
{
|
{
|
||||||
lexDelimitedString();
|
lexDelimitedString();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
goto default;
|
goto default;
|
||||||
|
@ -611,7 +611,7 @@ private:
|
||||||
if (!r.isRangeEoF() && r.front == '"')
|
if (!r.isRangeEoF() && r.front == '"')
|
||||||
{
|
{
|
||||||
lexString();
|
lexString();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
goto default;
|
goto default;
|
||||||
|
@ -624,13 +624,13 @@ private:
|
||||||
if (!r.isRangeEoF() && r.front == '"')
|
if (!r.isRangeEoF() && r.front == '"')
|
||||||
{
|
{
|
||||||
lexHexString();
|
lexHexString();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
goto default;
|
goto default;
|
||||||
case '#':
|
case '#':
|
||||||
lexSpecialTokenSequence();
|
lexSpecialTokenSequence();
|
||||||
break;
|
return;
|
||||||
default:
|
default:
|
||||||
while(!isEoF() && !isSeparating(currentElement()))
|
while(!isEoF() && !isSeparating(currentElement()))
|
||||||
{
|
{
|
||||||
|
@ -649,7 +649,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(config.iterStyle & TokenStyle.doNotReplaceSpecial))
|
if (!(config.iterStyle & TokenStyle.doNotReplaceSpecial))
|
||||||
break;
|
return;
|
||||||
|
|
||||||
switch (current.type)
|
switch (current.type)
|
||||||
{
|
{
|
||||||
|
@ -657,12 +657,12 @@ private:
|
||||||
current.type = TokenType.stringLiteral;
|
current.type = TokenType.stringLiteral;
|
||||||
auto time = Clock.currTime();
|
auto time = Clock.currTime();
|
||||||
current.value = format("%s %02d %04d", time.month, time.day, time.year);
|
current.value = format("%s %02d %04d", time.month, time.day, time.year);
|
||||||
break;
|
return;
|
||||||
case TokenType.time:
|
case TokenType.time:
|
||||||
auto time = Clock.currTime();
|
auto time = Clock.currTime();
|
||||||
current.type = TokenType.stringLiteral;
|
current.type = TokenType.stringLiteral;
|
||||||
current.value = (cast(TimeOfDay)(time)).toISOExtString();
|
current.value = (cast(TimeOfDay)(time)).toISOExtString();
|
||||||
break;
|
return;
|
||||||
case TokenType.timestamp:
|
case TokenType.timestamp:
|
||||||
auto time = Clock.currTime();
|
auto time = Clock.currTime();
|
||||||
auto dt = cast(DateTime) time;
|
auto dt = cast(DateTime) time;
|
||||||
|
@ -670,27 +670,26 @@ private:
|
||||||
current.value = format("%s %s %02d %02d:%02d:%02d %04d",
|
current.value = format("%s %s %02d %02d:%02d:%02d %04d",
|
||||||
dt.dayOfWeek, dt.month, dt.day, dt.hour, dt.minute,
|
dt.dayOfWeek, dt.month, dt.day, dt.hour, dt.minute,
|
||||||
dt.second, dt.year);
|
dt.second, dt.year);
|
||||||
break;
|
return;
|
||||||
case TokenType.vendor:
|
case TokenType.vendor:
|
||||||
current.type = TokenType.stringLiteral;
|
current.type = TokenType.stringLiteral;
|
||||||
current.value = config.vendorString;
|
current.value = config.vendorString;
|
||||||
break;
|
return;
|
||||||
case TokenType.compilerVersion:
|
case TokenType.compilerVersion:
|
||||||
current.type = TokenType.stringLiteral;
|
current.type = TokenType.stringLiteral;
|
||||||
current.value = format("%d", config.versionNumber);
|
current.value = format("%d", config.versionNumber);
|
||||||
break;
|
return;
|
||||||
case TokenType.line:
|
case TokenType.line:
|
||||||
current.type = TokenType.intLiteral;
|
current.type = TokenType.intLiteral;
|
||||||
current.value = format("%d", current.line);
|
current.value = format("%d", current.line);
|
||||||
break;
|
return;
|
||||||
case TokenType.file:
|
case TokenType.file:
|
||||||
current.type = TokenType.stringLiteral;
|
current.type = TokenType.stringLiteral;
|
||||||
current.value = config.fileName;
|
current.value = config.fileName;
|
||||||
break;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,8 +1467,8 @@ private:
|
||||||
|
|
||||||
void keepNonNewlineChar()
|
void keepNonNewlineChar()
|
||||||
{
|
{
|
||||||
if (bufferIndex + 2 >= buffer.length)
|
if (bufferIndex >= buffer.length)
|
||||||
buffer.length += (1024 * 4);
|
buffer.length += 1024;
|
||||||
static if (isArray!R)
|
static if (isArray!R)
|
||||||
buffer[bufferIndex++] = range[index++];
|
buffer[bufferIndex++] = range[index++];
|
||||||
else
|
else
|
||||||
|
@ -1483,7 +1482,7 @@ private:
|
||||||
void keepChar()
|
void keepChar()
|
||||||
{
|
{
|
||||||
if (bufferIndex + 2 >= buffer.length)
|
if (bufferIndex + 2 >= buffer.length)
|
||||||
buffer.length += (1024 * 4);
|
buffer.length += 1024;
|
||||||
bool foundNewline;
|
bool foundNewline;
|
||||||
if (currentElement() == '\r')
|
if (currentElement() == '\r')
|
||||||
{
|
{
|
||||||
|
@ -1531,7 +1530,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementType!R currentElement()
|
ElementType!R currentElement() const
|
||||||
{
|
{
|
||||||
assert (index < range.length, "%d, %d".format(index, range.length));
|
assert (index < range.length, "%d, %d".format(index, range.length));
|
||||||
static if (isArray!R)
|
static if (isArray!R)
|
||||||
|
@ -1554,18 +1553,17 @@ private:
|
||||||
current.value = cache.get(buffer[startIndex .. endIndex]);
|
current.value = cache.get(buffer[startIndex .. endIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEoF()
|
bool isEoF() const
|
||||||
{
|
{
|
||||||
static if (isArray!R)
|
static if (isArray!R)
|
||||||
{
|
{
|
||||||
// import std.stdio;
|
|
||||||
// stderr.writefln("%d %d", index, range.length);
|
|
||||||
return index >= range.length || range[index] == 0 || range[index] == 0x1a;
|
return index >= range.length || range[index] == 0 || range[index] == 0x1a;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return range.empty || range.front == 0 || range.front == 0x1a;
|
return range.empty || range.front == 0 || range.front == 0x1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
immutable bufferSize = 1024 * 8;
|
||||||
Token current;
|
Token current;
|
||||||
uint lineNumber;
|
uint lineNumber;
|
||||||
size_t index;
|
size_t index;
|
||||||
|
@ -2100,164 +2098,175 @@ pure nothrow TokenType lookupTokenType(const const(char)[] input)
|
||||||
switch(input.length)
|
switch(input.length)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "do": return TokenType.do_;
|
case 'd': if (input == "do") return TokenType.do_; else break;
|
||||||
case "if": return TokenType.if_;
|
case 'i':
|
||||||
case "in": return TokenType.in_;
|
if (input == "if") return TokenType.if_;
|
||||||
case "is": return TokenType.is_;
|
else if (input == "in") return TokenType.in_;
|
||||||
|
else if (input == "is") return TokenType.is_;
|
||||||
|
else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "asm": return TokenType.asm_;
|
case 'a': if (input == "asm") return TokenType.asm_; else break;
|
||||||
case "for": return TokenType.for_;
|
case 'f': if (input == "for") return TokenType.for_; else break;
|
||||||
case "int": return TokenType.int_;
|
case 'i': if (input == "int") return TokenType.int_; else break;
|
||||||
case "new": return TokenType.new_;
|
case 'n': if (input == "new") return TokenType.new_; else break;
|
||||||
case "out": return TokenType.out_;
|
case 'o': if (input == "out") return TokenType.out_; else break;
|
||||||
case "ref": return TokenType.ref_;
|
case 'r': if (input == "ref") return TokenType.ref_; else break;
|
||||||
case "try": return TokenType.try_;
|
case 't': if (input == "try") return TokenType.try_; else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "auto": return TokenType.auto_;
|
case 'a': if (input == "auto") return TokenType.auto_; else break;
|
||||||
case "body": return TokenType.body_;
|
case 'b': if (input == "body") return TokenType.body_;
|
||||||
case "bool": return TokenType.bool_;
|
else if (input == "bool") return TokenType.bool_;
|
||||||
case "byte": return TokenType.byte_;
|
else if (input == "byte") return TokenType.byte_;
|
||||||
case "case": return TokenType.case_;
|
else break;
|
||||||
case "cast": return TokenType.cast_;
|
case 'c': if (input == "case") return TokenType.case_;
|
||||||
case "cent": return TokenType.cent_;
|
else if (input == "cast") return TokenType.cast_;
|
||||||
case "char": return TokenType.char_;
|
else if (input == "cent") return TokenType.cent_;
|
||||||
case "else": return TokenType.else_;
|
else if (input == "char") return TokenType.char_;
|
||||||
case "enum": return TokenType.enum_;
|
else break;
|
||||||
case "goto": return TokenType.goto_;
|
case 'e': if (input == "else") return TokenType.else_;
|
||||||
case "lazy": return TokenType.lazy_;
|
else if (input == "enum") return TokenType.enum_;
|
||||||
case "long": return TokenType.long_;
|
else break;
|
||||||
case "null": return TokenType.null_;
|
case 'g': if (input == "goto") return TokenType.goto_; else break;
|
||||||
case "pure": return TokenType.pure_;
|
case 'l': if (input == "lazy") return TokenType.lazy_;
|
||||||
case "real": return TokenType.real_;
|
else if (input == "long") return TokenType.long_;
|
||||||
case "this": return TokenType.this_;
|
else break;
|
||||||
case "true": return TokenType.true_;
|
case 'n': if (input == "null") return TokenType.null_; else break;
|
||||||
case "uint": return TokenType.uint_;
|
case 'p': if (input == "pure") return TokenType.pure_; else break;
|
||||||
case "void": return TokenType.void_;
|
case 'r': if (input == "real") return TokenType.real_; else break;
|
||||||
case "with": return TokenType.with_;
|
case 't': if (input == "this") return TokenType.this_;
|
||||||
|
else if (input == "true") return TokenType.true_;
|
||||||
|
else break;
|
||||||
|
case 'u': if (input == "uint") return TokenType.uint_; else break;
|
||||||
|
case 'v': if (input == "void") return TokenType.void_; else break;
|
||||||
|
case 'w': if (input == "with") return TokenType.with_; else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "alias": return TokenType.alias_;
|
case 'a': if (input == "alias") return TokenType.alias_;
|
||||||
case "align": return TokenType.align_;
|
else if (input == "align") return TokenType.align_; else break;
|
||||||
case "break": return TokenType.break_;
|
case 'b': if (input == "break") return TokenType.break_; else break;
|
||||||
case "catch": return TokenType.catch_;
|
case 'c': if (input == "catch") return TokenType.catch_;
|
||||||
case "class": return TokenType.class_;
|
else if (input == "class") return TokenType.class_;
|
||||||
case "const": return TokenType.const_;
|
else if (input == "const") return TokenType.const_;
|
||||||
case "creal": return TokenType.creal_;
|
else if (input == "creal") return TokenType.creal_;
|
||||||
case "dchar": return TokenType.dchar_;
|
else break;
|
||||||
case "debug": return TokenType.debug_;
|
case 'd': if (input == "dchar") return TokenType.dchar_;
|
||||||
case "false": return TokenType.false_;
|
else if (input == "debug") return TokenType.debug_; else break;
|
||||||
case "final": return TokenType.final_;
|
case 'f': if (input == "false") return TokenType.false_;
|
||||||
case "float": return TokenType.float_;
|
else if (input == "final") return TokenType.final_;
|
||||||
case "inout": return TokenType.inout_;
|
else if (input == "float") return TokenType.float_;
|
||||||
case "ireal": return TokenType.ireal_;
|
else break;
|
||||||
case "macro": return TokenType.macro_;
|
case 'i': if (input == "inout") return TokenType.inout_;
|
||||||
case "mixin": return TokenType.mixin_;
|
else if (input == "ireal") return TokenType.ireal_; else break;
|
||||||
case "scope": return TokenType.scope_;
|
case 'm': if (input == "macro") return TokenType.macro_;
|
||||||
case "short": return TokenType.short_;
|
else if (input == "mixin") return TokenType.mixin_; else break;
|
||||||
case "super": return TokenType.super_;
|
case 's': if (input == "scope") return TokenType.scope_;
|
||||||
case "throw": return TokenType.throw_;
|
else if (input == "short") return TokenType.short_;
|
||||||
case "ubyte": return TokenType.ubyte_;
|
else if (input == "super") return TokenType.super_; else break;
|
||||||
case "ucent": return TokenType.ucent_;
|
case 't': if (input == "throw") return TokenType.throw_; else break;
|
||||||
case "ulong": return TokenType.ulong_;
|
case 'u': if (input == "ubyte") return TokenType.ubyte_;
|
||||||
case "union": return TokenType.union_;
|
else if (input == "ucent") return TokenType.ucent_;
|
||||||
case "wchar": return TokenType.wchar_;
|
else if (input == "ulong") return TokenType.ulong_;
|
||||||
case "while": return TokenType.while_;
|
else if (input == "union") return TokenType.union_;
|
||||||
|
else break;
|
||||||
|
case 'w': if (input == "wchar") return TokenType.wchar_;
|
||||||
|
else if (input == "while") return TokenType.while_;
|
||||||
|
else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "assert": return TokenType.assert_;
|
case 'a': if (input == "assert") return TokenType.assert_; else break;
|
||||||
case "cfloat": return TokenType.cfloat_;
|
case 'c': if (input == "cfloat") return TokenType.cfloat_; else break;
|
||||||
case "delete": return TokenType.delete_;
|
case 'd': if (input == "delete") return TokenType.delete_;
|
||||||
case "double": return TokenType.double_;
|
else if (input == "double") return TokenType.double_; else break;
|
||||||
case "export": return TokenType.export_;
|
case 'e': if (input == "export") return TokenType.export_;
|
||||||
case "extern": return TokenType.extern_;
|
else if (input == "extern") return TokenType.extern_; else break;
|
||||||
case "ifloat": return TokenType.ifloat_;
|
case 'i': if (input == "ifloat") return TokenType.ifloat_;
|
||||||
case "import": return TokenType.import_;
|
else if (input == "import") return TokenType.import_; else break;
|
||||||
case "module": return TokenType.module_;
|
case 'm': if (input == "module") return TokenType.module_; else break;
|
||||||
case "pragma": return TokenType.pragma_;
|
case 'p': if (input == "pragma") return TokenType.pragma_;
|
||||||
case "public": return TokenType.public_;
|
else if (input == "public") return TokenType.public_; else break;
|
||||||
case "return": return TokenType.return_;
|
case 'r': if (input == "return") return TokenType.return_; else break;
|
||||||
case "shared": return TokenType.shared_;
|
case 's': if (input == "shared") return TokenType.shared_;
|
||||||
case "static": return TokenType.static_;
|
else if (input == "static") return TokenType.static_;
|
||||||
case "struct": return TokenType.struct_;
|
else if (input == "struct") return TokenType.struct_;
|
||||||
case "switch": return TokenType.switch_;
|
else if (input == "switch") return TokenType.switch_; else break;
|
||||||
case "typeid": return TokenType.typeid_;
|
case 't': if (input == "typeid") return TokenType.typeid_;
|
||||||
case "typeof": return TokenType.typeof_;
|
else if (input == "typeof") return TokenType.typeof_; else break;
|
||||||
case "ushort": return TokenType.ushort_;
|
case 'u': if (input == "ushort") return TokenType.ushort_; else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "__EOF__": return TokenType.eof;
|
case '_': if (input == "__EOF__") return TokenType.eof; else break;
|
||||||
case "cdouble": return TokenType.cdouble_;
|
case 'c': if (input == "cdouble") return TokenType.cdouble_; else break;
|
||||||
case "default": return TokenType.default_;
|
case 'd': if (input == "default") return TokenType.default_; else break;
|
||||||
case "finally": return TokenType.finally_;
|
case 'f': if (input == "finally") return TokenType.finally_;
|
||||||
case "foreach": return TokenType.foreach_;
|
else if (input == "foreach") return TokenType.foreach_; else break;
|
||||||
case "idouble": return TokenType.idouble_;
|
case 'i': if (input == "idouble") return TokenType.idouble_; else break;
|
||||||
case "nothrow": return TokenType.nothrow_;
|
case 'n': if (input == "nothrow") return TokenType.nothrow_; else break;
|
||||||
case "package": return TokenType.package_;
|
case 'p': if (input == "package") return TokenType.package_;
|
||||||
case "private": return TokenType.private_;
|
else if (input == "private") return TokenType.private_; else break;
|
||||||
case "typedef": return TokenType.typedef_;
|
case 't': if (input == "typedef") return TokenType.typedef_; else break;
|
||||||
case "version": return TokenType.version_;
|
case 'v': if (input == "version") return TokenType.version_; else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "override": return TokenType.override_;
|
case '_': if (input == "__DATE__") return TokenType.date;
|
||||||
case "continue": return TokenType.continue_;
|
else if (input == "__FILE__") return TokenType.file;
|
||||||
case "__LINE__": return TokenType.line;
|
else if (input == "__LINE__") return TokenType.line;
|
||||||
case "template": return TokenType.template_;
|
else if (input == "__TIME__") return TokenType.time;
|
||||||
case "abstract": return TokenType.abstract_;
|
else if (input == "__traits") return TokenType.traits; else break;
|
||||||
case "__traits": return TokenType.traits;
|
case 'a': if (input == "abstract") return TokenType.abstract_; else break;
|
||||||
case "volatile": return TokenType.volatile_;
|
case 'c': if (input == "continue") return TokenType.continue_; else break;
|
||||||
case "delegate": return TokenType.delegate_;
|
case 'd': if (input == "delegate") return TokenType.delegate_; else break;
|
||||||
case "function": return TokenType.function_;
|
case 'f': if (input == "function") return TokenType.function_; else break;
|
||||||
case "unittest": return TokenType.unittest_;
|
case 'o': if (input == "override") return TokenType.override_; else break;
|
||||||
case "__FILE__": return TokenType.file;
|
case 't': if (input == "template") return TokenType.template_; else break;
|
||||||
case "__DATE__": return TokenType.date;
|
case 'u': if (input == "unittest") return TokenType.unittest_; else break;
|
||||||
case "__TIME__": return TokenType.time;
|
case 'v': if (input == "volatile") return TokenType.volatile_; else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "__gshared": return TokenType.gshared;
|
case '_': if (input == "__gshared") return TokenType.gshared; else break;
|
||||||
case "immutable": return TokenType.immutable_;
|
case 'i': if (input == "immutable") return TokenType.immutable_;
|
||||||
case "interface": return TokenType.interface_;
|
else if (input == "interface") return TokenType.interface_;
|
||||||
case "invariant": return TokenType.invariant_;
|
else if (input == "invariant") return TokenType.invariant_; else break;
|
||||||
case "protected": return TokenType.protected_;
|
case 'p': if (input == "protected") return TokenType.protected_; else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
switch (input)
|
switch (input[0])
|
||||||
{
|
{
|
||||||
case "deprecated": return TokenType.deprecated_;
|
case 'd': if (input == "deprecated") return TokenType.deprecated_; else break;
|
||||||
case "__VENDOR__": return TokenType.vendor;
|
case '_': if (input == "__VENDOR__") return TokenType.vendor; else break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2329,12 +2338,12 @@ string printCaseStatements(K, V)(TrieNode!(K,V) node, string indentString)
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\t{\n";
|
caseStatement ~= "\t{\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\tcurrent.value = getTokenValue(current.type);\n";
|
caseStatement ~= "\t\tcurrent.value = getTokenValue(current.type);\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\t\tcurrent.type = " ~ node.children[k].value;
|
caseStatement ~= "\t\tcurrent.type = " ~ node.children[k].value;
|
||||||
caseStatement ~= ";\n";
|
caseStatement ~= ";\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\t\tbreak;\n";
|
caseStatement ~= "\t\treturn;\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\t}\n";
|
caseStatement ~= "\t}\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
|
@ -2349,13 +2358,13 @@ string printCaseStatements(K, V)(TrieNode!(K,V) node, string indentString)
|
||||||
caseStatement ~= v.value;
|
caseStatement ~= v.value;
|
||||||
caseStatement ~= ";\n";
|
caseStatement ~= ";\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\tcurrent.value = getTokenValue(current.type);\n";
|
caseStatement ~= "\t\tcurrent.value = getTokenValue(current.type);\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\t\tbreak;\n";
|
caseStatement ~= "\t\treturn;\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\t}\n";
|
caseStatement ~= "\t}\n";
|
||||||
caseStatement ~= indentString;
|
// caseStatement ~= indentString;
|
||||||
caseStatement ~= "\tbreak;\n";
|
// caseStatement ~= "\treturn;\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2366,7 +2375,7 @@ string printCaseStatements(K, V)(TrieNode!(K,V) node, string indentString)
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\tcurrent.value = getTokenValue(current.type);\n";
|
caseStatement ~= "\tcurrent.value = getTokenValue(current.type);\n";
|
||||||
caseStatement ~= indentString;
|
caseStatement ~= indentString;
|
||||||
caseStatement ~= "\tbreak;\n";
|
caseStatement ~= "\treturn;\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return caseStatement;
|
return caseStatement;
|
||||||
|
@ -2384,62 +2393,54 @@ string generateCaseTrie(string[] args ...)
|
||||||
|
|
||||||
struct StringCache
|
struct StringCache
|
||||||
{
|
{
|
||||||
|
string get(const ubyte[] bytes)
|
||||||
void initialize()
|
|
||||||
{
|
|
||||||
pages.length = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
string get(ubyte[] bytes)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
string* val = (cast(string) bytes) in index;
|
size_t bucket;
|
||||||
|
hash_t h;
|
||||||
|
string* val = find(bytes, bucket, h);
|
||||||
if (val !is null)
|
if (val !is null)
|
||||||
{
|
{
|
||||||
return *val;
|
return *val;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto s = insert(bytes);
|
auto s = (cast(char[]) bytes).idup;
|
||||||
index[s] = s;
|
index[bucket] ~= s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
immutable pageSize = 1024 * 256;
|
string* find(const ubyte[] data, out size_t bucket, out hash_t h)
|
||||||
|
|
||||||
string insert(ubyte[] bytes)
|
|
||||||
{
|
{
|
||||||
if (bytes.length >= pageSize)
|
h = hash(data);
|
||||||
assert(false);
|
bucket = h % mapSize;
|
||||||
size_t last = pages.length - 1;
|
foreach (i; 0 .. index[bucket].length)
|
||||||
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;
|
if (index[bucket][i] == data)
|
||||||
p.lastUsed += bytes.length;
|
return &index[bucket][i];
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Page
|
static hash_t hash(const(ubyte)[] data)
|
||||||
{
|
{
|
||||||
ubyte[pageSize] data = void;
|
hash_t h = 5381;
|
||||||
size_t lastUsed;
|
int c;
|
||||||
|
size_t i;
|
||||||
|
while (i < data.length)
|
||||||
|
{
|
||||||
|
c = data[i++];
|
||||||
|
h = ((h << 5) + h) ^ c;
|
||||||
}
|
}
|
||||||
Page[] pages;
|
return h;
|
||||||
string[string] index;
|
}
|
||||||
|
|
||||||
|
immutable mapSize = 997;
|
||||||
|
string[][mapSize] index;
|
||||||
}
|
}
|
||||||
|
|
||||||
//void main(string[] args) {}
|
//void main(string[] args) {}
|
||||||
|
|
Loading…
Reference in New Issue