libdparse integration experiments

This commit is contained in:
Vadim Lopatin 2015-02-18 14:07:19 +03:00
parent e8cd7b882c
commit be2e3cdc54
5 changed files with 103 additions and 13 deletions

View File

@ -66,7 +66,7 @@
<debuglevel>0</debuglevel> <debuglevel>0</debuglevel>
<debugids>DebugInfo DCD</debugids> <debugids>DebugInfo DCD</debugids>
<versionlevel>0</versionlevel> <versionlevel>0</versionlevel>
<versionids>Unicode USE_FREETYPE</versionids> <versionids>Unicode USE_FREETYPE USE_LIBDPARSE</versionids>
<dump_source>0</dump_source> <dump_source>0</dump_source>
<mapverbosity>3</mapverbosity> <mapverbosity>3</mapverbosity>
<createImplib>0</createImplib> <createImplib>0</createImplib>

View File

@ -73,9 +73,15 @@ class DCDInterface {
return output; 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; 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)); debug(DCD) Log.d("DCD Context: ", dumpContext(content, index));
string[] arguments = ["-l", "-c"]; string[] arguments = ["-l", "-c"];
@ -122,7 +128,7 @@ class DCDInterface {
return result; 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)); debug(DCD) Log.d("DCD Context: ", dumpContext(content, index));

View File

@ -28,7 +28,7 @@ class DEditorTool : EditorTool
string[] importPaths = editor.importPaths(); string[] importPaths = editor.importPaths();
string content = toUTF8(editor.text); string content = toUTF8(editor.text);
auto byteOffset = caretPositionToByteOffset(content, caretPosition); auto byteOffset = caretPositionToByteOffset(content, caretPosition);
ResultSet output = _dcd.goToDefinition(importPaths, content, byteOffset); ResultSet output = _dcd.goToDefinition(importPaths, editor.filename, content, byteOffset);
switch(output.result) { switch(output.result) {
@ -66,7 +66,7 @@ class DEditorTool : EditorTool
string content = toUTF8(editor.text); string content = toUTF8(editor.text);
auto byteOffset = caretPositionToByteOffset(content, caretPosition); auto byteOffset = caretPositionToByteOffset(content, caretPosition);
ResultSet output = _dcd.getCompletions(importPaths, content, byteOffset); ResultSet output = _dcd.getCompletions(importPaths, editor.filename, content, byteOffset);
switch(output.result) { switch(output.result) {
//TODO: Show dialog //TODO: Show dialog
case DCDResult.FAIL: case DCDResult.FAIL:

View File

@ -1,5 +1,7 @@
module dlangide.tools.d.dparser; module dlangide.tools.d.dparser;
import dlangui.core.logger;
import std.d.lexer; import std.d.lexer;
import std.d.parser; import std.d.parser;
import std.d.ast; import std.d.ast;
@ -14,21 +16,64 @@ class DParsedModule {
protected string _moduleFile; protected string _moduleFile;
protected StringCache* _cache; protected StringCache* _cache;
protected Module _ast; protected Module _ast;
protected string[] _imports;
const(Token)[] _tokens; const(Token)[] _tokens;
LexerConfig _lexerConfig; LexerConfig _lexerConfig;
@property string filename() { @property string filename() { return _moduleFile; }
return _moduleFile; /// module name, e.g. "std.stdio"
} @property string moduleName() { return _moduleName; }
this(StringCache* cache, string filename) { this(StringCache* cache, string filename) {
_cache = cache; _cache = cache;
_moduleFile = filename; _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) { void parse(ubyte[] sourceCode) {
_tokens = getTokensForParser(sourceCode, _lexerConfig, _cache); _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] _moduleByName;
protected DParsedModule[string] _moduleByFile; protected DParsedModule[string] _moduleByFile;
protected bool[string] _notFoundModules; protected bool[string] _notFoundModules;
protected DParsedModule _currentModule; // current module
this() { this() {
_cache = StringCache(16); _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) { DParsedModule scan(ubyte[] sourceCode, string filename) {
Log.d("scanning ", filename);
destroy(_notFoundModules); destroy(_notFoundModules);
DParsedModule res = new DParsedModule(&_cache, filename); DParsedModule res = new DParsedModule(&_cache, filename);
res.parse(sourceCode); 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; return res;
} }
@ -77,21 +144,36 @@ class DParsingService {
string findModuleFile(string moduleName) { string findModuleFile(string moduleName) {
string packagePath = moduleNameToPackagePath(moduleName); string packagePath = moduleNameToPackagePath(moduleName);
foreach(ip; _importPaths) { foreach(ip; _importPaths) {
//Log.d("packagePath: ", packagePath, " importPath: ", ip);
string path = buildNormalizedPath(ip, packagePath); string path = buildNormalizedPath(ip, packagePath);
if (path.exists && path.isFile) if (path.exists && path.isFile) {
//Log.d("found ", path);
return path; return path;
}
string pathImports = path ~ "i";
if (pathImports.exists && pathImports.isFile) {
//Log.d("found ", pathImports);
return pathImports;
}
} }
return null; return null;
} }
DParsedModule getOrParseModule(string moduleName) { DParsedModule getOrParseModule(string moduleName) {
if (_currentModule) {
if (moduleName.equal(_currentModule.moduleName))
return _currentModule; // module being scanned
}
if (auto m = moduleName in _moduleByName) { if (auto m = moduleName in _moduleByName) {
return *m; 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 return null; // already listed as not found
}
string filename = findModuleFile(moduleName); string filename = findModuleFile(moduleName);
if (!filename) { if (!filename) {
Log.d("module not found: ", moduleName);
_notFoundModules[moduleName] = true; _notFoundModules[moduleName] = true;
return null; return null;
} }
@ -103,12 +185,14 @@ class DParsingService {
_moduleByFile[filename] = res; _moduleByFile[filename] = res;
return res; return res;
} catch (Exception e) { } catch (Exception e) {
Log.d("exception while parsing: ", moduleName, " : ", e);
_notFoundModules[moduleName] = true; _notFoundModules[moduleName] = true;
return null; return null;
} }
} }
void addImportPaths(string[] paths) { void addImportPaths(in string[] paths) {
Log.d("addImportPaths: ", paths);
foreach(p; paths) { foreach(p; paths) {
string ap = absolutePath(buildNormalizedPath(p)); string ap = absolutePath(buildNormalizedPath(p));
bool found = false; bool found = false;

View File

@ -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(); } // 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(); }