Logo Search packages:      
Sourcecode: ldc version File versions

interpret.c

// Compiler implementation of the D programming language
// Copyright (c) 1999-2009 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "rmem.h"

#include "statement.h"
#include "expression.h"
#include "cond.h"
#include "init.h"
#include "staticassert.h"
#include "mtype.h"
#include "scope.h"
#include "declaration.h"
#include "aggregate.h"
#include "id.h"

#define LOG 0

struct InterState
{
    InterState *caller;       // calling function's InterState
    FuncDeclaration *fd;      // function being interpreted
    Dsymbols vars;            // variables used in this function
    Statement *start;         // if !=NULL, start execution at this statement
    Statement *gotoTarget;    // target of EXP_GOTO_INTERPRET result
    Expression *localThis;    // value of 'this', or NULL if none

    InterState();
};

InterState::InterState()
{
    memset(this, 0, sizeof(InterState));
}

Expression *interpret_aaLen(InterState *istate, Expressions *arguments);
Expression *interpret_aaKeys(InterState *istate, Expressions *arguments);
Expression *interpret_aaValues(InterState *istate, Expressions *arguments);

/*************************************
 * Attempt to interpret a function given the arguments.
 * Input:
 *    istate     state for calling function (NULL if none)
 *      arguments  function arguments
 *      thisarg    'this', if a needThis() function, NULL if not. 
 *
 * Return result expression if successful, NULL if not.
 */

Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg)
{
#if LOG
    printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars());
    printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun);
#endif
    if (global.errors)
      return NULL;
    if (ident == Id::aaLen)
      return interpret_aaLen(istate, arguments);
    else if (ident == Id::aaKeys)
      return interpret_aaKeys(istate, arguments);
    else if (ident == Id::aaValues)
      return interpret_aaValues(istate, arguments);

    if (cantInterpret || semanticRun == 3)
      return NULL;

    if (!fbody)
    { cantInterpret = 1;
      return NULL;
    }

    if (semanticRun < 3 && scope)
    {
      semantic3(scope);
      if (global.errors)      // if errors compiling this function
          return NULL;
    }
    if (semanticRun < 4)
      return NULL;

    Type *tb = type->toBasetype();
    assert(tb->ty == Tfunction);
    TypeFunction *tf = (TypeFunction *)tb;
    Type *tret = tf->next->toBasetype();
    if (tf->varargs)
    { cantInterpret = 1;
      error("Variadic functions are not yet implemented in CTFE");
      return NULL;
    }
    
    // Ensure there are no lazy parameters
    if (tf->parameters)
    { size_t dim = Argument::dim(tf->parameters);
      for (size_t i = 0; i < dim; i++)
      {   Argument *arg = Argument::getNth(tf->parameters, i);
          if (arg->storageClass & STClazy)
          {   cantInterpret = 1;
            return NULL;
          }
      }
    }

    InterState istatex;
    istatex.caller = istate;
    istatex.fd = this;
    istatex.localThis = thisarg;

    Expressions vsave;        // place to save previous parameter values
    size_t dim = 0;
    if (needThis() && !thisarg)
    { cantInterpret = 1;
      // error, no this. Prevent segfault.
      error("need 'this' to access member %s", toChars());
      return NULL;
    }
    if (arguments)
    {
      dim = arguments->dim;
      assert(!dim || (parameters && (parameters->dim == dim)));
      vsave.setDim(dim);

      /* Evaluate all the arguments to the function,
       * store the results in eargs[]
       */
      Expressions eargs;
      eargs.setDim(dim);

      for (size_t i = 0; i < dim; i++)
      {   Expression *earg = (Expression *)arguments->data[i];
          Argument *arg = Argument::getNth(tf->parameters, i);

          if (arg->storageClass & (STCout | STCref))
          {
          }
          else
          { /* Value parameters
             */
            Type *ta = arg->type->toBasetype();
            if (ta->ty == Tsarray && earg->op == TOKaddress)
            {
                /* Static arrays are passed by a simple pointer.
                 * Skip past this to get at the actual arg.
                 */
                earg = ((AddrExp *)earg)->e1;
            }
            earg = earg->interpret(istate ? istate : &istatex);
            if (earg == EXP_CANT_INTERPRET)
            {   cantInterpret = 1;
                return NULL;
            }
          }
          eargs.data[i] = earg;
      }

      for (size_t i = 0; i < dim; i++)
      {   Expression *earg = (Expression *)eargs.data[i];
          Argument *arg = Argument::getNth(tf->parameters, i);
          VarDeclaration *v = (VarDeclaration *)parameters->data[i];
          vsave.data[i] = v->value;
#if LOG
          printf("arg[%d] = %s\n", i, earg->toChars());
#endif
          if (arg->storageClass & (STCout | STCref) && earg->op==TOKvar)
          {
            /* Bind out or ref parameter to the corresponding
             * variable v2
             */
            if (!istate)
            {   cantInterpret = 1;
                error("%s cannot be by passed by reference at compile time", earg->toChars());
                return NULL;  // can't bind to non-interpreted vars
            }           
            // We need to chase down all of the the passed parameters until
            // we find something that isn't a TOKvar, then create a variable
            // containg that expression.
            VarDeclaration *v2;
            while (1)
            {
                VarExp *ve = (VarExp *)earg;
                v2 = ve->var->isVarDeclaration();
                if (!v2)
                {   cantInterpret = 1;
                  return NULL;
                }
                if (!v2->value || v2->value->op != TOKvar)
                  break;
                if (((VarExp *)v2->value)->var->isStaticStructInitDeclaration())             
                { // This can happen if v is a struct initialized to
                  // 0 using an __initZ StaticStructInitDeclaration from
                  // TypeStruct::defaultInit()
                  break; // eg default-initialized variable
                }
                earg = v2->value;
            }

            v->value = new VarExp(earg->loc, v2);

            /* Don't restore the value of v2 upon function return
             */
            assert(istate);
            for (size_t i = 0; i < istate->vars.dim; i++)
            {   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
                if (v == v2)
                { istate->vars.data[i] = NULL;
                  break;
                }
            }
          }
          else
          { // Value parameters and non-trivial references
            v->value = earg;
          }
#if LOG
          printf("interpreted arg[%d] = %s\n", i, earg->toChars());
#endif
      }
    }
    // Don't restore the value of 'this' upon function return
    if (needThis() && thisarg->op==TOKvar) {
      VarDeclaration *thisvar = ((VarExp *)(thisarg))->var->isVarDeclaration();
      for (size_t i = 0; i < istate->vars.dim; i++)
      {   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
          if (v == thisvar)
          { istate->vars.data[i] = NULL;
            break;
          }
      }
    }

    /* Save the values of the local variables used
     */
    Expressions valueSaves;
    if (istate && !isNested())
    {
      //printf("saving local variables...\n");
      valueSaves.setDim(istate->vars.dim);
      for (size_t i = 0; i < istate->vars.dim; i++)
      {   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
          if (v)
          {
            //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
            valueSaves.data[i] = v->value;
            v->value = NULL;
          }
      }
    }

    Expression *e = NULL;
    while (1)
    {
      e = fbody->interpret(&istatex);
      if (e == EXP_CANT_INTERPRET)
      {
#if LOG
          printf("function body failed to interpret\n");
#endif
          e = NULL;
      }

      /* This is how we deal with a recursive statement AST
       * that has arbitrary goto statements in it.
       * Bubble up a 'result' which is the target of the goto
       * statement, then go recursively down the AST looking
       * for that statement, then execute starting there.
       */
      if (e == EXP_GOTO_INTERPRET)
      {
          istatex.start = istatex.gotoTarget;   // set starting statement
          istatex.gotoTarget = NULL;
      }
      else
          break;
    }
    /* Restore the parameter values
     */
    for (size_t i = 0; i < dim; i++)
    {
      VarDeclaration *v = (VarDeclaration *)parameters->data[i];
      v->value = (Expression *)vsave.data[i];
    }

    if (istate && !isNested())
    {
      /* Restore the variable values
       */
      //printf("restoring local variables...\n");
      for (size_t i = 0; i < istate->vars.dim; i++)
      {   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
          if (v)
          { v->value = (Expression *)valueSaves.data[i];
            //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
          }
      }
    }
    return e;
}

/******************************** Statement ***************************/

#define START()                     \
    if (istate->start)              \
    { if (istate->start != this)    \
          return NULL;        \
      istate->start = NULL;         \
    }

/***********************************
 * Interpret the statement.
 * Returns:
 *    NULL  continue to next statement
 *    EXP_CANT_INTERPRET      cannot interpret statement at compile time
 *    !NULL expression from return statement
 */

Expression *Statement::interpret(InterState *istate)
{
#if LOG
    printf("Statement::interpret()\n");
#endif
    START()
    return EXP_CANT_INTERPRET;
}

Expression *ExpStatement::interpret(InterState *istate)
{
#if LOG
    printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : "");
#endif
    START()
    if (exp)
    {
      Expression *e = exp->interpret(istate);
      if (e == EXP_CANT_INTERPRET)
      {
          //printf("-ExpStatement::interpret(): %p\n", e);
          return EXP_CANT_INTERPRET;
      }
    }
    return NULL;
}

