From be2e3cdc5497fea472592f2fc34398fa2925c9a5 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Wed, 18 Feb 2015 14:07:19 +0300 Subject: [PATCH] libdparse integration experiments --- dlangide.visualdproj | 2 +- src/dlangide/tools/d/dcdinterface.d | 10 ++- src/dlangide/tools/d/deditortool.d | 4 +- src/dlangide/tools/d/dparser.d | 98 ++++++++++++++++++++++++++--- workspaces/tetris/src/tetris.d | 2 +- 5 files changed, 103 insertions(+), 13 deletions(-) diff --git a/dlangide.visualdproj b/dlangide.visualdproj index a37a585..014ed4d 100644 --- a/dlangide.visualdproj +++ b/dlangide.visualdproj @@ -66,7 +66,7 @@ 0 DebugInfo DCD 0 - Unicode USE_FREETYPE + Unicode USE_FREETYPE USE_LIBDPARSE 0 3 0 diff --git a/src/dlangide/tools/d/dcdinterface.d b/src/dlangide/tools/d/dcdinterface.d index b87a6d4..b0e089e 100644 --- a/src/dlangide/tools/d/dcdinterface.d +++ b/src/dlangide/tools/d/dcdinterface.d @@ -73,8 +73,14 @@ class DCDInterface { return output; } - ResultSet goToDefinition(in string[] importPaths, in string content, int index) { + ResultSet goToDefinition(in string[] importPaths, in string filename, in string content, int index) { ResultSet result; + + version(USE_LIBDPARSE) { + import dlangide.tools.d.dparser; + DParsingService.instance.addImportPaths(importPaths); + DParsedModule m = DParsingService.instance.scan(cast(ubyte[])content, filename); + } debug(DCD) Log.d("DCD Context: ", dumpContext(content, index)); @@ -122,7 +128,7 @@ class DCDInterface { return result; } - ResultSet getCompletions(in string[] importPaths, in string content, int index) { + ResultSet getCompletions(in string[] importPaths, in string filename, in string content, int index) { debug(DCD) Log.d("DCD Context: ", dumpContext(content, index)); diff --git a/src/dlangide/tools/d/deditortool.d b/src/dlangide/tools/d/deditortool.d index c3acc30..15d840e 100644 --- a/src/dlangide/tools/d/deditortool.d +++ b/src/dlangide/tools/d/deditortool.d @@ -28,7 +28,7 @@ class DEditorTool : EditorTool string[] importPaths = editor.importPaths(); string content = toUTF8(editor.text); auto byteOffset = caretPositionToByteOffset(content, caretPosition); - ResultSet output = _dcd.goToDefinition(importPaths, content, byteOffset); + ResultSet output = _dcd.goToDefinition(importPaths, editor.filename, content, byteOffset); switch(output.result) { @@ -66,7 +66,7 @@ class DEditorTool : EditorTool string content = toUTF8(editor.text); auto byteOffset = caretPositionToByteOffset(content, caretPosition); - ResultSet output = _dcd.getCompletions(importPaths, content, byteOffset); + ResultSet output = _dcd.getCompletions(importPaths, editor.filename, content, byteOffset); switch(output.result) { //TODO: Show dialog case DCDResult.FAIL: diff --git a/src/dlangide/tools/d/dparser.d b/src/dlangide/tools/d/dparser.d index 9451410..9848eb0 100644 --- a/src/dlangide/tools/d/dparser.d +++ b/src/dlangide/tools/d/dparser.d @@ -1,5 +1,7 @@ module dlangide.tools.d.dparser; +import dlangui.core.logger; + import std.d.lexer; import std.d.parser; import std.d.ast; @@ -14,21 +16,64 @@ class DParsedModule { protected string _moduleFile; protected StringCache* _cache; protected Module _ast; + protected string[] _imports; const(Token)[] _tokens; LexerConfig _lexerConfig; - @property string filename() { - return _moduleFile; - } + @property string filename() { return _moduleFile; } + /// module name, e.g. "std.stdio" + @property string moduleName() { return _moduleName; } this(StringCache* cache, string filename) { _cache = cache; _moduleFile = filename; } + private static string importDeclToModuleName(IdentifierChain chain) { + char[] buf; + foreach(token; chain.identifiers) { + if (buf.length) + buf ~= '.'; + buf ~= token.text; + } + return buf.dup; + } + + void scanImports(Declaration[] declarations) { + foreach(d; declarations) { + if (d.importDeclaration) { + foreach(imp; d.importDeclaration.singleImports) { + addImport(importDeclToModuleName(imp.identifierChain)); + } + } else if (d.declarations) { + scanImports(d.declarations); + } + } + } + + static void msgFunction(string fn, size_t line, size_t col, string msg, bool isError) { + debug(DParseErrors) Log.d("parser error: ", fn, "(", line, ":", col, ") : ", isError ? "Error: ": "Warning: ", msg); + } + void parse(ubyte[] sourceCode) { _tokens = getTokensForParser(sourceCode, _lexerConfig, _cache); - _ast = parseModule(_tokens, _moduleFile); + uint errorCount; + uint warningCount; + _ast = parseModule(_tokens, _moduleFile, null, &msgFunction, &errorCount, &warningCount); + _moduleName = importDeclToModuleName(_ast.moduleDeclaration.moduleName); + scanImports(_ast.declarations); + + } + + private void addImport(string m) { + foreach(imp; _imports) + if (imp.equal(m)) + return; + _imports ~= m; + } + + @property string[] imports() { + return _imports; } } @@ -55,15 +100,37 @@ class DParsingService { protected DParsedModule[string] _moduleByName; protected DParsedModule[string] _moduleByFile; protected bool[string] _notFoundModules; + protected DParsedModule _currentModule; // current module this() { _cache = StringCache(16); } + void scanDeps(DParsedModule m, ref DParsedModule[string]scanned) { + foreach(imp; m.imports) { + if (imp !in scanned) { + DParsedModule impModule = getOrParseModule(imp); + scanned[imp] = impModule; + if (impModule) + scanDeps(impModule, scanned); + } + } + } + DParsedModule scan(ubyte[] sourceCode, string filename) { + Log.d("scanning ", filename); destroy(_notFoundModules); DParsedModule res = new DParsedModule(&_cache, filename); res.parse(sourceCode); + _currentModule = res; + Log.d("moduleName: ", res.moduleName, " imports: ", res.imports); + Log.d("deps:"); + DParsedModule[string] scanned; + scanned[res.moduleName] = res; + scanDeps(res, scanned); + foreach(key, value; scanned) { + Log.d(" module ", key, " : ", value ? value.filename : "NOT FOUND"); + } return res; } @@ -77,21 +144,36 @@ class DParsingService { string findModuleFile(string moduleName) { string packagePath = moduleNameToPackagePath(moduleName); foreach(ip; _importPaths) { + //Log.d("packagePath: ", packagePath, " importPath: ", ip); string path = buildNormalizedPath(ip, packagePath); - if (path.exists && path.isFile) + if (path.exists && path.isFile) { + //Log.d("found ", path); return path; + } + string pathImports = path ~ "i"; + if (pathImports.exists && pathImports.isFile) { + //Log.d("found ", pathImports); + return pathImports; + } } return null; } DParsedModule getOrParseModule(string moduleName) { + if (_currentModule) { + if (moduleName.equal(_currentModule.moduleName)) + return _currentModule; // module being scanned + } if (auto m = moduleName in _moduleByName) { return *m; } - if (moduleName in _notFoundModules) + if (moduleName in _notFoundModules) { + Log.d("module is in not found: ", moduleName); return null; // already listed as not found + } string filename = findModuleFile(moduleName); if (!filename) { + Log.d("module not found: ", moduleName); _notFoundModules[moduleName] = true; return null; } @@ -103,12 +185,14 @@ class DParsingService { _moduleByFile[filename] = res; return res; } catch (Exception e) { + Log.d("exception while parsing: ", moduleName, " : ", e); _notFoundModules[moduleName] = true; return null; } } - void addImportPaths(string[] paths) { + void addImportPaths(in string[] paths) { + Log.d("addImportPaths: ", paths); foreach(p; paths) { string ap = absolutePath(buildNormalizedPath(p)); bool found = false; diff --git a/workspaces/tetris/src/tetris.d b/workspaces/tetris/src/tetris.d index 58fa71c..3341ce1 100644 --- a/workspaces/tetris/src/tetris.d +++ b/workspaces/tetris/src/tetris.d @@ -1 +1 @@ -// Written in the D programming language. /** This app is a Tetris demo for DlangUI library. Synopsis: ---- dub run dlangui:tetris ---- Copyright: Vadim Lopatin, 2014 License: Boost License 1.0 Authors: Vadim Lopatin, coolreader.org@gmail.com */ module main; import dlangui.all; import model; import gui; /// Required for Windows platform: DMD cannot find WinMain if it's in library mixin APP_ENTRY_POINT; /// entry point for dlangui based application extern (C) int UIAppMain(string[] args) { //auto power2 = delegate(int X) { return X * X; }; auto power2 = (int X) => X * X; // embed resources listed in views/resources.list into executable embeddedResourceList.addResources(embedResourcesFromList!("resources.list")()); // select translation file - for english language Platform.instance.uiLanguage = "en"; // load theme from file "theme_default.xml" Platform.instance.uiTheme = "theme_default"; // create window Window window = Platform.instance.createWindow("DLangUI: Tetris game example"d, null, WindowFlag.Modal); window.mainWidget = new GameWidget(); window.windowIcon = drawableCache.getImage("dtetris-logo1"); window.show(); // run message loop return Platform.instance.enterMessageLoop(); } \ No newline at end of file +// Written in the D programming language. /** This app is a Tetris demo for DlangUI library. Synopsis: ---- dub run dlangui:tetris ---- Copyright: Vadim Lopatin, 2014 License: Boost License 1.0 Authors: Vadim Lopatin, coolreader.org@gmail.com */ module main; import dlangui.all; import model; import gui; import std.stdio; /// Required for Windows platform: DMD cannot find WinMain if it's in library mixin APP_ENTRY_POINT; /// entry point for dlangui based application extern (C) int UIAppMain(string[] args) { //auto power2 = delegate(int X) { return X * X; }; auto power2 = (int X) => X * X; // embed resources listed in views/resources.list into executable embeddedResourceList.addResources(embedResourcesFromList!("resources.list")()); // select translation file - for english language Platform.instance.uiLanguage = "en"; // load theme from file "theme_default.xml" Platform.instance.uiTheme = "theme_default"; // create window Window window = Platform.instance.createWindow("DLangUI: Tetris game example"d, null, WindowFlag.Modal); window.mainWidget = new GameWidget(); window.windowIcon = drawableCache.getImage("dtetris-logo1"); window.show(); // run message loop return Platform.instance.enterMessageLoop(); } \ No newline at end of file