1 // This file is part of Visual D
2 //
3 // Visual D integrates the D programming language into Visual Studio
4 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
8 //
9 // Interpretation passes around a context, holding the current variable stack
10 // class Context { Scope sc; Value[Node] vars; Context parent; }
11 //
12 // static shared values are not looked up in the context
13 // thread local static values are looked up in a global thread context
14 // non-static values are looked up in the current context
15 //
16 // member/field lookup in aggregates uses an instance specific Context
17 //
18 // when entering a scope, a new Context is created with the current
19 //  Context as parent
20 // when leaving a scope, the context is destroyed together with scoped values
21 //  created within the lifetime of the context
22 // a delegate value saves the current context to be used when calling the delegate
23 //
24 // local functions are called with the context of the enclosing function
25 // member functions are called with the context of the instance
26 // static or global functions are called with the thread context
27 //
28 module vdc.interpret;
29 
30 import vdc.util;
31 import vdc.semantic;
32 import vdc.lexer;
33 import vdc.logger;
34 
35 import vdc.ast.decl;
36 import vdc.ast.type;
37 import vdc.ast.aggr;
38 import vdc.ast.expr;
39 import vdc.ast.node;
40 import vdc.ast.writer;
41 
42 import stdext.util;
43 import stdext.string;
44 
45 import std.conv;
46 import std.meta;
47 import std.string;
48 import std.traits;
49 import std.utf;
50 import std.variant;
51 
52 template Singleton(T, ARGS...)
53 {
54     T get()
55     {
56         static T instance;
57         if(!instance)
58             instance = new T(ARGS);
59         return instance;
60     }
61 }
62 
63 class Value
64 {
65     bool mutable = true;
66     bool literal = false;
67     debug string sval;
68     debug string ident;
69 
70     static T _create(T, V)(V val)
71     {
72         T v = new T;
73         *v.pval = val;
74         debug v.sval = v.toStr();
75         return v;
76     }
77 
78     static Value create(bool    v) { return _create!BoolValue   (v); }
79     static Value create(byte    v) { return _create!ByteValue   (v); }
80     static Value create(ubyte   v) { return _create!UByteValue  (v); }
81     static Value create(short   v) { return _create!ShortValue  (v); }
82     static Value create(ushort  v) { return _create!UShortValue (v); }
83     static Value create(int     v) { return _create!IntValue    (v); }
84     static Value create(uint    v) { return _create!UIntValue   (v); }
85     static Value create(long    v) { return _create!LongValue   (v); }
86     static Value create(ulong   v) { return _create!ULongValue  (v); }
87     static Value create(char    v) { return _create!CharValue   (v); }
88     static Value create(wchar   v) { return _create!WCharValue  (v); }
89     static Value create(dchar   v) { return _create!DCharValue  (v); }
90     static Value create(float   v) { return _create!FloatValue  (v); }
91     static Value create(double  v) { return _create!DoubleValue (v); }
92     static Value create(real    v) { return _create!RealValue   (v); }
93     static Value create(string  v) { return createStringValue (v); }
94 
95     Type getType()
96     {
97         semanticError("cannot get type of ", this);
98         return Singleton!(ErrorType).get();
99     }
100 
101     bool toBool()
102     {
103         semanticError("cannot convert ", this, " to bool");
104         return false;
105     }
106 
107     int toInt()
108     {
109         long lng = toLong();
110         return cast(int) lng;
111     }
112 
113     long toLong()
114     {
115         semanticError("cannot convert ", this, " to integer");
116         return 0;
117     }
118 
119     void setLong(long lng)
120     {
121         semanticError("cannot convert long to ", this);
122     }
123 
124     string toStr()
125     {
126         semanticError("cannot convert ", this, " to string");
127         return "";
128     }
129 
130     string toMixin()
131     {
132         semanticError("cannot convert ", this, " to mixin");
133         return "";
134     }
135 
136     Value getElement(size_t idx)
137     {
138         return semanticErrorValue("cannot get ", idx, ". element of array of ", this);
139     }
140 
141     void setElements(size_t oldcnt, size_t newcnt)
142     {
143         semanticError("cannot set no of elements of array of ", this);
144     }
145 
146     PointerValue toPointer(TypePointer to)
147     {
148         return null;
149     }
150 
151     final void validate()
152     {
153         debug sval = toStr();
154     }
155 
156     //override string toString()
157     //{
158     //    return text(getType(), ":", toStr());
159     //}
160 
161     version(all)
162     Value opBin(Context ctx, int tokid, Value v)
163     {
164         return semanticErrorValue("cannot calculate ", this, " ", tokenString(tokid), " ", v);
165         //return semanticErrorValue("binary operator ", tokenString(tokid), " on ", this, " not implemented");
166     }
167 
168     Value opBin_r(Context ctx, int tokid, Value v)
169     {
170         return semanticErrorValue("cannot calculate ", v, " ", tokenString(tokid), " ", this);
171         //return semanticErrorValue("binary operator ", tokenString(tokid), " on ", this, " not implemented");
172     }
173 
174     Value opUn(Context ctx, int tokid)
175     {
176         switch(tokid)
177         {
178             case TOK_and:        return opRefPointer();
179             case TOK_mul:        return opDerefPointer();
180             default: break;
181         }
182         return semanticErrorValue("unary operator ", tokenString(tokid), " on ", this, " not implemented");
183     }
184 
185     Value opRefPointer()
186     {
187         auto tp = new TypePointer();
188         tp.setNextType(getType()); //addMember(getType().clone());
189         return PointerValue._create(tp, this);
190     }
191     Value opDerefPointer()
192     {
193         return semanticErrorValue("cannot dereference a ", this);
194     }
195 
196     final Value interpretProperty(Context ctx, string prop)
197     {
198         if(Value v = _interpretProperty(ctx, prop))
199             return v;
200         return semanticErrorValue("cannot calculate property ", prop, " of value ", toStr());
201     }
202 
203     Value _interpretProperty(Context ctx, string prop)
204     {
205         return getType()._interpretProperty(ctx, prop);
206     }
207 
208     Value doCast(Value v)
209     {
210         return semanticErrorValue("cannot cast a ", v, " to ", this);
211     }
212 
213     Value opIndex(Value v)
214     {
215         return semanticErrorValue("cannot index a ", this);
216     }
217 
218     Value opSlice(Value b, Value e)
219     {
220         return semanticErrorValue("cannot slice a ", this);
221     }
222 
223     Value opCall(Context sc, Value args)
224     {
225         return semanticErrorValue("cannot call a ", this);
226     }
227 
228     //mixin template operators()
229     version(none)
230         Value opassign(string op)(Value v)
231         {
232             TypeInfo ti1 = typeid(this);
233             TypeInfo ti2 = typeid(v);
234             foreach(iv1; BasicTypeValues)
235             {
236                 if(ti1 is typeid(iv1))
237                 {
238                     foreach(iv2; BasicTypeValues)
239                     {
240                         if(ti2 is typeid(iv2))
241                             static if (__traits(compiles, {
242                                 iv1.ValType x;
243                                 iv2.ValType y;
244                                 mixin("x " ~ op ~ "y;");
245                             }))
246                             {
247                                 iv2.ValType v2 = (cast(iv2) v).val;
248                                 static if(op == "/=" || op == "%=")
249                                     if(v2 == 0)
250                                         return semanticErrorValue("division by zero");
251                                 mixin("(cast(iv1) this).val " ~ op ~ "v2;");
252                                 return this;
253                             }
254                     }
255                 }
256             }
257             return semanticErrorValue("cannot execute ", op, " on a ", v, " with a ", this);
258         }
259 
260     version(none)
261         Value opBinOp(string op)(Value v)
262         {
263             TypeInfo ti1 = typeid(this);
264             TypeInfo ti2 = typeid(v);
265             foreach(iv1; BasicTypeValues)
266             {
267                 if(ti1 is typeid(iv1))
268                 {
269                     foreach(iv2; BasicTypeValues)
270                     {
271                         if(ti2 is typeid(iv2))
272                         {
273                             static if (__traits(compiles, {
274                                 iv1.ValType x;
275                                 iv2.ValType y;
276                                 mixin("auto z = x " ~ op ~ "y;");
277                             }))
278                             {
279                                 iv1.ValType v1 = (cast(iv1) this).val;
280                                 iv2.ValType v2 = (cast(iv2) v).val;
281                                 static if(op == "/" || op == "%")
282                                     if(v2 == 0)
283                                         return semanticErrorValue("division by zero");
284                                 mixin("auto z = v1 " ~ op ~ "v2;");
285                                 return create(z);
286                             }
287                             else
288                             {
289                                 return semanticErrorValue("cannot calculate ", op, " on a ", this, " and a ", v);
290                             }
291                         }
292                     }
293                 }
294             }
295             return semanticErrorValue("cannot calculate ", op, " on a ", this, " and a ", v);
296         }
297 
298     version(none)
299         Value opUnOp(string op)()
300         {
301             TypeInfo ti1 = typeid(this);
302             foreach(iv1; BasicTypeValues)
303             {
304                 if(ti1 is typeid(iv1))
305                 {
306                     static if (__traits(compiles, {
307                         iv1.ValType x;
308                         mixin("auto z = " ~ op ~ "x;");
309                     }))
310                     {
311                         mixin("auto z = " ~ op ~ "(cast(iv1) this).val;");
312                         return create(z);
313                     }
314                 }
315             }
316             return semanticErrorValue("cannot calculate ", op, " on a ", this);
317         }
318 
319     ////////////////////////////////////////////////////////////
320     mixin template mixinBinaryOp1(string op, iv2)
321     {
322         Value binOp1(Value v)
323         {
324             if(auto vv = cast(iv2) v)
325             {
326                 iv2.ValType v2 = *vv.pval;
327                 static if(op == "/" || op == "%")
328                     if(v2 == 0)
329                         return semanticErrorValue("division by zero");
330                 mixin("auto z = *pval " ~ op ~ "v2;");
331                 return create(z);
332             }
333             return semanticErrorValue("cannot calculate ", op, " on ", this, " and ", v);
334         }
335     }
336 
337     mixin template mixinBinaryOp(string op, Types...)
338     {
339         Value binOp(Value v)
340         {
341             TypeInfo ti = typeid(v);
342             foreach(iv2; Types)
343             {
344                 if(ti is typeid(iv2))
345                 {
346                     static if (__traits(compiles, {
347                         iv2.ValType y;
348                         mixin("auto z = (*pval) " ~ op ~ " y;");
349                     }))
350                     {
351                         iv2.ValType v2 = *(cast(iv2) v).pval;
352                         static if(op == "/" || op == "%")
353                             if(v2 == 0)
354                                 return semanticErrorValue("division by zero");
355                         static if(op == "^^" && isIntegral!(ValType) && isIntegral!(iv2.ValType))
356                             if(v2 < 0)
357                                 return semanticErrorValue("integer pow with negative exponent");
358 
359                         mixin("auto z = (*pval) " ~ op ~ " v2;");
360                         return create(z);
361                     }
362                     else
363                         break;
364                 }
365             }
366             return semanticErrorValue("cannot calculate ", op, " on a ", this, " and a ", v);
367         }
368     }
369 
370     mixin template mixinAssignOp(string op, Types...)
371     {
372         Value assOp(Value v)
373         {
374             if(!mutable)
375                 return semanticErrorValue(this, " value is not mutable");
376 
377             TypeInfo ti = typeid(v);
378             foreach(iv2; Types)
379             {
380                 if(ti is typeid(iv2))
381                 {
382                     static if (__traits(compiles, {
383                         iv2.ValType y;
384                         mixin("*pval " ~ op ~ " y;");
385                     }))
386                     {
387                         iv2.ValType v2 = *(cast(iv2) v).pval;
388                         static if(op == "/=" || op == "%=")
389                             if(v2 == 0)
390                                 return semanticErrorValue("division by zero");
391                         static if(op == "%=" && (is(T == float) || is(T == double) || is(T == real))) // compiler bug
392                             mixin("*pval = *pval % v2;");
393                         else
394                             mixin("*pval " ~ op ~ " v2;");
395 
396                         debug logInfo("value %s changed by %s to %s", ident, op, toStr());
397                         debug sval = toStr();
398                         return this;
399                     }
400                     else
401                         break;
402                 }
403             }
404             return semanticErrorValue("cannot assign ", op, " a ", v, " to a ", this);
405         }
406     }
407 }
408 
409 T createInitValue(T)(Context ctx, Value initValue)
410 {
411     T v = new T;
412     if(initValue)
413         v.opBin(ctx, TOK_assign, initValue);
414     return v;
415 }
416 
417 alias AliasSeq!(bool, byte, ubyte, short, ushort,
418                 int, uint, long, ulong,
419                 char, wchar, dchar,
420                 float, double, real,
421                 ifloat, idouble, ireal,
422                 cfloat, cdouble, creal) BasicTypes;
423 
424 alias AliasSeq!(BoolValue, ByteValue, UByteValue, ShortValue, UShortValue,
425                 IntValue, UIntValue, LongValue, ULongValue,
426                 CharValue, WCharValue, DCharValue,
427                 FloatValue, DoubleValue, RealValue) BasicTypeValues;
428 alias AliasSeq!(BasicTypeValues, SetLengthValue) RHS_BasicTypeValues;
429 
430 alias AliasSeq!(TOK_bool, TOK_byte, TOK_ubyte, TOK_short, TOK_ushort,
431                 TOK_int, TOK_uint, TOK_long, TOK_ulong,
432                 TOK_char, TOK_wchar, TOK_dchar,
433                 TOK_float, TOK_double, TOK_real) BasicTypeTokens;
434 
435 int BasicType2Token(T)()     { return BasicTypeTokens[staticIndexOf!(T, BasicTypes)]; }
436 
437 template BasicType2ValueType(T)
438 {
439     alias BasicTypeValues[staticIndexOf!(T, BasicTypes)] BasicType2ValueType;
440 }
441 
442 template Token2BasicType(int tok)
443 {
444     alias BasicTypes[staticIndexOf!(tok, BasicTypeTokens)] Token2BasicType;
445 }
446 
447 template Token2ValueType(int tok)
448 {
449     alias BasicTypeValues[staticIndexOf!(tok, BasicTypeTokens)] Token2ValueType;
450 }
451 
452 class ValueT(T) : Value
453 {
454     alias T ValType;
455 
456     ValType* pval;
457 
458     this()
459     {
460         pval = (new ValType[1]).ptr;
461         debug sval = toStr();
462     }
463 
464     static int getTypeIndex() { return staticIndexOf!(ValType, BasicTypes); }
465 
466     override Type getType()
467     {
468         static Type instance;
469         if(!instance)
470             instance = createBasicType(BasicTypeTokens[getTypeIndex()]);
471         return instance;
472     }
473 
474     override string toStr()
475     {
476         return to!string(*pval);
477     }
478 
479     override Value getElement(size_t idx)
480     {
481         alias BasicTypeValues[getTypeIndex()] ValueType;
482         auto v = new ValueType;
483         v.pval = pval + idx;
484         debug v.sval = v.toStr();
485         return v;
486     }
487 
488     override void setElements(size_t oldcnt, size_t newcnt)
489     {
490         ValType[] arr = pval[0 .. oldcnt];
491         arr.length = newcnt;
492         pval = arr.ptr;
493         debug sval = toStr();
494     }
495 
496 //    pragma(msg, ValType);
497 //    pragma(msg, text(" compiles?", __traits(compiles, val ? true : false )));
498 
499     // pragma(msg, "toBool " ~ ValType.stringof ~ (__traits(compiles, *pval ? true : false) ? " compiles" : " fails"));
500     static if(__traits(compiles, *pval ? true : false))
501         override bool toBool()
502         {
503             return *pval ? true : false;
504         }
505 
506     // pragma(msg, "toLong " ~ ValType.stringof ~ (__traits(compiles, function long () { ValType v; return v; }) ? " compiles" : " fails"));
507     static if(__traits(compiles, function long () { ValType v; return v; } ))
508         override long toLong()
509         {
510             return *pval;
511         }
512 
513     ////////////////////////////////////////////////////////////
514     static string genMixinBinOpAll()
515     {
516         string s;
517         for(int i = TOK_binaryOperatorFirst; i <= TOK_binaryOperatorLast; i++)
518         {
519             static if(!supportUnorderedCompareOps) if(i >= TOK_unorderedOperatorFirst && i <= TOK_unorderedOperatorLast)
520                 continue;
521             if(i >= TOK_assignOperatorFirst && i <= TOK_assignOperatorLast)
522                 s ~= text("mixin mixinAssignOp!(\"", tokenString(i), "\", RHS_BasicTypeValues) ass_", operatorName(i), ";\n");
523             else
524                 s ~= text("mixin mixinBinaryOp!(\"", tokenString(i), "\", RHS_BasicTypeValues) bin_", operatorName(i), ";\n");
525         }
526         return s;
527     }
528 
529     mixin(genMixinBinOpAll());
530     mixin mixinBinaryOp!("is", RHS_BasicTypeValues) bin_is;
531 
532     static string genBinOpCases()
533     {
534         string s;
535         for(int i = TOK_binaryOperatorFirst; i <= TOK_binaryOperatorLast; i++)
536         {
537             static if(!supportUnorderedCompareOps) if(i >= TOK_unorderedOperatorFirst && i <= TOK_unorderedOperatorLast)
538                 continue;
539             if(i >= TOK_assignOperatorFirst && i <= TOK_assignOperatorLast)
540                 s ~= text("case ", i, ": return ass_", operatorName(i), ".assOp(v);\n");
541             else
542                 s ~= text("case ", i, ": return bin_", operatorName(i), ".binOp(v);\n");
543         }
544         return s;
545     }
546 
547     override Value opBin(Context ctx, int tokid, Value v)
548     {
549         switch(tokid)
550         {
551             mixin(genBinOpCases());
552             case TOK_is: return bin_is.binOp(v);
553             default: break;
554         }
555 
556         return semanticErrorValue("cannot calculate '", tokenString(tokid), "' on a ", this, " and a ", v);
557     }
558 
559     ////////////////////////////////////////////////////////////
560     mixin template mixinUnaryOp(string op)
561     {
562         Value unOp()
563         {
564             static if (__traits(compiles, { mixin("auto z = " ~ op ~ "(*pval);"); }))
565             {
566                 mixin("auto z = " ~ op ~ "(*pval);");
567                 return create(z);
568             }
569             else
570             {
571                 return semanticErrorValue("cannot calculate '", op, "' on a ", this);
572             }
573         }
574     }
575 
576     enum int[] unOps = [ TOK_plusplus, TOK_minusminus, TOK_min, TOK_add, TOK_not, TOK_tilde ];
577 
578     static string genMixinUnOpAll()
579     {
580         string s;
581         foreach(id; unOps)
582             s ~= text("mixin mixinUnaryOp!(\"", tokenString(id), "\") un_", operatorName(id), ";\n");
583         return s;
584     }
585 
586     mixin(genMixinUnOpAll());
587 
588     static string genUnOpCases()
589     {
590         string s;
591         foreach(id; unOps)
592             s ~= text("case ", id, ": return un_", operatorName(id), ".unOp();\n");
593         return s;
594     }
595 
596     override Value opUn(Context ctx, int tokid)
597     {
598         switch(tokid)
599         {
600             case TOK_and:        return opRefPointer();
601             case TOK_mul:        return opDerefPointer();
602             mixin(genUnOpCases());
603             default: break;
604         }
605         return semanticErrorValue("cannot calculate '", tokenString(tokid), "' on a ", this);
606     }
607 
608     override Value doCast(Value v)
609     {
610         if(!mutable) // doCast changes this value
611             return semanticErrorValue(this, " value is not mutable");
612 
613         TypeInfo ti = typeid(v);
614         foreach(iv2; RHS_BasicTypeValues)
615         {
616             if(ti is typeid(iv2))
617             {
618                 static if (__traits(compiles, {
619                     iv2.ValType y;
620                     *pval = cast(ValType)(y);
621                 }))
622                 {
623                     iv2.ValType v2 = *(cast(iv2) v).pval;
624                     *pval = cast(ValType)(v2);
625 
626                     debug logInfo("value %s changed by cast(" ~ ValType.stringof ~ ") to %s", ident, toStr());
627                     debug sval = toStr();
628                     return this;
629                 }
630                 else
631                     break;
632             }
633         }
634         return super.doCast(v);
635     }
636 }
637 
638 class VoidValue : Value
639 {
640     override string toStr()
641     {
642         return "void";
643     }
644 }
645 
646 VoidValue _theVoidValue;
647 
648 @property VoidValue theVoidValue()
649 {
650     if(!_theVoidValue)
651     {
652         _theVoidValue = new VoidValue;
653         _theVoidValue.mutable = false;
654     }
655     return _theVoidValue;
656 }
657 
658 class ErrorValue : Value
659 {
660     override string toStr()
661     {
662         return "_error_";
663     }
664 
665     override Type getType()
666     {
667         return Singleton!ErrorType.get();
668     }
669 }
670 
671 class NullValue : Value
672 {
673     override string toStr()
674     {
675         return "null";
676     }
677 
678     override Type getType()
679     {
680         return Singleton!NullType.get();
681     }
682 }
683 
684 class BoolValue : ValueT!bool
685 {
686 }
687 
688 class ByteValue : ValueT!byte
689 {
690 }
691 
692 class UByteValue : ValueT!ubyte
693 {
694 }
695 
696 class ShortValue : ValueT!short
697 {
698 }
699 
700 class UShortValue : ValueT!ushort
701 {
702 }
703 
704 class IntValue : ValueT!int
705 {
706 }
707 
708 class UIntValue : ValueT!uint
709 {
710 }
711 
712 class LongValue : ValueT!long
713 {
714 }
715 
716 class ULongValue : ValueT!ulong
717 {
718 }
719 
720 class CharValue : ValueT!char
721 {
722     override string toStr()
723     {
724         return "'" ~ toUTF8Safe(pval[0..1]) ~ "'";
725     }
726 }
727 
728 class WCharValue : ValueT!wchar
729 {
730     override string toStr()
731     {
732         return "'" ~ toUTF8Safe(pval[0..1]) ~ "'w";
733     }
734 }
735 
736 class DCharValue : ValueT!dchar
737 {
738     override string toStr()
739     {
740         return "'" ~ toUTF8Safe(pval[0..1]) ~ "'d";
741     }
742 }
743 
744 class FloatValue : ValueT!float
745 {
746 }
747 
748 class DoubleValue : ValueT!double
749 {
750 }
751 
752 class RealValue : ValueT!real
753 {
754 }
755 
756 class ArrayValueBase : Value
757 {
758     Value first;
759     size_t len;
760 
761     override string toStr()
762     {
763         string s = "[";
764         for(size_t i = 0; i < len; i++)
765         {
766             if(i > 0)
767                 s ~= ",";
768             Value v = first.getElement(i);
769             s ~= v.toStr();
770         }
771         s ~= "]";
772         return s;
773     }
774 
775     override Value opIndex(Value v)
776     {
777         int idx = v.toInt();
778         if(idx < 0 || idx >= len)
779             return semanticErrorValue("index ", idx, " out of bounds on value tuple");
780         return first.getElement(idx);
781     }
782 
783     void setItem(Context ctx, size_t idx, Value v)
784     {
785         if(idx < 0 || idx >= len)
786             return semanticError("index ", idx, " out of bounds on dynamic array");
787         first.getElement(idx).opBin(ctx, TOK_assign, v);
788     }
789 
790     ArrayValueBase createResultArray(Context ctx, Value fv, size_t nlen)
791     {
792         auto dim = new IntegerLiteralExpression();
793         dim.txt = to!string(nlen);
794         dim.value = nlen;
795         auto ntype = new TypeStaticArray;
796         ntype.addMember(fv.getType().clone());
797         ntype.addMember(dim);
798 
799         auto narr = static_cast!ArrayValueBase(ntype.createValue(ctx, null));
800         narr.first.getElement(0).opBin(ctx, TOK_assign, fv);
801         return narr;
802     }
803 
804     private Value getItem(size_t idx)
805     {
806         return first.getElement(idx);
807     }
808 
809     static Value _opBin(Context ctx, int tokid, Value v1, Value v2, bool reverse)
810     {
811         if(reverse)
812             return v2.opBin(ctx, tokid, v1);
813         return v1.opBin(ctx, tokid, v2);
814     }
815 
816     Value _opBin(Context ctx, int tokid, Value v, bool reverse)
817     {
818         switch(tokid)
819         {
820             case TOK_equal:
821             case TOK_lt:
822             case TOK_le:
823             case TOK_gt:
824             case TOK_ge:
825         static if(supportUnorderedCompareOps) {
826             case TOK_unord:
827             case TOK_ue:
828             case TOK_lg:
829             case TOK_leg:
830             case TOK_ule:
831             case TOK_ul:
832             case TOK_uge:
833             case TOK_ug:
834         }
835             //case TOK_notcontains:
836             //case TOK_notidentity:
837             //case TOK_is:
838             //case TOK_in:
839                 if(auto tv = cast(ArrayValueBase) v)
840                 {
841                     if(tv.len != len)
842                         return Value.create(false);
843                     for(int i = 0; i < len; i++)
844                         if(!_opBin(ctx, tokid, first.getElement(i), tv.first.getElement(i), reverse).toBool())
845                             return Value.create(false);
846                     return Value.create(true);
847                 }
848                 for(int i = 0; i < len; i++)
849                     if(!_opBin(ctx, tokid, first.getElement(i), v, reverse).toBool())
850                         return Value.create(false);
851                 return Value.create(true);
852 
853             case TOK_notequal:
854                 return Value.create(!opBin(ctx, TOK_equal, v).toBool());
855 
856             case TOK_add:
857             case TOK_min:
858             case TOK_mul:
859             case TOK_div:
860             case TOK_mod:
861             case TOK_pow:
862             case TOK_shl:
863             case TOK_shr:
864             case TOK_ushr:
865             case TOK_xor:
866             case TOK_or:
867             case TOK_and:
868             //case TOK_cat:
869                 if(auto tv = cast(ArrayValueBase) v)
870                 {
871                     if(tv.len != len)
872                         return semanticErrorValue(tokenString(tokid), " on arrays of different length ", len, " and ", tv.len);
873 
874                     if(len == 0)
875                         return getType().createValue(ctx, null);
876 
877                     Value fv = _opBin(ctx, tokid, first.getElement(0), tv.first.getElement(0), reverse);
878                     auto narr = createResultArray(ctx, fv, len);
879                     for(int i = 1; i < len; i++)
880                     {
881                         fv = _opBin(ctx, tokid, first.getElement(i), tv.first.getElement(i), reverse);
882                         narr.first.getElement(i).opBin(ctx, TOK_assign, fv);
883                     }
884                     debug narr.sval = narr.toStr();
885                     return narr;
886                 }
887 
888                 if(len == 0)
889                     return getType().createValue(ctx, null);
890 
891                 Value fv = _opBin(ctx, tokid, first.getElement(0), v, reverse);
892                 auto narr = createResultArray(ctx, fv, len);
893                 for(int i = 1; i < len; i++)
894                 {
895                     fv = _opBin(ctx, tokid, first.getElement(i), v, reverse);
896                     narr.first.getElement(i).opBin(ctx, TOK_assign, fv);
897                 }
898                 debug narr.sval = narr.toStr();
899                 return narr;
900 
901             default:
902                 if(reverse)
903                     return super.opBin_r(ctx, tokid, v);
904                 return super.opBin(ctx, tokid, v);
905         }
906     }
907 
908     override Value opBin(Context ctx, int tokid, Value v)
909     {
910         switch(tokid)
911         {
912             case TOK_addass:
913             case TOK_minass:
914             case TOK_mulass:
915             case TOK_divass:
916             case TOK_modass:
917             case TOK_powass:
918             case TOK_shlass:
919             case TOK_shrass:
920             case TOK_ushrass:
921             case TOK_xorass:
922             case TOK_orass:
923             case TOK_andass:
924             //case TOK_catass:
925                 if(auto tv = cast(ArrayValueBase) v)
926                 {
927                     if(tv.len != len)
928                         return semanticErrorValue(tokenString(tokid), " on arrays of different length ", len, " and ", tv.len);
929                     for(int i = 0; i < len; i++)
930                         first.getElement(i).opBin(ctx, tokid, tv.first.getElement(i));
931                 }
932                 else
933                 {
934                     for(int i = 0; i < len; i++)
935                         first.getElement(i).opBin(ctx, tokid, v);
936                 }
937                 debug sval = toStr();
938                 return this;
939 
940             default:
941                 return _opBin(ctx, tokid, v, false);
942         }
943     }
944 
945     override Value opBin_r(Context ctx, int tokid, Value v)
946     {
947         return _opBin(ctx, tokid, v, true);
948     }
949 
950     override Value opUn(Context ctx, int tokid)
951     {
952         switch(tokid)
953         {
954             case TOK_add:
955             case TOK_min:
956             case TOK_not:
957             case TOK_tilde:
958                 if(len == 0)
959                     return getType().createValue(ctx, null);
960 
961                 Value fv = first.getElement(0).opUn(ctx, tokid);
962                 auto narr = createResultArray(ctx, fv, len);
963                 for(int i = 1; i < len; i++)
964                 {
965                     fv = first.getElement(i).opUn(ctx, tokid);
966                     narr.first.getElement(i).opBin(ctx, TOK_assign, fv);
967                 }
968                 return narr;
969             default:
970                 return super.opUn(ctx, tokid);
971         }
972     }
973 }
974 
975 class ArrayValue(T) : ArrayValueBase
976 {
977     T type;
978 
979     void setLength(Context ctx, size_t newlen)
980     {
981         if(newlen > len)
982         {
983             if(len == 0)
984             {
985                 first = type.getNextType().createValue(ctx, null);
986                 first.setElements(1, newlen);
987             }
988             else
989                 first.setElements(len, newlen);
990         }
991         len = newlen;
992         // intermediate state, cannot set sval yet
993     }
994 
995     override Value opSlice(Value b, Value e)
996     {
997         int idxb = b.toInt();
998         int idxe = e.toInt();
999         if(idxb < 0 || idxb > len || idxe < idxb || idxe > len)
1000             return semanticErrorValue("slice [", idxb, "..", idxe, "] out of bounds on value ", toStr());
1001         auto nv = type.opSlice(idxb, idxe).createValue(nullContext, null);
1002         if(auto arr = cast(ArrayValueBase) nv)
1003         {
1004             if(idxb == 0)
1005                 arr.first = first;
1006             else
1007                 arr.first = first.getElement(idxb);
1008             arr.len = idxe - idxb;
1009         }
1010         debug nv.sval = nv.toStr();
1011         return nv;
1012     }
1013 
1014 }
1015 
1016 class DynArrayValue : ArrayValue!TypeDynamicArray
1017 {
1018     this(TypeDynamicArray t)
1019     {
1020         type = t;
1021         debug sval = toStr();
1022     }
1023 
1024     override string toStr()
1025     {
1026         if(isString())
1027             return "\"" ~ toMixin() ~ "\"";
1028 
1029         return super.toStr();
1030     }
1031 
1032     override Type getType()
1033     {
1034         return type;
1035     }
1036 
1037     override Value opBin(Context ctx, int tokid, Value v)
1038     {
1039         switch(tokid)
1040         {
1041             case TOK_assign:
1042                 if(auto tv = cast(ArrayValueBase) v)
1043                 {
1044                     if(tv.len == 0)
1045                         first = null;
1046                     else
1047                         first = tv.first.getElement(0); // create copy of "ptr" value
1048                     len = tv.len;
1049                 }
1050                 else if(cast(NullValue) v)
1051                 {
1052                     first = null;
1053                     len = 0;
1054                 }
1055                 else
1056                     return semanticErrorValue("cannot assign ", v, " to ", this);
1057                 debug sval = toStr();
1058                 return this;
1059 
1060             case TOK_tilde:
1061                 if(auto ev = cast(ErrorValue) v)
1062                     return v;
1063                 auto nv = new DynArrayValue(type);
1064                 if(auto tv = cast(DynArrayValue) v)
1065                 {
1066                     nv.setLength(ctx, len + tv.len);
1067                     for(size_t i = 0; i < len; i++)
1068                         nv.setItem(ctx, i, getItem(i));
1069                     for(size_t i = 0; i < tv.len; i++)
1070                         nv.setItem(ctx, len + i, tv.getItem(i));
1071                 }
1072                 else
1073                 {
1074                     nv.setLength(ctx, len + 1);
1075                     for(size_t i = 0; i < len; i++)
1076                         nv.setItem(ctx, i, getItem(i));
1077                     nv.setItem(ctx, len, v);
1078                 }
1079                 debug nv.sval = nv.toStr();
1080                 return nv;
1081 
1082             case TOK_catass:
1083                 size_t oldlen = len;
1084                 if(auto ev = cast(ErrorValue) v)
1085                     return v;
1086                 if(auto tv = cast(DynArrayValue) v)
1087                 {
1088                     setLength(ctx, len + tv.len);
1089                     for(size_t i = 0; i < tv.len; i++)
1090                         setItem(ctx, oldlen + i, tv.getItem(i));
1091                 }
1092                 else
1093                 {
1094                     setLength(ctx, len + 1);
1095                     setItem(ctx, oldlen, v);
1096                 }
1097                 debug sval = toStr();
1098                 return this;
1099 
1100             default:
1101                 return super.opBin(ctx, tokid, v);
1102         }
1103     }
1104 
1105     bool isString()
1106     {
1107         auto t = type.getNextType().unqualified();
1108 
1109         if(auto bt = cast(BasicType) t)
1110             if(bt.id == TOK_char || bt.id == TOK_wchar || bt.id == TOK_dchar)
1111                 return true;
1112         return false;
1113     }
1114 
1115     override PointerValue toPointer(TypePointer to)
1116     {
1117         // TODO: implementation here just to satisfy string -> C const char* conversion
1118         if(isString())
1119         {
1120             Value nfirst = first;
1121             auto nt = type.getNextType();
1122             auto nto = to.getNextType();
1123             if(literal)
1124             {
1125                 // automatic conversion between string,wstring,dstring
1126                 auto uto = nto.unqualified();
1127                 auto ut = nt.unqualified();
1128                 if(auto bt = cast(BasicType) ut)
1129                     if(auto bto = cast(BasicType) uto)
1130                     {
1131                         if(bt.id != bto.id)
1132                         {
1133                             semanticErrorValue("literal string conversion not implemented!");
1134 
1135                             DynArrayValue nv;
1136                             switch(bto.id)
1137                             {
1138                                 case TOK_char:
1139                                     string s;
1140                                     switch(bt.id)
1141                                     {
1142                                         case TOK_wchar:
1143                                         case TOK_dchar:
1144                                         default:
1145                                             break;
1146                                     }
1147                                     nv = createStringValue(s);
1148                                     break;
1149                                 case TOK_wchar:
1150                                     wstring s;
1151                                     switch(bt.id)
1152                                     {
1153                                         case TOK_char:
1154                                         case TOK_dchar:
1155                                         default:
1156                                             break;
1157                                     }
1158                                     nv = createStringValue(s);
1159                                     break;
1160                                 case TOK_dchar:
1161                                     dstring s;
1162                                     switch(bt.id)
1163                                     {
1164                                         case TOK_char:
1165                                         case TOK_wchar:
1166                                         default:
1167                                             break;
1168                                     }
1169                                     nv = createStringValue(s);
1170                                     break;
1171                                 default:
1172                                     assert(0);
1173                             }
1174                             nfirst = nv.first;
1175                         }
1176                     }
1177             }
1178             PointerValue pv = new PointerValue;
1179             auto tp = new TypePointer;
1180             tp.setNextType(nto);
1181             pv.type = tp;
1182             pv.pval = nfirst;
1183             debug pv.sval = pv.toStr();
1184             return pv;
1185         }
1186         return super.toPointer(to);
1187     }
1188 
1189     override string toMixin()
1190     {
1191         if(isString())
1192         {
1193             if(len == 0)
1194                 return "";
1195             if(auto cv = cast(CharValue)first)
1196                 return toUTF8Safe(cv.pval[0..len]);
1197             if(auto wv = cast(WCharValue)first)
1198                 return toUTF8Safe(wv.pval[0..len]);
1199             if(auto dv = cast(DCharValue)first)
1200                 return toUTF8Safe(dv.pval[0..len]);
1201         }
1202         return super.toMixin();
1203     }
1204 
1205     override Value _interpretProperty(Context ctx, string prop)
1206     {
1207         switch(prop)
1208         {
1209             case "length":
1210                 return new SetLengthValue(this);
1211             default:
1212                 return super._interpretProperty(ctx, prop);
1213         }
1214     }
1215 }
1216 
1217 class SetLengthValue : UIntValue
1218 {
1219     DynArrayValue array;
1220 
1221     this(DynArrayValue a)
1222     {
1223         array = a;
1224         super();
1225         debug sval = toStr();
1226     }
1227 
1228     override string toStr()
1229     {
1230         return array.toStr() ~ ".length";
1231     }
1232 
1233     override Value opBin(Context ctx, int tokid, Value v)
1234     {
1235         switch(tokid)
1236         {
1237             case TOK_assign:
1238                 int len = v.toInt();
1239                 array.setLength(ctx, len);
1240                 debug array.sval = array.toStr();
1241                 return this;
1242             default:
1243                 return super.opBin(ctx, tokid, v);
1244         }
1245     }
1246 
1247 }
1248 
1249 DynArrayValue createStringValue(C)(immutable(C)[] s)
1250 {
1251     DynArrayValue dav = new DynArrayValue(getTypeString!C());
1252     auto cv = new BasicType2ValueType!C;
1253     cv.mutable = false;
1254     cv.pval = cast(C*) s.ptr;
1255     debug cv.sval = cv.toStr();
1256     dav.first = cv;
1257     dav.len = s.length;
1258     dav.literal = true;
1259     debug dav.sval = dav.toStr();
1260     return dav;
1261 }
1262 
1263 class StaticArrayValue : ArrayValue!TypeStaticArray
1264 {
1265     this(TypeStaticArray t)
1266     {
1267         type = t;
1268         debug sval = toStr();
1269     }
1270 
1271     override Type getType()
1272     {
1273         return type;
1274     }
1275 
1276     override Value opBin(Context ctx, int tokid, Value v)
1277     {
1278         switch(tokid)
1279         {
1280             case TOK_assign:
1281                 if(auto tv = cast(ArrayValueBase) v)
1282                 {
1283                     if(tv.len != len)
1284                         return semanticErrorValue("different length in assignment from ", v, " to ", this);
1285 
1286                     IntValue idxval = new IntValue;
1287                     for(int i = 0; i < len; i++)
1288                     {
1289                         *(idxval.pval) = i;
1290                         Value vidx = v.opIndex(idxval);
1291                         auto idx = opIndex(idxval);
1292                         idx.opBin(ctx, TOK_assign, vidx);
1293                     }
1294                 }
1295                 else
1296                     return semanticErrorValue("cannot assign ", v, " to ", this);
1297                 debug sval = toStr();
1298                 return this;
1299 
1300             default:
1301                 return super.opBin(ctx, tokid, v);
1302         }
1303     }
1304 
1305 }
1306 
1307 alias AliasSeq!(CharValue, WCharValue, DCharValue, StringValue) StringTypeValues;
1308 
1309 class StringValue : Value
1310 {
1311     alias string ValType;
1312 
1313     ValType* pval;
1314 
1315     this()
1316     {
1317         pval = (new string[1]).ptr;
1318         debug sval = toStr();
1319     }
1320 
1321     this(string s)
1322     {
1323         pval = (new string[1]).ptr;
1324         *pval = s;
1325         debug sval = toStr();
1326     }
1327 
1328     static StringValue _create(string s)
1329     {
1330         StringValue sv = new StringValue(s);
1331         return sv;
1332     }
1333 
1334     override Type getType()
1335     {
1336         return getTypeString!char();
1337     }
1338 
1339     override string toStr()
1340     {
1341         return '"' ~ *pval ~ '"';
1342     }
1343 
1344     override string toMixin()
1345     {
1346         return *pval;
1347     }
1348 
1349     override PointerValue toPointer(TypePointer to)
1350     {
1351         // TODO: implementation here just to satisfy string -> C const char* conversion
1352         PointerValue pv = new PointerValue;
1353         pv.type = new TypePointer;
1354         pv.type.addMember(createBasicType(TOK_char));
1355         pv.pval = this;
1356         debug pv.sval = pv.toStr();
1357         return pv;
1358     }
1359 
1360     override bool toBool()
1361     {
1362         return *pval !is null;
1363     }
1364 
1365     mixin mixinAssignOp!("=",  StringTypeValues) ass_assign;
1366     mixin mixinAssignOp!("~=", StringTypeValues) ass_catass;
1367     mixin mixinBinaryOp!("~",  StringTypeValues) bin_tilde;
1368     mixin mixinBinaryOp1!("<",  StringValue) bin_lt;
1369     mixin mixinBinaryOp1!(">",  StringValue) bin_gt;
1370     mixin mixinBinaryOp1!("<=", StringValue) bin_le;
1371     mixin mixinBinaryOp1!(">=", StringValue) bin_ge;
1372     mixin mixinBinaryOp1!("==", StringValue) bin_equal;
1373     mixin mixinBinaryOp1!("!=", StringValue) bin_notequal;
1374 
1375     override Value opBin(Context ctx, int tokid, Value v)
1376     {
1377         switch(tokid)
1378         {
1379             case TOK_assign:
1380                 auto rv = ass_assign.assOp(v);
1381                 debug sval = toStr();
1382                 return rv;
1383             case TOK_catass:
1384                 auto rv = ass_catass.assOp(v);
1385                 debug sval = toStr();
1386                 return rv;
1387             case TOK_tilde:    return bin_tilde.binOp(v);
1388             case TOK_lt:       return bin_lt.binOp1(v);
1389             case TOK_gt:       return bin_gt.binOp1(v);
1390             case TOK_le:       return bin_le.binOp1(v);
1391             case TOK_ge:       return bin_ge.binOp1(v);
1392             case TOK_equal:    return bin_equal.binOp1(v);
1393             case TOK_notequal: return bin_notequal.binOp1(v);
1394             default:           return super.opBin(ctx, tokid, v);
1395         }
1396     }
1397 
1398     override Value opIndex(Value v)
1399     {
1400         int idx = v.toInt();
1401         if(idx < 0 || idx >= (*pval).length)
1402             return semanticErrorValue("index ", idx, " out of bounds on ", *pval);
1403         return create((*pval)[idx]);
1404     }
1405 }
1406 
1407 class PointerValue : Value
1408 {
1409     TypePointer type;  // type of pointer
1410     Value pval; // Value is a class type, so its a reference, i.e. a pointer to the value
1411 
1412     override string toStr()
1413     {
1414         return pval ? "&" ~ pval.toStr() : "null";
1415     }
1416 
1417     static PointerValue _create(TypePointer type, Value v)
1418     {
1419         PointerValue pv = new PointerValue;
1420         pv.type = type;
1421         pv.pval = v;
1422         debug pv.sval = pv.toStr();
1423         return pv;
1424     }
1425 
1426     override Type getType()
1427     {
1428         return type;
1429     }
1430 
1431     override bool toBool()
1432     {
1433         return pval !is null;
1434     }
1435 
1436     override PointerValue toPointer(TypePointer to)
1437     {
1438         return this;
1439     }
1440 
1441     override Value opDerefPointer()
1442     {
1443         if(!pval)
1444             return semanticErrorValue("dereferencing a null pointer");
1445         return pval;
1446     }
1447 
1448     override Value opBin(Context ctx, int tokid, Value v)
1449     {
1450         switch(tokid)
1451         {
1452             case TOK_assign:
1453                 auto pv = v.toPointer(type);
1454                 if(!v)
1455                     pval = null;
1456                 else if(!pv)
1457                     return semanticErrorValue("cannot convert value ", v, " to pointer of type ", type);
1458                 else if(type.convertableFromImplicite(pv.type))
1459                     pval = pv.pval;
1460                 else
1461                     return semanticErrorValue("cannot convert pointer type ", pv.type, " to ", type);
1462                 debug sval = toStr();
1463                 return this;
1464             case TOK_equal:
1465             case TOK_notequal:
1466                 auto pv = cast(PointerValue)v;
1467                 if(!pv || (!pv.type.convertableFromImplicite(type) && !type.convertableFromImplicite(pv.type)))
1468                     return semanticErrorValue("cannot compare types ", v.getType(), " and ", type);
1469                 if(tokid == TOK_equal)
1470                     return Value.create(pv.pval is pval);
1471                 else
1472                     return Value.create(pv.pval !is pval);
1473             default:
1474                 return super.opBin(ctx, tokid, v);
1475         }
1476     }
1477 
1478     override Value _interpretProperty(Context ctx, string prop)
1479     {
1480         switch(prop)
1481         {
1482             case "init":
1483                 return _create(type, null);
1484             default:
1485                 if(!pval)
1486                     return semanticErrorValue("dereferencing null pointer");
1487                 return pval._interpretProperty(ctx, prop);
1488         }
1489     }
1490 }
1491 
1492 class TypeValue : Value
1493 {
1494     Type type;
1495 
1496     this(Type t)
1497     {
1498         type = t;
1499         debug sval = toStr();
1500     }
1501 
1502     override Type getType()
1503     {
1504         return type;
1505     }
1506 
1507     override string toStr()
1508     {
1509         return writeD(type);
1510     }
1511 
1512     override Value opCall(Context sc, Value vargs)
1513     {
1514         return type.createValue(sc, vargs);
1515     }
1516 }
1517 
1518 class AliasValue : Value
1519 {
1520     IdentifierList id;
1521 
1522     this(IdentifierList _id)
1523     {
1524         id = _id;
1525         debug sval = toStr();
1526     }
1527 
1528     Node resolve()
1529     {
1530         return id.resolve();
1531     }
1532 
1533     override Type getType()
1534     {
1535         return id.calcType();
1536     }
1537 
1538     override string toStr()
1539     {
1540         return writeD(id);
1541     }
1542 }
1543 
1544 class TupleValue : Value
1545 {
1546 private:
1547     Value[] _values;
1548 public:
1549     this()
1550     {
1551         debug sval = toStr();
1552     }
1553 
1554     @property Value[] values()
1555     {
1556         return _values;
1557     }
1558     @property void values(Value[] v)
1559     {
1560         _values = v;
1561         debug sval = toStr();
1562     }
1563     void addValue(Value v)
1564     {
1565         _values ~= v;
1566         debug sval = toStr();
1567     }
1568     void setValuesLength(size_t len)
1569     {
1570         _values.length = len;
1571     }
1572 
1573     override string toStr()
1574     {
1575         return _toStr("(", ")");
1576     }
1577 
1578     string _toStr(string open, string close)
1579     {
1580         string s = open;
1581         foreach(i, v; values)
1582         {
1583             if(i > 0)
1584                 s ~= ",";
1585             s ~= v.toStr();
1586         }
1587         s ~= close;
1588         return s;
1589     }
1590 
1591     override Value opIndex(Value v)
1592     {
1593         int idx = v.toInt();
1594         if(idx < 0 || idx >= values.length)
1595             return semanticErrorValue("index ", idx, " out of bounds on value tuple");
1596         return values[idx];
1597     }
1598 
1599     override Value opSlice(Value b, Value e)
1600     {
1601         int idxb = b.toInt();
1602         int idxe = e.toInt();
1603         if(idxb < 0 || idxb > values.length || idxe < idxb || idxe > values.length)
1604             return semanticErrorValue("slice [", idxb, "..", idxe, "] out of bounds on value tuple");
1605         auto nv = new TupleValue;
1606         nv._values = _values[idxb..idxe];
1607         return nv;
1608     }
1609 
1610     override Value opBin(Context ctx, int tokid, Value v)
1611     {
1612         switch(tokid)
1613         {
1614             case TOK_equal:
1615                 if(auto tv = cast(TupleValue) v)
1616                 {
1617                     if(tv.values.length != values.length)
1618                         return Value.create(false);
1619                     for(int i = 0; i < values.length; i++)
1620                         if(!values[i].opBin(ctx, TOK_equal, tv.values[i]).toBool())
1621                             return Value.create(false);
1622                     return Value.create(true);
1623                 }
1624                 return semanticErrorValue("cannot compare ", v, " to ", this);
1625             case TOK_notequal:
1626                 return Value.create(!opBin(ctx, TOK_equal, v).toBool());
1627 
1628             case TOK_assign:
1629                 if(auto tv = cast(TupleValue) v)
1630                     values = tv.values;
1631                 else
1632                     return semanticErrorValue("cannot assign ", v, " to ", this);
1633                 debug sval = toStr();
1634                 return this;
1635 
1636             case TOK_tilde:
1637                 auto nv = new TupleValue;
1638                 if(auto tv = cast(TupleValue) v)
1639                     nv._values = _values ~ tv._values;
1640                 else
1641                     nv._values = _values ~ v;
1642                 return nv;
1643 
1644             case TOK_catass:
1645                 if(auto tv = cast(TupleValue) v)
1646                     _values ~= tv._values;
1647                 else
1648                     _values ~= v;
1649                 return this;
1650 
1651             default:
1652                 return super.opBin(ctx, tokid, v);
1653         }
1654     }
1655 
1656     override Value _interpretProperty(Context ctx, string prop)
1657     {
1658         switch(prop)
1659         {
1660             case "length":
1661                 return create(values.length);
1662             default:
1663                 return super._interpretProperty(ctx, prop);
1664         }
1665     }
1666 }
1667 
1668 Value doCall(CallableNode funcNode, Context sc, ParameterList params, Value vargs)
1669 {
1670     if(!funcNode)
1671         return semanticErrorValue("calling null reference");
1672 
1673     auto ctx = new Context(sc);
1674 
1675     auto args = static_cast!TupleValue(vargs);
1676     auto numparams = params.members.length;
1677     auto numargs = args ? args.values.length : 0;
1678     if(params.anonymous_varargs)
1679     {
1680         if(numargs < numparams)
1681             return semanticErrorValue("too few arguments");
1682         // TODO: add _arguments and _argptr variables
1683     }
1684     else if(params.varargs)
1685     {
1686         if(numargs < numparams - 1)
1687             return semanticErrorValue("too few arguments");
1688         numparams--;
1689     }
1690     else if(numargs != numparams)
1691         return semanticErrorValue("incorrect number of arguments");
1692 
1693     for(size_t p = 0; p < numparams; p++)
1694     {
1695         if(auto decl = params.getParameter(p).getParameterDeclarator().getDeclarator())
1696         {
1697             Value v = args.values[p];
1698             Type t = v.getType();
1699             if(!decl.isRef)
1700                 v = decl.calcType().createValue(sc, v); // if not ref, always create copy
1701             else if(!t.compare(decl.calcType()))
1702                 return semanticErrorValue("cannot create reference of incompatible type", v.getType());
1703             ctx.setValue(decl, v);
1704         }
1705     }
1706     if(params.varargs)
1707     {
1708         // TODO: pack remaining arguments into array
1709         auto decl = params.getParameter(numparams).getParameterDeclarator();
1710         auto vdecl = decl.getDeclarator();
1711         if(!vdecl)
1712             return semanticErrorValue("cannot pack remaining arguments into parameter", decl);
1713         Value arr = vdecl.calcType().createValue(ctx, null);
1714         if(auto darr = cast(DynArrayValue) arr)
1715         {
1716             darr.setLength(ctx, args.values.length - numparams);
1717             for(size_t n = numparams; n < args.values.length; n++)
1718             {
1719                 Value v = args.values[n];
1720                 Type t = v.getType();
1721                 v = t.createValue(sc, v); // if not ref, always create copy
1722                 darr.setItem(ctx, n - numparams, v);
1723             }
1724             debug darr.sval = darr.toStr();
1725             ctx.setValue(vdecl, darr);
1726         }
1727         else
1728             return semanticErrorValue("array type expected for variable argument parameter");
1729     }
1730     Value retVal = funcNode.interpretCall(ctx);
1731     return retVal ? retVal : theVoidValue;
1732 }
1733 
1734 class FunctionValue : Value
1735 {
1736     TypeFunction functype;
1737     bool adr;
1738 
1739     override string toStr()
1740     {
1741         if(!functype.funcDecl)
1742             return "null";
1743         if(!functype.funcDecl.ident)
1744             return "_funcliteral_";
1745         return "&" ~ functype.funcDecl.ident;
1746     }
1747 
1748     override Value opCall(Context sc, Value vargs)
1749     {
1750         return doCall(functype.funcDecl, threadContext, functype.getParameters(), vargs);
1751     }
1752 
1753     override Value opBin(Context ctx, int tokid, Value v)
1754     {
1755         FunctionValue dg = cast(FunctionValue) v;
1756         if(!dg)
1757             return semanticErrorValue("cannot assign ", v, " to function");
1758         //! TODO: verify compatibility of types
1759         switch(tokid)
1760         {
1761             case TOK_assign:
1762                 functype = dg.functype;
1763                 debug sval = toStr();
1764                 return this;
1765             case TOK_equal:
1766                 return Value.create(functype.compare(dg.functype));
1767             case TOK_notequal:
1768                 return Value.create(!functype.compare(dg.functype));
1769             default:
1770                 return super.opBin(ctx, tokid, v);
1771         }
1772     }
1773 
1774     override Type getType()
1775     {
1776         return functype;
1777     }
1778 
1779     override Value opRefPointer()
1780     {
1781         adr = true;
1782         return this;
1783     }
1784 }
1785 
1786 class DelegateValue : FunctionValue
1787 {
1788     Context context;
1789 
1790     override Value opCall(Context sc, Value vargs)
1791     {
1792         return doCall(functype.funcDecl, context, functype.getParameters(), vargs);
1793     }
1794 
1795     override Value opBin(Context ctx, int tokid, Value v)
1796     {
1797         DelegateValue dg = cast(DelegateValue) v;
1798         if(!dg)
1799             return semanticErrorValue("cannot assign ", v, " to delegate");
1800         //! TODO: verify compatibility of types
1801         switch(tokid)
1802         {
1803             case TOK_assign:
1804                 context = dg.context;
1805                 functype = dg.functype;
1806                 debug sval = toStr();
1807                 return this;
1808             case TOK_equal:
1809                 return Value.create((context is dg.context) && functype.compare(dg.functype));
1810             case TOK_notequal:
1811                 return Value.create((context !is dg.context) || !functype.compare(dg.functype));
1812             default:
1813                 return super.opBin(ctx, tokid, v);
1814         }
1815     }
1816 }
1817 
1818 class AggrValue : TupleValue
1819 {
1820     Context outer;
1821     AggrContext context;
1822 
1823     abstract override Aggregate getType();
1824 
1825     override string toStr()
1826     {
1827         if(auto t = getType())
1828             return t.ident ~ _toStr("{", "}");
1829         return "<notype>" ~ _toStr("{", "}");
1830     }
1831 
1832     override Value _interpretProperty(Context ctx, string prop)
1833     {
1834         auto type = getType();
1835         if(Value v = type.getProperty(this, prop, true))
1836             return v;
1837         if(Value v = type.getStaticProperty(prop))
1838             return v;
1839         if(!context)
1840             context = new AggrContext(outer, this);
1841         if(Value v = super._interpretProperty(context, prop))
1842             return v;
1843 
1844         //if(outer) // TODO: outer checked after super?
1845         //    if(Value v = outer._interpretProperty(ctx, prop))
1846         //        return v;
1847         //
1848         return null;
1849     }
1850 
1851     override Value opBin(Context ctx, int tokid, Value v)
1852     {
1853         switch(tokid)
1854         {
1855             case TOK_equal:
1856                 if(Value fv = getType().getProperty(this, "opEquals", true))
1857                 {
1858                     auto tctx = new AggrContext(ctx, this);
1859                     auto tv = new TupleValue;
1860                     tv.addValue(v);
1861                     return fv.opCall(tctx, tv);
1862                 }
1863                 return super.opBin(ctx, tokid, v);
1864             case TOK_is:
1865                 return Value.create(v is this);
1866             case TOK_notidentity:
1867                 return Value.create(v !is this);
1868             default:
1869                 return super.opBin(ctx, tokid, v);
1870         }
1871     }
1872 }
1873 
1874 class AggrValueT(T) : AggrValue
1875 {
1876     T type;
1877 
1878     this(T t)
1879     {
1880         type = t;
1881         debug sval = toStr();
1882     }
1883 
1884     override Aggregate getType()
1885     {
1886         return type;
1887     }
1888 }
1889 
1890 class StructValue : AggrValueT!Struct
1891 {
1892     this(Struct t)
1893     {
1894         super(t);
1895     }
1896 }
1897 
1898 class UnionValue : AggrValueT!Union
1899 {
1900     this(Union t)
1901     {
1902         super(t);
1903     }
1904 }
1905 
1906 class ClassInstanceValue : AggrValueT!Class
1907 {
1908     this(Class t)
1909     {
1910         super(t);
1911     }
1912 }
1913 
1914 class ReferenceValue : Value
1915 {
1916     ClassInstanceValue instance;
1917     bool insideToStr;
1918 
1919     override string toStr()
1920     {
1921         if(!instance)
1922             return "null";
1923         if(insideToStr)
1924             return "recursive-toStr";
1925         insideToStr = true;
1926         scope(exit) insideToStr = false;
1927         return instance.toStr();
1928     }
1929 
1930     override Value opBin(Context ctx, int tokid, Value v)
1931     {
1932         ClassInstanceValue other;
1933         if(auto cv = cast(ReferenceValue) v)
1934             other = cv.instance;
1935         else if(!cast(NullValue) v)
1936             return super.opBin(ctx, tokid, v);
1937 
1938         switch(tokid)
1939         {
1940             case TOK_assign:
1941                 instance = other;
1942                 debug sval = toStr();
1943                 return this;
1944             case TOK_equal:
1945                 if(instance is other)
1946                     return Value.create(true);
1947                 if(!instance || !other)
1948                     return Value.create(false);
1949                 return instance.opBin(ctx, TOK_equal, other);
1950             case TOK_is:
1951                 return Value.create(instance is other);
1952             case TOK_notidentity:
1953                 return Value.create(instance !is other);
1954             default:
1955                 return super.opBin(ctx, tokid, v);
1956         }
1957     }
1958 
1959 }
1960 
1961 class ReferenceValueT(T) : ReferenceValue
1962 {
1963     T type;
1964 
1965     this(T t)
1966     {
1967         type = t;
1968     }
1969 
1970     override T getType()
1971     {
1972         return type;
1973     }
1974 
1975     override Value _interpretProperty(Context ctx, string prop)
1976     {
1977         if(instance)
1978             if(Value v = instance._interpretProperty(ctx, prop))
1979                 return v;
1980         if(Value v = type.getStaticProperty(prop))
1981             return v;
1982         return super._interpretProperty(ctx, prop);
1983     }
1984 
1985     override Value doCast(Value v)
1986     {
1987         if(cast(NullValue) v)
1988         {
1989             instance = null;
1990             return this;
1991         }
1992         if(auto cv = cast(ReferenceValue) v)
1993         {
1994             if(type.convertableFrom(cv.getType(), Type.ConversionFlags.kImpliciteConversion))
1995                 instance = cv.instance;
1996             else
1997                 instance = null;
1998             return this;
1999         }
2000         return super.doCast(v);
2001     }
2002 }
2003 
2004 class ClassValue : ReferenceValueT!Class
2005 {
2006     this(Class t, ClassInstanceValue inst = null)
2007     {
2008         super(t);
2009         instance = inst;
2010         validate();
2011     }
2012 }
2013 
2014 class InterfaceValue : ReferenceValueT!Intrface
2015 {
2016     this(Intrface t)
2017     {
2018         super(t);
2019         validate();
2020     }
2021 }
2022 
2023 class AnonymousClassInstanceValue : AggrValueT!AnonymousClass
2024 {
2025     this(AnonymousClass t)
2026     {
2027         super(t);
2028         validate();
2029     }
2030 }
2031 
2032 class AnonymousClassValue : ReferenceValueT!AnonymousClass
2033 {
2034     this(AnonymousClass t)
2035     {
2036         super(t);
2037         validate();
2038     }
2039 }
2040 
2041 ////////////////////////////////////////////////////////////////////////
2042 // program control
2043 class ProgramControlValue : Value
2044 {
2045     string label;
2046 }
2047 
2048 class BreakValue : ProgramControlValue
2049 {
2050     this(string s)
2051     {
2052         label = s;
2053     }
2054 }
2055 
2056 class ContinueValue : ProgramControlValue
2057 {
2058     this(string s)
2059     {
2060         label = s;
2061     }
2062 }
2063 
2064 class GotoValue : ProgramControlValue
2065 {
2066     this(string s)
2067     {
2068         label = s;
2069     }
2070 }
2071 
2072 class GotoCaseValue : ProgramControlValue
2073 {
2074     this(string s)
2075     {
2076         label = s;
2077     }
2078 }