blob: d18e0549aace1411b2505c11484462a8f8262bed [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
* https://github.com/D-Programming-Language/dmd/blob/master/src/init.c
*/
#include "root/dsystem.h"
#include "root/checkedint.h"
#include "mars.h"
#include "init.h"
#include "expression.h"
#include "statement.h"
#include "identifier.h"
#include "declaration.h"
#include "aggregate.h"
#include "scope.h"
#include "mtype.h"
#include "hdrgen.h"
#include "template.h"
#include "id.h"
#include "tokens.h"
/********************************** Initializer *******************************/
Initializer::Initializer(Loc loc)
{
this->loc = loc;
}
Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
{
Initializers *a = NULL;
if (ai)
{
a = new Initializers();
a->setDim(ai->length);
for (size_t i = 0; i < a->length; i++)
(*a)[i] = (*ai)[i]->syntaxCopy();
}
return a;
}
const char *Initializer::toChars()
{
OutBuffer buf;
HdrGenState hgs;
::toCBuffer(this, &buf, &hgs);
return buf.extractChars();
}
/********************************** ErrorInitializer ***************************/
ErrorInitializer::ErrorInitializer()
: Initializer(Loc())
{
}
Initializer *ErrorInitializer::syntaxCopy()
{
return this;
}
/********************************** VoidInitializer ***************************/
VoidInitializer::VoidInitializer(Loc loc)
: Initializer(loc)
{
type = NULL;
}
Initializer *VoidInitializer::syntaxCopy()
{
return new VoidInitializer(loc);
}
/********************************** StructInitializer *************************/
StructInitializer::StructInitializer(Loc loc)
: Initializer(loc)
{
}
Initializer *StructInitializer::syntaxCopy()
{
StructInitializer *ai = new StructInitializer(loc);
assert(field.length == value.length);
ai->field.setDim(field.length);
ai->value.setDim(value.length);
for (size_t i = 0; i < field.length; i++)
{
ai->field[i] = field[i];
ai->value[i] = value[i]->syntaxCopy();
}
return ai;
}
void StructInitializer::addInit(Identifier *field, Initializer *value)
{
//printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
this->field.push(field);
this->value.push(value);
}
/********************************** ArrayInitializer ************************************/
ArrayInitializer::ArrayInitializer(Loc loc)
: Initializer(loc)
{
dim = 0;
type = NULL;
sem = false;
}
Initializer *ArrayInitializer::syntaxCopy()
{
//printf("ArrayInitializer::syntaxCopy()\n");
ArrayInitializer *ai = new ArrayInitializer(loc);
assert(index.length == value.length);
ai->index.setDim(index.length);
ai->value.setDim(value.length);
for (size_t i = 0; i < ai->value.length; i++)
{
ai->index[i] = index[i] ? index[i]->syntaxCopy() : NULL;
ai->value[i] = value[i]->syntaxCopy();
}
return ai;
}
void ArrayInitializer::addInit(Expression *index, Initializer *value)
{
this->index.push(index);
this->value.push(value);
dim = 0;
type = NULL;
}
bool ArrayInitializer::isAssociativeArray()
{
for (size_t i = 0; i < value.length; i++)
{
if (index[i])
return true;
}
return false;
}
/********************************
* If possible, convert array initializer to associative array initializer.
*/
Expression *ArrayInitializer::toAssocArrayLiteral()
{
Expression *e;
//printf("ArrayInitializer::toAssocArrayInitializer()\n");
//static int i; if (++i == 2) halt();
Expressions *keys = new Expressions();
keys->setDim(value.length);
Expressions *values = new Expressions();
values->setDim(value.length);
for (size_t i = 0; i < value.length; i++)
{
e = index[i];
if (!e)
goto Lno;
(*keys)[i] = e;
Initializer *iz = value[i];
if (!iz)
goto Lno;
e = initializerToExpression(iz);
if (!e)
goto Lno;
(*values)[i] = e;
}
e = new AssocArrayLiteralExp(loc, keys, values);
return e;
Lno:
delete keys;
delete values;
error(loc, "not an associative array initializer");
return new ErrorExp();
}
/********************************** ExpInitializer ************************************/
ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
: Initializer(loc)
{
this->exp = exp;
this->expandTuples = false;
}
Initializer *ExpInitializer::syntaxCopy()
{
return new ExpInitializer(loc, exp->syntaxCopy());
}
#if 1 // should be removed and rely on ctfeInterpreter()
bool arrayHasNonConstPointers(Expressions *elems);
bool hasNonConstPointers(Expression *e)
{
if (e->type->ty == Terror)
return false;
if (e->op == TOKnull)
return false;
if (e->op == TOKstructliteral)
{
StructLiteralExp *se = (StructLiteralExp *)e;
return arrayHasNonConstPointers(se->elements);
}
if (e->op == TOKarrayliteral)
{
if (!e->type->nextOf()->hasPointers())
return false;
ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
return arrayHasNonConstPointers(ae->elements);
}
if (e->op == TOKassocarrayliteral)
{
AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
if (ae->type->nextOf()->hasPointers() &&
arrayHasNonConstPointers(ae->values))
return true;
if (((TypeAArray *)ae->type)->index->hasPointers())
return arrayHasNonConstPointers(ae->keys);
return false;
}
if (e->op == TOKaddress)
{
AddrExp *ae = (AddrExp *)e;
if (ae->e1->op == TOKstructliteral)
{
StructLiteralExp *se = (StructLiteralExp *)ae->e1;
if (!(se->stageflags & stageSearchPointers))
{
int old = se->stageflags;
se->stageflags |= stageSearchPointers;
bool ret = arrayHasNonConstPointers(se->elements);
se->stageflags = old;
return ret;
}
else
{
return false;
}
}
return true;
}
if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
{
if (e->op == TOKsymoff) // address of a global is OK
return false;
if (e->op == TOKint64) // cast(void *)int is OK
return false;
if (e->op == TOKstring) // "abc".ptr is OK
return false;
return true;
}
return false;
}
bool arrayHasNonConstPointers(Expressions *elems)
{
for (size_t i = 0; i < elems->length; i++)
{
Expression *e = (*elems)[i];
if (e && hasNonConstPointers(e))
return true;
}
return false;
}
#endif