Mercurial > projects > ldc
diff dmd/interpret.c @ 1630:44b145be2ef5
Merge dmd 1.056.
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Sat, 06 Feb 2010 15:53:52 +0000 |
parents | e83f0778c260 |
children | 9bf06e02070b |
line wrap: on
line diff
--- a/dmd/interpret.c Wed Jan 06 19:53:35 2010 +0100 +++ b/dmd/interpret.c Sat Feb 06 15:53:52 2010 +0000 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -52,6 +52,8 @@ Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration *fd); Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd); +ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, Expression *elem, size_t dim); + /************************************* * Attempt to interpret a function given the arguments. * Input: @@ -92,7 +94,7 @@ } #endif - if (cantInterpret || semanticRun == 3) + if (cantInterpret || semanticRun == PASSsemantic3) return NULL; if (!fbody) @@ -100,13 +102,13 @@ return NULL; } - if (semanticRun < 3 && scope) + if (semanticRun < PASSsemantic3 && scope) { semantic3(scope); if (global.errors) // if errors compiling this function return NULL; } - if (semanticRun < 4) + if (semanticRun < PASSsemantic3done) return NULL; Type *tb = type->toBasetype(); @@ -160,7 +162,7 @@ { Expression *earg = (Expression *)arguments->data[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); - if (arg->storageClass & (STCout | STCref)) + if (arg->storageClass & (STCout | STCref | STClazy)) { } else @@ -1005,6 +1007,35 @@ return this; } +Expression *FuncExp::interpret(InterState *istate) +{ +#if LOG + printf("FuncExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *SymOffExp::interpret(InterState *istate) +{ +#if LOG + printf("SymOffExp::interpret() %s\n", toChars()); +#endif + if (var->isFuncDeclaration() && offset == 0) + { + return this; + } + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; +} + +Expression *DelegateExp::interpret(InterState *istate) +{ +#if LOG + printf("DelegateExp::interpret() %s\n", toChars()); +#endif + return this; +} + Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) { Expression *e = EXP_CANT_INTERPRET; @@ -1013,6 +1044,11 @@ if (v) { #if DMDV2 + /* Magic variable __ctfe always returns true when interpreting + */ + if (v->ident == Id::ctfe) + return new IntegerExp(loc, 1, Type::tbool); + if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->value) #else if (v->isConst() && v->init) @@ -1021,6 +1057,16 @@ if (e && !e->type) e->type = v->type; } + else if (v->isCTFE() && !v->value) + { + if (v->init) + { + e = v->init->toExpression(); + e = e->interpret(istate); + } + else // This should never happen + e = v->type->defaultInitLiteral(); + } else { e = v->value; if (!v->isCTFE()) @@ -1482,7 +1528,7 @@ } /*************************************** - * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint..$] + * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint+newelems.length..$] */ Expressions *spliceElements(Expressions *oldelems, Expressions *newelems, size_t insertpoint) @@ -1499,6 +1545,26 @@ return expsx; } +/*************************************** + * Returns oldstr[0..insertpoint] ~ newstr ~ oldstr[insertpoint+newlen..$] + */ +StringExp *spliceStringExp(StringExp *oldstr, StringExp *newstr, size_t insertpoint) +{ + assert(oldstr->sz==newstr->sz); + unsigned char *s; + size_t oldlen = oldstr->len; + size_t newlen = newstr->len; + size_t sz = oldstr->sz; + s = (unsigned char *)mem.calloc(oldlen + 1, sz); + memcpy(s, oldstr->string, oldlen * sz); + memcpy(s + insertpoint * sz, newstr->string, newlen * sz); + StringExp *se2 = new StringExp(oldstr->loc, s, oldlen); + se2->committed = oldstr->committed; + se2->postfix = oldstr->postfix; + se2->type = oldstr->type; + return se2; +} + /****************************** * Create an array literal consisting of 'elem' duplicated 'dim' times. */ @@ -1514,6 +1580,28 @@ return ae; } +/****************************** + * Create a string literal consisting of 'value' duplicated 'dim' times. + */ +StringExp *createBlockDuplicatedStringLiteral(Type *type, + unsigned value, size_t dim, int sz) +{ + unsigned char *s; + s = (unsigned char *)mem.calloc(dim + 1, sz); + for (int elemi=0; elemi<dim; ++elemi) + { + switch (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); + } + } + StringExp *se = new StringExp(0, s, dim); + se->type = type; + return se; +} /******************************** * Add v to the istate list, unless it already exists there. @@ -1582,13 +1670,16 @@ // To reduce code complexity of handling dotvar expressions, // extract the aggregate now. Expression *aggregate; - if (e1->op == TOKdotvar) { + if (e1->op == TOKdotvar) + { aggregate = ((DotVarExp *)e1)->e1; // Get rid of 'this'. if (aggregate->op == TOKthis && istate->localThis) - aggregate = istate->localThis; + aggregate = istate->localThis; } - + if (e1->op == TOKthis && istate->localThis) + e1 = istate->localThis; + /* Assignment to variable of the form: * v = e2 */ @@ -1623,7 +1714,8 @@ if (e2 == EXP_CANT_INTERPRET) return e2; - addVarToInterstate(istate, v); + if (istate) + addVarToInterstate(istate, v); v->value = e2; e = Cast(type, type, post ? ev : e2); } @@ -1668,16 +1760,21 @@ * on the void value - to do that we'd need a VoidExp. * That's probably a good enhancement idea. */ - v->value = v->type->defaultInit(); + v->value = v->type->defaultInitLiteral(); } Expression *vie = v->value; + assert(vie != EXP_CANT_INTERPRET); + if (vie->op == TOKvar) { Declaration *d = ((VarExp *)vie)->var; vie = getVarExp(e1->loc, istate, d); } if (vie->op != TOKstructliteral) + { + error("Cannot assign %s=%s in CTFE", v->toChars(), vie->toChars()); return EXP_CANT_INTERPRET; + } StructLiteralExp *se = (StructLiteralExp *)vie; VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration(); if (!vf) @@ -2015,19 +2112,19 @@ 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 SymbolDeclaration from - // TypeStruct::defaultInit() - } - else - v = ve2->var->isVarDeclaration(); - assert(v); + // 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 SymbolDeclaration from + // TypeStruct::defaultInit() } + else + v = ve2->var->isVarDeclaration(); + assert(v); + } /* Set the $ variable */ Expression *ee = v->value ? ArrayLength(Type::tsize_t, v->value) @@ -2062,10 +2159,7 @@ 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; - } + dim = ((StringExp *)v->value)->len; } else { @@ -2075,69 +2169,89 @@ 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); + error("Array bounds [0..%d] exceeded in slice [%d..%d]", + dim, lowerbound, upperbound); return EXP_CANT_INTERPRET; } - if (upperbound-lowerbound != dim) + // Could either be slice assignment (v[] = e[]), + // or block assignment (v[] = val). + // For the former, we check that the lengths match. + bool isSliceAssignment = (e2->op == TOKarrayliteral) + || (e2->op == TOKstring); + size_t srclen = 0; + if (e2->op == TOKarrayliteral) + srclen = ((ArrayLiteralExp *)e2)->elements->dim; + else if (e2->op == TOKstring) + srclen = ((StringExp *)e2)->len; + if (isSliceAssignment && srclen != (upperbound - lowerbound)) { - // 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); - } + error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); + return e; } - 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 { + ArrayLiteralExp *existing; + // 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); // value[] = value[0..lower] ~ ae ~ value[upper..$] existing->elements = spliceElements(existing->elements, ae->elements, lowerbound); v->value = existing; } return e2; } + else if (e2->op == TOKstring) + { + StringExp *se = (StringExp *)e2; + if (upperbound-lowerbound == dim) + v->value = e2; + else + { + if (!v->value) + v->value = createBlockDuplicatedStringLiteral(se->type, + se->type->defaultInit()->toInteger(), dim, se->sz); + if (v->value->op==TOKstring) + v->value = spliceStringExp((StringExp *)v->value, se, lowerbound); + else + error("String slice assignment is not yet supported in CTFE"); + } + return e2; + } else if (t->nextOf()->ty == e2->type->ty) { - // Static array block assignment - if (upperbound-lowerbound ==dim) + // Static array block assignment + if (upperbound - lowerbound == dim) v->value = createBlockDuplicatedArrayLiteral(v->type, e2, dim); else { + ArrayLiteralExp *existing; + // 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); // value[] = value[0..lower] ~ ae ~ value[upper..$] - existing->elements = spliceElements(existing->elements, createBlockDuplicatedArrayLiteral(v->type, e2, upperbound-lowerbound)->elements, lowerbound); + 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()); @@ -2260,74 +2374,118 @@ #if LOG printf("CallExp::interpret() %s\n", toChars()); #endif - if (e1->op == TOKdotvar) + + Expression * pthis = NULL; + FuncDeclaration *fd = NULL; + Expression *ecall = e1; + if (ecall->op == TOKindex) + ecall = e1->interpret(istate); + if (ecall->op == TOKdotvar && !((DotVarExp*)ecall)->var->isFuncDeclaration()) + ecall = e1->interpret(istate); + + if (ecall->op == TOKdotvar) + { // Calling a member function + pthis = ((DotVarExp*)e1)->e1; + fd = ((DotVarExp*)e1)->var->isFuncDeclaration(); + } + else if (ecall->op == TOKvar) { - 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); + VarDeclaration *vd = ((VarExp *)ecall)->var->isVarDeclaration(); + if (vd && vd->value) + ecall = vd->value; + else // Calling a function + fd = ((VarExp *)e1)->var->isFuncDeclaration(); + } + if (ecall->op == TOKdelegate) + { // Calling a delegate + fd = ((DelegateExp *)ecall)->func; + pthis = ((DelegateExp *)ecall)->e1; + } + else if (ecall->op == TOKfunction) + { // Calling a delegate literal + fd = ((FuncExp*)ecall)->fd; + } + else if (ecall->op == TOKstar && ((PtrExp*)ecall)->e1->op==TOKfunction) + { // Calling a function literal + fd = ((FuncExp*)((PtrExp*)ecall)->e1)->fd; + } + else if (ecall->op == TOKstar && ((PtrExp*)ecall)->e1->op==TOKvar) + { // Calling a function pointer + VarDeclaration *vd = ((VarExp *)((PtrExp*)ecall)->e1)->var->isVarDeclaration(); + if (vd && vd->value && vd->value->op==TOKsymoff) + fd = ((SymOffExp *)vd->value)->var->isFuncDeclaration(); + } + + TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; + if (!tf) + { // DAC: I'm not sure if this ever happens + //printf("ecall=%s %d %d\n", ecall->toChars(), ecall->op, TOKcall); + error("cannot evaluate %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + if (pthis && fd) + { // Member function call + if (pthis->op == TOKthis) + pthis = istate->localThis; + else if (pthis->op == TOKcomma) + pthis = pthis->interpret(istate); + 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; + } + else if (fd) + { // function call +#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; - } + } + } + else + { 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; + return e; } Expression *CommaExp::interpret(InterState *istate) @@ -2335,6 +2493,21 @@ #if LOG printf("CommaExp::interpret() %s\n", toChars()); #endif + // If the comma returns a temporary variable, it needs to be an lvalue + // (this is particularly important for struct constructors) + if (e1->op == TOKdeclaration && e2->op == TOKvar + && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var) + { + VarExp* ve = (VarExp *)e2; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!v->init && !v->value) + v->value = v->type->defaultInitLiteral(); + if (!v->value) + v->value = v->init->toExpression(); + v->value = v->value->interpret(istate); + return e2; + } + Expression *e = e1->interpret(istate); if (e != EXP_CANT_INTERPRET) e = e2->interpret(istate); @@ -2516,14 +2689,18 @@ 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 (ade->e1->op == TOKthis && istate->localThis) + if (ade->e1->op == TOKdotvar + && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis) + return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var); + else + return istate->localThis->interpret(istate); } -if (this->e1->op == TOKthis) -{ - if(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;