/*****
* constructor.cc
* Andy Hammerlindl 2007/05/12
*
* Using
*
* void operator init(<args>)
*
* as a field in the definition structure named Foo implicitly creates a
* function that could be explicitly defined with code similar to
*
* static Foo Foo(<args>) {
* Foo a=new Foo;
* a.operator init(<args>);
* return a;
* }
*
* This function is usable within further code in the structure definition and,
* after the end of the structure definition, is carried over into the enclosing
* scope so that it lasts as long as the type definition.
*****/
// Defined in dec.cc.
varEntry *makeVarEntry(position pos, coenv &e, record *r, types::ty *t);
bool definesImplicitConstructor(coenv &e, record *r, varEntry *v, symbol id)
{
if (id == symbol::initsym &&
r != 0 &&
v->getType()->kind == ty_function &&
e.c.isStatic() == false &&
e.c.isTopLevel() == false)
{
function *ft=dynamic_cast<function *>(v->getType());
if (ft->getResult()->kind == ty_void)
return true;
}
return false;
}
// Given the coenv of the body of the constructor, encode the neccessary
// instructions to make a new initialized object.
void transConstructorBody(position pos, coenv &e, record *r, varEntry *init)
{
assert(r);
assert(init);
// Create a varEntry to hold the new object. Foo a;
varEntry *v=makeVarEntry(pos, e, 0 /* not a field */, r);
// Initialize the object. a=new Foo;
newRecordExp::transFromTyEntry(pos, e, new tyEntry(r, 0, 0, nullPos));
v->encode(WRITE, pos, e.c);
e.c.encodePop();
// Push the args onto the stack.
size_t numArgs=init->getSignature()->getNumFormals();
for (size_t i=0; i<numArgs; ++i) {
access *a=e.c.accessFormal((Int)i);
a->encode(READ, pos, e.c);
}
// Push the object on the stack.
v->encode(READ, pos, e.c);
// Call the 'operator init' field of the object.
init->encode(action::CALL, pos, e.c, v->getLevel());
// Push the object again.
v->encode(READ, pos, e.c);
// Return the initialized object.
e.c.encode(inst::ret);
}
// Constructors are declared statically.
e.c.pushModifier(EXPLICIT_STATIC);
varEntry *v=constructorFromInitializer(pos, e, r, init);
// Add the constructor function under the same name as the record.
addVar(e, r, v, r->getName());
// Add to the "post definition environment" of the record, so it will also be
// added to the enclosing scope when the record definition ends.
r->postdefenv.addVar(r->getName(), v);