1 module orelang.Value; 2 import orelang.expression.ImmediateValue, 3 orelang.operator.DynamicOperator, 4 orelang.expression.IExpression, 5 orelang.expression.SymbolValue, 6 orelang.expression.ClassType, 7 orelang.operator.IOperator, 8 orelang.Closure; 9 import std.algorithm, 10 std.exception, 11 std.array, 12 std.traits, 13 std.regex, 14 std.conv; 15 16 enum ValueType { 17 ImmediateValue, 18 SymbolValue, 19 IExpression, 20 ClassType, 21 IOperator, 22 Closure, 23 HashMap, 24 Numeric, 25 String, 26 Ubyte, 27 Bool, 28 Null, 29 Array 30 } 31 32 class Value { 33 ValueType type; 34 35 private { 36 double numeric_value; 37 string string_value; 38 bool bool_value; 39 ubyte ubyte_value; 40 Value[] array_value; 41 ImmediateValue imv_value; 42 SymbolValue sym_value; 43 IExpression ie_value; 44 ClassType class_value; 45 IOperator io_value; 46 Closure closure_value; 47 Value[string] hashmap_value; 48 } 49 50 this() { this.type = ValueType.Null; } 51 this(ValueType type) { this.type = type; } 52 this(T)(T value) if (isNumeric!T) { this.opAssign(value); } 53 this(string value) { this.opAssign(value); } 54 this(bool value) { this.opAssign(value); } 55 this(ubyte value) { 56 this.init; 57 this.ubyte_value = value; 58 this.type = ValueType.Ubyte; 59 } 60 this(Value[] value) { this.opAssign(value); } 61 this(ImmediateValue value) { 62 this.init; 63 this.imv_value = value; 64 this.type = ValueType.ImmediateValue; } 65 this(SymbolValue value) { 66 this.init; 67 this.sym_value = value; 68 this.type = ValueType.SymbolValue; } 69 this(IExpression value) { this.opAssign(value); } 70 this(ClassType value) { this.opAssign(value); } 71 this(IOperator value) { this.opAssign(value); } 72 this(Closure value) { this.opAssign(value); } 73 this(Value[string] value) { this.opAssign(value); } 74 75 double getNumeric() { enforce(this.type == ValueType.Numeric); 76 return this.numeric_value; } 77 string getString() { enforce(this.type == ValueType.String || this.type == ValueType.SymbolValue); 78 return this.type == ValueType.String ? this.string_value : this.sym_value.value; } 79 bool getBool() { enforce(this.type == ValueType.Bool); 80 return this.bool_value; } 81 ubyte getUbyte() { enforce(this.type == ValueType.Ubyte); 82 return this.ubyte_value; } 83 auto getNull() { throw new Error("Can't get from NULL value"); } 84 Value[] getArray() { enforce(this.type == ValueType.Array); 85 return this.array_value; } 86 ImmediateValue getImmediateValue() { enforce(this.type == ValueType.ImmediateValue); 87 return this.imv_value; } 88 SymbolValue getSymbolValue() { enforce(this.type == ValueType.SymbolValue); 89 return this.sym_value; } 90 IExpression getIExpression() { enforce(this.type == ValueType.IExpression); 91 return this.ie_value; } 92 ClassType getClassType() { enforce(this.type == ValueType.ClassType); 93 return this.class_value; } 94 IOperator getIOperator() { enforce(this.type == ValueType.IOperator); 95 return this.io_value; } 96 Closure getClosure() { enforce(this.type == ValueType.Closure); 97 return this.closure_value; } 98 Value[string] getHashMap() { enforce(this.type == ValueType.HashMap); 99 return this.hashmap_value; } 100 101 void opAssign(T)(T value) if (isNumeric!T) { 102 this.init; 103 this.numeric_value = value; 104 this.type = ValueType.Numeric; 105 } 106 107 void opAssign(T)(T value) if (is(T == string)) { 108 this.init; 109 this.string_value = value; 110 this.type = ValueType.String; 111 } 112 113 void opAssign(bool value) { 114 this.init; 115 this.bool_value = value; 116 this.type = ValueType.Bool; 117 } 118 119 void opAssign(T)(T[] value) if (is(T == Value)) { 120 this.init; 121 this.array_value = value; 122 this.type = ValueType.Array; 123 } 124 125 void opAssign(T)(T[] value) if (!is(T == Value) && !is(T == immutable(char))) { 126 this.init; 127 this.array_value = []; 128 129 foreach (e; value) this.array_value ~= new Value(e); 130 131 this.type = ValueType.Array; 132 } 133 134 void opAssign(IExpression value) { 135 this.init; 136 this.ie_value = value; 137 this.type = ValueType.IExpression; 138 } 139 140 void opAssign(ClassType value) { 141 this.init; 142 this.class_value = value; 143 this.type = ValueType.ClassType; 144 } 145 146 void opAssign(IOperator value) { 147 this.init; 148 this.io_value = value; 149 this.type = ValueType.IOperator; 150 } 151 152 void opAssign(Closure value) { 153 this.init; 154 this.closure_value = value; 155 this.type = ValueType.Closure; 156 } 157 158 void opAssign(Value[string] value) { 159 this.init; 160 this.hashmap_value = value; 161 this.type = ValueType.HashMap; 162 } 163 164 override string toString() { 165 final switch(this.type) with (ValueType) { 166 case Numeric: return this.numeric_value.to!string; 167 case String: return this.string_value; 168 case Bool: return this.bool_value.to!string; 169 case Ubyte: return this.ubyte_value.to!string; 170 case Null: return "null"; 171 case Array: return "[" ~ this.array_value.map!(value => value.toString).array.join(", ") ~ "]"; 172 case HashMap: return this.hashmap_value.to!string; 173 case ImmediateValue: return this.imv_value.toString; 174 case SymbolValue: return this.sym_value.value; 175 case IExpression: return this.ie_value.stringof; 176 case ClassType: return this.class_value.stringof; 177 case IOperator: return this.io_value.stringof; 178 case Closure: return this.closure_value.stringof; 179 } 180 } 181 182 void addTo(Value value) { 183 enforce(this.type == value.type && value.type == ValueType.Numeric); 184 this.numeric_value += value.getNumeric; 185 } 186 187 void subTo(Value value) { 188 enforce(this.type == value.type && value.type == ValueType.Numeric); 189 this.numeric_value -= value.getNumeric; 190 } 191 192 void mulTo(Value value) { 193 enforce(this.type == value.type && value.type == ValueType.Numeric); 194 this.numeric_value *= value.getNumeric; 195 } 196 197 void divTo(Value value) { 198 enforce(this.type == value.type && value.type == ValueType.Numeric); 199 this.numeric_value /= value.getNumeric; 200 } 201 202 void modTo(Value value) { 203 enforce(this.type == value.type && value.type == ValueType.Numeric); 204 this.numeric_value %= value.getNumeric; 205 } 206 207 Value opBinary(string op)(Value value) if (op == "+") { 208 enforce(value.type == ValueType.Numeric); 209 return new Value(this.numeric_value + value.getNumeric); 210 } 211 212 Value opBinary(string op)(Value value) if (op == "-") { 213 enforce(value.type == ValueType.Numeric); 214 215 return new Value(this.numeric_value - value.getNumeric); 216 } 217 218 Value opBinary(string op)(Value value) if (op == "*") { 219 enforce(value.type == ValueType.Numeric); 220 return new Value(this.numeric_value * value.getNumeric); 221 } 222 223 Value opBinary(string op)(Value value) if (op == "/") { 224 enforce(value.type == ValueType.Numeric); 225 return new Value(this.numeric_value / value.getNumeric); 226 } 227 228 Value opBinary(string op)(Value value) if (op == "%") { 229 enforce(value.type == ValueType.Numeric); 230 return new Value(this.numeric_value % value.getNumeric); 231 } 232 233 void init() { 234 if (this.type != ValueType.Null) { 235 if (this.type == ValueType.Numeric) { this.numeric_value = 0; } 236 if (this.type == ValueType.String) { this.string_value = ""; } 237 if (this.type == ValueType.Array) { this.array_value = []; } 238 if (this.type == ValueType.Bool) { this.bool_value = false; } 239 if (this.type == ValueType.Ubyte) { this.ubyte_value = 0; } 240 if (this.type == ValueType.ImmediateValue) { this.imv_value = null; } 241 if (this.type == ValueType.SymbolValue) { this.sym_value = null; } 242 if (this.type == ValueType.IExpression) { this.ie_value = null; } 243 if (this.type == ValueType.ClassType) { this.class_value = null; } 244 if (this.type == ValueType.IOperator) { this.io_value = null; } 245 if (this.type == ValueType.Closure) { this.closure_value = null; } 246 if (this.type == ValueType.HashMap) { this.hashmap_value = null; } 247 248 this.type = ValueType.Null; 249 } 250 } 251 252 Value opIndex() { 253 enforce(this.type == ValueType.Array); 254 255 return new Value; 256 } 257 258 Value opIndex(size_t idx) { 259 enforce(this.type == ValueType.Array); 260 261 if (!(idx < this.array_value.length)) { 262 throw new Error("Out of index of the Array, orded - " ~ idx.to!string ~ " but length of the array is " ~ this.array_value.length.to!string); 263 } 264 265 return this.array_value[idx]; 266 } 267 268 Value opIndex(Value value) { 269 enforce(this.type == ValueType.HashMap); 270 271 if (value.getString !in this.hashmap_value) { 272 throw new Error("No such a key in the hash, key - " ~ value.toString ~ ", hash - " ~ this.hashmap_value.stringof); 273 } 274 275 return this.hashmap_value[value.getString]; 276 } 277 278 override bool opEquals(Object _value) { 279 if ((cast(Value)_value) is null) { 280 throw new Error("Can not compare between incompatibility"); 281 } 282 283 Value value = cast(Value)_value; 284 285 if (this.type != value.type) { 286 throw new Error("Can not compare between incompatibility type " ~ this.type.to!string ~ " and " ~ value.type.to!string); 287 } 288 289 final switch(this.type) with (ValueType) { 290 case ImmediateValue: 291 throw new Error("Can't compare with ImmediateValue"); 292 case SymbolValue: 293 return this.sym_value.value == value.getSymbolValue.value; 294 case IExpression: 295 throw new Error("Can't compare with IExpression"); 296 case ClassType: 297 throw new Error("Can't compare with ClassType"); 298 case IOperator: 299 throw new Error("Can't compare with IOperator"); 300 case Closure: 301 throw new Error("Can't compare with Closure"); 302 case HashMap: 303 throw new Error("Can't compare with HashMap"); 304 case Numeric: 305 return this.numeric_value == value.numeric_value; 306 case String: 307 return this.string_value == value.string_value; 308 case Bool: 309 return this.bool_value == value.bool_value; 310 case Ubyte: 311 return this.ubyte_value == value.ubyte_value; 312 case Null: 313 throw new Error("Can't compare with Null"); 314 case Array: 315 Value[] a = this.getArray, 316 b = value.getArray; 317 318 if (a.length != b.length) { 319 return false; 320 } 321 322 foreach (idx; 0..(a.length)) { 323 if (a[idx].opCmp(b[idx]) != 0) { return false; } 324 } 325 326 return true; 327 } 328 } 329 330 override int opCmp(Object _value) { 331 if ((cast(Value)_value) is null) { 332 throw new Error("Can not compare between incompatibility"); 333 } 334 335 Value value = cast(Value)_value; 336 337 if (this.type != value.type) { 338 throw new Error("Can not compare between incompatibility type " ~ this.type.to!string ~ " and " ~ value.type.to!string); 339 } 340 341 final switch(this.type) with (ValueType) { 342 case ImmediateValue: 343 throw new Error("Can't compare with ImmediateValue"); 344 case SymbolValue: 345 auto c = this.sym_value.value, 346 d = value.getSymbolValue.value; 347 if (c == d) { return 0; } 348 if (c < d) { return -1; } 349 return 1; 350 case IExpression: 351 throw new Error("Can't compare with IExpression"); 352 case ClassType: 353 throw new Error("Can't compare with ClassType"); 354 case IOperator: 355 throw new Error("Can't compare with IOperator"); 356 case Closure: 357 throw new Error("Can't compare with Closure"); 358 case HashMap: 359 throw new Error("Can't compare with HashMap"); 360 case Numeric: 361 auto c = this.numeric_value, 362 d = value.numeric_value; 363 364 if (c == d) { return 0; } 365 if (c < d) { return -1; } 366 return 1; 367 case String: 368 auto c = this.string_value, 369 d = value.string_value; 370 371 if (c == d) { return 0; } 372 if (c < d) { return -1; } 373 return 1; 374 case Ubyte: 375 auto c = this.ubyte_value, 376 d = value.ubyte_value; 377 378 if (c == d) { return 0; } 379 if (c < d) { return -1; } 380 return 1; 381 case Bool: 382 throw new Error("Can't compare with Bool"); 383 case Null: 384 throw new Error("Can't compare with Null"); 385 case Array: 386 Value[] a = this.getArray, 387 b = value.getArray; 388 389 if (a.length != b.length) { 390 throw new Error("Can't compare between different size array"); 391 } 392 393 foreach (idx; 0..(a.length)) { 394 if (a[idx].opCmp(b[idx]) != 0) { return 1; } 395 } 396 397 return 0; 398 } 399 } 400 401 Value dup() { 402 final switch (this.type) with (ValueType) { 403 case ImmediateValue: 404 return new Value(this.imv_value); 405 case SymbolValue: 406 return new Value(this.sym_value); 407 case IExpression: 408 return new Value(this.ie_value); 409 case ClassType: 410 return new Value(this.class_value); 411 case IOperator: 412 return new Value(this.io_value); 413 case Closure: 414 return new Value(this.closure_value); 415 case HashMap: 416 return new Value(this.hashmap_value); 417 case Numeric: 418 return new Value(this.numeric_value); 419 case String: 420 return new Value(this.string_value); 421 case Bool: 422 return new Value(this.bool_value); 423 case Ubyte: 424 return new Value(this.ubyte_value); 425 case Null: 426 return new Value; 427 case Array: 428 return new Value(this.array_value.dup); 429 } 430 } 431 }