Expression *CompoundStatement::interpret(InterState *istate)
{   Expression *e = NULL;

#if LOG
    printf("CompoundStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    if (statements)
    {
      for (size_t i = 0; i < statements->dim; i++)
      {   Statement *s = (Statement *)statements->data[i];

          if (s)
          {
            e = s->interpret(istate);
            if (e)
                break;
          }
      }
    }
#if LOG
    printf("-CompoundStatement::interpret() %p\n", e);
#endif
    return e;
}

Expression *UnrolledLoopStatement::interpret(InterState *istate)
{   Expression *e = NULL;

#if LOG
    printf("UnrolledLoopStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    if (statements)
    {
      for (size_t i = 0; i < statements->dim; i++)
      {   Statement *s = (Statement *)statements->data[i];

          e = s->interpret(istate);
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e == EXP_CONTINUE_INTERPRET)
          { e = NULL;
            continue;
          }
          if (e == EXP_BREAK_INTERPRET)
          { e = NULL;
            break;
          }
          if (e)
            break;
      }
    }
    return e;
}

Expression *IfStatement::interpret(InterState *istate)
{
#if LOG
    printf("IfStatement::interpret(%s)\n", condition->toChars());
#endif

    if (istate->start == this)
      istate->start = NULL;
    if (istate->start)
    {
      Expression *e = NULL;
      if (ifbody)
          e = ifbody->interpret(istate);
      if (istate->start && elsebody)
          e = elsebody->interpret(istate);
      return e;
    }

    Expression *e = condition->interpret(istate);
    assert(e);
    //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n");
    if (e != EXP_CANT_INTERPRET)
    {
      if (e->isBool(TRUE))
          e = ifbody ? ifbody->interpret(istate) : NULL;
      else if (e->isBool(FALSE))
          e = elsebody ? elsebody->interpret(istate) : NULL;
      else
      {
          e = EXP_CANT_INTERPRET;
      }
    }
    return e;
}

Expression *ScopeStatement::interpret(InterState *istate)
{
#if LOG
    printf("ScopeStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    return statement ? statement->interpret(istate) : NULL;
}

Expression *ReturnStatement::interpret(InterState *istate)
{
#if LOG
    printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : "");
#endif
    START()
    if (!exp)
      return EXP_VOID_INTERPRET;
#if LOG
    Expression *e = exp->interpret(istate);
    printf("e = %p\n", e);
    return e;
#else
    return exp->interpret(istate);
#endif
}

Expression *BreakStatement::interpret(InterState *istate)
{
#if LOG
    printf("BreakStatement::interpret()\n");
#endif
    START()
    if (ident)
      return EXP_CANT_INTERPRET;
    else
      return EXP_BREAK_INTERPRET;
}

Expression *ContinueStatement::interpret(InterState *istate)
{
#if LOG
    printf("ContinueStatement::interpret()\n");
#endif
    START()
    if (ident)
      return EXP_CANT_INTERPRET;
    else
      return EXP_CONTINUE_INTERPRET;
}

Expression *WhileStatement::interpret(InterState *istate)
{
#if LOG
    printf("WhileStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    Expression *e;

    if (istate->start)
    {
      e = body ? body->interpret(istate) : NULL;
      if (istate->start)
          return NULL;
      if (e == EXP_CANT_INTERPRET)
          return e;
      if (e == EXP_BREAK_INTERPRET)
          return NULL;
      if (e && e != EXP_CONTINUE_INTERPRET)
          return e;
    }

    while (1)
    {
      e = condition->interpret(istate);
      if (e == EXP_CANT_INTERPRET)
          break;
      if (!e->isConst())
      {   e = EXP_CANT_INTERPRET;
          break;
      }
      if (e->isBool(TRUE))
      {   e = body ? body->interpret(istate) : NULL;
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e == EXP_CONTINUE_INTERPRET)
            continue;
          if (e == EXP_BREAK_INTERPRET)
          { e = NULL;
            break;
          }
          if (e)
            break;
      }
      else if (e->isBool(FALSE))
      {   e = NULL;
          break;
      }
      else
          assert(0);
    }
    return e;
}

Expression *DoStatement::interpret(InterState *istate)
{
#if LOG
    printf("DoStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    Expression *e;

    if (istate->start)
    {
      e = body ? body->interpret(istate) : NULL;
      if (istate->start)
          return NULL;
      if (e == EXP_CANT_INTERPRET)
          return e;
      if (e == EXP_BREAK_INTERPRET)
          return NULL;
      if (e == EXP_CONTINUE_INTERPRET)
          goto Lcontinue;
      if (e)
          return e;
    }

    while (1)
    {
      e = body ? body->interpret(istate) : NULL;
      if (e == EXP_CANT_INTERPRET)
          break;
      if (e == EXP_BREAK_INTERPRET)
      {   e = NULL;
          break;
      }
      if (e && e != EXP_CONTINUE_INTERPRET)
          break;

    Lcontinue:
      e = condition->interpret(istate);
      if (e == EXP_CANT_INTERPRET)
          break;
      if (!e->isConst())
      {   e = EXP_CANT_INTERPRET;
          break;
      }
      if (e->isBool(TRUE))
      {
      }
      else if (e->isBool(FALSE))
      {   e = NULL;
          break;
      }
      else
          assert(0);
    }
    return e;
}

Expression *ForStatement::interpret(InterState *istate)
{
#if LOG
    printf("ForStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    Expression *e;

    if (init)
    {
      e = init->interpret(istate);
      if (e == EXP_CANT_INTERPRET)
          return e;
      assert(!e);
    }

    if (istate->start)
    {
      e = body ? body->interpret(istate) : NULL;
      if (istate->start)
          return NULL;
      if (e == EXP_CANT_INTERPRET)
          return e;
      if (e == EXP_BREAK_INTERPRET)
          return NULL;
      if (e == EXP_CONTINUE_INTERPRET)
          goto Lcontinue;
      if (e)
          return e;
    }

    while (1)
    {
      if (!condition)
          goto Lhead;
      e = condition->interpret(istate);
      if (e == EXP_CANT_INTERPRET)
          break;
      if (!e->isConst())
      {   e = EXP_CANT_INTERPRET;
          break;
      }
      if (e->isBool(TRUE))
      {
      Lhead:
          e = body ? body->interpret(istate) : NULL;
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e == EXP_BREAK_INTERPRET)
          {   e = NULL;
            break;
          }
          if (e && e != EXP_CONTINUE_INTERPRET)
            break;
      Lcontinue:
          if (increment)
          {
            e = increment->interpret(istate);
            if (e == EXP_CANT_INTERPRET)
                break;
          }
      }
      else if (e->isBool(FALSE))
      {   e = NULL;
          break;
      }
      else
          assert(0);
    }
    return e;
}

Expression *ForeachStatement::interpret(InterState *istate)
{
#if LOG
    printf("ForeachStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    if (istate->start)
      return NULL;

    Expression *e = NULL;
    Expression *eaggr;

    if (value->isOut() || value->isRef())
      return EXP_CANT_INTERPRET;

    eaggr = aggr->interpret(istate);
    if (eaggr == EXP_CANT_INTERPRET)
      return EXP_CANT_INTERPRET;

    Expression *dim = ArrayLength(Type::tsize_t, eaggr);
    if (dim == EXP_CANT_INTERPRET)
      return EXP_CANT_INTERPRET;

    Expression *keysave = key ? key->value : NULL;
    Expression *valuesave = value->value;

    uinteger_t d = dim->toUInteger();
    uinteger_t index;

    if (op == TOKforeach)
    {
      for (index = 0; index < d; index++)
      {
          Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
          if (key)
            key->value = ekey;
          e = Index(value->type, eaggr, ekey);
          if (e == EXP_CANT_INTERPRET)
            break;
          value->value = e;

          e = body ? body->interpret(istate) : NULL;
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e == EXP_BREAK_INTERPRET)
          {   e = NULL;
            break;
          }
          if (e == EXP_CONTINUE_INTERPRET)
            e = NULL;
          else if (e)
            break;
      }
    }
    else // TOKforeach_reverse
    {
      for (index = d; index-- != 0;)
      {
          Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
          if (key)
            key->value = ekey;
          e = Index(value->type, eaggr, ekey);
          if (e == EXP_CANT_INTERPRET)
            break;
          value->value = e;

          e = body ? body->interpret(istate) : NULL;
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e == EXP_BREAK_INTERPRET)
          {   e = NULL;
            break;
          }
          if (e == EXP_CONTINUE_INTERPRET)
            e = NULL;
          else if (e)
            break;
      }
    }
    value->value = valuesave;
    if (key)
      key->value = keysave;
    return e;
}

#if DMDV2
Expression *ForeachRangeStatement::interpret(InterState *istate)
{
#if LOG
    printf("ForeachRangeStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    if (istate->start)
      return NULL;

    Expression *e = NULL;
    Expression *elwr = lwr->interpret(istate);
    if (elwr == EXP_CANT_INTERPRET)
      return EXP_CANT_INTERPRET;

    Expression *eupr = upr->interpret(istate);
    if (eupr == EXP_CANT_INTERPRET)
      return EXP_CANT_INTERPRET;

    Expression *keysave = key->value;

    if (op == TOKforeach)
    {
      key->value = elwr;

      while (1)
      {
          e = Cmp(TOKlt, key->value->type, key->value, eupr);
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e->isBool(TRUE) == FALSE)
          { e = NULL;
            break;
          }

          e = body ? body->interpret(istate) : NULL;
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e == EXP_BREAK_INTERPRET)
          {   e = NULL;
            break;
          }
          if (e == NULL || e == EXP_CONTINUE_INTERPRET)
          { e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
            if (e == EXP_CANT_INTERPRET)
                break;
            key->value = e;
          }
          else
            break;
      }
    }
    else // TOKforeach_reverse
    {
      key->value = eupr;

      do
      {
          e = Cmp(TOKgt, key->value->type, key->value, elwr);
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e->isBool(TRUE) == FALSE)
          { e = NULL;
            break;
          }

          e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
          if (e == EXP_CANT_INTERPRET)
            break;
          key->value = e;

          e = body ? body->interpret(istate) : NULL;
          if (e == EXP_CANT_INTERPRET)
            break;
          if (e == EXP_BREAK_INTERPRET)
          {   e = NULL;
            break;
          }
      } while (e == NULL || e == EXP_CONTINUE_INTERPRET);
    }
    key->value = keysave;
    return e;
}
#endif

