Skip to content

Commit

Permalink
implement missing opDollar calls
Browse files Browse the repository at this point in the history
- extend ArrayScopeSymbol::search to handle opDollar for SliceExp
- merge existing code into resolveOpDollar helper functions
  • Loading branch information
MartinNowak committed Oct 28, 2012
1 parent c055b21 commit 091446b
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 130 deletions.
121 changes: 63 additions & 58 deletions src/dsymbol.c
Expand Up @@ -1310,62 +1310,9 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
* $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
*/
ArrayExp *ae = (ArrayExp *)exp;
AggregateDeclaration *ad = NULL;

Type *t = ae->e1->type->toBasetype();
if (t->ty == Tclass)
{
ad = ((TypeClass *)t)->sym;
}
else if (t->ty == Tstruct)
{
ad = ((TypeStruct *)t)->sym;
}
assert(ad);

Dsymbol *dsym = search_function(ad, Id::opDollar);
if (!dsym) // no dollar exists -- search in higher scope
return NULL;
VarDeclaration *v = ae->lengthVar;
if (!v)
{ // $ is lazily initialized. Create it now.
TemplateDeclaration *td = dsym->isTemplateDeclaration();
if (td)
{ // Instantiate opDollar!(dim) with the index as a template argument
Objects *tdargs = new Objects();
tdargs->setDim(1);

Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t);
x = x->semantic(sc);
tdargs->data[0] = x;

//TemplateInstance *ti = new TemplateInstance(loc, td, tdargs);
//ti->semantic(sc);

DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs);

v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte));
}
else
{ /* opDollar exists, but it's a function, not a template.
* This is acceptable ONLY for single-dimension indexing.
* Note that it's impossible to have both template & function opDollar,
* because both take no arguments.
*/
if (ae->arguments->dim != 1) {
ae->error("%s only defines opDollar for one dimension", ad->toChars());
return NULL;
}
FuncDeclaration *fd = dsym->isFuncDeclaration();
assert(fd);
Expression * x = new DotVarExp(loc, ae->e1, fd);

v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x));
}
v->semantic(sc);
ae->lengthVar = v;
}
return v;
pvar = &ae->lengthVar;
ce = ae->e1;
}
else
/* Didn't find $, look in enclosing scope(s).
Expand All @@ -1391,15 +1338,73 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
if (!*pvar) // if not already initialized
{ /* Create variable v and set it to the value of $
*/
VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
VarDeclaration *v;
Type *t;
if (ce->op == TOKtuple)
{ /* It is for an expression tuple, so the
* length will be a const.
*/
Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t);
v->init = new ExpInitializer(0, e);
v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(0, e));
v->storage_class |= STCstatic | STCconst;
}
else if (ce->type && (t = ce->type->toBasetype()) &&
(t->ty == Tstruct || t->ty == Tclass))
{ // Look for opDollar
assert(exp->op == TOKarray || exp->op == TOKslice);
AggregateDeclaration *ad = NULL;

if (t->ty == Tclass)
{
ad = ((TypeClass *)t)->sym;
}
else if (t->ty == Tstruct)
{
ad = ((TypeStruct *)t)->sym;
}
assert(ad);

Dsymbol *dsym = search_function(ad, Id::opDollar);
if (!dsym) // no dollar exists -- search in higher scope
return NULL;

// Check for multi-dimensional opDollar(dim)(). Only for ArrayExp.
TemplateDeclaration *td;
if (exp->op == TOKarray && (td = dsym->isTemplateDeclaration()))
{ ArrayExp *ae = (ArrayExp *)exp;
// Instantiate opDollar!(dim) with the index as a template argument
Objects *tdargs = new Objects();
tdargs->setDim(1);

Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t);
x = x->semantic(sc);
tdargs->data[0] = x;

//TemplateInstance *ti = new TemplateInstance(loc, td, tdargs);
//ti->semantic(sc);

DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs);

v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte));
}
else
{ /* opDollar exists, but it's a function, not a template.
* This is acceptable ONLY for single-dimension indexing.
* Note that it's impossible to have both template & function opDollar,
* because both take no arguments.
*/
if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->dim != 1)
{
exp->error("%s only defines opDollar for one dimension", ad->toChars());
return NULL;
}
FuncDeclaration *fd = dsym->isFuncDeclaration();
assert(fd);
Expression * x = new DotVarExp(loc, ce, fd);

