1 // SDLang-D 2 // Written in the D programming language. 3 4 module sdlang.util; 5 6 import std.algorithm; 7 import std.array; 8 import std.conv; 9 import std.datetime; 10 import std.range; 11 import std.stdio; 12 import std..string; 13 14 import sdlang.exception; 15 import sdlang.token; 16 17 enum sdlangVersion = "0.9.1"; 18 19 alias immutable(ubyte)[] ByteString; 20 21 auto startsWith(T)(string haystack, T needle) 22 if( is(T:ByteString) || is(T:string) ) 23 { 24 return std.algorithm.startsWith( cast(ByteString)haystack, cast(ByteString)needle ); 25 } 26 27 struct Location 28 { 29 string file; /// Filename (including path) 30 int line; /// Zero-indexed 31 int col; /// Zero-indexed, Tab counts as 1 32 size_t index; /// Index into the source 33 34 this(int line, int col, int index) 35 { 36 this.line = line; 37 this.col = col; 38 this.index = index; 39 } 40 41 this(string file, int line, int col, int index) 42 { 43 this.file = file; 44 this.line = line; 45 this.col = col; 46 this.index = index; 47 } 48 49 /// Convert to string. Optionally takes output range as a sink. 50 string toString() 51 { 52 Appender!string sink; 53 this.toString(sink); 54 return sink.data; 55 } 56 57 ///ditto 58 void toString(Sink)(ref Sink sink) if(isOutputRange!(Sink,char)) 59 { 60 sink.put(file); 61 sink.put("("); 62 sink.put(to!string(line+1)); 63 sink.put(":"); 64 sink.put(to!string(col+1)); 65 sink.put(")"); 66 } 67 } 68 69 struct FullName 70 { 71 string namespace; 72 string name; 73 74 /// Convert to string. Optionally takes output range as a sink. 75 string toString() 76 { 77 if(namespace == "") 78 return name; 79 80 Appender!string sink; 81 this.toString(sink); 82 return sink.data; 83 } 84 85 ///ditto 86 void toString(Sink)(ref Sink sink) if(isOutputRange!(Sink,char)) 87 { 88 if(namespace != "") 89 { 90 sink.put(namespace); 91 sink.put(":"); 92 } 93 94 sink.put(name); 95 } 96 97 /// 98 static string combine(string namespace, string name) 99 { 100 return FullName(namespace, name).toString(); 101 } 102 /// 103 @("FullName.combine example") 104 unittest 105 { 106 assert(FullName.combine("", "name") == "name"); 107 assert(FullName.combine("*", "name") == "*:name"); 108 assert(FullName.combine("namespace", "name") == "namespace:name"); 109 } 110 111 /// 112 static FullName parse(string fullName) 113 { 114 FullName result; 115 116 auto parts = fullName.findSplit(":"); 117 if(parts[1] == "") // No colon 118 { 119 result.namespace = ""; 120 result.name = parts[0]; 121 } 122 else 123 { 124 result.namespace = parts[0]; 125 result.name = parts[2]; 126 } 127 128 return result; 129 } 130 /// 131 @("FullName.parse example") 132 unittest 133 { 134 assert(FullName.parse("name") == FullName("", "name")); 135 assert(FullName.parse("*:name") == FullName("*", "name")); 136 assert(FullName.parse("namespace:name") == FullName("namespace", "name")); 137 } 138 139 /// Throws with appropriate message if this.name is "*". 140 /// Wildcards are only supported for namespaces, not names. 141 void ensureNoWildcardName(string extaMsg = null) 142 { 143 if(name == "*") 144 throw new ArgumentException(`Wildcards ("*") only allowed for namespaces, not names. `~extaMsg); 145 } 146 } 147 struct Foo { string foo; } 148 149 void removeIndex(E)(ref E[] arr, ptrdiff_t index) 150 { 151 arr = arr[0..index] ~ arr[index+1..$]; 152 } 153 154 void trace(string file=__FILE__, size_t line=__LINE__, TArgs...)(TArgs args) 155 { 156 version(sdlangTrace) 157 { 158 writeln(file, "(", line, "): ", args); 159 stdout.flush(); 160 } 161 } 162 163 string toString(TypeInfo ti) 164 { 165 if (ti == typeid( bool )) return "bool"; 166 else if(ti == typeid( string )) return "string"; 167 else if(ti == typeid( dchar )) return "dchar"; 168 else if(ti == typeid( int )) return "int"; 169 else if(ti == typeid( long )) return "long"; 170 else if(ti == typeid( float )) return "float"; 171 else if(ti == typeid( double )) return "double"; 172 else if(ti == typeid( real )) return "real"; 173 else if(ti == typeid( Date )) return "Date"; 174 else if(ti == typeid( DateTimeFrac )) return "DateTimeFrac"; 175 else if(ti == typeid( DateTimeFracUnknownZone )) return "DateTimeFracUnknownZone"; 176 else if(ti == typeid( SysTime )) return "SysTime"; 177 else if(ti == typeid( Duration )) return "Duration"; 178 else if(ti == typeid( ubyte[] )) return "ubyte[]"; 179 else if(ti == typeid( typeof(null) )) return "null"; 180 181 return "{unknown}"; 182 } 183 184 enum BOM { 185 UTF8, /// UTF-8 186 UTF16LE, /// UTF-16 (little-endian) 187 UTF16BE, /// UTF-16 (big-endian) 188 UTF32LE, /// UTF-32 (little-endian) 189 UTF32BE, /// UTF-32 (big-endian) 190 } 191 192 enum NBOM = __traits(allMembers, BOM).length; 193 immutable ubyte[][NBOM] ByteOrderMarks = 194 [ 195 [0xEF, 0xBB, 0xBF], //UTF8 196 [0xFF, 0xFE], //UTF16LE 197 [0xFE, 0xFF], //UTF16BE 198 [0xFF, 0xFE, 0x00, 0x00], //UTF32LE 199 [0x00, 0x00, 0xFE, 0xFF] //UTF32BE 200 ];