Expression *SwitchStatement::interpret(InterState *istate)
{
#if LOG
    printf("SwitchStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    Expression *e = NULL;

    if (istate->start)
    {
      e = body ? body->interpret(istate) : NULL;
      if (istate->start)
          return NULL;
      if (e == EXP_CANT_INTERPRET)
          return e;
      if (e == EXP_BREAK_INTERPRET)
          return NULL;
      return e;
    }


    Expression *econdition = condition->interpret(istate);
    if (econdition == EXP_CANT_INTERPRET)
      return EXP_CANT_INTERPRET;

    Statement *s = NULL;
    if (cases)
    {
      for (size_t i = 0; i < cases->dim; i++)
      {
          CaseStatement *cs = (CaseStatement *)cases->data[i];
          e = Equal(TOKequal, Type::tint32, econdition, cs->exp);
          if (e == EXP_CANT_INTERPRET)
            return EXP_CANT_INTERPRET;
          if (e->isBool(TRUE))
          { s = cs;
            break;
          }
      }
    }
    if (!s)
    { if (hasNoDefault)
          error("no default or case for %s in switch statement", econdition->toChars());
      s = sdefault;
    }

    assert(s);
    istate->start = s;
    e = body ? body->interpret(istate) : NULL;
    assert(!istate->start);
    if (e == EXP_BREAK_INTERPRET)
      return NULL;
    return e;
}

Expression *CaseStatement::interpret(InterState *istate)
{
#if LOG
    printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this);
#endif
    if (istate->start == this)
      istate->start = NULL;
    if (statement)
      return statement->interpret(istate);
    else
      return NULL;
}

Expression *DefaultStatement::interpret(InterState *istate)
{
#if LOG
    printf("DefaultStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    if (statement)
      return statement->interpret(istate);
    else
      return NULL;
}

Expression *GotoStatement::interpret(InterState *istate)
{
#if LOG
    printf("GotoStatement::interpret()\n");
#endif
    START()
    assert(label && label->statement);
    istate->gotoTarget = label->statement;
    return EXP_GOTO_INTERPRET;
}

Expression *GotoCaseStatement::interpret(InterState *istate)
{
#if LOG
    printf("GotoCaseStatement::interpret()\n");
#endif
    START()
    assert(cs);
    istate->gotoTarget = cs;
    return EXP_GOTO_INTERPRET;
}

Expression *GotoDefaultStatement::interpret(InterState *istate)
{
#if LOG
    printf("GotoDefaultStatement::interpret()\n");
#endif
    START()
    assert(sw && sw->sdefault);
    istate->gotoTarget = sw->sdefault;
    return EXP_GOTO_INTERPRET;
}

Expression *LabelStatement::interpret(InterState *istate)
{
#if LOG
    printf("LabelStatement::interpret()\n");
#endif
    if (istate->start == this)
      istate->start = NULL;
    return statement ? statement->interpret(istate) : NULL;
}

/******************************** Expression ***************************/

Expression *Expression::interpret(InterState *istate)
{
#if LOG
    printf("Expression::interpret() %s\n", toChars());
    printf("type = %s\n", type->toChars());
    dump(0);
#endif
    error("Cannot interpret %s at compile time", toChars());
    return EXP_CANT_INTERPRET;
}

Expression *ThisExp::interpret(InterState *istate)
{
    if (istate->localThis)
        return istate->localThis->interpret(istate);
    return EXP_CANT_INTERPRET;
}

Expression *NullExp::interpret(InterState *istate)
{
    return this;
}

Expression *IntegerExp::interpret(InterState *istate)
{
#if LOG
    printf("IntegerExp::interpret() %s\n", toChars());
#endif
    return this;
}

Expression *RealExp::interpret(InterState *istate)
{
#if LOG
    printf("RealExp::interpret() %s\n", toChars());
#endif
    return this;
}

Expression *ComplexExp::interpret(InterState *istate)
{
    return this;
}

Expression *StringExp::interpret(InterState *istate)
{
#if LOG
    printf("StringExp::interpret() %s\n", toChars());
#endif
    return this;
}

Expression *getVarExp(Loc loc, InterState *istate, Declaration *d)
{
    Expression *e = EXP_CANT_INTERPRET;
    VarDeclaration *v = d->isVarDeclaration();
#if IN_LLVM
    StaticStructInitDeclaration *s = d->isStaticStructInitDeclaration();
#else
    SymbolDeclaration *s = d->isSymbolDeclaration();
#endif
    if (v)
    {
#if DMDV2
      if ((v->isConst() || v->isInvariant() || v->storage_class & STCmanifest) && v->init && !v->value)
#else
      if (v->isConst() && v->init)
#endif
      {   e = v->init->toExpression();
          if (e && !e->type)
            e->type = v->type;
      }
      else
      {   e = v->value;
          if (v->isDataseg())
          { error(loc, "static variable %s cannot be read at compile time", v->toChars());
            e = EXP_CANT_INTERPRET;
          }
          else if (!e)
            error(loc, "variable %s is used before initialization", v->toChars());
          else if (e != EXP_CANT_INTERPRET)
            e = e->interpret(istate);
      }
      if (!e)
          e = EXP_CANT_INTERPRET;
    }
    else if (s)
    {
      Expressions *exps = new Expressions();
      e = new StructLiteralExp(0, s->dsym, exps);
      e = e->semantic(NULL);
    }
    return e;
}

Expression *VarExp::interpret(InterState *istate)
{
#if LOG
    printf("VarExp::interpret() %s\n", toChars());
#endif
    return getVarExp(loc, istate, var);
}

Expression *DeclarationExp::interpret(InterState *istate)
{
#if LOG
    printf("DeclarationExp::interpret() %s\n", toChars());
#endif
    Expression *e;
    VarDeclaration *v = declaration->isVarDeclaration();
    if (v)
    {
      Dsymbol *s = v->toAlias();
      if (s == v && !v->isStatic() && v->init)
      {
          ExpInitializer *ie = v->init->isExpInitializer();
          if (ie)
            e = ie->exp->interpret(istate);
          else if (v->init->isVoidInitializer())
            e = NULL;
      }
#if DMDV2
      else if (s == v && (v->isConst() || v->isInvariant()) && v->init)
#else
      else if (s == v && v->isConst() && v->init)
#endif
      {   e = v->init->toExpression();
          if (!e)
            e = EXP_CANT_INTERPRET;
          else if (!e->type)
            e->type = v->type;
      }
    }
    else if (declaration->isAttribDeclaration() ||
           declaration->isTemplateMixin() ||
           declaration->isTupleDeclaration())
    { // These can be made to work, too lazy now
    error("Declaration %s is not yet implemented in CTFE", toChars());

      e = EXP_CANT_INTERPRET;
    }
    else
    { // Others should not contain executable code, so are trivial to evaluate
      e = NULL;
    }
#if LOG
    printf("-DeclarationExp::interpret(%s): %p\n", toChars(), e);
#endif
    return e;
}

Expression *TupleExp::interpret(InterState *istate)
{
#if LOG
    printf("TupleExp::interpret() %s\n", toChars());
#endif
    Expressions *expsx = NULL;

    for (size_t i = 0; i < exps->dim; i++)
    {   Expression *e = (Expression *)exps->data[i];
      Expression *ex;

      ex = e->interpret(istate);
      if (ex == EXP_CANT_INTERPRET)
      {   delete expsx;
          return ex;
      }

      /* If any changes, do Copy On Write
       */
      if (ex != e)
      {
          if (!expsx)
          { expsx = new Expressions();
            expsx->setDim(exps->dim);
            for (size_t j = 0; j < i; j++)
            {
                expsx->data[j] = exps->data[j];
            }
          }
          expsx->data[i] = (void *)ex;
      }
    }
    if (expsx)
    { TupleExp *te = new TupleExp(loc, expsx);
      expandTuples(te->exps);
      te->type = new TypeTuple(te->exps);
      return te;
    }
    return this;
}

Expression *ArrayLiteralExp::interpret(InterState *istate)
{   Expressions *expsx = NULL;

#if LOG
    printf("ArrayLiteralExp::interpret() %s\n", toChars());
#endif
    if (elements)
    {
      for (size_t i = 0; i < elements->dim; i++)
      {   Expression *e = (Expression *)elements->data[i];
          Expression *ex;

          ex = e->interpret(istate);
          if (ex == EXP_CANT_INTERPRET)
          {   delete expsx;
            return EXP_CANT_INTERPRET;
          }

          /* If any changes, do Copy On Write
           */
          if (ex != e)
          {
            if (!expsx)
            {   expsx = new Expressions();
                expsx->setDim(elements->dim);
                for (size_t j = 0; j < elements->dim; j++)
                {
                  expsx->data[j] = elements->data[j];
                }
            }
            expsx->data[i] = (void *)ex;
          }
      }
    }
    if (elements && expsx)
    {
      expandTuples(expsx);
      if (expsx->dim != elements->dim)
      {   delete expsx;
          return EXP_CANT_INTERPRET;
      }
      ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx);
      ae->type = type;
      return ae;
    }
    return this;
}

