diff --git a/src/actypes.d b/src/actypes.d index 19c955f..2d9ce3c 100644 --- a/src/actypes.d +++ b/src/actypes.d @@ -278,13 +278,12 @@ struct Scope */ ACSymbol*[] getSymbolsByName(string name) { - import std.range; ACSymbol s = ACSymbol(name); auto er = symbols.equalRange(&s); if (!er.empty) return array(er); -// Check symbols from "with" statement + // Check symbols from "with" statement ACSymbol ir2 = ACSymbol(WITH_SYMBOL_NAME); auto r2 = symbols.equalRange(&ir2); if (!r2.empty) @@ -412,6 +411,11 @@ private immutable(string[24]) builtinTypeNames; * static construction. */ immutable string IMPORT_SYMBOL_NAME; + +/** + * Name given to the symbol in a "with" expression. Initialized during a static + * constructor. + */ immutable string WITH_SYMBOL_NAME; /** @@ -676,10 +680,5 @@ static this() ucent_.type = ucent_; builtinSymbols.insert(void_); void_.type = void_; - -// writeln(">>Builtin symbols"); -// foreach (symbol; builtinSymbols[]) -// writeln(symbol.name, " ", symbol.name.ptr); -// writeln("< a !is null && a.identifierChain !is null)) @@ -401,8 +413,8 @@ final class FirstPass : ASTVisitor override void visit(const VersionCondition versionCondition) { - import std.algorithm; - import constants; + import std.algorithm : canFind; + import constants : predefinedVersions; // TODO: This is a bit of a hack if (predefinedVersions.canFind(versionCondition.token.text)) versionCondition.accept(this); @@ -491,8 +503,10 @@ final class FirstPass : ASTVisitor /// The module SemanticSymbol* rootSymbol; + /// Allocator used for symbol allocation CAllocator symbolAllocator; + /// Number of symbols allocated uint symbolsAllocated; private: @@ -515,12 +529,11 @@ private: symbol.protection = protection; symbol.acSymbol.doc = internString(dec.comment); - size_t scopeBegin = dec.name.index + dec.name.text.length; - size_t scopeEnd = void; + immutable size_t scopeBegin = dec.name.index + dec.name.text.length; static if (is (AggType == const(TemplateDeclaration))) - scopeEnd = dec.endLocation; + immutable size_t scopeEnd = dec.endLocation; else - scopeEnd = dec.structBody is null ? scopeBegin : dec.structBody.endLocation; + immutable size_t scopeEnd = dec.structBody is null ? scopeBegin : dec.structBody.endLocation; Scope* s = allocate!Scope(semanticAllocator, scopeBegin, scopeEnd); s.parent = currentScope; currentScope.children.insert(s); @@ -752,7 +765,7 @@ string[] iotcToStringArray(A)(ref A allocator, const IdentifierOrTemplateChain i static string convertChainToImportPath(const IdentifierChain ic) { - import std.path; + import std.path : dirSeparator; QuickAllocator!1024 q; auto app = Appender!(char, typeof(q), 1024)(q); scope(exit) q.deallocate(app.mem); diff --git a/src/conversion/second.d b/src/conversion/second.d index 19e8553..4ec3fb8 100644 --- a/src/conversion/second.d +++ b/src/conversion/second.d @@ -112,9 +112,12 @@ private: } body { + // top-level package name immutable string firstPart = info.importParts[].front; - ACSymbol*[] symbols = currentScope.getSymbolsByName(firstPart); + + // top-level package symbol ACSymbol* firstSymbol = void; + ACSymbol*[] symbols = currentScope.getSymbolsByName(firstPart); if (symbols.length > 0) firstSymbol = symbols[0]; else @@ -124,13 +127,14 @@ private: size_t i = 0; foreach (string importPart; info.importParts[]) { - if (i++ == 0) + i++; + if (i == 1) // Skip the top-level package continue; if (i + 2 >= info.importParts.length) // Skip the last item as it's the module name break; symbols = currentSymbol.getPartsByName(importPart); ACSymbol* s = null; - if (symbols.length > 0) foreach (sy; symbols) + foreach (sy; symbols) { if (sy.kind == CompletionKind.packageName) { @@ -147,19 +151,29 @@ private: return currentSymbol; } + /** + * Creates or adds symbols to the given scope based off of the import + * statements contained therein. + */ void resolveImports(Scope* currentScope) { - import modulecache; - import std.stdio; + import modulecache : ModuleCache; foreach (importInfo; currentScope.importInformation[]) { - string location = ModuleCache.resolveImportLoctation(importInfo.modulePath); - ACSymbol* symbol = location is null ? null : ModuleCache.getModuleSymbol(location); + // Get symbol for the imported module + immutable string moduleAbsPath = ModuleCache.resolveImportLoctation( + importInfo.modulePath); + ACSymbol* symbol = moduleAbsPath is null ? null + : ModuleCache.getModuleSymbol(moduleAbsPath); if (symbol is null) continue; + ACSymbol* moduleSymbol = createImportSymbols(importInfo, currentScope, symbol); + + // if this is a selective import if (importInfo.importedSymbols.length == 0) { + // if this import is at module scope if (importInfo.isPublic && currentScope.parent is null) rootSymbol.acSymbol.parts.insert(allocate!ACSymbol(symbolAllocator, IMPORT_SYMBOL_NAME, CompletionKind.importSymbol, symbol)); @@ -168,9 +182,10 @@ private: currentScope.symbols.insert(moduleSymbol); continue; } - - foreach (tup; importInfo.importedSymbols[]) + else foreach (tup; importInfo.importedSymbols[]) { + // Handle selective and renamed imports + ACSymbol needle = ACSymbol(tup[1]); ACSymbol* sym; auto r = symbol.parts.equalRange(&needle); @@ -205,6 +220,8 @@ private: rootSymbol.acSymbol.parts.insert(sym); } } + + // Recurse to child scopes foreach (childScope; currentScope.children) resolveImports(childScope); } diff --git a/src/conversion/third.d b/src/conversion/third.d index 33864b9..638ccda 100644 --- a/src/conversion/third.d +++ b/src/conversion/third.d @@ -40,23 +40,40 @@ import string_interning; struct ThirdPass { public: - this(ref SecondPass second, string name = "none") pure + + /** + * Params: + * second = The second conversion pass. Results are taken from this to + * run the third pass. + */ + this(ref SecondPass second) pure { this.rootSymbol = second.rootSymbol; this.moduleScope = second.moduleScope; - this.name = name; this.symbolAllocator = second.symbolAllocator; } - string name; - + /** + * Runs the third pass. + */ void run() { thirdPass(rootSymbol); } + /** + * The module-level symbol + */ SemanticSymbol* rootSymbol; + + /** + * The module-level scope + */ Scope* moduleScope; + + /** + * The Symbol allocator + */ CAllocator symbolAllocator; private: @@ -106,6 +123,8 @@ private: thirdPass(child); } + // Alias this and mixin templates are resolved after child nodes are + // resolved so that the correct symbol information will be available. with (CompletionKind) switch (currentSymbol.acSymbol.kind) { case className: @@ -162,7 +181,6 @@ private: { foreach (mix; currentSymbol.mixinTemplates[]) { - import stupidlog; auto symbols = moduleScope.getSymbolsByNameAndCursor(mix[0], currentSymbol.acSymbol.location); if (symbols.length == 0) @@ -187,31 +205,28 @@ private: { if (initializer.empty) return null; -// import stupidlog; -// Log.trace("resolveInitializerType: ", __LINE__, ":", initializer[]); auto slice = initializer[]; bool literal = slice.front[0] == '*'; if (literal && initializer.length > 1) { -// Log.trace("Popping ", slice.front, " from slice"); slice.popFront(); literal = false; } auto symbols = moduleScope.getSymbolsByNameAndCursor(internString( literal ? slice.front[1 .. $] : slice.front), location); + if (symbols.length == 0) - { -// Log.trace("Could not find ", literal ? slice.front[1 .. $] : slice.front); return null; - } + if (literal) return symbols[0]; + slice.popFront(); auto s = symbols[0]; + while (s !is null && s.type !is null && !slice.empty) { s = s.type; -// Log.trace("resolveInitializerType: ", __LINE__, ":", slice.front); if (slice.front == "foreach") { if (s.qualifier == SymbolQualifier.array) @@ -293,7 +308,6 @@ private: ACSymbol* processSuffix(ACSymbol* symbol, const TypeSuffix suffix, const Type t) { - import std.d.formatter; if (suffix.star) return symbol; if (suffix.array || suffix.type) @@ -307,9 +321,9 @@ private: } if (suffix.parameters) { - import conversion.first; - import memory.allocators; - import memory.appender; + import conversion.first : formatNode; + import memory.allocators : QuickAllocator; + import memory.appender : Appender; ACSymbol* s = allocate!ACSymbol(symbolAllocator, null); s.type = symbol; s.qualifier = SymbolQualifier.func; @@ -325,12 +339,9 @@ private: ACSymbol* convertBuiltinType(const Type2 type2) { - import std.stdio; string stringRepresentation = getBuiltinTypeName(type2.builtinType); -// writefln(">> %s %016X", stringRepresentation, stringRepresentation.ptr); ACSymbol s = ACSymbol(stringRepresentation); assert(s.name.ptr == stringRepresentation.ptr); -// writefln(">> %s %016X", s.name, s.name.ptr); return builtinSymbols.equalRange(&s).front(); } } diff --git a/src/dcd_version.d b/src/dcd_version.d index fb0397d..e1a4797 100644 --- a/src/dcd_version.d +++ b/src/dcd_version.d @@ -18,5 +18,16 @@ module dcd_version; -enum DCD_VERSION = "v0.4.0"; -version (Windows) {} else enum GIT_HASH = import("githash.txt"); +/** + * Human-readable version number + */ +enum DCD_VERSION = "v0.4.1-dev"; + +version (Windows) {} +else +{ + /** + * Current build's Git commit hash + */ + enum GIT_HASH = import("githash.txt"); +} diff --git a/src/modulecache.d b/src/modulecache.d index 848ee06..c7f6743 100644 --- a/src/modulecache.d +++ b/src/modulecache.d @@ -103,7 +103,6 @@ struct ModuleCache */ static void addImportPaths(string[] paths) { - import core.memory; foreach (path; paths.filter!(a => existanceCheck(a))) importPaths.insert(path); @@ -129,9 +128,9 @@ struct ModuleCache */ static ACSymbol* getModuleSymbol(string location) { - import string_interning; - import std.stdio; - import std.typecons; + import string_interning : internString; + import std.stdio : File; + import std.typecons : scoped; assert (location !is null); @@ -156,17 +155,25 @@ struct ModuleCache immutable fileSize = cast(size_t) f.size; if (fileSize == 0) return null; - ubyte[] source = cast(ubyte[]) Mallocator.it.allocate(fileSize); - f.rawRead(source); - LexerConfig config; - config.fileName = cachedLocation; - auto parseStringCache = StringCache(StringCache.defaultBucketCount); - auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 64))); - const(Token)[] tokens = getTokensForParser( - (source.length >= 3 && source[0 .. 3] == "\xef\xbb\xbf"c) ? source[3 .. $] : source, - config, &parseStringCache); - Mallocator.it.deallocate(source); + const(Token)[] tokens; + { + ubyte[] source = cast(ubyte[]) Mallocator.it.allocate(fileSize); + scope (exit) Mallocator.it.deallocate(source); + f.rawRead(source); + LexerConfig config; + config.fileName = cachedLocation; + auto parseStringCache = StringCache(StringCache.defaultBucketCount); + + // The first three bytes are sliced off here if the file starts with a + // Unicode byte order mark. The lexer/parser don't handle them. + tokens = getTokensForParser( + (source.length >= 3 && source[0 .. 3] == "\xef\xbb\xbf"c) + ? source[3 .. $] : source, + config, &parseStringCache); + } + + auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 64))); Module m = parseModuleSimple(tokens[], cachedLocation, semanticAllocator); assert (symbolAllocator); @@ -177,7 +184,7 @@ struct ModuleCache SecondPass second = SecondPass(first); second.run(); - ThirdPass third = ThirdPass(second, cachedLocation); + ThirdPass third = ThirdPass(second); third.run(); symbol = third.rootSymbol.acSymbol; diff --git a/src/semantic.d b/src/semantic.d index aeca837..efde002 100644 --- a/src/semantic.d +++ b/src/semantic.d @@ -33,7 +33,9 @@ struct SemanticSymbol { public: + /// Disable default construction. @disable this(); + /// Disable copy construction @disable this(this); /** @@ -104,7 +106,7 @@ Type argumentsType; static this() { - import std.allocator; + import std.allocator : allocate; // _argptr has type void* argptrType = allocate!Type(Mallocator.it); argptrType.type2 = allocate!Type2(Mallocator.it); diff --git a/src/server.d b/src/server.d index 0bc3595..e92bb9b 100644 --- a/src/server.d +++ b/src/server.d @@ -42,6 +42,7 @@ import actypes; import core.memory; import dcd_version; +/// Name of the server configuration file enum CONFIG_FILE_NAME = "dcd.conf"; version(linux) version = useXDG; @@ -252,6 +253,9 @@ string getConfigurationLocation() } } +/** + * Prints a warning message to the user when an old config file is detected. + */ void warnAboutOldConfigLocation() { version (linux) if ("~/.config/dcd".expandTilde().exists() @@ -282,6 +286,9 @@ string[] loadConfiguredImportDirs() .array(); } +/** + * Implements the --help switch. + */ void printHelp(string programName) { writefln( diff --git a/src/string_interning.d b/src/string_interning.d index 60dd18b..c880465 100644 --- a/src/string_interning.d +++ b/src/string_interning.d @@ -20,19 +20,12 @@ module string_interning; import std.d.lexer; +/** + * Interns the given string and returns the interned version. + */ string internString(string s) { -// import std.stdio; -// import std.string; -// size_t* p = s in dupCheck; -// auto r = stringCache.intern(s); return stringCache.intern(s); -// if (p !is null) -// assert (*p == cast(size_t) r.ptr, format("%s, %016x, %016x", s, *p, r.ptr)); -// else -// dupCheck[s] = cast(size_t) r.ptr; -// stderr.writefln("%s\t%016x", r, r.ptr); -// return r; } static this()