1 /** 2 * Copyright: Enalye 3 * License: Zlib 4 * Authors: Enalye 5 */ 6 module grimoire.compiler.library; 7 8 import std.traits; 9 import std.conv : to; 10 import grimoire.runtime; 11 import grimoire.compiler.primitive; 12 import grimoire.compiler.type; 13 import grimoire.compiler.mangle; 14 import grimoire.compiler.pretty; 15 16 /** 17 Contains type information and D linked functions. 18 */ 19 class GrLibrary { 20 package(grimoire) { 21 /// Opaque pointer types. \ 22 /// They're pointer only defined by a name. \ 23 /// Can only be used with primitives. 24 GrAbstractForeignDefinition[] _abstractForeignDefinitions; 25 /// Type aliases 26 GrTypeAliasDefinition[] _aliasDefinitions; 27 /// Enum types. 28 GrEnumDefinition[] _enumDefinitions; 29 /// Object types. 30 GrClassDefinition[] _abstractClassDefinitions; 31 /// Variable types 32 GrVariableDefinition[] _variableDefinitions; 33 34 /// All primitives, used for both the compiler and the runtime. 35 GrPrimitive[] _abstractPrimitives; 36 37 /// All the primitive callbacks. 38 GrCallback[] _callbacks; 39 } 40 41 /// Define a variable 42 void addVariable(string name, GrType type, bool isConstant) { 43 GrVariableDefinition variable = new GrVariableDefinition; 44 variable.name = name; 45 variable.type = type; 46 variable.isConstant = isConstant; 47 _variableDefinitions ~= variable; 48 } 49 50 /// Define a variable with a default value 51 void addVariable(T)(string name, GrType type, T defaultValue, bool isConstant) { 52 GrVariableDefinition variable = new GrVariableDefinition; 53 variable.name = name; 54 variable.type = type; 55 variable.isConstant = isConstant; 56 57 final switch (type.baseType) with (GrBaseType) { 58 case bool_: 59 case int_: 60 case enum_: 61 case float_: 62 case string_: 63 break; 64 case class_: 65 case chan: 66 case function_: 67 case task: 68 case array_: 69 case foreign: 70 case void_: 71 case null_: 72 case internalTuple: 73 case reference: 74 throw new Exception( 75 "can't initialize library variable of type `" ~ grGetPrettyType(type) ~ "`"); 76 } 77 static if (isIntegral!T) { 78 if (type.baseType != GrBaseType.int_ && type.baseType != GrBaseType.enum_) 79 throw new Exception( 80 "the default value of `" ~ name ~ "` doesn't match the type of `" ~ grGetPrettyType( 81 type) ~ "`"); 82 variable.ivalue = cast(int) defaultValue; 83 } 84 else static if (is(T == bool)) { 85 if (type.baseType != GrBaseType.bool_) 86 throw new Exception( 87 "the default value of `" ~ name ~ "` doesn't match the type of `" ~ grGetPrettyType( 88 type) ~ "`"); 89 variable.ivalue = defaultValue ? 1 : 0; 90 } 91 else static if (isFloatingPoint!T) { 92 if (type.baseType != GrBaseType.float_) 93 throw new Exception( 94 "the default value of `" ~ name ~ "` doesn't match the type of `" ~ grGetPrettyType( 95 type) ~ "`"); 96 variable.fvalue = cast(float) defaultValue; 97 } 98 static if (is(T == string)) { 99 if (type.baseType != GrBaseType.string_) 100 throw new Exception( 101 "the default value of `" ~ name ~ "` doesn't match the type of `" ~ grGetPrettyType( 102 type) ~ "`"); 103 variable.svalue = defaultValue; 104 } 105 variable.isInitialized = true; 106 _variableDefinitions ~= variable; 107 } 108 109 /// Define an enumeration 110 GrType addEnum(string name, string[] fields) { 111 GrEnumDefinition enum_ = new GrEnumDefinition; 112 enum_.name = name; 113 enum_.fields = fields; 114 enum_.isPublic = true; 115 _enumDefinitions ~= enum_; 116 117 GrType type = GrBaseType.enum_; 118 type.mangledType = name; 119 return type; 120 } 121 122 /// Define a class type. 123 GrType addClass(string name, string[] fields, GrType[] signature, 124 string[] templateVariables = [], string parent = "", 125 GrType[] parentTemplateSignature = []) { 126 if (fields.length != signature.length) 127 throw new Exception("class signature mismatch"); 128 GrClassDefinition class_ = new GrClassDefinition; 129 class_.name = name; 130 class_.parent = parent; 131 class_.signature = signature; 132 class_.fields = fields; 133 class_.templateVariables = templateVariables; 134 class_.parentTemplateSignature = parentTemplateSignature; 135 class_.isPublic = true; 136 class_.isParsed = true; 137 _abstractClassDefinitions ~= class_; 138 139 class_.fieldsInfo.length = fields.length; 140 for (int i; i < class_.fieldsInfo.length; ++i) { 141 class_.fieldsInfo[i].fileId = 0; 142 class_.fieldsInfo[i].isPublic = true; 143 class_.fieldsInfo[i].position = 0; 144 } 145 146 GrType type = GrBaseType.class_; 147 type.mangledType = name; 148 type.isAbstract = class_.templateVariables.length > 0; 149 return type; 150 } 151 152 /// Define a type alias 153 GrType addTypeAlias(string name, GrType type) { 154 GrTypeAliasDefinition typeAlias = new GrTypeAliasDefinition; 155 typeAlias.name = name; 156 typeAlias.type = type; 157 typeAlias.isPublic = true; 158 _aliasDefinitions ~= typeAlias; 159 return type; 160 } 161 162 /// Define an opaque pointer type. 163 GrType addForeign(string name, string[] templateVariables = [], 164 string parent = "", GrType[] parentTemplateSignature = []) { 165 if (name == parent) 166 throw new Exception("`" ~ name ~ "` can't be its own parent"); 167 GrAbstractForeignDefinition foreign = new GrAbstractForeignDefinition; 168 foreign.name = name; 169 foreign.templateVariables = templateVariables; 170 foreign.parent = parent; 171 foreign.parentTemplateSignature = parentTemplateSignature; 172 _abstractForeignDefinitions ~= foreign; 173 174 GrType type = GrBaseType.foreign; 175 type.mangledType = name; 176 type.isAbstract = foreign.templateVariables.length > 0; 177 return type; 178 } 179 180 /// Define a new primitive. 181 GrPrimitive addPrimitive(GrCallback callback, string name, 182 GrType[] inSignature = [], GrType[] outSignature = []) { 183 bool isAbstract; 184 foreach (GrType type; inSignature) { 185 if (type.isAbstract) 186 throw new Exception("`" ~ grGetPrettyFunction(name, inSignature, 187 outSignature) ~ "` can't use type `" ~ grGetPrettyType( 188 type) ~ "` as it is abstract"); 189 if (type.isAny) { 190 isAbstract = true; 191 break; 192 } 193 } 194 foreach (GrType type; outSignature) { 195 if (type.isAbstract) 196 throw new Exception("`" ~ grGetPrettyFunction(name, inSignature, 197 outSignature) ~ "` can't use type `" ~ grGetPrettyType( 198 type) ~ "` as it is abstract"); 199 } 200 201 GrPrimitive primitive = new GrPrimitive; 202 primitive.inSignature = inSignature; 203 primitive.outSignature = outSignature; 204 primitive.name = name; 205 primitive.callbackId = cast(int) _callbacks.length; 206 207 _callbacks ~= callback; 208 209 _abstractPrimitives ~= primitive; 210 return primitive; 211 } 212 213 /// Type of operator overloading 214 enum Operator { 215 add, 216 substract, 217 multiply, 218 divide, 219 concatenate, 220 remainder, 221 power, 222 equal, 223 doubleEqual, 224 threeWayComparison, 225 notEqual, 226 greaterOrEqual, 227 greater, 228 lesserOrEqual, 229 lesser, 230 leftShift, 231 rightShift, 232 and, 233 or, 234 xor, 235 not, 236 } 237 238 /** 239 An operator is a function that replace a binary or unary grimoire operator such as `+`, `==`, etc 240 The name of the function must be that of the operator like "+", "-", "or", etc. 241 */ 242 GrPrimitive addOperator(GrCallback callback, Operator operator, 243 GrType[] inSignature, GrType outType) { 244 string name; 245 final switch (operator) with (Operator) { 246 case add: 247 name = "+"; 248 break; 249 case substract: 250 name = "-"; 251 break; 252 case multiply: 253 name = "*"; 254 break; 255 case divide: 256 name = "/"; 257 break; 258 case concatenate: 259 name = "~"; 260 break; 261 case remainder: 262 name = "%"; 263 break; 264 case power: 265 name = "^"; 266 break; 267 case equal: 268 name = "=="; 269 break; 270 case doubleEqual: 271 name = "==="; 272 break; 273 case threeWayComparison: 274 name = "<=>"; 275 break; 276 case notEqual: 277 name = "!="; 278 break; 279 case greaterOrEqual: 280 name = ">="; 281 break; 282 case greater: 283 name = ">"; 284 break; 285 case lesserOrEqual: 286 name = "<="; 287 break; 288 case lesser: 289 name = "<"; 290 break; 291 case leftShift: 292 name = "<<"; 293 break; 294 case rightShift: 295 name = ">>"; 296 break; 297 case and: 298 name = "and"; 299 break; 300 case or: 301 name = "or"; 302 break; 303 case xor: 304 name = "xor"; 305 break; 306 case not: 307 name = "not"; 308 break; 309 } 310 return addOperator(callback, name, inSignature, outType); 311 } 312 /// Ditto 313 GrPrimitive addOperator(GrCallback callback, string name, GrType[] inSignature, GrType outType) { 314 if (inSignature.length > 2uL) 315 throw new Exception( 316 "The operator `" ~ name ~ "` cannot take more than 2 parameters: " ~ grGetPrettyFunctionCall("", 317 inSignature)); 318 return addPrimitive(callback, "@op_" ~ name, inSignature, [outType]); 319 } 320 321 /** 322 A cast operator allows to convert from one type to another. 323 It have to have only one parameter and return the casted value. 324 */ 325 GrPrimitive addCast(GrCallback callback, GrType srcType, GrType dstType, bool isExplicit = false) { 326 auto primitive = addPrimitive(callback, "@as", [srcType, dstType], [ 327 dstType 328 ]); 329 primitive.isExplicit = isExplicit; 330 return primitive; 331 } 332 333 private string getPrettyPrimitive(GrPrimitive primitive) { 334 import std.conv : to; 335 336 string result = primitive.name; 337 auto nbParameters = primitive.inSignature.length; 338 if (primitive.name == "@as") 339 nbParameters = 1; 340 result ~= "("; 341 for (int i; i < nbParameters; i++) { 342 result ~= grGetPrettyType(primitive.inSignature[i]); 343 if ((i + 2) <= nbParameters) 344 result ~= ", "; 345 } 346 result ~= ")"; 347 for (int i; i < primitive.outSignature.length; i++) { 348 result ~= i ? ", " : " "; 349 result ~= grGetPrettyType(primitive.outSignature[i]); 350 } 351 return result; 352 } 353 }