1 module bamboo.codegen.helpers; 2 3 import bamboo.codegen; 4 5 mixin template ParentConstructors() 6 { 7 import std.traits : Parameters, FunctionTypeOf; 8 9 static if (is(super.ctor)) 10 { 11 static if (!is(FunctionTypeOf!(super.__ctor) == void)) 12 { 13 static foreach (ctor; __traits(getOverloads, typeof(super), "__ctor", true)) 14 { 15 this(Parameters!ctor args) 16 { 17 ctor(args); 18 } 19 } 20 } 21 } 22 } 23 24 string generateDefinition(Parameter parameter) 25 { 26 switch (parameter.syntaxKind) 27 { 28 case SyntaxKind.StructParameter: 29 return generateDefinition(cast(StructParameter) parameter); 30 case SyntaxKind.ArrayParameter: 31 return generateDefinition(cast(ArrayParameter) parameter); 32 case SyntaxKind.SizedParameter: 33 return generateDefinition(cast(SizedParameter) parameter); 34 case SyntaxKind.NumericParameter: 35 return generateDefinition(cast(NumericParameter) parameter); 36 default: 37 assert(0); 38 } 39 } 40 41 string generateDefinition(StructParameter parameter) 42 { 43 enum string format = `${type} ${name}`; 44 45 string type = mapType(parameter.type.symbol); 46 string name = generateName(parameter.symbol, type, 1); 47 48 parameter.symbol = name; 49 50 return mixin(interp!format); 51 } 52 53 string generateDefinition(ArrayParameter array) 54 { 55 enum string format = `${type}[${maxLength}] ${name}`; 56 57 string type = mapType(array.elementType.symbol); 58 string name = generateName(array.symbol, type, 2); 59 string maxLength = ""; 60 61 version (RespectFixedLength) 62 { 63 if (array.hasRange && array.size.isFixedLength) 64 { 65 maxLength = array.size.maxLength.to!string; 66 } 67 } 68 69 array.symbol = name; 70 71 return mixin(interp!format); 72 } 73 74 string generateDefinition(SizedParameter array) 75 { 76 enum string format = `${type} ${name}`; 77 78 string type; 79 string maxLength = ""; 80 string defaultVal = ""; 81 82 version (RespectFixedLength) 83 { 84 if (array.hasRange && array.size.isFixedLength) 85 { 86 maxLength = array.size.maxLength.to!string; 87 } 88 89 switch (array.parameterType) with (Type) 90 { 91 case string_: 92 case varstring: 93 type = "immutable char[${maxLength}]"; 94 break; 95 case blob: 96 case varblob: 97 type = "immutable ubyte[${maxLength}]"; 98 break; 99 default: 100 assert(0); 101 } 102 type = mixin(interp!type); 103 } 104 else 105 { 106 switch (array.parameterType) with (Type) 107 { 108 case string_: 109 case varstring: 110 type = "string"; 111 break; 112 case blob: 113 case varblob: 114 type = "blob"; 115 break; 116 default: 117 assert(0); 118 } 119 } 120 121 type = mapType(type); 122 123 string name = generateName(array.symbol, type, 3); 124 125 if (array.defaultVal.length > 0) 126 { 127 defaultVal = mixin(interp!" = \"${array.defaultVal}\""); 128 } 129 130 array.symbol = name; 131 132 return mixin(interp!format); 133 } 134 135 string generateDefinition(NumericParameter numeric) 136 { 137 enum string format = `${type} ${name}`; 138 139 string type = mapType(numeric.type.to!string()); 140 string name = generateName(numeric.symbol, type, 4); 141 142 numeric.symbol = name; 143 144 return mixin(interp!format); 145 } 146 147 string mapType(string type) 148 { 149 // dfmt off 150 enum types = [ 151 "int8": "byte", 152 "int16": "short", 153 "int32": "int", 154 "int64": "long", 155 "uint8": "ubyte", 156 "uint16": "ushort", 157 "uint32": "uint", 158 "uint64": "ulong", 159 "float32": "float", 160 "float64": "double", 161 "char_": "char", 162 "varstring": "string", 163 "blob": "ubyte[]", 164 "varblob": "ubyte[]", 165 ]; 166 // dfmt on 167 168 if (auto ret = type in types) 169 { 170 return *ret; 171 } 172 return type; 173 } 174 175 string generateContractFor(Parameter parameter) 176 { 177 if (auto array = cast(SizedParameter) parameter) 178 { 179 return generateContract(array); 180 } 181 else if (auto array = cast(ArrayParameter) parameter) 182 { 183 return generateContract(array); 184 } 185 else if (auto numeric = cast(NumericParameter) parameter) 186 { 187 return generateContract(numeric); 188 } 189 return ""; 190 } 191 192 string generateContract(SizedParameter array) 193 { 194 enum string format = ` 195 assert(${parameter}.length <= ${maxLength}, "${parameter} is oversized!"); 196 assert(${parameter}.length >= ${minLength}, "${parameter} is undersized!"); 197 `; 198 199 if (!array.hasRange) 200 { 201 return ""; 202 } 203 204 string parameter = array.symbol; 205 string maxLength = array.size.maxSize.to!string; 206 string minLength = array.size.minSize.to!string; 207 208 return mixin(interp!format); 209 } 210 211 string generateContract(ArrayParameter array) 212 { 213 enum string format = ` 214 assert(${parameter}.length <= ${maxLength}, "${parameter} is oversized!"); 215 assert(${parameter}.length >= ${minLength}, "${parameter} is undersized!"); 216 `; 217 218 if (!array.hasRange) 219 { 220 return ""; 221 } 222 223 string parameter = array.symbol; 224 string maxLength = array.size.maxLength.to!string; 225 string minLength = array.size.minLength.to!string; 226 227 return mixin(interp!format); 228 } 229 230 string generateContract(NumericParameter numeric) 231 { 232 string formatStr(string parameter, string op, string value, string msg) 233 { 234 return `assert(` ~ parameter ~ ` ` ~ op ~ ` ` ~ value ~ `, "` ~ parameter 235 ~ ` is too ` ~ msg ~ `!");`; 236 } 237 238 string format; 239 240 if (!numeric.hasRange) 241 { 242 return ""; 243 } 244 245 string parameter = numeric.symbol; 246 string max = numeric.range.max.to!string; 247 string min; 248 249 format ~= formatStr(parameter, "<=", max, "large"); 250 251 if (!isNaN(numeric.range.min)) 252 { 253 min = numeric.range.min.to!string; 254 format ~= formatStr(parameter, ">=", min, "small"); 255 } 256 257 return format; 258 } 259 260 string generateName(string name, string type, int counter) 261 { 262 if (name.length == 0) 263 { 264 name = mixin(interp!"_${type.toLower}${counter}"); 265 } 266 return name; 267 }