1 module localimport; 2 3 /** 4 * Check if string can be used as a straight module import. 5 */ 6 private template IsModuleImport(string import_) { 7 enum IsModuleImport = __traits(compiles, { mixin("import ", import_, ";"); }); 8 } 9 10 /** 11 * Check if the requested symbol is found in the specified module. 12 */ 13 private template IsSymbolInModule(string module_, string symbol) { 14 static if (IsModuleImport!module_) { 15 enum import_ = module_ ~ ":" ~ symbol; 16 enum IsSymbolInModule = __traits(compiles, { 17 mixin("import ", import_, ";"); 18 }); 19 } else { 20 enum IsSymbolInModule = false; 21 } 22 } 23 24 /** 25 * Used to generate useful error messages. 26 */ 27 private template failedSymbol(string symbol, string module_) { 28 void failedSymbol(Args...)(auto ref Args args) { 29 throw new Exception("Symbol \"" ~ symbol ~ "\" not found in " ~ module_); 30 } 31 } 32 33 /** 34 * Here the magic happens. 35 * Recursively descends along the dots in usage until it can resolve an imported 36 * module or symbol from module or reaches the end of the dot chain. 37 */ 38 private struct FromImpl(string module_) { 39 // opDispatch handles access to missing members of an object. 40 template opDispatch(string symbol) { 41 // statically check if symbol is in given module 42 static if (IsSymbolInModule!(module_, symbol)) { 43 // Symbol import: emit module import and alias opDispatch to 44 // the symbol. 45 mixin("import ", module_, "; alias opDispatch = ", symbol, ";"); 46 } else { // symbol not in module 47 static if (module_.length == 0) { 48 // module string is of zero length, import of a top level module. 49 enum opDispatch = FromImpl!(symbol)(); 50 } else { 51 // Check if we have a full module import. 52 enum import_ = module_ ~ "." ~ symbol; 53 static if (IsModuleImport!import_) { 54 // full module import 55 enum opDispatch = FromImpl!(import_)(); 56 } else { 57 // failed symbol import as well as full module import and 58 // the last symbol is of nonzero length. 59 // -> resolution failed! 60 alias opDispatch = failedSymbol!(symbol, module_); 61 } 62 } 63 } 64 } 65 } 66 67 /** 68 * Used as entry point for local imports. 69 */ 70 enum from = FromImpl!null(); 71 72 /** 73 * Test things that should work. 74 */ 75 unittest { 76 // use a function from standard library directly. 77 from.std.stdio.writeln("Hallo"); 78 // assign something from standard library to a local variable. 79 auto _ = from.std.datetime.stopwatch.AutoStart.yes; 80 } 81 82 /** 83 * Test things that should not work. 84 */ 85 unittest { 86 auto throws = false; 87 try { 88 from.std.stdio.thisFunctionDoesNotExist("Hallo"); 89 } catch (Exception ex) { 90 throws = true; 91 } 92 try { 93 from.std.stdio.thisFunctionDoesNotExist(42); 94 throws = false; 95 } catch (Exception ex) { 96 throws = true; 97 } 98 99 assert(throws); 100 101 }