Expression *AssocArrayLiteralExp::interpret(InterState *istate)
{   Expressions *keysx = keys;
    Expressions *valuesx = values;

#if LOG
    printf("AssocArrayLiteralExp::interpret() %s\n", toChars());
#endif
    for (size_t i = 0; i < keys->dim; i++)
    {   Expression *ekey = (Expression *)keys->data[i];
      Expression *evalue = (Expression *)values->data[i];
      Expression *ex;

      ex = ekey->interpret(istate);
      if (ex == EXP_CANT_INTERPRET)
          goto Lerr;

      /* If any changes, do Copy On Write
       */
      if (ex != ekey)
      {
          if (keysx == keys)
            keysx = (Expressions *)keys->copy();
          keysx->data[i] = (void *)ex;
      }

      ex = evalue->interpret(istate);
      if (ex == EXP_CANT_INTERPRET)
          goto Lerr;

      /* If any changes, do Copy On Write
       */
      if (ex != evalue)
      {
          if (valuesx == values)
            valuesx = (Expressions *)values->copy();
          valuesx->data[i] = (void *)ex;
      }
    }
    if (keysx != keys)
      expandTuples(keysx);
    if (valuesx != values)
      expandTuples(valuesx);
    if (keysx->dim != valuesx->dim)
      goto Lerr;

    /* Remove duplicate keys
     */
    for (size_t i = 1; i < keysx->dim; i++)
    {   Expression *ekey = (Expression *)keysx->data[i - 1];

      for (size_t j = i; j < keysx->dim; j++)
      {   Expression *ekey2 = (Expression *)keysx->data[j];
          Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2);
          if (ex == EXP_CANT_INTERPRET)
            goto Lerr;
          if (ex->isBool(TRUE))     // if a match
          {
            // Remove ekey
            if (keysx == keys)
                keysx = (Expressions *)keys->copy();
            if (valuesx == values)
                valuesx = (Expressions *)values->copy();
            keysx->remove(i - 1);
            valuesx->remove(i - 1);
            i -= 1;           // redo the i'th iteration
            break;
          }
      }
    }

    if (keysx != keys || valuesx != values)
    {
      AssocArrayLiteralExp *ae;
      ae = new AssocArrayLiteralExp(loc, keysx, valuesx);
      ae->type = type;
      return ae;
    }
    return this;

Lerr:
    if (keysx != keys)
      delete keysx;
    if (valuesx != values)
      delete values;
    return EXP_CANT_INTERPRET;
}

Expression *StructLiteralExp::interpret(InterState *istate)
{   Expressions *expsx = NULL;

#if LOG
    printf("StructLiteralExp::interpret() %s\n", toChars());
#endif
    /* We don't know how to deal with overlapping fields
     */
    if (sd->hasUnions)
      {   error("Unions with overlapping fields are not yet supported in CTFE");
            return EXP_CANT_INTERPRET;
    }

    if (elements)
    {
      for (size_t i = 0; i < elements->dim; i++)
      {   Expression *e = (Expression *)elements->data[i];
          if (!e)
            continue;

          Expression *ex = e->interpret(istate);
          if (ex == EXP_CANT_INTERPRET)
          {   delete expsx;
            return EXP_CANT_INTERPRET;
          }

          /* If any changes, do Copy On Write
           */
          if (ex != e)
          {
            if (!expsx)
            {   expsx = new Expressions();
                expsx->setDim(elements->dim);
                for (size_t j = 0; j < elements->dim; j++)
                {
                  expsx->data[j] = elements->data[j];
                }
            }
            expsx->data[i] = (void *)ex;
          }
      }
    }
    if (elements && expsx)
    {
      expandTuples(expsx);
      if (expsx->dim != elements->dim)
      {   delete expsx;
          return EXP_CANT_INTERPRET;
      }
      StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx);
      se->type = type;
      return se;
    }
    return this;
}

Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *))
{   Expression *e;
    Expression *e1;

#if LOG
    printf("UnaExp::interpretCommon() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (e1->isConst() != 1)
      goto Lcant;

    e = (*fp)(type, e1);
    return e;

Lcant:
    return EXP_CANT_INTERPRET;
}

#define UNA_INTERPRET(op) \
Expression *op##Exp::interpret(InterState *istate)    \
{                                         \
    return interpretCommon(istate, &op);        \
}

UNA_INTERPRET(Neg)
UNA_INTERPRET(Com)
UNA_INTERPRET(Not)
UNA_INTERPRET(Bool)


typedef Expression *(*fp_t)(Type *, Expression *, Expression *);

Expression *BinExp::interpretCommon(InterState *istate, fp_t fp)
{   Expression *e;
    Expression *e1;
    Expression *e2;

#if LOG
    printf("BinExp::interpretCommon() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (e1->isConst() != 1)
      goto Lcant;

    e2 = this->e2->interpret(istate);
    if (e2 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (e2->isConst() != 1)
      goto Lcant;

    e = (*fp)(type, e1, e2);
    return e;

Lcant:
    return EXP_CANT_INTERPRET;
}

#define BIN_INTERPRET(op) \
Expression *op##Exp::interpret(InterState *istate)    \
{                                         \
    return interpretCommon(istate, &op);        \
}

BIN_INTERPRET(Add)
BIN_INTERPRET(Min)
BIN_INTERPRET(Mul)
BIN_INTERPRET(Div)
BIN_INTERPRET(Mod)
BIN_INTERPRET(Shl)
BIN_INTERPRET(Shr)
BIN_INTERPRET(Ushr)
BIN_INTERPRET(And)
BIN_INTERPRET(Or)
BIN_INTERPRET(Xor)


typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *);

Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp)
{   Expression *e;
    Expression *e1;
    Expression *e2;

#if LOG
    printf("BinExp::interpretCommon2() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (e1->isConst() != 1 &&
      e1->op != TOKnull &&
      e1->op != TOKstring &&
      e1->op != TOKarrayliteral &&
      e1->op != TOKstructliteral)
      goto Lcant;

    e2 = this->e2->interpret(istate);
    if (e2 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (e2->isConst() != 1 &&
      e2->op != TOKnull &&
      e2->op != TOKstring &&
      e2->op != TOKarrayliteral &&
      e2->op != TOKstructliteral)
      goto Lcant;

    e = (*fp)(op, type, e1, e2);
    return e;

Lcant:
    return EXP_CANT_INTERPRET;
}

#define BIN_INTERPRET2(op) \
Expression *op##Exp::interpret(InterState *istate)    \
{                                         \
    return interpretCommon2(istate, &op);       \
}

BIN_INTERPRET2(Equal)
BIN_INTERPRET2(Identity)
BIN_INTERPRET2(Cmp)

/* Helper functions for BinExp::interpretAssignCommon
 */

/***************************************
 * Duplicate the elements array, then set field 'indexToChange' = newelem.
 */
Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void *newelem)
{
    Expressions *expsx = new Expressions();
    expsx->setDim(oldelems->dim);
    for (size_t j = 0; j < expsx->dim; j++)
    {
      if (j == indexToChange)
          expsx->data[j] = newelem;
      else
          expsx->data[j] = oldelems->data[j];
    }
    return expsx;
}

/***************************************
 * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint..$]
 */
Expressions *spliceElements(Expressions *oldelems,
      Expressions *newelems, size_t insertpoint)
{
    Expressions *expsx = new Expressions();
    expsx->setDim(oldelems->dim);
    for (size_t j = 0; j < expsx->dim; j++)
    {
      if (j >= insertpoint && j < insertpoint + newelems->dim)
          expsx->data[j] = newelems->data[j - insertpoint];
      else
          expsx->data[j] = oldelems->data[j];
    }
    return expsx;
}

/******************************
 * Create an array literal consisting of 'elem' duplicated 'dim' times.
 */
ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type,
      Expression *elem, size_t dim)
{
    Expressions *elements = new Expressions();
    elements->setDim(dim);
    for (size_t i = 0; i < dim; i++)
       elements->data[i] = elem;    
    ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
    ae->type = type;
    return ae;
}


