Skip to content

Commit

Permalink
6504 Regression(2.041): "str" ~ [arr] allows string literal to be mod…
Browse files Browse the repository at this point in the history
…ified

(a) Move slicing functions from interpret.c into constfold.c
(b) move existing  string ~ [arr] -> string into interpret.c
(c) create         string ~ [arr] -> [arr]  for non-CTFE functions.
The CTFE slicing functions are used for the conversion, to avoid code
duplication.

Fixes bug 6504.
  • Loading branch information
Don Clugston committed Feb 2, 2012
1 parent 127d011 commit 5fd8196
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 111 deletions.
132 changes: 85 additions & 47 deletions src/constfold.c
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,64 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
return e;
}

/* Set a slice of char array literal 'existingAE' from a string 'newval'.
* existingAE[firstIndex..firstIndex+newval.length] = newval.
*/
void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex)
{
size_t newlen = newval->len;
size_t sz = newval->sz;
unsigned char *s = (unsigned char *)newval->string;
Type *elemType = existingAE->type->nextOf();
for (size_t j = 0; j < newlen; j++)
{
dinteger_t val;
switch (sz)
{
case 1: val = s[j]; break;
case 2: val = ((unsigned short *)s)[j]; break;
case 4: val = ((unsigned *)s)[j]; break;
default:
assert(0);
break;
}
existingAE->elements->tdata()[j+firstIndex]
= new IntegerExp(newval->loc, val, elemType);
}
}

/* Set a slice of string 'existingSE' from a char array literal 'newae'.
* existingSE[firstIndex..firstIndex+newae.length] = newae.
*/
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
for (size_t j = 0; j < newae->elements->dim; j++)
{
unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger());
switch (existingSE->sz)
{
case 1: s[j+firstIndex] = value; break;
case 2: ((unsigned short *)s)[j+firstIndex] = value; break;
case 4: ((unsigned *)s)[j+firstIndex] = value; break;
default:
assert(0);
break;
}
}
}

/* Set a slice of string 'existingSE' from a string 'newstr'.
* existingSE[firstIndex..firstIndex+newstr.length] = newstr.
*/
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
size_t sz = existingSE->sz;
assert(sz == newstr->sz);
memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len);
}

/* Also return EXP_CANT_INTERPRET if this fails
*/
Expression *Cat(Type *type, Expression *e1, Expression *e2)
Expand Down Expand Up @@ -1592,62 +1650,42 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2)
else if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
t1->nextOf()->isintegral())
{
// Concatenate the strings
StringExp *es1 = (StringExp *)e2;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + i * sz, &v, sz);
// [chars] ~ string --> [chars]
StringExp *es = (StringExp *)e2;
ArrayLiteralExp *ea = (ArrayLiteralExp *)e1;
size_t len = es->len + ea->elements->dim;
Expressions * elems = new Expressions;
elems->setDim(len);
for (size_t i= 0; i < ea->elements->dim; ++i)
{
elems->tdata()[i] = ea->elements->tdata()[i];
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0;
es->type = type;
e = es;
ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems);
dest->type = type;
sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim);
return dest;
}
else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
t2->nextOf()->isintegral())
{
// Concatenate the strings
StringExp *es1 = (StringExp *)e1;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy(s, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz);
// string ~ [chars] --> [chars]
StringExp *es = (StringExp *)e1;
ArrayLiteralExp *ea = (ArrayLiteralExp *)e2;
size_t len = es->len + ea->elements->dim;
Expressions * elems = new Expressions;
elems->setDim(len);
for (size_t i= 0; i < ea->elements->dim; ++i)
{
elems->tdata()[es->len + i] = ea->elements->tdata()[i];
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0; //es1->committed;
es->type = type;
e = es;
ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems);
dest->type = type;
sliceAssignArrayLiteralFromString(dest, es, 0);
return dest;
}
else if (e1->op == TOKstring && e2->op == TOKint64)
{
// Concatenate the strings
// string ~ char --> string
void *s;
StringExp *es1 = (StringExp *)e1;
StringExp *es;
Expand Down
7 changes: 7 additions & 0 deletions src/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -1686,4 +1686,11 @@ Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2);

Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr);

