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 }