/********************************
 * Necessary because defaultInit() for a struct is a VarExp, not a StructLiteralExp.
 */
StructLiteralExp *createDefaultInitStructLiteral(Loc loc, StructDeclaration *sym)
{
    Expressions *structelems = new Expressions();
    structelems->setDim(sym->fields.dim);
    for (size_t j = 0; j < structelems->dim; j++)
    {
      structelems->data[j] = ((VarDeclaration *)(sym->fields.data[j]))->type->defaultInit();
    }
    StructLiteralExp *structinit = new StructLiteralExp(loc, sym, structelems);
    // Why doesn't the StructLiteralExp constructor do this, when
    // sym->type != NULL ?
    structinit->type = sym->type;
    return structinit;
}

/********************************
 *  Add v to the istate list, unless it already exists there.
 */
void addVarToInterstate(InterState *istate, VarDeclaration *v)
{
    if (!v->isParameter())
    {
      for (size_t i = 0; 1; i++)
      {
          if (i == istate->vars.dim)
          {   istate->vars.push(v);
            //printf("\tadding %s to istate\n", v->toChars());
            break;
          }
          if (v == (VarDeclaration *)istate->vars.data[i])
            break;
      }
    }
}

Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post)
{
#if LOG
    printf("BinExp::interpretAssignCommon() %s\n", toChars());
#endif
    Expression *e = EXP_CANT_INTERPRET;
    Expression *e1 = this->e1;

    if (fp)
    {
      if (e1->op == TOKcast)
      {   CastExp *ce = (CastExp *)e1;
          e1 = ce->e1;
      }
    }
    if (e1 == EXP_CANT_INTERPRET)
      return e1;
    Expression *e2 = this->e2->interpret(istate);
    if (e2 == EXP_CANT_INTERPRET)
      return e2;
      
    // Chase down rebinding of out and ref.
    if (e1->op == TOKvar)
    {
      VarExp *ve = (VarExp *)e1;
      VarDeclaration *v = ve->var->isVarDeclaration();
      if (v && v->value && v->value->op == TOKvar)
      {
          VarExp *ve2 = (VarExp *)v->value;
          if (ve2->var->isStaticStructInitDeclaration())
          { // This can happen if v is a struct initialized to
            // 0 using an __initZ StaticStructInitDeclaration from
            // TypeStruct::defaultInit()
          }
          else
            e1 = v->value;
      }
      else if (v && v->value && (v->value->op==TOKindex || v->value->op == TOKdotvar))
      {
            // It is no longer be a TOKvar, eg when a[4] is passed by ref.
          e1 = v->value;          
      }
    }

    // To reduce code complexity of handling dotvar expressions,
    // extract the aggregate now.
    Expression *aggregate;
    if (e1->op == TOKdotvar) {
        aggregate = ((DotVarExp *)e1)->e1;
      // Get rid of 'this'.
        if (aggregate->op == TOKthis && istate->localThis)
            aggregate = istate->localThis;      
    }
    
    /* Assignment to variable of the form:
     *      v = e2
     */
    if (e1->op == TOKvar)
    {
      VarExp *ve = (VarExp *)e1;
      VarDeclaration *v = ve->var->isVarDeclaration();
      assert(v);
      if (v && v->isDataseg())
      {   // Can't modify global or static data
          error("%s cannot be modified at compile time", v->toChars());
          return EXP_CANT_INTERPRET;
      }
      if (v && !v->isDataseg())
      {
          Expression *ev = v->value;
          if (fp && !ev)
          { error("variable %s is used before initialization", v->toChars());
            return e;
          }
          if (fp)
            e2 = (*fp)(v->type, ev, e2);
          else
          { /* Look for special case of struct being initialized with 0.
             */
            if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64)
            {
                e2 = v->type->defaultInit();
            }
            e2 = Cast(v->type, v->type, e2);
          }
          if (e2 == EXP_CANT_INTERPRET)
            return e2;

          addVarToInterstate(istate, v);
          v->value = e2;
          e = Cast(type, type, post ? ev : e2);
      }
    }
    else if (e1->op == TOKdotvar && aggregate->op == TOKdotvar)
    { // eg  v.u.var = e2,  v[3].u.var = e2, etc.
      error("Nested struct assignment %s is not yet supported in CTFE", toChars());
    }
    /* Assignment to struct member of the form:
     *   v.var = e2
     */
    else if (e1->op == TOKdotvar && aggregate->op == TOKvar)
    { VarDeclaration *v = ((VarExp *)aggregate)->var->isVarDeclaration();

      if (v->isDataseg())
      {   // Can't modify global or static data
          error("%s cannot be modified at compile time", v->toChars());
          return EXP_CANT_INTERPRET;
      } else {
          // Chase down rebinding of out and ref
          if (v->value && v->value->op == TOKvar)
          {
            VarExp *ve2 = (VarExp *)v->value;
            if (ve2->var->isStaticStructInitDeclaration())
            {     // This can happen if v is a struct initialized to
                  // 0 using an __initZ StaticStructInitDeclaration from
                  // TypeStruct::defaultInit()
            }
            else
                v = ve2->var->isVarDeclaration();
            assert(v);
          }
      }
      if (fp && !v->value)
      {   error("variable %s is used before initialization", v->toChars());
          return e;
      }
      if (v->value == NULL && v->init->isVoidInitializer())
      {   /* Since a void initializer initializes to undefined
           * values, it is valid here to use the default initializer.
           * No attempt is made to determine if someone actually relies
           * on the void value - to do that we'd need a VoidExp.
           * That's probably a good enhancement idea.
           */
          v->value = v->type->defaultInit();
      }
      Expression *vie = v->value;
      if (vie->op == TOKvar)
      {
          Declaration *d = ((VarExp *)vie)->var;
          vie = getVarExp(e1->loc, istate, d);
      }
      if (vie->op != TOKstructliteral)
          return EXP_CANT_INTERPRET;
      StructLiteralExp *se = (StructLiteralExp *)vie;
      VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration();
      if (!vf)
          return EXP_CANT_INTERPRET;
      int fieldi = se->getFieldIndex(type, vf->offset);
      if (fieldi == -1)
          return EXP_CANT_INTERPRET;
      Expression *ev = se->getField(type, vf->offset);
      if (fp)
          e2 = (*fp)(type, ev, e2);
      else
          e2 = Cast(type, type, e2);
      if (e2 == EXP_CANT_INTERPRET)
          return e2;

      addVarToInterstate(istate, v);

      /* Create new struct literal reflecting updated fieldi
       */
      Expressions *expsx = changeOneElement(se->elements, fieldi, e2);
      v->value = new StructLiteralExp(se->loc, se->sd, expsx);
      v->value->type = se->type;

      e = Cast(type, type, post ? ev : e2);
    }
    /* Assignment to struct member of the form:
     *   *(symoffexp) = e2
     */
    else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff)
    { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1;
      VarDeclaration *v = soe->var->isVarDeclaration();

      if (v->isDataseg())
      {
          error("%s cannot be modified at compile time", v->toChars());
          return EXP_CANT_INTERPRET;
      }
      if (fp && !v->value)
      {   error("variable %s is used before initialization", v->toChars());
          return e;
      }
      Expression *vie = v->value;
      if (vie->op == TOKvar)
      {
          Declaration *d = ((VarExp *)vie)->var;
          vie = getVarExp(e1->loc, istate, d);
      }
      if (vie->op != TOKstructliteral)
          return EXP_CANT_INTERPRET;
      StructLiteralExp *se = (StructLiteralExp *)vie;
      int fieldi = se->getFieldIndex(type, soe->offset);
      if (fieldi == -1)
          return EXP_CANT_INTERPRET;
      Expression *ev = se->getField(type, soe->offset);
      if (fp)
          e2 = (*fp)(type, ev, e2);
      else
          e2 = Cast(type, type, e2);
      if (e2 == EXP_CANT_INTERPRET)
          return e2;

      addVarToInterstate(istate, v);

      /* Create new struct literal reflecting updated fieldi
       */
      Expressions *expsx = changeOneElement(se->elements, fieldi, e2);
      v->value = new StructLiteralExp(se->loc, se->sd, expsx);
      v->value->type = se->type;

      e = Cast(type, type, post ? ev : e2);
    }
    /* Assignment to array element of the form:
     *   a[i] = e2
     */
    else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar)
    { IndexExp *ie = (IndexExp *)e1;
      VarExp *ve = (VarExp *)ie->e1;
      VarDeclaration *v = ve->var->isVarDeclaration();
      if (!v || v->isDataseg())
      {
          error("%s cannot be modified at compile time", v ? v->toChars(): "void");
          return EXP_CANT_INTERPRET;
      }
          if (v->value && v->value->op == TOKvar)
          {
            VarExp *ve2 = (VarExp *)v->value;
            if (ve2->var->isStaticStructInitDeclaration())
            {     // This can happen if v is a struct initialized to
                  // 0 using an __initZ StaticStructInitDeclaration from
                  // TypeStruct::defaultInit()
            }
            else
                v = ve2->var->isVarDeclaration();
            assert(v);
          }
      if (!v->value)
      {
          if (fp)
          {   error("variable %s is used before initialization", v->toChars());
            return e;
          }

          Type *t = v->type->toBasetype();
          if (t->ty == Tsarray)
          {
            /* This array was void initialized. Create a
             * default initializer for it.
             * What we should do is fill the array literal with
             * NULL data, so use-before-initialized can be detected.
             * But we're too lazy at the moment to do it, as that
             * involves redoing Index() and whoever calls it.
             */

            size_t dim = ((TypeSArray *)t)->dim->toInteger();
              v->value = createBlockDuplicatedArrayLiteral(v->type,
                  v->type->defaultInit(), dim);
          }
          else
            return EXP_CANT_INTERPRET;
      }

      ArrayLiteralExp *ae = NULL;
      AssocArrayLiteralExp *aae = NULL;
      StringExp *se = NULL;
      if (v->value->op == TOKarrayliteral)
          ae = (ArrayLiteralExp *)v->value;
      else if (v->value->op == TOKassocarrayliteral)
          aae = (AssocArrayLiteralExp *)v->value;
      else if (v->value->op == TOKstring)
          se = (StringExp *)v->value;
      else if (v->value->op == TOKnull)
      {
          // This would be a runtime segfault
          error("Cannot index null array %s", v->toChars());
          return EXP_CANT_INTERPRET;
      }
      else
          return EXP_CANT_INTERPRET;

      /* Set the $ variable
       */
      Expression *ee = ArrayLength(Type::tsize_t, v->value);
      if (ee != EXP_CANT_INTERPRET && ie->lengthVar)
          ie->lengthVar->value = ee;
      Expression *index = ie->e2->interpret(istate);
      if (index == EXP_CANT_INTERPRET)
          return EXP_CANT_INTERPRET;
      Expression *ev;
      if (fp || ae || se)     // not for aae, because key might not be there
      {
          ev = Index(type, v->value, index);
          if (ev == EXP_CANT_INTERPRET)
            return EXP_CANT_INTERPRET;
      }

      if (fp)
          e2 = (*fp)(type, ev, e2);
      else
          e2 = Cast(type, type, e2);
      if (e2 == EXP_CANT_INTERPRET)
          return e2;
      
      addVarToInterstate(istate, v);
      if (ae)
      {
          /* Create new array literal reflecting updated elem
           */
          int elemi = index->toInteger();
          Expressions *expsx = changeOneElement(ae->elements, elemi, e2);
          v->value = new ArrayLiteralExp(ae->loc, expsx);
          v->value->type = ae->type;
      }
      else if (aae)
      {
          /* Create new associative array literal reflecting updated key/value
           */
          Expressions *keysx = aae->keys;
          Expressions *valuesx = new Expressions();
          valuesx->setDim(aae->values->dim);
          int updated = 0;
          for (size_t j = valuesx->dim; j; )
          { j--;
            Expression *ekey = (Expression *)aae->keys->data[j];
            Expression *ex = Equal(TOKequal, Type::tbool, ekey, index);
            if (ex == EXP_CANT_INTERPRET)
                return EXP_CANT_INTERPRET;
            if (ex->isBool(TRUE))
            {   valuesx->data[j] = (void *)e2;
                updated = 1;
            }
            else
                valuesx->data[j] = aae->values->data[j];
          }
          if (!updated)
          { // Append index/e2 to keysx[]/valuesx[]
            valuesx->push(e2);
            keysx = (Expressions *)keysx->copy();
            keysx->push(index);
          }
          v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx);
          v->value->type = aae->type;
      }
      else if (se)
      {
          /* Create new string literal reflecting updated elem
           */
          int elemi = index->toInteger();
          unsigned char *s;
          s = (unsigned char *)mem.calloc(se->len + 1, se->sz);
          memcpy(s, se->string, se->len * se->sz);
          unsigned value = e2->toInteger();
          switch (se->sz)
          {
            case 1:     s[elemi] = value; break;
            case 2:     ((unsigned short *)s)[elemi] = value; break;
            case 4:     ((unsigned *)s)[elemi] = value; break;
            default:
                assert(0);
                break;
          }
          StringExp *se2 = new StringExp(se->loc, s, se->len);
          se2->committed = se->committed;
          se2->postfix = se->postfix;
          se2->type = se->type;
          v->value = se2;
      }
      else
          assert(0);

      e = Cast(type, type, post ? ev : e2);
    }
    
    /* Assignment to struct element in array, of the form:
     *  a[i].var = e2
     */
    else if (e1->op == TOKdotvar && aggregate->op == TOKindex &&
           ((IndexExp *)aggregate)->e1->op == TOKvar)
    {
        IndexExp * ie = (IndexExp *)aggregate;
      VarExp *ve = (VarExp *)(ie->e1);
      VarDeclaration *v = ve->var->isVarDeclaration();
      if (!v || v->isDataseg())
      {
          error("%s cannot be modified at compile time", v ? v->toChars(): "void");
          return EXP_CANT_INTERPRET;
      }
      Type *t = ve->type->toBasetype();
      ArrayLiteralExp *ae = (ArrayLiteralExp *)v->value;
      if (!ae)
      {
          // assignment to one element in an uninitialized (static) array.
          // This is quite difficult, because defaultInit() for a struct is a VarExp,
          // not a StructLiteralExp.
          Type *t = v->type->toBasetype();
          if (t->ty != Tsarray)
          {
            error("Cannot index an uninitialized variable");
            return EXP_CANT_INTERPRET;
          }

          Type *telem = ((TypeSArray *)t)->nextOf()->toBasetype();
          if (telem->ty != Tstruct) { return EXP_CANT_INTERPRET; }

          // Create a default struct literal...
          StructDeclaration *sym = ((TypeStruct *)telem)->sym;
          StructLiteralExp *structinit = createDefaultInitStructLiteral(v->loc, sym);

          // ... and use to create a blank array literal
          size_t dim = ((TypeSArray *)t)->dim->toInteger();
          ae = createBlockDuplicatedArrayLiteral(v->type, structinit, dim);
          v->value = ae;
      }
      if ((Expression *)(ae->elements) == EXP_CANT_INTERPRET)
      {
          // Note that this would be a runtime segfault
          error("Cannot index null array %s", v->toChars());
          return EXP_CANT_INTERPRET;
      }
      // Set the $ variable
      Expression *ee = ArrayLength(Type::tsize_t, v->value);
      if (ee != EXP_CANT_INTERPRET && ie->lengthVar)
          ie->lengthVar->value = ee;
      // Determine the index, and check that it's OK.
      Expression *index = ie->e2->interpret(istate);
      if (index == EXP_CANT_INTERPRET)
          return EXP_CANT_INTERPRET;

      int elemi = index->toInteger();
      if (elemi >= ae->elements->dim)
      {
          error("array index %d is out of bounds %s[0..%d]", elemi,
            v->toChars(), ae->elements->dim);
          return EXP_CANT_INTERPRET;
      }
      // Get old element
      Expression *vie = (Expression *)(ae->elements->data[elemi]);
      if (vie->op != TOKstructliteral)
          return EXP_CANT_INTERPRET;

      // Work out which field needs to be changed
      StructLiteralExp *se = (StructLiteralExp *)vie;
      VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration();
      if (!vf)
          return EXP_CANT_INTERPRET;

      int fieldi = se->getFieldIndex(type, vf->offset);
      if (fieldi == -1)
          return EXP_CANT_INTERPRET;
            
      Expression *ev = se->getField(type, vf->offset);
      if (fp)
          e2 = (*fp)(type, ev, e2);
      else
          e2 = Cast(type, type, e2);
      if (e2 == EXP_CANT_INTERPRET)
          return e2;

      // Create new struct literal reflecting updated field
      Expressions *expsx = changeOneElement(se->elements, fieldi, e2);
      Expression * newstruct = new StructLiteralExp(se->loc, se->sd, expsx);

      // Create new array literal reflecting updated struct elem
      ae->elements = changeOneElement(ae->elements, elemi, newstruct);
      return ae;
    }
    /* Slice assignment, initialization of static arrays
     *   a[] = e
     */
    else if (e1->op == TOKslice && ((SliceExp *)e1)->e1->op==TOKvar)
    {
        SliceExp * sexp = (SliceExp *)e1;
      VarExp *ve = (VarExp *)(sexp->e1);
      VarDeclaration *v = ve->var->isVarDeclaration();
      if (!v || v->isDataseg())
      {
          error("%s cannot be modified at compile time", v->toChars());
          return EXP_CANT_INTERPRET;
      }
          // Chase down rebinding of out and ref
          if (v->value && v->value->op == TOKvar)
          {
            VarExp *ve2 = (VarExp *)v->value;
            if (ve2->var->isStaticStructInitDeclaration())
            {     // This can happen if v is a struct initialized to
                  // 0 using an __initZ StaticStructInitDeclaration from
                  // TypeStruct::defaultInit()
            }
            else
                v = ve2->var->isVarDeclaration();
            assert(v);
          }
      /* Set the $ variable
       */
      Expression *ee = v->value ? ArrayLength(Type::tsize_t, v->value)
                          : EXP_CANT_INTERPRET;
      if (ee != EXP_CANT_INTERPRET && sexp->lengthVar)
          sexp->lengthVar->value = ee;
      Expression *upper = NULL;
      Expression *lower = NULL;
      if (sexp->upr)
      {
          upper = sexp->upr->interpret(istate);
          if (upper == EXP_CANT_INTERPRET)
            return EXP_CANT_INTERPRET;
      }
      if (sexp->lwr)
      {
          lower = sexp->lwr->interpret(istate);
          if (lower == EXP_CANT_INTERPRET)
            return EXP_CANT_INTERPRET;
      }
      Type *t = v->type->toBasetype();
      size_t dim;
      if (t->ty == Tsarray)               
          dim = ((TypeSArray *)t)->dim->toInteger();
      else if (t->ty == Tarray)
      {
          if (!v->value || v->value->op == TOKnull)
          {
            error("cannot assign to null array %s", v->toChars());
            return EXP_CANT_INTERPRET;
          }
          if (v->value->op == TOKarrayliteral)
            dim = ((ArrayLiteralExp *)v->value)->elements->dim;
          else if (v->value->op ==TOKstring)
          {
            error("String slice assignment is not yet supported in CTFE");
            return EXP_CANT_INTERPRET;
          }
      }
      else
      {
          error("%s cannot be evaluated at compile time", toChars());
          return EXP_CANT_INTERPRET;
      }
      int upperbound = upper ? upper->toInteger() : dim;
      int lowerbound = lower ? lower->toInteger() : 0;

      ArrayLiteralExp *existing;
      if (((int)lowerbound < 0) || (upperbound > dim))
      {
          error("Array bounds [0..%d] exceeded in slice [%d..%d]", dim, lowerbound, upperbound);
          return EXP_CANT_INTERPRET;
      }
      if (upperbound-lowerbound != dim)
      {
          // Only modifying part of the array. Must create a new array literal.
          // If the existing array is uninitialized (this can only happen
          // with static arrays), create it.
          if (v->value && v->value->op == TOKarrayliteral)
                existing = (ArrayLiteralExp *)v->value;
          else
          {
            // this can only happen with static arrays
            existing = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim);
          }
      }

      if (e2->op == TOKarrayliteral)
      {
          // Static array assignment from literal
          ArrayLiteralExp *ae = (ArrayLiteralExp *)e2;                        
          if (ae->elements->dim != (upperbound - lowerbound))
          {
            error("Array length mismatch assigning [0..%d] to [%d..%d]", ae->elements->dim, lowerbound, upperbound);
            return e;
          }
          if (upperbound - lowerbound == dim)
            v->value = ae;
          else
          {
            // value[] = value[0..lower] ~ ae ~ value[upper..$]
            existing->elements = spliceElements(existing->elements, ae->elements, lowerbound);
            v->value = existing;
          }
          return e2;
      }
      else if (t->nextOf()->ty == e2->type->ty)
      {
           // Static array block assignment
          if (upperbound-lowerbound ==dim)
            v->value = createBlockDuplicatedArrayLiteral(v->type, e2, dim);
          else
          {
            // value[] = value[0..lower] ~ ae ~ value[upper..$]
            existing->elements = spliceElements(existing->elements, createBlockDuplicatedArrayLiteral(v->type, e2, upperbound-lowerbound)->elements, lowerbound);
            v->value = existing;
          }                   
          return e2;
      }
      else if (e2->op == TOKstring)
      {
          StringExp *se = (StringExp *)e2;
          // This is problematic. char[8] should be storing
          // values as a string literal, not
          // as an array literal. Then, for static arrays, we
          // could do modifications
          // in-place, with a dramatic memory and speed improvement.
          error("String slice assignment is not yet supported in CTFE");
          return e2;
      }
      else
      {
          error("Slice operation %s cannot be evaluated at compile time", toChars());
          return e;
      }
    }
    else
    {
      error("%s cannot be evaluated at compile time", toChars());
#ifdef DEBUG
      dump(0);
#endif
    }
    return e;
}