v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x));
}
}
else
{ /* For arrays, $ will either be a compile-time constant
* (in which case its value in set during constant-folding),
Expand All @@ -1408,7 +1413,7 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
*/
VoidInitializer *e = new VoidInitializer(0);
e->type = Type::tsize_t;
v->init = e;
v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e);
v->storage_class |= STCctfe; // it's never a true static variable
}
*pvar = v;
Expand Down
129 changes: 89 additions & 40 deletions src/expression.c
Expand Up @@ -9350,17 +9350,15 @@ Expression *SliceExp::semantic(Scope *sc)
if (search_function(ad, Id::slice))
{
// Rewrite as e1.slice(lwr, upr)
e = new DotIdExp(loc, e1, Id::slice);

if (lwr)
{
assert(upr);
e = new CallExp(loc, e, lwr, upr);
}
else
{ assert(!upr);
e = new CallExp(loc, e);
}
SliceExp *se = resolveOpDollar(sc, this);
Expressions *a = new Expressions();
assert(!se->lwr || se->upr);
if (se->lwr)
{ a->push(se->lwr);
a->push(se->upr);
}
e = new DotIdExp(loc, se->e1, Id::slice);
e = new CallExp(loc, e, a);
e = e->semantic(sc);
return e;
}
Expand Down Expand Up @@ -10211,33 +10209,13 @@ Expression *AssignExp::semantic(Scope *sc)
L1:
// Rewrite (a[i] = value) to (a.opIndexAssign(value, i))
if (search_function(ad, Id::indexass))
{ Expression *e = new DotIdExp(loc, ae->e1, Id::indexass);
{
// Deal with $
for (size_t i = 0; i < ae->arguments->dim; i++)
{ Expression *x = (*ae->arguments)[i];
// Create scope for '$' variable for this dimension
ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
sym->loc = loc;
sym->parent = sc->scopesym;
sc = sc->push(sym);
ae->lengthVar = NULL; // Create it only if required
ae->currentDimension = i; // Dimension for $, if required

x = x->semantic(sc);
if (!x->type)
ae->error("%s has no value", x->toChars());
if (ae->lengthVar)
{ // If $ was used, declare it now
Expression *av = new DeclarationExp(ae->loc, ae->lengthVar);
x = new CommaExp(0, av, x);
x->semantic(sc);
}
(*ae->arguments)[i] = x;
sc = sc->pop();
}
ae = resolveOpDollar(sc, ae);
Expressions *a = (Expressions *)ae->arguments->copy();

a->insert(0, e2);

Expression *e = new DotIdExp(loc, ae->e1, Id::indexass);
e = new CallExp(loc, e, a);
e = e->semantic(sc);
return e;
Expand Down Expand Up @@ -10285,17 +10263,16 @@ Expression *AssignExp::semantic(Scope *sc)
L2:
// Rewrite (a[i..j] = value) to (a.opSliceAssign(value, i, j))
if (search_function(ad, Id::sliceass))
{ Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass);
{
ae = resolveOpDollar(sc, ae);
Expressions *a = new Expressions();

a->push(e2);
assert(!ae->lwr || ae->upr);
if (ae->lwr)
{ a->push(ae->lwr);
assert(ae->upr);
a->push(ae->upr);
}
else
assert(!ae->upr);
Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass);
e = new CallExp(loc, e, a);
e = e->semantic(sc);
return e;
Expand Down Expand Up @@ -12621,4 +12598,76 @@ Expression *LineInitExp::resolveLoc(Loc loc, Scope *sc)
return e;
}

/**************************************
* Runs semantic on ae->arguments. Declares temporary variables
* if '$' was used.
*/

ArrayExp *resolveOpDollar(Scope *sc, ArrayExp *ae)
{
assert(!ae->lengthVar);

for (size_t i = 0; i < ae->arguments->dim; i++)
{
// Create scope for '$' variable for this dimension
ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
sym->loc = ae->loc;
sym->parent = sc->scopesym;
sc = sc->push(sym);
ae->lengthVar = NULL; // Create it only if required
ae->currentDimension = i; // Dimension for $, if required

Expression *e = (*ae->arguments)[i];
e = e->semantic(sc);
e = resolveProperties(sc, e);
if (!e->type)
ae->error("%s has no value", e->toChars());
if (ae->lengthVar)
{ // If $ was used, declare it now
Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
e = new CommaExp(0, de, e);
e = e->semantic(sc);
}
(*ae->arguments)[i] = e;
sc = sc->pop();
}
return ae;
}

/**************************************
* Runs semantic on se->lwr and se->upr. Declares a temporary variable
* if '$' was used.
*/

SliceExp *resolveOpDollar(Scope *sc, SliceExp *se)
{
assert(!se->lengthVar);
assert(!se->lwr || se->upr);

if (!se->lwr) return se;

// create scope for '$'
ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, se);
sym->loc = se->loc;
sym->parent = sc->scopesym;
sc = sc->push(sym);

for (size_t i = 0; i < 2; ++i)
{
Expression *e = i == 0 ? se->lwr : se->upr;
e = e->semantic(sc);
e = resolveProperties(sc, e);
if (!e->type)
se->error("%s has no value", e->toChars());
i == 0 ? se->lwr : se->upr = e;
}

if (se->lengthVar)
{ // If $ was used, declare it now
Expression *de = new DeclarationExp(se->loc, se->lengthVar);
se->lwr = new CommaExp(0, de, se->lwr);
se->lwr = se->lwr->semantic(sc);
}
sc = sc->pop();
return se;
}
2 changes: 2 additions & 0 deletions src/expression.h
Expand Up @@ -85,6 +85,8 @@ Expression *resolveAliasThis(Scope *sc, Expression *e);
Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope);
int checkPostblit(Loc loc, Type *t);
#endif
struct ArrayExp *resolveOpDollar(Scope *sc, struct ArrayExp *ae);
struct SliceExp *resolveOpDollar(Scope *sc, struct SliceExp *se);

/* Interpreter: what form of return value expression is required?
*/
Expand Down

0 comments on commit 091446b

Please sign in to comment.