1 module orelang.Value; 2 import orelang.expression.ImmediateValue, orelang.operator.DynamicOperator, 3 orelang.expression.IExpression, orelang.expression.SymbolValue, 4 orelang.expression.ClassType, orelang.operator.IOperator, 5 orelang.expression.Macro, orelang.Closure; 6 import std.algorithm, std.exception, std.stdio, std.array, std.format, 7 std.traits, std.regex, std.conv; 8 9 enum ValueType { 10 ImmediateValue, 11 SymbolValue, 12 IExpression, 13 ClassType, 14 IOperator, 15 Closure, 16 HashMap, 17 Numeric, 18 String, 19 Ubyte, 20 Bool, 21 Null, 22 Array, 23 Macro, 24 CCException, 25 RAWPointer 26 } 27 28 class CCException { 29 string msg; 30 31 this(string msg) { 32 this.msg = msg; 33 } 34 } 35 36 class Value { 37 ValueType type; 38 39 private { 40 double numeric_value; 41 string string_value; 42 bool bool_value; 43 ubyte ubyte_value; 44 Value[] array_value; 45 ImmediateValue imv_value; 46 SymbolValue sym_value; 47 IExpression ie_value; 48 ClassType class_value; 49 IOperator io_value; 50 Closure closure_value; 51 Value[string] hashmap_value; 52 Macro macro_value; 53 CCException excep_value; 54 void* raw_pointer; 55 } 56 57 this() { 58 this.type = ValueType.Null; 59 } 60 61 this(ValueType type) { 62 this.type = type; 63 } 64 65 this(T)(T value) if (isNumeric!T) { 66 this.opAssign(value); 67 } 68 69 this(string value) { 70 this.opAssign(value); 71 } 72 73 this(bool value) { 74 this.opAssign(value); 75 } 76 77 this(ubyte value) { 78 this.init; 79 this.ubyte_value = value; 80 this.type = ValueType.Ubyte; 81 } 82 83 this(Value[] value) { 84 this.opAssign(value); 85 } 86 87 this(ImmediateValue value) { 88 this.init; 89 this.imv_value = value; 90 this.type = ValueType.ImmediateValue; 91 } 92 93 this(SymbolValue value) { 94 this.init; 95 this.sym_value = value; 96 this.type = ValueType.SymbolValue; 97 } 98 99 this(IExpression value) { 100 this.opAssign(value); 101 } 102 103 this(ClassType value) { 104 this.opAssign(value); 105 } 106 107 this(IOperator value) { 108 this.opAssign(value); 109 } 110 111 this(Closure value) { 112 this.opAssign(value); 113 } 114 115 this(Value[string] value) { 116 this.opAssign(value); 117 } 118 119 this(Macro value) { 120 this.init; 121 this.macro_value = value; 122 this.type = ValueType.Macro; 123 } 124 125 this(CCException excep) { 126 this.init; 127 this.excep_value = excep; 128 this.type = ValueType.CCException; 129 } 130 131 this(void* ptr) { 132 this.init; 133 this.raw_pointer = ptr; 134 this.type = ValueType.RAWPointer; 135 } 136 137 double getNumeric() { 138 enforce(this.type == ValueType.Numeric); 139 return this.numeric_value; 140 } 141 142 string getString() { 143 enforce(this.type == ValueType.String || this.type == ValueType.SymbolValue); 144 return this.type == ValueType.String ? this.string_value : this.sym_value.value; 145 } 146 147 bool getBool() { 148 enforce(this.type == ValueType.Bool); 149 return this.bool_value; 150 } 151 152 ubyte getUbyte() { 153 enforce(this.type == ValueType.Ubyte); 154 return this.ubyte_value; 155 } 156 157 auto getNull() { 158 throw new Exception("Can't get from NULL value"); 159 } 160 161 Value[] getArray() { 162 enforce(this.type == ValueType.Array); 163 return this.array_value; 164 } 165 166 ImmediateValue getImmediateValue() { 167 enforce(this.type == ValueType.ImmediateValue); 168 return this.imv_value; 169 } 170 171 SymbolValue getSymbolValue() { 172 enforce(this.type == ValueType.SymbolValue); 173 return this.sym_value; 174 } 175 176 IExpression getIExpression() { 177 enforce(this.type == ValueType.IExpression); 178 return this.ie_value; 179 } 180 181 ClassType getClassType() { 182 enforce(this.type == ValueType.ClassType); 183 return this.class_value; 184 } 185 186 IOperator getIOperator() { 187 enforce(this.type == ValueType.IOperator); 188 return this.io_value; 189 } 190 191 Closure getClosure() { 192 enforce(this.type == ValueType.Closure); 193 return this.closure_value; 194 } 195 196 Value[string] getHashMap() { 197 enforce(this.type == ValueType.HashMap); 198 return this.hashmap_value; 199 } 200 201 Macro getMacro() { 202 enforce(this.type == ValueType.Macro); 203 return this.macro_value; 204 } 205 206 CCException getCCException() { 207 enforce(this.type == ValueType.CCException); 208 return this.excep_value; 209 } 210 211 void* getRAWPointer() { 212 enforce(this.type == ValueType.RAWPointer); 213 return this.raw_pointer; 214 } 215 216 void opAssign(T)(T value) if (isNumeric!T) { 217 this.init; 218 this.numeric_value = value; 219 this.type = ValueType.Numeric; 220 } 221 222 void opAssign(T)(T value) if (is(T == string)) { 223 this.init; 224 this.string_value = value; 225 this.type = ValueType.String; 226 } 227 228 void opAssign(bool value) { 229 this.init; 230 this.bool_value = value; 231 this.type = ValueType.Bool; 232 } 233 234 void opAssign(T)(T[] value) if (is(T == Value)) { 235 this.init; 236 this.array_value = value; 237 this.type = ValueType.Array; 238 } 239 240 void opAssign(T)(T[] value) if (!is(T == Value) && !is(T == immutable(char))) { 241 this.init; 242 this.array_value = []; 243 244 foreach (e; value) 245 this.array_value ~= new Value(e); 246 247 this.type = ValueType.Array; 248 } 249 250 void opAssign(IExpression value) { 251 this.init; 252 this.ie_value = value; 253 this.type = ValueType.IExpression; 254 } 255 256 void opAssign(ClassType value) { 257 this.init; 258 this.class_value = value; 259 this.type = ValueType.ClassType; 260 } 261 262 void opAssign(IOperator value) { 263 this.init; 264 this.io_value = value; 265 this.type = ValueType.IOperator; 266 } 267 268 void opAssign(Closure value) { 269 this.init; 270 this.closure_value = value; 271 this.type = ValueType.Closure; 272 } 273 274 void opAssign(Value[string] value) { 275 this.init; 276 this.hashmap_value = value; 277 this.type = ValueType.HashMap; 278 } 279 280 override string toString() { 281 final switch (this.type) with (ValueType) { 282 case Numeric: 283 return this.numeric_value.to!string; 284 case String: 285 return this.string_value; 286 case Bool: 287 return this.bool_value.to!string; 288 case Ubyte: 289 return this.ubyte_value.to!string; 290 case Null: 291 return "null"; 292 case Array: 293 return "[" ~ this.array_value.map!(value => value.toString).array.join(", ") ~ "]"; 294 case HashMap: 295 return this.hashmap_value.to!string; 296 case ImmediateValue: 297 return this.imv_value.toString; 298 case SymbolValue: 299 return this.sym_value.value; 300 case IExpression: 301 return this.ie_value.stringof; 302 case ClassType: 303 return this.class_value.stringof; 304 case IOperator: 305 return this.io_value.stringof; 306 case Closure: 307 return this.closure_value.stringof; 308 case Macro: 309 return this.macro_value.stringof; 310 case CCException: 311 return this.excep_value.msg; 312 case RAWPointer: 313 return "Pointer<%x>".format(this.raw_pointer); 314 } 315 } 316 317 void addTo(Value value) { 318 enforce(this.type == value.type && value.type == ValueType.Numeric); 319 this.numeric_value += value.getNumeric; 320 } 321 322 void subTo(Value value) { 323 enforce(this.type == value.type && value.type == ValueType.Numeric); 324 this.numeric_value -= value.getNumeric; 325 } 326 327 void mulTo(Value value) { 328 enforce(this.type == value.type && value.type == ValueType.Numeric); 329 this.numeric_value *= value.getNumeric; 330 } 331 332 void divTo(Value value) { 333 enforce(this.type == value.type && value.type == ValueType.Numeric); 334 this.numeric_value /= value.getNumeric; 335 } 336 337 void modTo(Value value) { 338 enforce(this.type == value.type && value.type == ValueType.Numeric); 339 this.numeric_value %= value.getNumeric; 340 } 341 342 Value opBinary(string op)(Value value) if (op == "+") { 343 enforce(value.type == ValueType.Numeric); 344 return new Value(this.numeric_value + value.getNumeric); 345 } 346 347 Value opBinary(string op)(Value value) if (op == "-") { 348 enforce(value.type == ValueType.Numeric); 349 350 return new Value(this.numeric_value - value.getNumeric); 351 } 352 353 Value opBinary(string op)(Value value) if (op == "*") { 354 enforce(value.type == ValueType.Numeric); 355 return new Value(this.numeric_value * value.getNumeric); 356 } 357 358 Value opBinary(string op)(Value value) if (op == "/") { 359 enforce(value.type == ValueType.Numeric); 360 return new Value(this.numeric_value / value.getNumeric); 361 } 362 363 Value opBinary(string op)(Value value) if (op == "%") { 364 enforce(value.type == ValueType.Numeric); 365 return new Value(this.numeric_value % value.getNumeric); 366 } 367 368 void init() { 369 if (this.type != ValueType.Null) { 370 if (this.type == ValueType.Numeric) { 371 this.numeric_value = 0; 372 } 373 if (this.type == ValueType.String) { 374 this.string_value = ""; 375 } 376 if (this.type == ValueType.Array) { 377 this.array_value = []; 378 } 379 if (this.type == ValueType.Bool) { 380 this.bool_value = false; 381 } 382 if (this.type == ValueType.Ubyte) { 383 this.ubyte_value = 0; 384 } 385 if (this.type == ValueType.ImmediateValue) { 386 this.imv_value = null; 387 } 388 if (this.type == ValueType.SymbolValue) { 389 this.sym_value = null; 390 } 391 if (this.type == ValueType.IExpression) { 392 this.ie_value = null; 393 } 394 if (this.type == ValueType.ClassType) { 395 this.class_value = null; 396 } 397 if (this.type == ValueType.IOperator) { 398 this.io_value = null; 399 } 400 if (this.type == ValueType.Closure) { 401 this.closure_value = null; 402 } 403 if (this.type == ValueType.HashMap) { 404 this.hashmap_value = null; 405 } 406 if (this.type == ValueType.Macro) { 407 this.macro_value = null; 408 } 409 if (this.type == ValueType.CCException) { 410 this.excep_value = null; 411 } 412 if (this.type == ValueType.RAWPointer) { 413 this.raw_pointer = null; 414 } 415 416 this.type = ValueType.Null; 417 } 418 } 419 420 Value opIndex() { 421 enforce(this.type == ValueType.Array); 422 423 return new Value; 424 } 425 426 Value opIndex(size_t idx) { 427 enforce(this.type == ValueType.Array); 428 429 if (!(idx < this.array_value.length)) { 430 throw new Exception("Out of index of the Array, orded - " ~ idx.to!string 431 ~ " but length of the array is " ~ this.array_value.length.to!string); 432 } 433 434 return this.array_value[idx]; 435 } 436 437 Value opIndex(Value value) { 438 enforce(this.type == ValueType.HashMap); 439 440 if (value.getString !in this.hashmap_value) { 441 throw new Exception( 442 "No such a key in the hash, key - " ~ value.toString ~ ", hash - " 443 ~ this.hashmap_value.stringof); 444 } 445 446 return this.hashmap_value[value.getString]; 447 } 448 449 override bool opEquals(Object _value) { 450 if ((cast(Value)_value) is null) { 451 throw new Exception("Can not compare between incompatibility"); 452 } 453 454 Value value = cast(Value)_value; 455 456 if (this.type != value.type) { 457 throw new Exception( 458 "Can not compare between incompatibility type " 459 ~ this.type.to!string ~ " and " ~ value.type.to!string); 460 } 461 462 final switch (this.type) with (ValueType) { 463 case ImmediateValue: 464 throw new Exception("Can't compare with ImmediateValue"); 465 case SymbolValue: 466 return this.sym_value.value == value.getSymbolValue.value; 467 case IExpression: 468 throw new Exception("Can't compare with IExpression"); 469 case ClassType: 470 throw new Exception("Can't compare with ClassType"); 471 case IOperator: 472 throw new Exception("Can't compare with IOperator"); 473 case Closure: 474 throw new Exception("Can't compare with Closure"); 475 case HashMap: 476 throw new Exception("Can't compare with HashMap"); 477 case Macro: 478 throw new Exception("Can't compare with Macro"); 479 case CCException: 480 throw new Exception("Can't compare with CCException"); 481 case Numeric: 482 return this.numeric_value == value.numeric_value; 483 case String: 484 return this.string_value == value.string_value; 485 case Bool: 486 return this.bool_value == value.bool_value; 487 case Ubyte: 488 return this.ubyte_value == value.ubyte_value; 489 case Null: 490 throw new Exception("Can't compare with Null"); 491 case Array: 492 Value[] a = this.getArray, b = value.getArray; 493 494 if (a.length != b.length) { 495 return false; 496 } 497 498 foreach (idx; 0 .. (a.length)) { 499 if (a[idx].opCmp(b[idx]) != 0) { 500 return false; 501 } 502 } 503 504 return true; 505 case RAWPointer: 506 return this.raw_pointer == value.raw_pointer; 507 } 508 } 509 510 override int opCmp(Object _value) { 511 if ((cast(Value)_value) is null) { 512 throw new Exception("Can not compare between incompatibility"); 513 } 514 515 Value value = cast(Value)_value; 516 517 if (this.type != value.type) { 518 throw new Exception( 519 "Can not compare between incompatibility type " 520 ~ this.type.to!string ~ " and " ~ value.type.to!string); 521 } 522 523 final switch (this.type) with (ValueType) { 524 case ImmediateValue: 525 throw new Exception("Can't compare with ImmediateValue"); 526 case SymbolValue: 527 auto c = this.sym_value.value, d = value.getSymbolValue.value; 528 if (c == d) { 529 return 0; 530 } 531 if (c < d) { 532 return -1; 533 } 534 return 1; 535 case IExpression: 536 throw new Exception("Can't compare with IExpression"); 537 case ClassType: 538 throw new Exception("Can't compare with ClassType"); 539 case IOperator: 540 throw new Exception("Can't compare with IOperator"); 541 case Closure: 542 throw new Exception("Can't compare with Closure"); 543 case HashMap: 544 throw new Exception("Can't compare with HashMap"); 545 case Macro: 546 throw new Exception("Can't compare with Macro"); 547 case CCException: 548 throw new Exception("Can't compare with CCException"); 549 case Numeric: 550 auto c = this.numeric_value, d = value.numeric_value; 551 552 if (c == d) { 553 return 0; 554 } 555 if (c < d) { 556 return -1; 557 } 558 return 1; 559 case String: 560 auto c = this.string_value, d = value.string_value; 561 562 if (c == d) { 563 return 0; 564 } 565 if (c < d) { 566 return -1; 567 } 568 return 1; 569 case Ubyte: 570 auto c = this.ubyte_value, d = value.ubyte_value; 571 572 if (c == d) { 573 return 0; 574 } 575 if (c < d) { 576 return -1; 577 } 578 return 1; 579 case Bool: 580 throw new Exception("Can't compare with Bool"); 581 case Null: 582 throw new Exception("Can't compare with Null"); 583 case Array: 584 Value[] a = this.getArray, b = value.getArray; 585 586 if (a.length != b.length) { 587 throw new Exception("Can't compare between different size array"); 588 } 589 590 foreach (idx; 0 .. (a.length)) { 591 if (a[idx].opCmp(b[idx]) != 0) { 592 return 1; 593 } 594 } 595 596 return 0; 597 case RAWPointer: 598 auto c = this.raw_pointer, d = value.raw_pointer; 599 600 if (c == d) { 601 return 0; 602 } 603 if (c < d) { 604 return -1; 605 } 606 return 1; 607 } 608 } 609 610 Value dup() { 611 final switch (this.type) with (ValueType) { 612 case ImmediateValue: 613 return new Value(this.imv_value); 614 case SymbolValue: 615 return new Value(this.sym_value); 616 case IExpression: 617 return new Value(this.ie_value); 618 case ClassType: 619 return new Value(this.class_value); 620 case IOperator: 621 return new Value(this.io_value); 622 case Closure: 623 return new Value(this.closure_value); 624 case HashMap: 625 return new Value(this.hashmap_value); 626 case Numeric: 627 return new Value(this.numeric_value); 628 case String: 629 return new Value(this.string_value); 630 case Bool: 631 return new Value(this.bool_value); 632 case Ubyte: 633 return new Value(this.ubyte_value); 634 case Null: 635 return new Value; 636 case Array: 637 return new Value(this.array_value.dup); 638 case Macro: 639 return new Value(this.macro_value); 640 case CCException: 641 return new Value(this.excep_value); 642 case RAWPointer: 643 return new Value(this.raw_pointer); 644 } 645 } 646 }