Expression *AssignExp::interpret(InterState *istate)
{
    return interpretAssignCommon(istate, NULL);
}

#define BIN_ASSIGN_INTERPRET(op) \
Expression *op##AssignExp::interpret(InterState *istate)    \
{                                               \
    return interpretAssignCommon(istate, &op);              \
}

BIN_ASSIGN_INTERPRET(Add)
BIN_ASSIGN_INTERPRET(Min)
BIN_ASSIGN_INTERPRET(Cat)
BIN_ASSIGN_INTERPRET(Mul)
BIN_ASSIGN_INTERPRET(Div)
BIN_ASSIGN_INTERPRET(Mod)
BIN_ASSIGN_INTERPRET(Shl)
BIN_ASSIGN_INTERPRET(Shr)
BIN_ASSIGN_INTERPRET(Ushr)
BIN_ASSIGN_INTERPRET(And)
BIN_ASSIGN_INTERPRET(Or)
BIN_ASSIGN_INTERPRET(Xor)

Expression *PostExp::interpret(InterState *istate)
{
#if LOG
    printf("PostExp::interpret() %s\n", toChars());
#endif
    Expression *e;
    if (op == TOKplusplus)
      e = interpretAssignCommon(istate, &Add, 1);
    else
      e = interpretAssignCommon(istate, &Min, 1);
#if LOG
    if (e == EXP_CANT_INTERPRET)
      printf("PostExp::interpret() CANT\n");
#endif
    return e;
}

