From 7cd99a8efea52f75bb196823f05660338d68d167 Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Sun, 3 May 2020 00:31:41 +0300 Subject: [PATCH 1/8] Added before & after functionality in statement semantic --- src/dmd/statement.d | 16 ++++++++++++++++ src/dmd/statementsem.d | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/src/dmd/statement.d b/src/dmd/statement.d index 0c06447300ec..fa6a735095ea 100644 --- a/src/dmd/statement.d +++ b/src/dmd/statement.d @@ -2548,3 +2548,19 @@ extern (C++) final class ImportStatement : Statement v.visit(this); } } + + +alias OnStatementSemanticStart = void delegate(Statement, Scope*); +alias OnStatementSemanticDone = void delegate(Statement, Scope*); + +/** + * Used to insert functionality before the start of the + * semantic analysis of a statement when importing DMD as a library + */ +OnStatementSemanticStart onStatementSemanticStart; + +/** + * Used to insert functionality after the end of the + * semantic analysis of a statement when importing DMD as a library + */ +OnStatementSemanticDone onStatementSemanticDone; diff --git a/src/dmd/statementsem.d b/src/dmd/statementsem.d index 45e1872a6c62..4323c98acb0b 100644 --- a/src/dmd/statementsem.d +++ b/src/dmd/statementsem.d @@ -123,8 +123,17 @@ private Expression checkAssignmentAsCondition(Expression e) // Performs semantic analysis in Statement AST nodes extern(C++) Statement statementSemantic(Statement s, Scope* sc) { + version (DMDasLib) + if (onStatementSemanticStart) + onStatementSemanticStart(s, sc); + scope v = new StatementSemanticVisitor(sc); s.accept(v); + + version (DMDasLib) + if (onStatementSemanticDone) + onStatementSemanticDone(s, sc); + return v.result; } From e462faf14040226a7aa297933a359f0991bc2b72 Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Tue, 12 May 2020 02:33:34 +0300 Subject: [PATCH 2/8] Moved callbacks to Compiler and changed version name --- src/dmd/compiler.d | 17 +++++++++++++++++ src/dmd/statement.d | 16 ---------------- src/dmd/statementsem.d | 13 +++++++------ 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/dmd/compiler.d b/src/dmd/compiler.d index 429ea3717400..fbe608930a3a 100644 --- a/src/dmd/compiler.d +++ b/src/dmd/compiler.d @@ -28,6 +28,7 @@ import dmd.root.ctfloat; import dmd.semantic2; import dmd.semantic3; import dmd.tokens; +import dmd.statement; extern (C++) __gshared { @@ -152,6 +153,22 @@ extern (C++) struct Compiler } return false; // this import will not be compiled } + + alias OnStatementSemanticStart = void delegate(Statement, Scope*); + alias OnStatementSemanticDone = void delegate(Statement, Scope*); + + /** + * Used to insert functionality before the start of the + * semantic analysis of a statement when importing DMD as a library + */ + __gshared OnStatementSemanticStart onStatementSemanticStart; + + /** + * Used to insert functionality after the end of the + * semantic analysis of a statement when importing DMD as a library + */ + __gshared OnStatementSemanticDone onStatementSemanticDone; + } /****************************** diff --git a/src/dmd/statement.d b/src/dmd/statement.d index fa6a735095ea..0c06447300ec 100644 --- a/src/dmd/statement.d +++ b/src/dmd/statement.d @@ -2548,19 +2548,3 @@ extern (C++) final class ImportStatement : Statement v.visit(this); } } - - -alias OnStatementSemanticStart = void delegate(Statement, Scope*); -alias OnStatementSemanticDone = void delegate(Statement, Scope*); - -/** - * Used to insert functionality before the start of the - * semantic analysis of a statement when importing DMD as a library - */ -OnStatementSemanticStart onStatementSemanticStart; - -/** - * Used to insert functionality after the end of the - * semantic analysis of a statement when importing DMD as a library - */ -OnStatementSemanticDone onStatementSemanticDone; diff --git a/src/dmd/statementsem.d b/src/dmd/statementsem.d index 4323c98acb0b..68097e606982 100644 --- a/src/dmd/statementsem.d +++ b/src/dmd/statementsem.d @@ -57,6 +57,7 @@ import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.visitor; +import dmd.compiler; /***************************************** * CTFE requires FuncDeclaration::labtab for the interpretation. @@ -123,16 +124,16 @@ private Expression checkAssignmentAsCondition(Expression e) // Performs semantic analysis in Statement AST nodes extern(C++) Statement statementSemantic(Statement s, Scope* sc) { - version (DMDasLib) - if (onStatementSemanticStart) - onStatementSemanticStart(s, sc); + version (callback_API) + if (Compiler.onStatementSemanticStart) + Compiler.onStatementSemanticStart(s, sc); scope v = new StatementSemanticVisitor(sc); s.accept(v); - version (DMDasLib) - if (onStatementSemanticDone) - onStatementSemanticDone(s, sc); + version (callback_API) + if (Compiler.onStatementSemanticDone) + Compiler.onStatementSemanticDone(s, sc); return v.result; } From 8c0e490a306d50fbc13ee51b626bd07233f2b43e Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Thu, 14 May 2020 14:02:42 +0300 Subject: [PATCH 3/8] Changed delegate to function --- src/dmd/compiler.d | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dmd/compiler.d b/src/dmd/compiler.d index fbe608930a3a..17e6faca61f7 100644 --- a/src/dmd/compiler.d +++ b/src/dmd/compiler.d @@ -154,19 +154,19 @@ extern (C++) struct Compiler return false; // this import will not be compiled } - alias OnStatementSemanticStart = void delegate(Statement, Scope*); - alias OnStatementSemanticDone = void delegate(Statement, Scope*); + alias OnStatementSemanticStart = void function(Statement, Scope*); + alias OnStatementSemanticDone = void function(Statement, Scope*); /** - * Used to insert functionality before the start of the - * semantic analysis of a statement when importing DMD as a library - */ + * Used to insert functionality before the start of the + * semantic analysis of a statement when importing DMD as a library + */ __gshared OnStatementSemanticStart onStatementSemanticStart; /** - * Used to insert functionality after the end of the - * semantic analysis of a statement when importing DMD as a library - */ + * Used to insert functionality after the end of the + * semantic analysis of a statement when importing DMD as a library + */ __gshared OnStatementSemanticDone onStatementSemanticDone; } From 3133de6415ae7bdc3ce8e03c57df29c742bcd482 Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Thu, 28 May 2020 00:20:49 +0300 Subject: [PATCH 4/8] Added dub_package test and refactored mars.d --- src/dmd/compiler.d | 32 ++-- src/dmd/mars.d | 204 +++++++++++++---------- test/dub_package/retrieveScope.d | 232 +++++++++++++++++++++++++++ test/dub_package/testfiles/correct.d | 61 +++++++ 4 files changed, 425 insertions(+), 104 deletions(-) create mode 100755 test/dub_package/retrieveScope.d create mode 100644 test/dub_package/testfiles/correct.d diff --git a/src/dmd/compiler.d b/src/dmd/compiler.d index 17e6faca61f7..4e21c97be78c 100644 --- a/src/dmd/compiler.d +++ b/src/dmd/compiler.d @@ -154,21 +154,23 @@ extern (C++) struct Compiler return false; // this import will not be compiled } - alias OnStatementSemanticStart = void function(Statement, Scope*); - alias OnStatementSemanticDone = void function(Statement, Scope*); - - /** - * Used to insert functionality before the start of the - * semantic analysis of a statement when importing DMD as a library - */ - __gshared OnStatementSemanticStart onStatementSemanticStart; - - /** - * Used to insert functionality after the end of the - * semantic analysis of a statement when importing DMD as a library - */ - __gshared OnStatementSemanticDone onStatementSemanticDone; - + version (callback_API) + { + alias OnStatementSemanticStart = void function(Statement, Scope*); + alias OnStatementSemanticDone = void function(Statement, Scope*); + + /** + * Used to insert functionality before the start of the + * semantic analysis of a statement when importing DMD as a library + */ + __gshared OnStatementSemanticStart onStatementSemanticStart; + + /** + * Used to insert functionality after the end of the + * semantic analysis of a statement when importing DMD as a library + */ + __gshared OnStatementSemanticDone onStatementSemanticDone; + } } /****************************** diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 40274cbe265d..7772c3e254f0 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -2614,124 +2614,150 @@ private void reconcileCommands(ref Param params, size_t numSrcFiles) } /** -Creates the list of modules based on the files provided +Creates the module based on the file provided -Files are dispatched in the various arrays +The file is dispatched in one of the various arrays (global.params.{ddocfiles,dllfiles,jsonfiles,etc...}) -according to their extension. -Binary files are added to libmodules. +according to its extension. +If it is a binary file, it is added to libmodules. Params: - files = File names to dispatch + file = File name to dispatch libmodules = Array to which binaries (shared/static libs and object files) will be appended Returns: - An array of path to D modules + A D module */ -Modules createModules(ref Strings files, ref Strings libmodules) +Module createModule(const(char)* file, ref Strings libmodules) { - Modules modules; - modules.reserve(files.dim); - bool firstmodule = true; - for (size_t i = 0; i < files.dim; i++) + const(char)[] name; + version (Windows) { - const(char)[] name; - version (Windows) + file = toWinPath(file); + } + const(char)[] p = file.toDString(); + p = FileName.name(p); // strip path + const(char)[] ext = FileName.ext(p); + if (ext) + { + /* Deduce what to do with a file based on its extension + */ + if (FileName.equals(ext, global.obj_ext)) { - files[i] = toWinPath(files[i]); + global.params.objfiles.push(file); + libmodules.push(file); + return null; } - const(char)[] p = files[i].toDString(); - p = FileName.name(p); // strip path - const(char)[] ext = FileName.ext(p); - if (ext) + if (FileName.equals(ext, global.lib_ext)) { - /* Deduce what to do with a file based on its extension - */ - if (FileName.equals(ext, global.obj_ext)) - { - global.params.objfiles.push(files[i]); - libmodules.push(files[i]); - continue; - } - if (FileName.equals(ext, global.lib_ext)) - { - global.params.libfiles.push(files[i]); - libmodules.push(files[i]); - continue; - } - static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) + global.params.libfiles.push(file); + libmodules.push(file); + return null; + } + static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) + { + if (FileName.equals(ext, global.dll_ext)) { - if (FileName.equals(ext, global.dll_ext)) - { - global.params.dllfiles.push(files[i]); - libmodules.push(files[i]); - continue; - } + global.params.dllfiles.push(file); + libmodules.push(file); + return null; } - if (ext == global.ddoc_ext) + } + if (ext == global.ddoc_ext) + { + global.params.ddocfiles.push(file); + return null; + } + if (FileName.equals(ext, global.json_ext)) + { + global.params.doJsonGeneration = true; + global.params.jsonfilename = file.toDString; + return null; + } + if (FileName.equals(ext, global.map_ext)) + { + global.params.mapfile = file.toDString; + return null; + } + static if (TARGET.Windows) + { + if (FileName.equals(ext, "res")) { - global.params.ddocfiles.push(files[i]); - continue; + global.params.resfile = file.toDString; + return null; } - if (FileName.equals(ext, global.json_ext)) + if (FileName.equals(ext, "def")) { - global.params.doJsonGeneration = true; - global.params.jsonfilename = files[i].toDString; - continue; + global.params.deffile = file.toDString; + return null; } - if (FileName.equals(ext, global.map_ext)) + if (FileName.equals(ext, "exe")) { - global.params.mapfile = files[i].toDString; - continue; + assert(0); // should have already been handled } - static if (TARGET.Windows) - { - if (FileName.equals(ext, "res")) - { - global.params.resfile = files[i].toDString; - continue; - } - if (FileName.equals(ext, "def")) - { - global.params.deffile = files[i].toDString; - continue; - } - if (FileName.equals(ext, "exe")) - { - assert(0); // should have already been handled - } - } - /* Examine extension to see if it is a valid - * D source file extension - */ - if (FileName.equals(ext, global.mars_ext) || FileName.equals(ext, global.hdr_ext) || FileName.equals(ext, "dd")) - { - name = FileName.removeExt(p); - if (!name.length || name == ".." || name == ".") - { - Linvalid: - error(Loc.initial, "invalid file name '%s'", files[i]); - fatal(); - } - } - else + } + /* Examine extension to see if it is a valid + * D source file extension + */ + if (FileName.equals(ext, global.mars_ext) || FileName.equals(ext, global.hdr_ext) || FileName.equals(ext, "dd")) + { + name = FileName.removeExt(p); + if (!name.length || name == ".." || name == ".") { - error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); + Linvalid: + error(Loc.initial, "invalid file name '%s'", file); fatal(); } } else { - name = p; - if (!name.length) - goto Linvalid; + error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); + fatal(); } - /* At this point, name is the D source file name stripped of - * its path and extension. - */ - auto id = Identifier.idPool(name); - auto m = new Module(files[i].toDString, id, global.params.doDocComments, global.params.doHdrGeneration); + } + else + { + name = p; + if (!name.length) + goto Linvalid; + } + /* At this point, name is the D source file name stripped of + * its path and extension. + */ + auto id = Identifier.idPool(name); + + return new Module(file.toDString, id, global.params.doDocComments, global.params.doHdrGeneration); +} + +/** +Creates the list of modules based on the files provided + +Files are dispatched in the various arrays +(global.params.{ddocfiles,dllfiles,jsonfiles,etc...}) +according to their extension. +Binary files are added to libmodules. + +Params: + files = File names to dispatch + libmodules = Array to which binaries (shared/static libs and object files) + will be appended + +Returns: + An array of path to D modules +*/ +Modules createModules(ref Strings files, ref Strings libmodules) +{ + Modules modules; + modules.reserve(files.dim); + bool firstmodule = true; + for (size_t i = 0; i < files.dim; i++) + { + auto m = createModule(files[i], libmodules); + + if (m is null) + continue; + modules.push(m); if (firstmodule) { diff --git a/test/dub_package/retrieveScope.d b/test/dub_package/retrieveScope.d new file mode 100755 index 000000000000..9b401a15243f --- /dev/null +++ b/test/dub_package/retrieveScope.d @@ -0,0 +1,232 @@ +#!/usr/bin/env dub +/+dub.sdl: +dependency "dmd" path="../.." +versions "callback_API" ++/ +/* + * This file contains an example of how to retrieve the scope of a statement. + * First, the callback system is used. This, however, will not work for fields + * of structs or classes, which is why the visitor will cover this corner case + */ + +import core.stdc.stdarg; + +import std.conv; +import std.string; +import std.algorithm.sorting; +import std.algorithm.mutation : SwapStrategy; + +import dmd.errors; +import dmd.frontend; +import dmd.mars; +import dmd.console; +import dmd.arraytypes; +import dmd.compiler; +import dmd.dmodule; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.semantic2; +import dmd.semantic3; +import dmd.statement; +import dmd.visitor; +import dmd.dscope; +import dmd.denum; +import dmd.nspace; +import dmd.dstruct; +import dmd.dclass; +import dmd.globals; + +import std.stdio : writeln; + +private bool isBefore(Loc loc1, Loc loc2) +{ + return loc1.linnum != loc2.linnum? loc1.linnum < loc2.linnum + : loc1.charnum < loc2.charnum; +} + +private struct CallbackHelper { + static Loc cursorLoc; + static Scope *scp; + + static extern (C++) void statementSem(Statement s, Scope *sc) { + if (s.loc.linnum == cursorLoc.linnum) { + sc.setNoFree(); + scp = sc; + } + } +}; + +int main() +{ + string dirName(string path, char separator) + { + for (size_t i = path.length - 1; i > 0; i--) + { + if (path[i] == separator) + return path[0..i]; + } + return path; + } + + version (Windows) + enum dmdParentDir = dirName(dirName(dirName(__FILE_FULL_PATH__, '\\'), '\\'), '\\'); + else + enum dmdParentDir = dirName(dirName(dirName(__FILE_FULL_PATH__, '/'), '/'), '/'); + global.path = new Strings(); + global.path.push(dmdParentDir ~ "/phobos"); + global.path.push(dmdParentDir ~ "/druntime/import"); + + /* comment for error output in parsing & semantic */ + diagnosticHandler = (const ref Loc location, + Color headerColor, + const(char)* header, + const(char)* messageFormat, + va_list args, + const(char)* prefix1, + const(char)* prefix2) => true; + global.gag = 1; + initDMD(diagnosticHandler); + + Strings libmodules; + Module m = createModule("testfiles/correct.d", libmodules); + m.importedFrom = m; // m.isRoot() == true + + m.read(Loc.initial); + m.parse(); + + CallbackHelper.cursorLoc = Loc(null, 22, 10); + + Compiler.onStatementSemanticStart = &CallbackHelper.statementSem; + + m.importAll(null); + + // semantic + m.dsymbolSemantic(null); + + Module.dprogress = 1; + Module.runDeferredSemantic(); + + m.semantic2(null); + Module.runDeferredSemantic2(); + + m.semantic3(null); + Module.runDeferredSemantic3(); + + + Dsymbol[] symbols; + + // if scope could not be retrieved through the callback, then traverse AST + if (!CallbackHelper.scp) { + auto visitor = new DsymbolsScopeRetrievingVisitor(CallbackHelper.cursorLoc); + m.accept(visitor); + + symbols = visitor.symbols; + } + + while (CallbackHelper.scp) { + if (CallbackHelper.scp.scopesym && CallbackHelper.scp.scopesym.symtab) + foreach (x; CallbackHelper.scp.scopesym.symtab.tab.asRange()) { + symbols ~= x.value; + } + CallbackHelper.scp = CallbackHelper.scp.enclosing; + } + + sort!("to!string(a.ident) < to!string(b.ident)", SwapStrategy.stable)(symbols); + + foreach (sym; symbols) { + writeln(sym.ident); + } + + deinitializeDMD(); + + return 0; +} + +private extern (C++) final class DsymbolsScopeRetrievingVisitor : Visitor +{ + Loc loc; + Dsymbol[] symbols; + alias visit = Visitor.visit; + +public: + extern (D) this(Loc loc) + { + this.loc = loc; + } + + override void visit(Dsymbol s) + { + } + + override void visit(ScopeDsymbol s) + { + visitScopeDsymbol(s); + } + + override void visit(EnumDeclaration d) + { + visitScopeDsymbol(d); + } + + override void visit(Nspace d) + { + visitScopeDsymbol(d); + } + + override void visit(StructDeclaration d) + { + visitScopeDsymbol(d); + } + + override void visit(ClassDeclaration d) + { + visitScopeDsymbol(d); + } + + void visitBaseClasses(ClassDeclaration d) + { + visitScopeDsymbol(d); + } + + override void visit(Module m) + { + visitScopeDsymbol(m); + } + + private void visitScopeDsymbol(ScopeDsymbol scopeDsym) + { + if (!scopeDsym.members) + return; + + Dsymbol dsym; + foreach (i, s; *scopeDsym.members) + { + if (s is null || s.ident is null) + continue; + + // if the current symbol is from another module + if (auto m = scopeDsym.isModule()) + if (!(to!string(s.loc.filename).endsWith(m.ident.toString() ~ ".d"))) + continue; + + if (!s.isImport()) + symbols ~= s; + + if (!i || dsym is null) { + dsym = s; + continue; + } + + // only visit a symbol which contains the cursor + // choose the symbol which is before and the closest to the cursor + if (isBefore(dsym.loc, loc) + && isBefore(dsym.loc, s.loc) + && isBefore(s.loc, loc)) { + dsym = s; + } + } + + dsym.accept(this); + } +} + diff --git a/test/dub_package/testfiles/correct.d b/test/dub_package/testfiles/correct.d new file mode 100644 index 000000000000..f96c038a7c01 --- /dev/null +++ b/test/dub_package/testfiles/correct.d @@ -0,0 +1,61 @@ +module correct; +dafaenfai; +int[] g; + +struct Foo { + int a; + + void b() { + + } + + struct Bar { + int c; + } +} + +/** + * Params: + * x = something cool + */ +int foo(int x) { + int a = 0; + + if (a == 1) { + int b, c, d; + } + + for (int i = 0; i < 10; ++i) { + int e; + int j; + + e = 7; + } + + while (0) { + int f = 5; + } + + foreach(k; 0..3) { + int g; + + g = 2; + } + + int z = a; + + return 0; +} + +int main(string[] args) { + int y = 0; + int x = 1; + int xx = 2; + int yy = 0; + int k = xx; + + return 0; +} + +int bar() {return 0;} + From c1bec70e8f437593216ffa39e1526e4901196a20 Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Thu, 28 May 2020 00:46:09 +0300 Subject: [PATCH 5/8] Added version callback_API to dub.sdl --- dub.sdl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dub.sdl b/dub.sdl index e0c9d98f7507..b1e1a00be072 100644 --- a/dub.sdl +++ b/dub.sdl @@ -31,6 +31,8 @@ subPackage { "src/dmd/utf.d" \ "src/dmd/utils.d" + versions "callback_API" + preGenerateCommands ` "$${DUB_EXE}" \ --arch=$${DUB_ARCH} \ @@ -60,6 +62,8 @@ subPackage { "src/dmd/permissivevisitor.d" \ "src/dmd/strictvisitor.d" + versions "callback_API" + dependency "dmd:lexer" version="*" } @@ -73,7 +77,8 @@ subPackage { "NoBackend" \ "GC" \ "NoMain" \ - "MARS" + "MARS" \ + "callback_API" excludedSourceFiles "src/dmd/backend/*" excludedSourceFiles "src/dmd/root/*" From d49409a12c1c2821d83282e6808185ef85f59400 Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Thu, 28 May 2020 22:17:28 +0300 Subject: [PATCH 6/8] Changed callback_API to CallbackAPI and slightly changed test --- dub.sdl | 6 +++--- src/dmd/compiler.d | 8 +++++--- src/dmd/statementsem.d | 10 ++++------ test/dub_package/retrieveScope.d | 22 +++++----------------- 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/dub.sdl b/dub.sdl index b1e1a00be072..e0c685012379 100644 --- a/dub.sdl +++ b/dub.sdl @@ -31,7 +31,7 @@ subPackage { "src/dmd/utf.d" \ "src/dmd/utils.d" - versions "callback_API" + versions "CallbackAPI" preGenerateCommands ` "$${DUB_EXE}" \ @@ -62,7 +62,7 @@ subPackage { "src/dmd/permissivevisitor.d" \ "src/dmd/strictvisitor.d" - versions "callback_API" + versions "CallbackAPI" dependency "dmd:lexer" version="*" } @@ -78,7 +78,7 @@ subPackage { "GC" \ "NoMain" \ "MARS" \ - "callback_API" + "CallbackAPI" excludedSourceFiles "src/dmd/backend/*" excludedSourceFiles "src/dmd/root/*" diff --git a/src/dmd/compiler.d b/src/dmd/compiler.d index 4e21c97be78c..360a2935c837 100644 --- a/src/dmd/compiler.d +++ b/src/dmd/compiler.d @@ -154,7 +154,7 @@ extern (C++) struct Compiler return false; // this import will not be compiled } - version (callback_API) + version (CallbackAPI) { alias OnStatementSemanticStart = void function(Statement, Scope*); alias OnStatementSemanticDone = void function(Statement, Scope*); @@ -163,13 +163,15 @@ extern (C++) struct Compiler * Used to insert functionality before the start of the * semantic analysis of a statement when importing DMD as a library */ - __gshared OnStatementSemanticStart onStatementSemanticStart; + __gshared OnStatementSemanticStart onStatementSemanticStart + = function void(Statement s, Scope *sc) {}; /** * Used to insert functionality after the end of the * semantic analysis of a statement when importing DMD as a library */ - __gshared OnStatementSemanticDone onStatementSemanticDone; + __gshared OnStatementSemanticDone onStatementSemanticDone + = function void(Statement s, Scope *sc) {}; } } diff --git a/src/dmd/statementsem.d b/src/dmd/statementsem.d index 68097e606982..f625d6e892e1 100644 --- a/src/dmd/statementsem.d +++ b/src/dmd/statementsem.d @@ -124,16 +124,14 @@ private Expression checkAssignmentAsCondition(Expression e) // Performs semantic analysis in Statement AST nodes extern(C++) Statement statementSemantic(Statement s, Scope* sc) { - version (callback_API) - if (Compiler.onStatementSemanticStart) - Compiler.onStatementSemanticStart(s, sc); + version (CallbackAPI) + Compiler.onStatementSemanticStart(s, sc); scope v = new StatementSemanticVisitor(sc); s.accept(v); - version (callback_API) - if (Compiler.onStatementSemanticDone) - Compiler.onStatementSemanticDone(s, sc); + version (CallbackAPI) + Compiler.onStatementSemanticDone(s, sc); return v.result; } diff --git a/test/dub_package/retrieveScope.d b/test/dub_package/retrieveScope.d index 9b401a15243f..54db3464cc8a 100755 --- a/test/dub_package/retrieveScope.d +++ b/test/dub_package/retrieveScope.d @@ -1,7 +1,7 @@ #!/usr/bin/env dub /+dub.sdl: dependency "dmd" path="../.." -versions "callback_API" +versions "CallbackAPI" +/ /* * This file contains an example of how to retrieve the scope of a statement. @@ -15,6 +15,7 @@ import std.conv; import std.string; import std.algorithm.sorting; import std.algorithm.mutation : SwapStrategy; +import std.path : dirName; import dmd.errors; import dmd.frontend; @@ -58,23 +59,10 @@ private struct CallbackHelper { int main() { - string dirName(string path, char separator) - { - for (size_t i = path.length - 1; i > 0; i--) - { - if (path[i] == separator) - return path[0..i]; - } - return path; - } - - version (Windows) - enum dmdParentDir = dirName(dirName(dirName(__FILE_FULL_PATH__, '\\'), '\\'), '\\'); - else - enum dmdParentDir = dirName(dirName(dirName(__FILE_FULL_PATH__, '/'), '/'), '/'); + auto dmdParentDir = dirName(dirName(dirName(__FILE_FULL_PATH__))); global.path = new Strings(); - global.path.push(dmdParentDir ~ "/phobos"); - global.path.push(dmdParentDir ~ "/druntime/import"); + global.path.push((dmdParentDir ~ "/phobos").ptr); + global.path.push((dmdParentDir ~ "/druntime/import").ptr); /* comment for error output in parsing & semantic */ diagnosticHandler = (const ref Loc location, From 3844afb3310849c0b6287d3aa87b4d07dbf853bf Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Fri, 29 May 2020 01:06:06 +0300 Subject: [PATCH 7/8] Fixed bug in test --- test/dub_package/retrieveScope.d | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/dub_package/retrieveScope.d b/test/dub_package/retrieveScope.d index 54db3464cc8a..53749ebe03c0 100755 --- a/test/dub_package/retrieveScope.d +++ b/test/dub_package/retrieveScope.d @@ -10,6 +10,7 @@ versions "CallbackAPI" */ import core.stdc.stdarg; +import core.stdc.string; import std.conv; import std.string; @@ -50,7 +51,8 @@ private struct CallbackHelper { static Scope *scp; static extern (C++) void statementSem(Statement s, Scope *sc) { - if (s.loc.linnum == cursorLoc.linnum) { + if (s.loc.linnum == cursorLoc.linnum + && strcmp(s.loc.filename, cursorLoc.filename) == 0) { sc.setNoFree(); scp = sc; } @@ -76,13 +78,14 @@ int main() initDMD(diagnosticHandler); Strings libmodules; - Module m = createModule("testfiles/correct.d", libmodules); + Module m = createModule((dirName(__FILE_FULL_PATH__) ~ "/testfiles/correct.d").ptr, + libmodules); m.importedFrom = m; // m.isRoot() == true m.read(Loc.initial); m.parse(); - CallbackHelper.cursorLoc = Loc(null, 22, 10); + CallbackHelper.cursorLoc = Loc(to!string(m.srcfile).ptr, 22, 10); Compiler.onStatementSemanticStart = &CallbackHelper.statementSem; From c2acfb08fbef0f3deffad673b85896351b75312e Mon Sep 17 00:00:00 2001 From: Cristian Creteanu Date: Fri, 5 Jun 2020 00:09:22 +0300 Subject: [PATCH 8/8] Changed the order of if branches in createModule --- src/dmd/mars.d | 124 +++++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 7772c3e254f0..85c4b6a7985e 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -2639,89 +2639,91 @@ Module createModule(const(char)* file, ref Strings libmodules) const(char)[] p = file.toDString(); p = FileName.name(p); // strip path const(char)[] ext = FileName.ext(p); - if (ext) + if (!ext) { - /* Deduce what to do with a file based on its extension - */ - if (FileName.equals(ext, global.obj_ext)) + if (!p.length) { - global.params.objfiles.push(file); - libmodules.push(file); - return null; + error(Loc.initial, "invalid file name '%s'", file); + fatal(); } - if (FileName.equals(ext, global.lib_ext)) + auto id = Identifier.idPool(p); + return new Module(file.toDString, id, global.params.doDocComments, global.params.doHdrGeneration); + } + + /* Deduce what to do with a file based on its extension + */ + if (FileName.equals(ext, global.obj_ext)) + { + global.params.objfiles.push(file); + libmodules.push(file); + return null; + } + if (FileName.equals(ext, global.lib_ext)) + { + global.params.libfiles.push(file); + libmodules.push(file); + return null; + } + static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) + { + if (FileName.equals(ext, global.dll_ext)) { - global.params.libfiles.push(file); + global.params.dllfiles.push(file); libmodules.push(file); return null; } - static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) - { - if (FileName.equals(ext, global.dll_ext)) - { - global.params.dllfiles.push(file); - libmodules.push(file); - return null; - } - } - if (ext == global.ddoc_ext) - { - global.params.ddocfiles.push(file); - return null; - } - if (FileName.equals(ext, global.json_ext)) + } + if (ext == global.ddoc_ext) + { + global.params.ddocfiles.push(file); + return null; + } + if (FileName.equals(ext, global.json_ext)) + { + global.params.doJsonGeneration = true; + global.params.jsonfilename = file.toDString; + return null; + } + if (FileName.equals(ext, global.map_ext)) + { + global.params.mapfile = file.toDString; + return null; + } + static if (TARGET.Windows) + { + if (FileName.equals(ext, "res")) { - global.params.doJsonGeneration = true; - global.params.jsonfilename = file.toDString; + global.params.resfile = file.toDString; return null; } - if (FileName.equals(ext, global.map_ext)) + if (FileName.equals(ext, "def")) { - global.params.mapfile = file.toDString; + global.params.deffile = file.toDString; return null; } - static if (TARGET.Windows) - { - if (FileName.equals(ext, "res")) - { - global.params.resfile = file.toDString; - return null; - } - if (FileName.equals(ext, "def")) - { - global.params.deffile = file.toDString; - return null; - } - if (FileName.equals(ext, "exe")) - { - assert(0); // should have already been handled - } - } - /* Examine extension to see if it is a valid - * D source file extension - */ - if (FileName.equals(ext, global.mars_ext) || FileName.equals(ext, global.hdr_ext) || FileName.equals(ext, "dd")) + if (FileName.equals(ext, "exe")) { - name = FileName.removeExt(p); - if (!name.length || name == ".." || name == ".") - { - Linvalid: - error(Loc.initial, "invalid file name '%s'", file); - fatal(); - } + assert(0); // should have already been handled } - else + } + /* Examine extension to see if it is a valid + * D source file extension + */ + if (FileName.equals(ext, global.mars_ext) || FileName.equals(ext, global.hdr_ext) || FileName.equals(ext, "dd")) + { + name = FileName.removeExt(p); + if (!name.length || name == ".." || name == ".") { - error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); + error(Loc.initial, "invalid file name '%s'", file); fatal(); } } else { - name = p; - if (!name.length) - goto Linvalid; + error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); + fatal(); } + /* At this point, name is the D source file name stripped of * its path and extension. */