diff --git a/actypes.d b/actypes.d index d4bdf4f..a911411 100644 --- a/actypes.d +++ b/actypes.d @@ -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; + this.parts = new RedBlackTree!(ACSymbol*, comparitor, true); } - /** - * 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); - } - /** * 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; diff --git a/astconverter.d b/astconverter.d index 8a404aa..f82a10d 100644 --- a/astconverter.d +++ b/astconverter.d @@ -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); -//} diff --git a/autocomplete.d b/autocomplete.d index 40e84a2..571cb8e 100644 --- a/autocomplete.d +++ b/autocomplete.d @@ -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); +//} diff --git a/modulecache.d b/modulecache.d index 7b957d2..8068fbc 100644 --- a/modulecache.d +++ b/modulecache.d @@ -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; diff --git a/semantic.d b/semantic.d index cae7507..0dfbab1 100644 --- a/semantic.d +++ b/semantic.d @@ -45,7 +45,7 @@ public: void addChild(SemanticSymbol* child) { children ~= child; - acSymbol.parts ~= child.acSymbol; + acSymbol.parts.insert(child.acSymbol); } /// Autocompletion symbol diff --git a/server.d b/server.d index d1c8836..4bc8185 100644 --- a/server.d +++ b/server.d @@ -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("/");