Expression *AndAndExp::interpret(InterState *istate)
{
#if LOG
    printf("AndAndExp::interpret() %s\n", toChars());
#endif
    Expression *e = e1->interpret(istate);
    if (e != EXP_CANT_INTERPRET)
    {
      if (e->isBool(FALSE))
          e = new IntegerExp(e1->loc, 0, type);
      else if (e->isBool(TRUE))
      {
          e = e2->interpret(istate);
          if (e != EXP_CANT_INTERPRET)
          {
            if (e->isBool(FALSE))
                e = new IntegerExp(e1->loc, 0, type);
            else if (e->isBool(TRUE))
                e = new IntegerExp(e1->loc, 1, type);
            else
                e = EXP_CANT_INTERPRET;
          }
      }
      else
          e = EXP_CANT_INTERPRET;
    }
    return e;
}

Expression *OrOrExp::interpret(InterState *istate)
{
#if LOG
    printf("OrOrExp::interpret() %s\n", toChars());
#endif
    Expression *e = e1->interpret(istate);
    if (e != EXP_CANT_INTERPRET)
    {
      if (e->isBool(TRUE))
          e = new IntegerExp(e1->loc, 1, type);
      else if (e->isBool(FALSE))
      {
          e = e2->interpret(istate);
          if (e != EXP_CANT_INTERPRET)
          {
            if (e->isBool(FALSE))
                e = new IntegerExp(e1->loc, 0, type);
            else if (e->isBool(TRUE))
                e = new IntegerExp(e1->loc, 1, type);
            else
                e = EXP_CANT_INTERPRET;
          }
      }
      else
          e = EXP_CANT_INTERPRET;
    }
    return e;
}


Expression *CallExp::interpret(InterState *istate)
{   Expression *e = EXP_CANT_INTERPRET;

#if LOG
    printf("CallExp::interpret() %s\n", toChars());
#endif
    if (e1->op == TOKdotvar)
    {
        Expression * pthis = ((DotVarExp*)e1)->e1;
      FuncDeclaration *fd = ((DotVarExp*)e1)->var->isFuncDeclaration();
      TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL;
      if (tf)
      {   // Member function call
          if(pthis->op == TOKthis)
            pthis = istate->localThis;        
          Expression *eresult = fd->interpret(istate, arguments, pthis);
          if (eresult)
            e = eresult;
          else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors)
            e = EXP_VOID_INTERPRET;
          else
            error("cannot evaluate %s at compile time", toChars());
          return e;
      } 
      error("cannot evaluate %s at compile time", toChars());
        return EXP_CANT_INTERPRET;
    }
    if (e1->op == TOKvar)
    {
      FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
      if (fd)
      {
#if DMDV2
          enum BUILTIN b = fd->isBuiltin();
          if (b)
          { Expressions args;
            args.setDim(arguments->dim);
            for (size_t i = 0; i < args.dim; i++)
            {
                Expression *earg = (Expression *)arguments->data[i];
                earg = earg->interpret(istate);
                if (earg == EXP_CANT_INTERPRET)
                  return earg;
                args.data[i] = (void *)earg;
            }
            e = eval_builtin(b, &args);
            if (!e)
                e = EXP_CANT_INTERPRET;
          }
          else
#endif
          // Inline .dup
          if (fd->ident == Id::adDup && arguments && arguments->dim == 2)
          {
            e = (Expression *)arguments->data[1];
            e = e->interpret(istate);
            if (e != EXP_CANT_INTERPRET)
            {
                e = expType(type, e);
            }
          }
          else
          {
            Expression *eresult = fd->interpret(istate, arguments);
            if (eresult)
                e = eresult;
            else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors)
                e = EXP_VOID_INTERPRET;
            else
                error("cannot evaluate %s at compile time", toChars());
          }
      }
    }
    return e;
}