// Const-folding functions used by CTFE

void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex);
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex);
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex);


#endif /* DMD_EXPRESSION_H */
137 changes: 73 additions & 64 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,73 @@ Expression *ctfeEqual(enum TOK op, Type *type, Expression *e1, Expression *e2)
return Equal(op, type, e1, e2);
}

Expression *ctfeCat(Type *type, Expression *e1, Expression *e2)
{
Loc loc = e1->loc;
Type *t1 = e1->type->toBasetype();
Type *t2 = e2->type->toBasetype();
Expression *e;
if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
t1->nextOf()->isintegral())
{
// [chars] ~ string => string (only valid for CTFE)
StringExp *es1 = (StringExp *)e2;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + i * sz, &v, sz);
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0;
es->type = type;
e = es;
return e;
}
else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
t2->nextOf()->isintegral())
{
// string ~ [chars] => string (only valid for CTFE)
// Concatenate the strings
StringExp *es1 = (StringExp *)e1;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy(s, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz);
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0; //es1->committed;
es->type = type;
e = es;
return e;
}
return Cat(type, e1, e2);
}

void scrubArray(Loc loc, Expressions *elems);

Expand Down Expand Up @@ -3213,66 +3280,6 @@ Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e)
return r;
}


/* Set a slice of char array literal 'existingAE' from a string 'newval'.
* existingAE[firstIndex..firstIndex+newval.length] = newval.
*/
void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex)
{
size_t newlen = newval->len;
size_t sz = newval->sz;
unsigned char *s = (unsigned char *)newval->string;
Type *elemType = existingAE->type->nextOf();
for (size_t j = 0; j < newlen; j++)
{
dinteger_t val;
switch (sz)
{
case 1: val = s[j]; break;
case 2: val = ((unsigned short *)s)[j]; break;
case 4: val = ((unsigned *)s)[j]; break;
default:
assert(0);
break;
}
existingAE->elements->tdata()[j+firstIndex]
= new IntegerExp(newval->loc, val, elemType);
}
}

/* Set a slice of string 'existingSE' from a char array literal 'newae'.
* existingSE[firstIndex..firstIndex+newae.length] = newae.
*/
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
for (size_t j = 0; j < newae->elements->dim; j++)
{
unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger());
switch (existingSE->sz)
{
case 1: s[j+firstIndex] = value; break;
case 2: ((unsigned short *)s)[j+firstIndex] = value; break;
case 4: ((unsigned *)s)[j+firstIndex] = value; break;
default:
assert(0);
break;
}
}
}

/* Set a slice of string 'existingSE' from a string 'newstr'.
* existingSE[firstIndex..firstIndex+newstr.length] = newstr.
*/
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
size_t sz = existingSE->sz;
assert(sz == newstr->sz);
memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len);
}


/* Set dest = src, where both dest and src are container value literals
* (ie, struct literals, or static arrays (can be an array literal or a string)
* Assignment is recursively in-place.
Expand Down Expand Up @@ -4425,15 +4432,17 @@ Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal)
return interpretAssignCommon(istate, goal, NULL);
}

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

#define BIN_ASSIGN_INTERPRET(op) BIN_ASSIGN_INTERPRET_CTFE(op, op)

BIN_ASSIGN_INTERPRET(Add)
BIN_ASSIGN_INTERPRET(Min)
BIN_ASSIGN_INTERPRET(Cat)
BIN_ASSIGN_INTERPRET_CTFE(Cat, ctfeCat)
BIN_ASSIGN_INTERPRET(Mul)
BIN_ASSIGN_INTERPRET(Div)
BIN_ASSIGN_INTERPRET(Mod)
Expand Down Expand Up @@ -5306,7 +5315,7 @@ Expression *CatExp::interpret(InterState *istate, CtfeGoal goal)
return e2;
if (e2->op == TOKslice)
e2 = resolveSlice(e2);
e = Cat(type, e1, e2);
e = ctfeCat(type, e1, e2);
if (e == EXP_CANT_INTERPRET)
error("%s cannot be interpreted at compile time", toChars());
// We know we still own it, because we interpreted both e1 and e2
Expand Down

0 comments on commit 5fd8196

Please sign in to comment.