Drastic performance increase. Helps address #108

This commit is contained in:
Hackerpilot 2014-02-07 01:15:49 -08:00
parent 2a812d372b
commit e6c03b6610
6 changed files with 272 additions and 245 deletions

262
actypes.d
View File

@ -26,6 +26,12 @@ import std.array;
import messages;
import std.array;
import std.typecons;
import std.container;
bool comparitor(const(ACSymbol)* a, const(ACSymbol)* b) pure nothrow
{
return a.name < b.name;
}
/**
* Any special information about a variable declaration symbol.
@ -49,6 +55,8 @@ struct ACSymbol
{
public:
@disable this();
/**
* Params:
* name = the symbol's name
@ -56,6 +64,7 @@ public:
this(string name)
{
this.name = name;
this.parts = new RedBlackTree!(ACSymbol*, comparitor, true);
}
/**
@ -67,6 +76,7 @@ public:
{
this.name = name;
this.kind = kind;
this.parts = new RedBlackTree!(ACSymbol*, comparitor, true);
}
/**
@ -75,51 +85,29 @@ public:
* kind = the symbol's completion kind
* resolvedType = the resolved type of the symbol
*/
this(string name, CompletionKind kind, const(ACSymbol)* type)
this(string name, CompletionKind kind, ACSymbol* type)
{
this.name = name;
this.kind = kind;
this.type = type;
}
/**
* Comparison operator sorts based on the name field
*/
int opCmp(string str) const
{
if (str < this.name) return -1;
if (str > this.name) return 1;
return 0;
}
/// ditto
int opCmp(const(ACSymbol)* other) const
{
return this.opCmp(other.name);
this.parts = new RedBlackTree!(ACSymbol*, comparitor, true);
}
/**
* Gets all parts whose name matches the given string.
*/
const(ACSymbol)*[] getPartsByName(string name) const
ACSymbol*[] getPartsByName(string name)
{
return cast(typeof(return)) parts.filter!(a => a.name == name).array;
}
size_t estimateMemory(size_t runningTotal) const
{
runningTotal = runningTotal + name.length + callTip.length
+ ACSymbol.sizeof;
foreach (part; parts)
runningTotal = part.estimateMemory(runningTotal);
return runningTotal;
import std.range;
ACSymbol s = ACSymbol(name);
return parts.equalRange(&s).array();
}
/**
* Symbols that compose this symbol, such as enum members, class variables,
* methods, etc.
*/
const(ACSymbol)*[] parts;
RedBlackTree!(ACSymbol*, comparitor, true) parts;
/**
* Symbol's name
@ -144,7 +132,7 @@ public:
/**
* The symbol that represents the type.
*/
const(ACSymbol)* type;
ACSymbol* type;
/**
* Symbol location
@ -164,6 +152,13 @@ public:
struct Scope
{
this (size_t begin, size_t end)
{
this.startLocation = begin;
this.endLocation = end;
this.symbols = new RedBlackTree!(ACSymbol*, comparitor, true);
}
Scope* getScopeByCursor(size_t cursorPosition) const
{
if (cursorPosition < startLocation) return null;
@ -177,32 +172,38 @@ struct Scope
return cast(typeof(return)) &this;
}
const(ACSymbol)*[] getSymbolsInCursorScope(size_t cursorPosition) const
ACSymbol*[] getSymbolsInCursorScope(size_t cursorPosition) const
{
auto s = getScopeByCursor(cursorPosition);
if (s is null)
return [];
const(ACSymbol)*[] symbols = cast(typeof(return)) s.symbols;
auto symbols = s.symbols;
Scope* sc = s.parent;
while (sc !is null)
{
symbols ~= sc.symbols;
foreach (sym; sc.symbols)
symbols.insert(sym);
sc = sc.parent;
}
return symbols;
return symbols.array();
}
const(ACSymbol)*[] getSymbolsByName(string name) const
ACSymbol*[] getSymbolsByName(string name) const
{
const(ACSymbol)*[] retVal = cast(typeof(return)) symbols.filter!(a => a.name == name).array();
if (retVal.length > 0)
return retVal;
import std.range;
ACSymbol s = ACSymbol(name);
RedBlackTree!(ACSymbol*, comparitor, true) t = cast() symbols;
auto r = t.equalRange(&s).array();
version(assert) foreach (n; r)
assert (n.name == name, name);
if (r.length > 0)
return cast(typeof(return)) r;
if (parent is null)
return [];
return parent.getSymbolsByName(name);
}
const(ACSymbol)*[] getSymbolsByNameAndCursor(string name, size_t cursorPosition) const
ACSymbol*[] getSymbolsByNameAndCursor(string name, size_t cursorPosition) const
{
auto s = getScopeByCursor(cursorPosition);
if (s is null)
@ -210,12 +211,23 @@ struct Scope
return s.getSymbolsByName(name);
}
const(ACSymbol)*[] symbols;
/// Imports contained in this scope
ImportInformation[] importInformation;
/// The scope that contains this one
Scope* parent;
/// Child scopes
Scope*[] children;
/// Start location of this scope in bytes
size_t startLocation;
/// End location of this scope in bytes
size_t endLocation;
/// Symbols contained in this scope
RedBlackTree!(ACSymbol*, comparitor, true) symbols;
}
struct ImportInformation
@ -236,6 +248,12 @@ struct ImportInformation
*/
static this()
{
auto bSym = new RedBlackTree!(ACSymbol*, comparitor, true);
auto arrSym = new RedBlackTree!(ACSymbol*, comparitor, true);
auto asarrSym = new RedBlackTree!(ACSymbol*, comparitor, true);
auto aggSym = new RedBlackTree!(ACSymbol*, comparitor, true);
auto clSym = new RedBlackTree!(ACSymbol*, comparitor, true);
auto bool_ = new ACSymbol("bool", CompletionKind.keyword);
auto int_ = new ACSymbol("int", CompletionKind.keyword);
auto long_ = new ACSymbol("long", CompletionKind.keyword);
@ -255,46 +273,44 @@ static this()
auto stringof_ = new ACSymbol("init", CompletionKind.keyword);
auto init = new ACSymbol("stringof", CompletionKind.keyword);
arraySymbols ~= alignof_;
arraySymbols ~= new ACSymbol("dup", CompletionKind.keyword);
arraySymbols ~= new ACSymbol("idup", CompletionKind.keyword);
arraySymbols ~= init;
arraySymbols ~= new ACSymbol("length", CompletionKind.keyword, ulong_);
arraySymbols ~= mangleof_;
arraySymbols ~= new ACSymbol("ptr", CompletionKind.keyword);
arraySymbols ~= new ACSymbol("reverse", CompletionKind.keyword);
arraySymbols ~= sizeof_;
arraySymbols ~= new ACSymbol("sort", CompletionKind.keyword);
arraySymbols ~= stringof_;
arraySymbols.sort();
arrSym.insert(alignof_);
arrSym.insert(new ACSymbol("dup", CompletionKind.keyword));
arrSym.insert(new ACSymbol("idup", CompletionKind.keyword));
arrSym.insert(init);
arrSym.insert(new ACSymbol("length", CompletionKind.keyword, ulong_));
arrSym.insert(mangleof_);
arrSym.insert(new ACSymbol("ptr", CompletionKind.keyword));
arrSym.insert(new ACSymbol("reverse", CompletionKind.keyword));
arrSym.insert(sizeof_);
arrSym.insert(new ACSymbol("sort", CompletionKind.keyword));
arrSym.insert(stringof_);
assocArraySymbols ~= alignof_;
assocArraySymbols ~= new ACSymbol("byKey", CompletionKind.keyword);
assocArraySymbols ~= new ACSymbol("byValue", CompletionKind.keyword);
assocArraySymbols ~= new ACSymbol("dup", CompletionKind.keyword);
assocArraySymbols ~= new ACSymbol("get", CompletionKind.keyword);
assocArraySymbols ~= new ACSymbol("init", CompletionKind.keyword);
assocArraySymbols ~= new ACSymbol("keys", CompletionKind.keyword);
assocArraySymbols ~= new ACSymbol("length", CompletionKind.keyword, ulong_);
assocArraySymbols ~= mangleof_;
assocArraySymbols ~= new ACSymbol("rehash", CompletionKind.keyword);
assocArraySymbols ~= sizeof_;
assocArraySymbols ~= stringof_;
assocArraySymbols ~= init;
assocArraySymbols ~= new ACSymbol("values", CompletionKind.keyword);
assocArraySymbols.sort();
asarrSym.insert(alignof_);
asarrSym.insert(new ACSymbol("byKey", CompletionKind.keyword));
asarrSym.insert(new ACSymbol("byValue", CompletionKind.keyword));
asarrSym.insert(new ACSymbol("dup", CompletionKind.keyword));
asarrSym.insert(new ACSymbol("get", CompletionKind.keyword));
asarrSym.insert(new ACSymbol("init", CompletionKind.keyword));
asarrSym.insert(new ACSymbol("keys", CompletionKind.keyword));
asarrSym.insert(new ACSymbol("length", CompletionKind.keyword, ulong_));
asarrSym.insert(mangleof_);
asarrSym.insert(new ACSymbol("rehash", CompletionKind.keyword));
asarrSym.insert(sizeof_);
asarrSym.insert(stringof_);
asarrSym.insert(init);
asarrSym.insert(new ACSymbol("values", CompletionKind.keyword));
foreach (s; [bool_, int_, long_, byte_, char_, dchar_, short_, ubyte_, uint_,
ulong_, ushort_, wchar_])
{
s.parts ~= new ACSymbol("init", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("min", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("max", CompletionKind.keyword, s);
s.parts ~= alignof_;
s.parts ~= sizeof_;
s.parts ~= stringof_;
s.parts ~= mangleof_;
s.parts ~= init;
s.parts.insert(new ACSymbol("init", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("min", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("max", CompletionKind.keyword, s));
s.parts.insert(alignof_);
s.parts.insert(sizeof_);
s.parts.insert(stringof_);
s.parts.insert(mangleof_);
s.parts.insert(init);
}
auto cdouble_ = new ACSymbol("cdouble", CompletionKind.keyword);
@ -312,54 +328,54 @@ static this()
foreach (s; [cdouble_, cent_, cfloat_, creal_, double_, float_,
idouble_, ifloat_, ireal_, real_, ucent_])
{
s.parts ~= alignof_;
s.parts ~= new ACSymbol("dig", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("epsilon", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("infinity", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("init", CompletionKind.keyword, s);
s.parts ~= mangleof_;
s.parts ~= new ACSymbol("mant_dig", CompletionKind.keyword, int_);
s.parts ~= new ACSymbol("max", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("max_10_exp", CompletionKind.keyword, int_);
s.parts ~= new ACSymbol("max_exp", CompletionKind.keyword, int_);
s.parts ~= new ACSymbol("min", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("min_exp", CompletionKind.keyword, int_);
s.parts ~= new ACSymbol("min_10_exp", CompletionKind.keyword, int_);
s.parts ~= new ACSymbol("min_normal", CompletionKind.keyword, s);
s.parts ~= new ACSymbol("nan", CompletionKind.keyword, s);
s.parts ~= sizeof_;
s.parts ~= stringof_;
s.parts.insert(alignof_);
s.parts.insert(new ACSymbol("dig", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("epsilon", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("infinity", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("init", CompletionKind.keyword, s));
s.parts.insert(mangleof_);
s.parts.insert(new ACSymbol("mant_dig", CompletionKind.keyword, int_));
s.parts.insert(new ACSymbol("max", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("max_10_exp", CompletionKind.keyword, int_));
s.parts.insert(new ACSymbol("max_exp", CompletionKind.keyword, int_));
s.parts.insert(new ACSymbol("min", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("min_exp", CompletionKind.keyword, int_));
s.parts.insert(new ACSymbol("min_10_exp", CompletionKind.keyword, int_));
s.parts.insert(new ACSymbol("min_normal", CompletionKind.keyword, s));
s.parts.insert(new ACSymbol("nan", CompletionKind.keyword, s));
s.parts.insert(sizeof_);
s.parts.insert(stringof_);
}
aggregateSymbols ~= new ACSymbol("tupleof", CompletionKind.variableName);
aggregateSymbols ~= mangleof_;
aggregateSymbols ~= alignof_;
aggregateSymbols ~= sizeof_;
aggregateSymbols ~= stringof_;
aggregateSymbols ~= init;
aggSym.insert(new ACSymbol("tupleof", CompletionKind.variableName));
aggSym.insert(mangleof_);
aggSym.insert(alignof_);
aggSym.insert(sizeof_);
aggSym.insert(stringof_);
aggSym.insert(init);
classSymbols ~= new ACSymbol("classInfo", CompletionKind.variableName);
classSymbols ~= new ACSymbol("tupleof", CompletionKind.variableName);
classSymbols ~= new ACSymbol("__vptr", CompletionKind.variableName);
classSymbols ~= new ACSymbol("__monitor", CompletionKind.variableName);
classSymbols ~= mangleof_;
classSymbols ~= alignof_;
classSymbols ~= sizeof_;
classSymbols ~= stringof_;
classSymbols ~= init;
clSym.insert(new ACSymbol("classInfo", CompletionKind.variableName));
clSym.insert(new ACSymbol("tupleof", CompletionKind.variableName));
clSym.insert(new ACSymbol("__vptr", CompletionKind.variableName));
clSym.insert(new ACSymbol("__monitor", CompletionKind.variableName));
clSym.insert(mangleof_);
clSym.insert(alignof_);
clSym.insert(sizeof_);
clSym.insert(stringof_);
clSym.insert(init);
ireal_.parts ~= new ACSymbol("im", CompletionKind.keyword, real_);
ifloat_.parts ~= new ACSymbol("im", CompletionKind.keyword, float_);
idouble_.parts ~= new ACSymbol("im", CompletionKind.keyword, double_);
ireal_.parts ~= new ACSymbol("re", CompletionKind.keyword, real_);
ifloat_.parts ~= new ACSymbol("re", CompletionKind.keyword, float_);
idouble_.parts ~= new ACSymbol("re", CompletionKind.keyword, double_);
ireal_.parts.insert(new ACSymbol("im", CompletionKind.keyword, real_));
ifloat_.parts.insert(new ACSymbol("im", CompletionKind.keyword, float_));
idouble_.parts.insert(new ACSymbol("im", CompletionKind.keyword, double_));
ireal_.parts.insert(new ACSymbol("re", CompletionKind.keyword, real_));
ifloat_.parts.insert(new ACSymbol("re", CompletionKind.keyword, float_));
idouble_.parts.insert(new ACSymbol("re", CompletionKind.keyword, double_));
auto void_ = new ACSymbol("void", CompletionKind.keyword);
builtinSymbols = [bool_, int_, long_, byte_, char_, dchar_, short_, ubyte_, uint_,
bSym.insert([bool_, int_, long_, byte_, char_, dchar_, short_, ubyte_, uint_,
ulong_, ushort_, wchar_, cdouble_, cent_, cfloat_, creal_, double_,
float_, idouble_, ifloat_, ireal_, real_, ucent_, void_];
float_, idouble_, ifloat_, ireal_, real_, ucent_, void_]);
// _argptr has type void*
argptrType = new Type;
@ -382,12 +398,18 @@ static this()
TypeSuffix argumentsTypeSuffix = new TypeSuffix;
argumentsTypeSuffix.array = true;
argumentsType.typeSuffixes ~= argptrTypeSuffix;
builtinSymbols = bSym;
arraySymbols = arrSym;
assocArraySymbols = asarrSym;
aggregateSymbols = aggSym;
classSymbols = clSym;
}
const(ACSymbol)*[] builtinSymbols;
const(ACSymbol)*[] arraySymbols;
const(ACSymbol)*[] assocArraySymbols;
const(ACSymbol)*[] aggregateSymbols;
const(ACSymbol)*[] classSymbols;
RedBlackTree!(ACSymbol*, comparitor, true) builtinSymbols;
RedBlackTree!(ACSymbol*, comparitor, true) arraySymbols;
RedBlackTree!(ACSymbol*, comparitor, true) assocArraySymbols;
RedBlackTree!(ACSymbol*, comparitor, true) aggregateSymbols;
RedBlackTree!(ACSymbol*, comparitor, true) classSymbols;
Type argptrType;
Type argumentsType;

View File

@ -122,7 +122,7 @@ final class FirstPass : ASTVisitor
dec.parameters, dec.comment);
symbol.protection = protection;
symbol.parent = currentSymbol;
symbol.acSymbol.doc = formatComment(dec.comment);
symbol.acSymbol.doc = dec.comment;
currentSymbol.addChild(symbol);
if (dec.functionBody !is null)
{
@ -183,7 +183,7 @@ final class FirstPass : ASTVisitor
symbol.type = t;
symbol.protection = protection;
symbol.parent = currentSymbol;
symbol.acSymbol.doc = formatComment(dec.comment);
symbol.acSymbol.doc = dec.comment;
currentSymbol.addChild(symbol);
}
}
@ -251,12 +251,8 @@ final class FirstPass : ASTVisitor
currentSymbol = new SemanticSymbol(null, CompletionKind.moduleName,
symbolFile);
rootSymbol = currentSymbol;
currentScope = new Scope();
currentScope.startLocation = 0;
currentScope.endLocation = size_t.max;
currentScope = new Scope(0, size_t.max);
moduleScope = currentScope;
mod.accept(this);
}
@ -268,7 +264,7 @@ final class FirstPass : ASTVisitor
CompletionKind.enumName, symbolFile, dec.name.index);
symbol.type = dec.type;
symbol.parent = currentSymbol;
symbol.acSymbol.doc = formatComment(dec.comment);
symbol.acSymbol.doc = dec.comment;
currentSymbol = symbol;
if (dec.enumBody !is null)
dec.enumBody.accept(this);
@ -283,7 +279,7 @@ final class FirstPass : ASTVisitor
CompletionKind.enumMember, symbolFile, member.name.index);
symbol.type = member.type;
symbol.parent = currentSymbol;
symbol.acSymbol.doc = formatComment(member.comment);
symbol.acSymbol.doc = member.comment;
currentSymbol.addChild(symbol);
}
@ -300,16 +296,14 @@ final class FirstPass : ASTVisitor
override void visit(StructBody structBody)
{
// Log.trace(__FUNCTION__, " ", typeof(structBody).stringof);
Scope* s = new Scope;
s.startLocation = structBody.startLocation;
s.endLocation = structBody.endLocation;
Scope* s = new Scope(structBody.startLocation, structBody.endLocation);
// Log.trace("Added scope ", s.startLocation, " ", s.endLocation);
ACSymbol* thisSymbol = new ACSymbol("this", CompletionKind.variableName,
currentSymbol.acSymbol);
thisSymbol.location = s.startLocation;
thisSymbol.symbolFile = symbolFile;
currentSymbol.acSymbol.parts ~= thisSymbol;
currentSymbol.acSymbol.parts.insert(thisSymbol);
s.parent = currentScope;
currentScope = s;
@ -353,11 +347,10 @@ final class FirstPass : ASTVisitor
override void visit(BlockStatement blockStatement)
{
// Log.trace(__FUNCTION__, " ", typeof(blockStatement).stringof);
Scope* s = new Scope;
Scope* s = new Scope(blockStatement.startLocation,
blockStatement.endLocation);
s.parent = currentScope;
currentScope.children ~= s;
s.startLocation = blockStatement.startLocation;
s.endLocation = blockStatement.endLocation;
if (currentSymbol.acSymbol.kind == CompletionKind.functionName)
{
@ -395,12 +388,12 @@ private:
SemanticSymbol* symbol = new SemanticSymbol(getCached(dec.name.text),
kind, symbolFile, dec.name.index);
if (kind == CompletionKind.className)
symbol.acSymbol.parts ~= classSymbols;
symbol.acSymbol.parts.insert(classSymbols[]);
else
symbol.acSymbol.parts ~= aggregateSymbols;
symbol.acSymbol.parts.insert(aggregateSymbols[]);
symbol.parent = currentSymbol;
symbol.protection = protection;
symbol.acSymbol.doc = formatComment(dec.comment);
symbol.acSymbol.doc = dec.comment;
currentSymbol = symbol;
dec.accept(this);
currentSymbol = symbol.parent;
@ -415,7 +408,7 @@ private:
processParameters(symbol, null, "this", parameters, doc);
symbol.protection = protection;
symbol.parent = currentSymbol;
symbol.acSymbol.doc = formatComment(doc);
symbol.acSymbol.doc = doc;
currentSymbol.addChild(symbol);
if (functionBody !is null)
{
@ -429,10 +422,10 @@ private:
{
SemanticSymbol* symbol = new SemanticSymbol("~this",
CompletionKind.functionName, symbolFile, location);
symbol.acSymbol.callTip = /*formatComment(doc) ~*/ "~this()";
symbol.acSymbol.callTip = "~this()";
symbol.protection = protection;
symbol.parent = currentSymbol;
symbol.acSymbol.doc = formatComment(doc);
symbol.acSymbol.doc = doc;
currentSymbol.addChild(symbol);
if (functionBody !is null)
{
@ -483,9 +476,6 @@ private:
if (returnType is null)
return "%s%s".format(name, parameterString);
return "%s %s%s".format(formatNode(returnType), name, parameterString);
// if (returnType is null)
// return "%s%s%s".format(formatComment(doc), name, parameterString);
// return "%s%s %s%s".format(formatComment(doc), formatNode(returnType), name, parameterString);
}
/// Current protection type
@ -537,11 +527,11 @@ public:
private:
void assignToScopes(const(ACSymbol)* currentSymbol)
void assignToScopes(ACSymbol* currentSymbol)
{
Scope* s = moduleScope.getScopeByCursor(currentSymbol.location);
s.symbols ~= currentSymbol;
foreach (part; currentSymbol.parts)
s.symbols.insert(currentSymbol);
foreach (part; currentSymbol.parts[])
assignToScopes(part);
}
@ -550,19 +540,21 @@ private:
Scope* currentScope)
{
immutable string firstPart = info.importParts[0];
const(ACSymbol)*[] symbols = currentScope.getSymbolsByName(firstPart);
ACSymbol*[] symbols = currentScope.getSymbolsByName(firstPart);
immutable bool found = symbols.length > 0;
const(ACSymbol)* firstSymbol = found
ACSymbol* firstSymbol = found
? symbols[0] : new ACSymbol(firstPart, CompletionKind.packageName);
if (!found)
currentScope.symbols ~= firstSymbol;
{
currentScope.symbols.insert(firstSymbol);
}
ACSymbol* currentSymbol = cast(ACSymbol*) firstSymbol;
foreach (size_t i, string importPart; info.importParts[1 .. $])
{
symbols = currentSymbol.getPartsByName(importPart);
ACSymbol* s = symbols.length > 0
? cast(ACSymbol*) symbols[0] : new ACSymbol(importPart, CompletionKind.packageName);
currentSymbol.parts ~= s;
currentSymbol.parts.insert(s);
currentSymbol = s;
}
currentSymbol.kind = CompletionKind.moduleName;
@ -573,18 +565,16 @@ private:
{
foreach (importInfo; currentScope.importInformation)
{
auto symbols = ModuleCache.getSymbolsInModule(
ACSymbol*[] symbols = ModuleCache.getSymbolsInModule(
ModuleCache.resolveImportLoctation(importInfo.modulePath));
ACSymbol* moduleSymbol = createImportSymbols(importInfo, currentScope);
currentScope.symbols ~= moduleSymbol;
currentScope.symbols ~= symbols;
currentScope.symbols.insert(moduleSymbol);
currentScope.symbols.insert(symbols);
if (importInfo.importedSymbols.length == 0)
{
currentScope.symbols ~= symbols;
moduleSymbol.parts ~= symbols;
if (importInfo.isPublic && currentScope.parent is null)
{
rootSymbol.acSymbol.parts ~= symbols;
rootSymbol.acSymbol.parts.insert(symbols);
}
continue;
}
@ -606,17 +596,17 @@ private:
s.qualifier = symbol.qualifier;
s.location = symbol.location;
s.symbolFile = symbol.symbolFile;
currentScope.symbols ~= s;
moduleSymbol.parts ~= s;
currentScope.symbols.insert(s);
moduleSymbol.parts.insert(s);
if (importInfo.isPublic && currentScope.parent is null)
rootSymbol.acSymbol.parts ~= s;
rootSymbol.acSymbol.parts.insert(s);
}
else
{
moduleSymbol.parts ~= symbol;
currentScope.symbols ~= symbol;
moduleSymbol.parts.insert(symbol);
currentScope.symbols.insert(symbol);
if (importInfo.isPublic && currentScope.parent is null)
rootSymbol.acSymbol.parts ~= symbol;
rootSymbol.acSymbol.parts.insert(symbol);
}
}
}
@ -673,7 +663,7 @@ private:
case memberVariableName:
case functionName:
case aliasName:
const(ACSymbol)* t = resolveType(currentSymbol.type,
ACSymbol* t = resolveType(currentSymbol.type,
currentSymbol.acSymbol.location);
while (t !is null && t.kind == CompletionKind.aliasName)
t = t.type;
@ -691,7 +681,6 @@ private:
case mixinTemplateName:
break;
}
foreach (child; currentSymbol.children)
{
thirdPass(child);
@ -703,7 +692,7 @@ private:
// Log.trace("Resolving inheritance for ", currentSymbol.acSymbol.name);
outer: foreach (string[] base; currentSymbol.baseClasses)
{
const(ACSymbol)* baseClass;
ACSymbol* baseClass;
if (base.length == 0)
continue;
auto symbols = moduleScope.getSymbolsByNameAndCursor(
@ -718,7 +707,7 @@ private:
continue outer;
baseClass = symbols[0];
}
currentSymbol.acSymbol.parts ~= baseClass.parts;
currentSymbol.acSymbol.parts.insert(baseClass.parts[]);
}
}
@ -732,11 +721,11 @@ private:
// TODO:
}
const(ACSymbol)* resolveType(Type t, size_t location)
ACSymbol* resolveType(Type t, size_t location)
{
if (t is null) return null;
if (t.type2 is null) return null;
const(ACSymbol)* s;
ACSymbol* s;
if (t.type2.builtinType != tok!"")
s = convertBuiltinType(t.type2);
else if (t.type2.typeConstructor != tok!"")
@ -780,21 +769,24 @@ private:
return strings;
}
static const(ACSymbol)* processSuffix(const(ACSymbol)* symbol, const TypeSuffix suffix)
static ACSymbol* processSuffix(ACSymbol* symbol, const TypeSuffix suffix)
{
import std.container;
if (suffix.star)
return symbol;
if (suffix.array || suffix.type)
{
ACSymbol* s = new ACSymbol;
s.parts = suffix.array ? arraySymbols : assocArraySymbols;
ACSymbol* s = new ACSymbol(null);
s.parts = new RedBlackTree!(ACSymbol*, comparitor, true);
s.parts.insert(suffix.array ? (cast() arraySymbols)[]
: (cast() assocArraySymbols)[]);
s.type = symbol;
s.qualifier = suffix.array ? SymbolQualifier.array : SymbolQualifier.assocArray;
return s;
}
if (suffix.parameters)
{
ACSymbol* s = new ACSymbol;
ACSymbol* s = new ACSymbol(null);
s.type = symbol;
s.qualifier = SymbolQualifier.func;
s.callTip = suffix.delegateOrFunction.text ~ formatNode(suffix.parameters);
@ -803,22 +795,21 @@ private:
return null;
}
static const(ACSymbol)* convertBuiltinType(const Type2 type2)
static ACSymbol* convertBuiltinType(const Type2 type2)
{
string stringRepresentation = str(type2.builtinType);
if (stringRepresentation is null) return null;
// TODO: Make this use binary search instead
foreach (s; builtinSymbols)
if (s.name == stringRepresentation)
return s;
return null;
auto t = cast() builtinSymbols;
ACSymbol s = ACSymbol(stringRepresentation);
return t.equalRange(&s).front();
}
SemanticSymbol* rootSymbol;
Scope* moduleScope;
}
const(ACSymbol)*[] convertAstToSymbols(const(Token)[] tokens, string symbolFile)
ACSymbol*[] convertAstToSymbols(const(Token)[] tokens, string symbolFile)
{
Module m = parseModuleSimple(tokens, symbolFile);
@ -831,7 +822,7 @@ const(ACSymbol)*[] convertAstToSymbols(const(Token)[] tokens, string symbolFile)
ThirdPass third = ThirdPass(second.rootSymbol, second.moduleScope);
third.run();
return cast(typeof(return)) third.rootSymbol.acSymbol.parts;
return third.rootSymbol.acSymbol.parts.array();
}
const(Scope)* generateAutocompleteTrees(const(Token)[] tokens, string symbolFile)
@ -953,28 +944,6 @@ string formatNode(T)(T node)
private void doesNothing(string a, size_t b, size_t c, string d, bool e) {}
string formatComment(string comment)
{
import std.string;
import std.regex;
enum tripleSlashRegex = `(?:\t )*///`;
enum slashStarRegex = `(?:^/\*\*+)|(?:\n?\s*\*+/$)|(?:(?<=\n)\s*\* ?)`;
enum slashPlusRegex = `(?:^/\+\++)|(?:\n?\s*\++/$)|(?:(?<=\n)\s*\+ ?)`;
if (comment is null)
return null;
string re;
if (comment[0 .. 3] == "///")
re = tripleSlashRegex;
else if (comment[1] == '+')
re = slashPlusRegex;
else
re = slashStarRegex;
return (comment.replaceAll(regex(re), ""))
.replaceFirst(regex("^\n"), "")
.replaceAll(regex(`\\`), `\\`)
.replaceAll(regex("\n"), `\n`).outdent();
}
/**
* Dummy doc comment for getCached
*/
@ -983,14 +952,3 @@ string getCached(string s)
return s.length == 0 ? ""
: ModuleCache.stringCache.cacheGet(cast(const(ubyte)[]) s);
}
//unittest
//{
// auto comment1 = "/**\n * This is some text\n */";
// auto result1 = formatComment(comment1);
// assert (result1 == `This is some text\n\n`, result1);
//
// auto comment2 = "///some\n///text";
// auto result2 = formatComment(comment2);
// assert (result2 == `some\ntext\n\n`, result2);
//}

View File

@ -66,7 +66,7 @@ AutocompleteResponse getDoc(const AutocompleteRequest request)
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
auto expression = getExpression(beforeTokens);
const(ACSymbol)*[] symbols = getSymbolsByTokenChain(completionScope, expression,
ACSymbol*[] symbols = getSymbolsByTokenChain(completionScope, expression,
request.cursorPosition, CompletionType.ddoc);
if (symbols.length == 0)
@ -79,7 +79,7 @@ AutocompleteResponse getDoc(const AutocompleteRequest request)
continue;
}
Log.trace("Adding doc comment for ", symbol.name, ": ", symbol.doc);
response.docComments ~= symbol.doc;
response.docComments ~= formatComment(symbol.doc);
}
return response;
}
@ -112,7 +112,7 @@ AutocompleteResponse findDeclaration(const AutocompleteRequest request)
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
auto expression = getExpression(beforeTokens);
const(ACSymbol)*[] symbols = getSymbolsByTokenChain(completionScope, expression,
ACSymbol*[] symbols = getSymbolsByTokenChain(completionScope, expression,
request.cursorPosition, CompletionType.location);
if (symbols.length > 0)
@ -156,12 +156,12 @@ bool shouldSwapWithType(CompletionType completionType, CompletionKind kind,
return completionType == CompletionType.identifiers && isInteresting;
}
const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
ACSymbol*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
T tokens, size_t cursorPosition, CompletionType completionType)
{
Log.trace("Getting symbols from token chain", tokens.map!"a.text");
// Find the symbol corresponding to the beginning of the chain
const(ACSymbol)*[] symbols = completionScope.getSymbolsByNameAndCursor(
ACSymbol*[] symbols = completionScope.getSymbolsByNameAndCursor(
tokens[0].text, cursorPosition);
if (symbols.length == 0)
{
@ -293,7 +293,7 @@ const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
skip();
Parser p = new Parser();
p.setTokens(tokens[h .. i].array());
const(ACSymbol)*[] overloads;
ACSymbol*[] overloads;
if (p.isSliceExpression())
overloads = symbols[0].getPartsByName("opSlice");
else
@ -395,7 +395,7 @@ dotCompletion:
case tok!"stringLiteral":
case tok!"wstringLiteral":
case tok!"dstringLiteral":
foreach (symbol; arraySymbols)
foreach (symbol; (cast() arraySymbols)[])
{
response.completionKinds ~= symbol.kind;
response.completions ~= symbol.name;
@ -478,7 +478,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
if (tokens.length == 0)
return;
const(ACSymbol)*[] symbols = getSymbolsByTokenChain(completionScope, tokens,
ACSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens,
cursorPosition, completionType);
if (symbols.length == 0)
@ -494,7 +494,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
if (symbols.length == 0)
return;
}
foreach (s; symbols[0].parts.filter!(a => a.name !is null
foreach (s; symbols[0].parts[].filter!(a => a.name !is null
&& a.name.length > 0 && a.name[0] != '*'
&& (partial is null ? true : a.name.toUpper().startsWith(partial.toUpper()))
&& !response.completions.canFind(a.name)))
@ -671,3 +671,36 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
}
}
}
string formatComment(string comment)
{
import std.string;
import std.regex;
enum tripleSlashRegex = `(?:\t )*///`;
enum slashStarRegex = `(?:^/\*\*+)|(?:\n?\s*\*+/$)|(?:(?<=\n)\s*\* ?)`;
enum slashPlusRegex = `(?:^/\+\++)|(?:\n?\s*\++/$)|(?:(?<=\n)\s*\+ ?)`;
if (comment is null)
return null;
string re;
if (comment[0 .. 3] == "///")
re = tripleSlashRegex;
else if (comment[1] == '+')
re = slashPlusRegex;
else
re = slashStarRegex;
return (comment.replaceAll(regex(re), ""))
.replaceFirst(regex("^\n"), "")
.replaceAll(regex(`\\`), `\\`)
.replaceAll(regex("\n"), `\n`).outdent();
}
//unittest
//{
// auto comment1 = "/**\n * This is some text\n */";
// auto result1 = formatComment(comment1);
// assert (result1 == `This is some text\n\n`, result1);
//
// auto comment2 = "///some\n///text";
// auto result2 = formatComment(comment2);
// assert (result2 == `some\ntext\n\n`, result2);
//}

View File

@ -29,16 +29,23 @@ import std.array;
import std.path;
import std.algorithm;
import std.conv;
import std.container;
import actypes;
import semantic;
import astconverter;
import stupidlog;
struct CacheEntry
bool cacheComparitor(CacheEntry* a, CacheEntry* b) pure nothrow
{
const(ACSymbol)*[] symbols;
return cast(ubyte[]) a.path < cast(ubyte[]) b.path;
}
private struct CacheEntry
{
ACSymbol*[] symbols;
SysTime modificationTime;
string path;
void opAssign(ref const CacheEntry other)
{
this.symbols = cast(typeof(symbols)) other.symbols;
@ -54,6 +61,11 @@ bool existanceCheck(A)(A path)
return false;
}
static this()
{
ModuleCache.cache = new RedBlackTree!(CacheEntry*, cacheComparitor);
}
/**
* Caches pre-parsed module information.
*/
@ -66,7 +78,7 @@ struct ModuleCache
*/
static void clear()
{
cache = cache.init;
cache.clear();
}
/**
@ -91,15 +103,18 @@ struct ModuleCache
* Returns:
* The symbols defined in the given module
*/
static const(ACSymbol)*[] getSymbolsInModule(string location)
static ACSymbol*[] getSymbolsInModule(string location)
{
if (location is null)
return [];
if (!needsReparsing(location))
{
if (location in cache)
return cache[location].symbols;
CacheEntry e;
e.path = location;
auto r = cache.equalRange(&e);
if (!r.empty)
return r.front.symbols;
return [];
}
@ -107,25 +122,21 @@ struct ModuleCache
recursionGuard[location] = true;
const(ACSymbol)*[] symbols;
ACSymbol*[] symbols;
try
{
import core.memory;
File f = File(location);
ubyte[] source = uninitializedArray!(ubyte[])(cast(size_t)f.size);
f.rawRead(source);
GC.disable();
LexerConfig config;
config.fileName = location;
StringCache* cache = new StringCache(StringCache.defaultBucketCount);
auto tokens = source.byToken(config, cache).array();
symbols = convertAstToSymbols(tokens, location);
// Parsing allocates a lot of AST nodes. We can greatly reduce the
// program's idle memory use by running the GC here.
// TODO: Re-visit this when D gets a precise GC.
import core.memory;
GC.collect();
GC.minimize();
GC.enable();
}
catch (Exception ex)
{
@ -135,8 +146,8 @@ struct ModuleCache
SysTime access;
SysTime modification;
getTimes(location, access, modification);
CacheEntry c = CacheEntry(symbols, modification);
cache[location] = c;
CacheEntry* c = new CacheEntry(symbols, modification, location);
cache.insert(c);
recursionGuard[location] = false;
return symbols;
}
@ -202,16 +213,21 @@ private:
return true;
if (recursionGuard[mod])
return false;
if (!exists(mod) || mod !in cache)
if (!exists(mod))
return true;
CacheEntry e;
e.path = mod;
auto r = cache.equalRange(&e);
if (r.empty)
return true;
SysTime access;
SysTime modification;
getTimes(mod, access, modification);
return cache[mod].modificationTime != modification;
return r.front.modificationTime != modification;
}
// Mapping of file paths to their cached symbols.
static CacheEntry[string] cache;
static RedBlackTree!(CacheEntry*, cacheComparitor) cache;
static bool[string] recursionGuard;

View File

@ -45,7 +45,7 @@ public:
void addChild(SemanticSymbol* child)
{
children ~= child;
acSymbol.parts ~= child.acSymbol;
acSymbol.parts.insert(child.acSymbol);
}
/// Autocompletion symbol

View File

@ -96,8 +96,6 @@ int main(string[] args)
sw.stop();
Log.info("Startup completed in ", sw.peek().to!("msecs", float), " milliseconds");
// ModuleCache.estimateMemory();
// No relative paths
version (Posix) chdir("/");