Expression *CommaExp::interpret(InterState *istate)
{
#if LOG
    printf("CommaExp::interpret() %s\n", toChars());
#endif
    Expression *e = e1->interpret(istate);
    if (e != EXP_CANT_INTERPRET)
      e = e2->interpret(istate);
    return e;
}

Expression *CondExp::interpret(InterState *istate)
{
#if LOG
    printf("CondExp::interpret() %s\n", toChars());
#endif
    Expression *e = econd->interpret(istate);
    if (e != EXP_CANT_INTERPRET)
    {
      if (e->isBool(TRUE))
          e = e1->interpret(istate);
      else if (e->isBool(FALSE))
          e = e2->interpret(istate);
      else
          e = EXP_CANT_INTERPRET;
    }
    return e;
}

Expression *ArrayLengthExp::interpret(InterState *istate)
{   Expression *e;
    Expression *e1;

#if LOG
    printf("ArrayLengthExp::interpret() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
    {
      e = ArrayLength(type, e1);
    }
    else if (e1->op == TOKnull)
    {
      e = new IntegerExp(loc, 0, type);
    }
    else
      goto Lcant;
    return e;

Lcant:
    return EXP_CANT_INTERPRET;
}

Expression *IndexExp::interpret(InterState *istate)
{   Expression *e;
    Expression *e1;
    Expression *e2;

#if LOG
    printf("IndexExp::interpret() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;

    if (e1->op == TOKstring || e1->op == TOKarrayliteral)
    {
      /* Set the $ variable
       */
      e = ArrayLength(Type::tsize_t, e1);
      if (e == EXP_CANT_INTERPRET)
          goto Lcant;
      if (lengthVar)
          lengthVar->value = e;
    }

    e2 = this->e2->interpret(istate);
    if (e2 == EXP_CANT_INTERPRET)
      goto Lcant;
    return Index(type, e1, e2);

Lcant:
    return EXP_CANT_INTERPRET;
}


Expression *SliceExp::interpret(InterState *istate)
{   Expression *e;
    Expression *e1;
    Expression *lwr;
    Expression *upr;

#if LOG
    printf("SliceExp::interpret() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (!this->lwr)
    {
      e = e1->castTo(NULL, type);
      return e->interpret(istate);
    }

    /* Set the $ variable
     */
    e = ArrayLength(Type::tsize_t, e1);
    if (e == EXP_CANT_INTERPRET)
      goto Lcant;
    if (lengthVar)
      lengthVar->value = e;

    /* Evaluate lower and upper bounds of slice
     */
    lwr = this->lwr->interpret(istate);
    if (lwr == EXP_CANT_INTERPRET)
      goto Lcant;
    upr = this->upr->interpret(istate);
    if (upr == EXP_CANT_INTERPRET)
      goto Lcant;

    return Slice(type, e1, lwr, upr);

Lcant:
    return EXP_CANT_INTERPRET;
}


Expression *CatExp::interpret(InterState *istate)
{   Expression *e;
    Expression *e1;
    Expression *e2;

#if LOG
    printf("CatExp::interpret() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
    {
      goto Lcant;
    }
    e2 = this->e2->interpret(istate);
    if (e2 == EXP_CANT_INTERPRET)
      goto Lcant;
    return Cat(type, e1, e2);

Lcant:
#if LOG
    printf("CatExp::interpret() %s CANT\n", toChars());
#endif
    return EXP_CANT_INTERPRET;
}


Expression *CastExp::interpret(InterState *istate)
{   Expression *e;
    Expression *e1;

#if LOG
    printf("CastExp::interpret() %s\n", toChars());
#endif
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;
    return Cast(type, to, e1);

Lcant:
#if LOG
    printf("CastExp::interpret() %s CANT\n", toChars());
#endif
    return EXP_CANT_INTERPRET;
}


Expression *AssertExp::interpret(InterState *istate)
{   Expression *e;
    Expression *e1;

#if LOG
    printf("AssertExp::interpret() %s\n", toChars());
#endif
    if( this->e1->op == TOKaddress)
    {   // Special case: deal with compiler-inserted assert(&this, "null this") 
      AddrExp *ade = (AddrExp *)this->e1;
      if(ade->e1->op == TOKthis && istate->localThis)       
      return istate->localThis->interpret(istate);
    }
if (this->e1->op == TOKthis)
{
      if(istate->localThis)         
      return istate->localThis->interpret(istate);
}    
    e1 = this->e1->interpret(istate);
    if (e1 == EXP_CANT_INTERPRET)
      goto Lcant;
    if (e1->isBool(TRUE))
    {
    }
    else if (e1->isBool(FALSE))
    {
      if (msg)
      {
          e = msg->interpret(istate);
          if (e == EXP_CANT_INTERPRET)
            goto Lcant;
          error("%s", e->toChars());
      }
      else
          error("%s failed", toChars());
      goto Lcant;
    }
    else
      goto Lcant;
    return e1;

Lcant:
    return EXP_CANT_INTERPRET;
}

Expression *PtrExp::interpret(InterState *istate)
{   Expression *e = EXP_CANT_INTERPRET;

#if LOG
    printf("PtrExp::interpret() %s\n", toChars());
#endif

    // Constant fold *(&structliteral + offset)
    if (e1->op == TOKadd)
    { AddExp *ae = (AddExp *)e1;
      if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
      {   AddrExp *ade = (AddrExp *)ae->e1;
          Expression *ex = ade->e1;
          ex = ex->interpret(istate);
          if (ex != EXP_CANT_INTERPRET)
          {
            if (ex->op == TOKstructliteral)
            {   StructLiteralExp *se = (StructLiteralExp *)ex;
                unsigned offset = ae->e2->toInteger();
                e = se->getField(type, offset);
                if (!e)
                  e = EXP_CANT_INTERPRET;
                return e;
            }
          }
      }
      e = Ptr(type, e1);
    }
    else if (e1->op == TOKsymoff)
    { SymOffExp *soe = (SymOffExp *)e1;
      VarDeclaration *v = soe->var->isVarDeclaration();
      if (v)
      {   Expression *ev = getVarExp(loc, istate, v);
          if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral)
          { StructLiteralExp *se = (StructLiteralExp *)ev;
            e = se->getField(type, soe->offset);
            if (!e)
                e = EXP_CANT_INTERPRET;
          }
      }
    }
#if DMDV2
#else // this is required for D1, where structs return *this instead of 'this'.    
    else if (e1->op == TOKthis)
    {
      if(istate->localThis)         
          return istate->localThis->interpret(istate);
    }
#endif    
#if LOG
    if (e == EXP_CANT_INTERPRET)
      printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars());
#endif
    return e;
}

Expression *DotVarExp::interpret(InterState *istate)
{   Expression *e = EXP_CANT_INTERPRET;

#if LOG
    printf("DotVarExp::interpret() %s\n", toChars());
#endif

    Expression *ex = e1->interpret(istate);
    if (ex != EXP_CANT_INTERPRET)
    {
      if (ex->op == TOKstructliteral)
      {   StructLiteralExp *se = (StructLiteralExp *)ex;
          VarDeclaration *v = var->isVarDeclaration();
          if (v)
          { e = se->getField(type, v->offset);
            if (!e)
                e = EXP_CANT_INTERPRET;
            return e;
          }
      } else error("%s.%s is not yet implemented at compile time", ex->toChars(), var->toChars());
    }

#if LOG
    if (e == EXP_CANT_INTERPRET)
      printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars());
#endif
    return e;
}

/******************************* Special Functions ***************************/

Expression *interpret_aaLen(InterState *istate, Expressions *arguments)
{
    if (!arguments || arguments->dim != 1)
      return NULL;
    Expression *earg = (Expression *)arguments->data[0];
    earg = earg->interpret(istate);
    if (earg == EXP_CANT_INTERPRET)
      return NULL;
    if (earg->op != TOKassocarrayliteral)
      return NULL;
    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
    Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t);
    return e;
}

Expression *interpret_aaKeys(InterState *istate, Expressions *arguments)
{
#if LOG
    printf("interpret_aaKeys()\n");
#endif
    if (!arguments || arguments->dim != 2)
      return NULL;
    Expression *earg = (Expression *)arguments->data[0];
    earg = earg->interpret(istate);
    if (earg == EXP_CANT_INTERPRET)
      return NULL;
    if (earg->op != TOKassocarrayliteral)
      return NULL;
    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
    Expression *e = new ArrayLiteralExp(aae->loc, aae->keys);
    Type *elemType = ((TypeAArray *)aae->type)->index;
    e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0));
    return e;
}

Expression *interpret_aaValues(InterState *istate, Expressions *arguments)
{
    //printf("interpret_aaValues()\n");
    if (!arguments || arguments->dim != 3)
      return NULL;
    Expression *earg = (Expression *)arguments->data[0];
    earg = earg->interpret(istate);
    if (earg == EXP_CANT_INTERPRET)
      return NULL;
    if (earg->op != TOKassocarrayliteral)
      return NULL;
    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
    Expression *e = new ArrayLiteralExp(aae->loc, aae->values);
    Type *elemType = ((TypeAArray *)aae->type)->next;
    e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0));
    //printf("result is %s\n", e->toChars());
    return e;
}


Generated by  Doxygen 1.6.0   Back to index