From d5d59de27b9d27649694e3fdca2737ca923550be Mon Sep 17 00:00:00 2001 From: William Blevins Date: Thu, 11 Aug 2016 18:02:10 +0100 Subject: Issue 1924: Updated D Language scanner support. Meets DLang specification 2.071.1 accessed 11 August 2016. URL: https://dlang.org/spec/module.html ImportDeclaration: import ImportList ; static import ImportList ; ImportList: Import ImportBindings Import , ImportList Import: ModuleFullyQualifiedName ModuleAliasIdentifier = ModuleFullyQualifiedName ImportBindings: Import : ImportBindList ImportBindList: ImportBind ImportBind , ImportBindList ImportBind: Identifier Identifier = Identifier ModuleAliasIdentifier: Identifier --- src/engine/SCons/Scanner/D.py | 16 +-- src/engine/SCons/Scanner/DTests.py | 271 +++++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+), 8 deletions(-) create mode 100644 src/engine/SCons/Scanner/DTests.py diff --git a/src/engine/SCons/Scanner/D.py b/src/engine/SCons/Scanner/D.py index 9402ed1..95496d5 100644 --- a/src/engine/SCons/Scanner/D.py +++ b/src/engine/SCons/Scanner/D.py @@ -32,8 +32,6 @@ Coded by Andy Friesen __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import re - import SCons.Scanner def DScanner(): @@ -43,13 +41,13 @@ def DScanner(): class D(SCons.Scanner.Classic): def __init__ (self): - SCons.Scanner.Classic.__init__ (self, + SCons.Scanner.Classic.__init__ ( + self, name = "DScanner", suffixes = '$DSUFFIXES', path_variable = 'DPATH', - regex = 'import\s+(?:[a-zA-Z0-9_.]+)\s*(?:,\s*(?:[a-zA-Z0-9_.]+)\s*)*;') - - self.cre2 = re.compile ('(?:import\s)?\s*([a-zA-Z0-9_.]+)\s*(?:,|;)', re.M) + regex = '(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)' + ) def find_include(self, include, source_dir, path): # translate dots (package separators) to slashes @@ -62,8 +60,10 @@ class D(SCons.Scanner.Classic): def find_include_names(self, node): includes = [] - for i in self.cre.findall(node.get_text_contents()): - includes = includes + self.cre2.findall(i) + for iii in self.cre.findall(node.get_text_contents()): + for jjj in iii.split(','): + kkk = jjj.split('=')[-1] + includes.append(kkk.strip()) return includes # Local Variables: diff --git a/src/engine/SCons/Scanner/DTests.py b/src/engine/SCons/Scanner/DTests.py new file mode 100644 index 0000000..c644e95 --- /dev/null +++ b/src/engine/SCons/Scanner/DTests.py @@ -0,0 +1,271 @@ +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import unittest + +import TestCmd +import TestUnit + +import SCons.Scanner.D + +test = TestCmd.TestCmd(workdir = '') + +import collections +import os + +class DummyEnvironment(collections.UserDict): + def __init__(self, **kw): + collections.UserDict.__init__(self) + self.data.update(kw) + self.fs = SCons.Node.FS.FS(test.workpath('')) + + def Dictionary(self, *args): + return self.data + + def subst(self, strSubst, target=None, source=None, conv=None): + if strSubst[0] == '$': + return self.data[strSubst[1:]] + return strSubst + + def subst_list(self, strSubst, target=None, source=None, conv=None): + if strSubst[0] == '$': + return [self.data[strSubst[1:]]] + return [[strSubst]] + + def subst_path(self, path, target=None, source=None, conv=None): + if not isinstance(path, list): + path = [path] + return list(map(self.subst, path)) + + def get_calculator(self): + return None + + def get_factory(self, factory): + return factory or self.fs.File + + def Dir(self, filename): + return self.fs.Dir(filename) + + def File(self, filename): + return self.fs.File(filename) + +if os.path.normcase('foo') == os.path.normcase('FOO'): + my_normpath = os.path.normcase +else: + my_normpath = os.path.normpath + +def deps_match(self, deps, headers): + global my_normpath + scanned = list(map(my_normpath, list(map(str, deps)))) + expect = list(map(my_normpath, headers)) + self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned)) + +""" +Examples from https://dlang.org/spec/module.html + +D Language: 2.071.1 +Accessed: 11 August 2016 +""" + +# Regular import +test.write('basic.d',""" +import A; + +void main() {} +""") + +# Static import +test.write('static.d',""" +static import A; + +void main() +{ + std.stdio.writeln("hello!"); // ok, writeln is fully qualified +} +""") + +# Public import +test.write('public.d',""" +public import A; + +void main() {} +""") + +# Renamed import +test.write('rename.d',""" +import B = A; + +void main() +{ + io.writeln("hello!"); // ok, calls std.stdio.writeln +} +""") + +# Selective import +test.write('selective.d',""" +import A : B, C = D; + +void main() +{ + writeln("hello!"); // ok, writeln bound into current namespace + foo("world"); // ok, calls std.stdio.write() +} +""") + +# Renamed and Selective import +test.write('renameAndSelective.d',""" +import B = A : C = D; + +void main() +{ +} +""") + +# Scoped import +test.write('scoped.d',""" +void main() +{ + import A; +} +""") + +# Combinatorial import +test.write('combinatorial.d',""" +import A, B, CCC = C, DDD = D : EEE = FFF; + +void main() +{ +} +""") + +# Subdirs import +test.write('subdirs.d',""" +import X.Y, X.Z, X.X.X; + +void main() {} +""") + +# Multiple import +test.write('multiple.d',""" +public import B; +static import C; + +import X = X.Y : Q, R, S, T = U; +void main() +{ + import A; +} +""") + +test.write('A.d',""" +module A; +void main() {} +""") + +test.write('B.d',""" +module B; +void main() {} +""") + +test.write('C.d',""" +module C; +void main() {} +""") + +test.write('D.d',""" +module D; +void main() {} +""") + +test.subdir('X', os.path.join('X','X')) + +test.write(os.path.join('X','Y.d'),""" +module Y; +void main() {} +""") + +test.write(os.path.join('X','Z.d'),""" +module Z; +void main() {} +""") + +test.write(os.path.join('X','X','X.d'),""" +module X; +void main() {} +""") + +class DScannerTestCase(unittest.TestCase): + def helper(self, filename, headers): + env = DummyEnvironment() + s = SCons.Scanner.D.DScanner() + path = s.path(env) + deps = s(env.File(filename), env, path) + deps_match(self, deps, headers) + + def test_BasicImport(self): + self.helper('basic.d', ['A.d']) + + def test_StaticImport(self): + self.helper('static.d', ['A.d']) + + def test_publicImport(self): + self.helper('public.d', ['A.d']) + + def test_RenameImport(self): + self.helper('rename.d', ['A.d']) + + def test_SelectiveImport(self): + self.helper('selective.d', ['A.d']) + + def test_RenameAndSelectiveImport(self): + self.helper('renameAndSelective.d', ['A.d']) + + def test_ScopedImport(self): + self.helper('scoped.d', ['A.d']) + + def test_CombinatorialImport(self): + self.helper('combinatorial.d', ['A.d', 'B.d', 'C.d', 'D.d']) + + def test_SubdirsImport(self): + self.helper('subdirs.d', [os.path.join('X','X','X.d'), os.path.join('X','Y.d'), os.path.join('X','Z.d')]) + + def test_MultipleImport(self): + self.helper('multiple.d', ['A.d', 'B.d', 'C.d', os.path.join('X','Y.d')]) + +if __name__ == "__main__": + suite = unittest.TestSuite() + tclasses = [ + DScannerTestCase, + ] + for tclass in tclasses: + names = unittest.getTestCaseNames(tclass, 'test_') + suite.addTests(list(map(tclass, names))) + TestUnit.run(suite) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: -- cgit v0.12 From 4daf33934df9ae29e01037ab4646bcbae80a5e2d Mon Sep 17 00:00:00 2001 From: William Blevins Date: Thu, 11 Aug 2016 18:29:45 +0100 Subject: Updated CHANGES.txt --- src/CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index db52cf0..28343a6 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -25,6 +25,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Added LoadableModule to the list of global functions (DefaultEnvironment builders). + From William Blevins: + - Updated D language scanner support to latest: 2.071.1. (PR #1924) + https://dlang.org/spec/module.html accessed 11 August 2016 + RELEASE 2.5.0 - Mon, 09 Apr 2016 11:27:42 -0700 From Dirk Baechle: -- cgit v0.12 From 65ff75bf1a44beaa4961af9ef6379c84aeb63a62 Mon Sep 17 00:00:00 2001 From: William Blevins Date: Fri, 12 Aug 2016 16:05:28 +0100 Subject: Added multiline support test. --- src/engine/SCons/Scanner/DTests.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/engine/SCons/Scanner/DTests.py b/src/engine/SCons/Scanner/DTests.py index c644e95..805508d 100644 --- a/src/engine/SCons/Scanner/DTests.py +++ b/src/engine/SCons/Scanner/DTests.py @@ -179,6 +179,14 @@ void main() } """) +# Multiline import +test.write('multiline.d',""" +import +A; + +void main() {} +""") + test.write('A.d',""" module A; void main() {} @@ -254,6 +262,9 @@ class DScannerTestCase(unittest.TestCase): def test_MultipleImport(self): self.helper('multiple.d', ['A.d', 'B.d', 'C.d', os.path.join('X','Y.d')]) + def test_MultilineImport(self): + self.helper('multiline.d', ['A.d']) + if __name__ == "__main__": suite = unittest.TestSuite() tclasses = [ -- cgit v0.12 From 05f53e20938706a5bfbff65c82d4820374daa829 Mon Sep 17 00:00:00 2001 From: William Blevins Date: Fri, 12 Aug 2016 16:10:40 +0100 Subject: Updated change notes to be explicit with regards to selective and renamed imports support. --- src/CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 28343a6..09271f5 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -28,6 +28,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER From William Blevins: - Updated D language scanner support to latest: 2.071.1. (PR #1924) https://dlang.org/spec/module.html accessed 11 August 2016 + - Added support for selective imports. + - Added support for renamed imports. RELEASE 2.5.0 - Mon, 09 Apr 2016 11:27:42 -0700 -- cgit v0.12 From 70fd8bc246d6453d3da36cbd69f563a59b63c487 Mon Sep 17 00:00:00 2001 From: William Blevins Date: Fri, 12 Aug 2016 16:25:46 +0100 Subject: Added change disclaimer of possible rebuild in Dlang projects after upgrade. --- src/CHANGES.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 09271f5..80ffc6b 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -28,8 +28,12 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER From William Blevins: - Updated D language scanner support to latest: 2.071.1. (PR #1924) https://dlang.org/spec/module.html accessed 11 August 2016 - - Added support for selective imports. - - Added support for renamed imports. + - Enhancements: + - Added support for selective imports. + - Added support for renamed imports. + - Notes: + - May find new (previously missed) Dlang dependencies. + - May cause rebuild after upgrade due to dependency changes. RELEASE 2.5.0 - Mon, 09 Apr 2016 11:27:42 -0700 -- cgit v0.12 From 944226d3beb4b158e4e55b577f46d99e63ca41f8 Mon Sep 17 00:00:00 2001 From: William Blevins Date: Fri, 12 Aug 2016 16:35:48 +0100 Subject: Updated selective test to remove impurity from a selection rename. --- src/engine/SCons/Scanner/DTests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/SCons/Scanner/DTests.py b/src/engine/SCons/Scanner/DTests.py index 805508d..51e527a 100644 --- a/src/engine/SCons/Scanner/DTests.py +++ b/src/engine/SCons/Scanner/DTests.py @@ -125,7 +125,7 @@ void main() # Selective import test.write('selective.d',""" -import A : B, C = D; +import A : B, C; void main() { -- cgit v0.12 From 59d3af904b80f672a3719653e30cff72f1a7a44c Mon Sep 17 00:00:00 2001 From: William Blevins Date: Sat, 13 Aug 2016 20:48:31 +0100 Subject: Added additional support examples to the changes.txt. --- src/CHANGES.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 80ffc6b..648027b 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -29,8 +29,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Updated D language scanner support to latest: 2.071.1. (PR #1924) https://dlang.org/spec/module.html accessed 11 August 2016 - Enhancements: - - Added support for selective imports. - - Added support for renamed imports. + - Added support for selective imports: "import A : B, C;" -> A + - Added support for renamed imports. "import B = A;" -> A + - Supports valid combinations: "A, B, CCC = C, DDD = D : EEE = FFF;" -> A, B, C, D - Notes: - May find new (previously missed) Dlang dependencies. - May cause rebuild after upgrade due to dependency changes. -- cgit v0.12 From 52815bb68d058b12288a4f05fc3b7051d520a89c Mon Sep 17 00:00:00 2001 From: William Blevins Date: Sat, 13 Aug 2016 20:58:53 +0100 Subject: Updated example text for clarity. --- src/CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 648027b..f032d93 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -31,7 +31,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - Enhancements: - Added support for selective imports: "import A : B, C;" -> A - Added support for renamed imports. "import B = A;" -> A - - Supports valid combinations: "A, B, CCC = C, DDD = D : EEE = FFF;" -> A, B, C, D + - Supports valid combinations: "import A, B, CCC = C, DDD = D : EEE = FFF;" -> A, B, C, D - Notes: - May find new (previously missed) Dlang dependencies. - May cause rebuild after upgrade due to dependency changes. -- cgit v0.12