1 module support; // dockerfile_parser; 2 import std.traits: ReturnType; 3 import std.experimental.allocator : make, makeArray; 4 import std.experimental.allocator.building_blocks.region: Region; 5 import std.experimental.allocator.building_blocks.allocator_list: AllocatorList; 6 import std.experimental.allocator.gc_allocator : GCAllocator; 7 import std.experimental.allocator.mallocator : Mallocator; 8 import std.experimental.allocator.showcase : mmapRegionList; 9 import std.experimental.allocator.typed: TypedAllocator, AllocFlag; 10 import std.experimental.allocator.building_blocks.scoped_allocator : ScopedAllocator; 11 import std.algorithm : max; 12 //@nogc: 13 14 //ScopedAllocator!Mallocator regionalAllocator; 15 alias MyTypedAllocator = AllocatorList!((size_t n) => Region!Mallocator(max(n,1024*1024))); 16 17 // MyTypedAllocator regionalAllocator = MyTypedAllocator(); 18 Region!Mallocator regionalAllocator; 19 20 shared static this() 21 { 22 regionalAllocator = Region!Mallocator(1024*1024*40); // Mallocator(1024*1024*100); 23 } 24 25 struct Result(T) 26 { 27 const(char)[] errorMessage; 28 T* result; 29 } 30 31 struct Command 32 { 33 string command; 34 string subCommand; 35 bool json; 36 string original; 37 int startLine; 38 int endLine; 39 string[] flags; 40 string[] values; 41 /+ 42 string toString() 43 { 44 import std.conv; 45 return this.to!string; 46 } 47 +/ 48 Command deepCopy() 49 { 50 import std.algorithm : map; 51 import std.array : array; 52 Command ret; 53 ret.command = this.command.idup; 54 ret.subCommand = this.subCommand.idup; 55 ret.json = this.json; 56 ret.original = this.original.idup; 57 ret.startLine = this.startLine; 58 ret.endLine = this.endLine; 59 ret.flags = this.flags.map!(flag => flag.idup).array; 60 ret.values = this.values.map!(value => value.idup).array; 61 return ret; 62 } 63 64 } 65 /+ 66 auto makeRegionalAllocator() 67 { 68 //alias RawAllocator = Region!MmapAllocator(1024); 69 //regionalTypedAllocator!RawAllocator regionalAllocator; 70 } 71 +/ 72 export extern(C) 73 void* return_success(void* ret) 74 { 75 import std.experimental.allocator: make; 76 auto result = regionalAllocator.make!(Result!(char))(null,cast(char*)ret); 77 return cast(void*) result; 78 } 79 80 T[] allocatorDup(T)(T[] values) 81 { 82 import std.traits: Unqual; 83 auto ret = regionalAllocator.makeArray!(Unqual!T)(values.length); 84 ret[0..values.length] = cast(Unqual!T[]) values; 85 return ret; 86 } 87 88 immutable(T)[] allocatorIdup(T)(T[] values) 89 { 90 import std.traits : Unqual; 91 auto ret = regionalAllocator.makeArray!(Unqual!T)(values.length); 92 ret[0..values.length] = values; 93 return cast(immutable(T)[]) ret; 94 } 95 96 const(char)* toStringz(const(char)[] s) 97 { 98 import std.traits: Unqual; 99 if (s.length == 0) 100 return null; 101 bool needsTerminator = (s.length == 0 || (s[$-1]!='\0')); 102 auto requiredLength = s.length + (needsTerminator ? 1 : 0); 103 auto p = regionalAllocator.makeArray!char(requiredLength); 104 assert(p.length == requiredLength); 105 p[0 .. s.length] = s[0.. $]; 106 if(needsTerminator) 107 p[s.length] = '\0'; 108 return cast(const(char)*) p.ptr; 109 } 110 111 string fromStringz(const(char)* p) 112 { 113 if (p is null) 114 return null; 115 size_t maxLen = 16384; 116 auto s= regionalAllocator.makeArray!char(maxLen); 117 assert(s.length == maxLen); 118 size_t i = 0; 119 while(p[i] != '\0') 120 { 121 s[i] = p[i]; 122 ++i; 123 if (i == maxLen) 124 { 125 maxLen *= 2; 126 auto s2 = regionalAllocator.makeArray!char(maxLen); 127 assert(s2.length == maxLen); 128 s2[0..s.length] = s[]; 129 regionalAllocator.deallocate(s); 130 s=s2; 131 } 132 } 133 s = s[0..i]; 134 return cast(string) s; 135 } 136 137 138 export extern(C) 139 void* raise(const(char)* errorMessage) 140 { 141 import std.experimental.allocator: make; 142 import core.stdc.stdlib : free; 143 bool shouldFree = true; 144 auto niceErrorMessage = (errorMessage is null) ? "UNKNOWN GOLANG ERROR" : errorMessage.fromStringz; 145 auto result = regionalAllocator.make!(Result!(char)); 146 result.errorMessage = niceErrorMessage; 147 if (errorMessage !is null) 148 free(cast(void*)errorMessage); 149 return cast(void*) result; 150 } 151 152 153 export extern(C) 154 void* command(char* cmd, char* sub_cmd, int json, char* original, int start_line, int end_line, void* flags, void* value) 155 { 156 import core.stdc.stdlib : free; 157 import std.experimental.allocator: make; 158 159 auto ret = regionalAllocator.make!Command; 160 ret.command = cmd.fromStringz.allocatorIdup; 161 ret.subCommand = sub_cmd.fromStringz.allocatorIdup; 162 ret.json = (json != 0); 163 ret.original = original.fromStringz.allocatorIdup; 164 ret.startLine = start_line; 165 ret.endLine = end_line; 166 auto flagsV = cast(StringSlice*) flags; 167 ret.flags = (*flagsV).values.allocatorDup; 168 auto valuesV = cast(StringSlice*) value; 169 ret.values = (*valuesV).values.allocatorDup; 170 free(cmd); 171 free(sub_cmd); 172 free(original); 173 return cast(void*) regionalAllocator.make!(Result!Command)(null,ret); 174 } 175 176 extern(C) void* parse_string(const(char)* s); 177 extern(C) void* parse_file(const(char)* filename); 178 extern(C) void* all_commands(); 179 180 alias CommandResult = Result!Command; 181 alias CommandSlice = Slice!Command; 182 alias CommandSliceResult = Result!(Slice!Command); 183 alias StringSlice = Slice!string; 184 alias StringSliceResult = Result!(Slice!string); 185 186 Command[] parseString(string s) 187 { 188 import std.algorithm : map; 189 import std.array : array; 190 import std.exception : enforce; 191 scope(exit) 192 { 193 regionalAllocator.deallocateAll(); 194 } 195 auto p = cast(CommandSliceResult*) parse_string(s.toStringz); 196 enforce(p !is null, "parse_string failed"); 197 enforce(p.errorMessage.length ==0, p.errorMessage); 198 auto result = *((*p).result); 199 return result.values.map!(command => command.deepCopy).array; 200 } 201 202 Command[] parseFile(string filename) 203 { 204 import std.algorithm : map; 205 import std.array : array; 206 import std.exception : enforce; 207 scope(exit) 208 { 209 regionalAllocator.deallocateAll(); 210 } 211 auto p = cast(CommandSliceResult*) parse_file(filename.toStringz); 212 enforce(p !is null, "parse_file failed"); 213 enforce(p.errorMessage.length ==0, p.errorMessage); 214 auto result = *((*p).result); 215 return result.values.map!(command => command.deepCopy).array; 216 } 217 218 string[] allCommands() 219 { 220 import std.algorithm : map; 221 import std.array : array; 222 import std.exception : enforce; 223 //regionalAllocator = TypedAllocator!(ScopedAllocator!(Mallocator))(Mallocator.instance); 224 scope(exit) 225 { 226 regionalAllocator.deallocateAll(); 227 } 228 auto p = cast(StringSliceResult*) all_commands(); 229 enforce(p !is null, "all_commands failed"); 230 enforce(p.errorMessage.length ==0, p.errorMessage); 231 auto result = *p.result; 232 return result.values.map!(value => value.idup).array; 233 } 234 235 236 struct Slice(T) 237 { 238 T[] values; 239 } 240 241 export extern(C) 242 void* stringSlice(size_t length) 243 { 244 import std.experimental.allocator : make; 245 assert(length >= 0); 246 auto ret = regionalAllocator.make!(Slice!string); 247 assert(ret !is null); 248 auto buf = regionalAllocator.makeArray!string(length,""); 249 assert(buf.length == length); 250 ret.values = buf; 251 assert(ret.values.length == length); 252 return cast(void*) ret; 253 } 254 255 export extern(C) 256 void* commandSlice(size_t length) 257 { 258 import std.experimental.allocator : make; 259 auto ret = regionalAllocator.make!(Slice!Command); 260 assert(ret !is null); 261 ret.values = regionalAllocator.makeArray!Command(length,Command.init); 262 return cast(void*) ret; 263 } 264 265 export extern(C) 266 void setStringElement(void* sliceV, size_t i, const(char)* s) 267 { 268 import core.stdc.stdlib : free; 269 import std.exception : enforce; 270 271 assert(s !is null); 272 auto slice = cast(StringSlice*) sliceV; 273 assert(slice !is null); 274 assert(i >=0); 275 assert(slice.values.length > i); 276 slice.values[i] = fromStringz(s); 277 free(cast(void*)s); 278 } 279 280 export extern(C) 281 void setCommandElement(void* sliceV, size_t i, void* p) 282 { 283 import std.exception : enforce; 284 assert(p !is null, "setCommandElement called with null"); 285 auto slice = cast(CommandSlice*) sliceV; 286 enforce(slice.values.length > i); 287 auto pTyped = *cast(CommandResult*) p; 288 slice.values[i] = *pTyped.result; 289 } 290