1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
/*****
* 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.
*****/
#include "stack.h"
#include "entry.h"
#include "coenv.h"
#include "dec.h"
#include "newexp.h"
namespace absyntax {
using namespace trans;
using namespace types;
// 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);
}
varEntry *constructorFromInitializer(position pos, coenv &e, record *r,
varEntry *init)
{
assert(r);
types::function *ft=new types::function(r, init->getSignature());
ostringstream out;
ft->printVar(out, symbol::trans("<constructor>"));
// Create a new function environment.
coder fc = e.c.newFunction(pos, out.str(), ft);
coenv fe(fc,e.e);
// Translate the function.
fe.e.beginScope();
transConstructorBody(pos, fe, r, init);
fe.e.endScope();
// Put an instance of the new function on the stack.
vm::lambda *l = fe.c.close();
e.c.encode(inst::pushclosure);
e.c.encode(inst::makefunc, l);
// Save it into a varEntry.
varEntry *v=makeVarEntry(pos, e, r, ft);
v->encode(WRITE, pos, e.c);
e.c.encodePop();
return v;
}
void addConstructorFromInitializer(position pos, coenv &e, record *r,
varEntry *init)
{
assert(r);
// 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);
e.c.popModifier();
}
} // namespace absyntax
|