summaryrefslogtreecommitdiff
path: root/graphics/asymptote/coder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/asymptote/coder.cc')
-rw-r--r--graphics/asymptote/coder.cc376
1 files changed, 376 insertions, 0 deletions
diff --git a/graphics/asymptote/coder.cc b/graphics/asymptote/coder.cc
new file mode 100644
index 0000000000..02bb27599f
--- /dev/null
+++ b/graphics/asymptote/coder.cc
@@ -0,0 +1,376 @@
+/*****
+ * coder.cc
+ * Andy Hammerlindl 2004/11/06
+ *
+ * Handles encoding of syntax into programs. It's methods are called by
+ * abstract syntax objects during translation to construct the virtual machine
+ * code.
+ *****/
+
+#include <utility>
+
+#include "errormsg.h"
+#include "coder.h"
+#include "genv.h"
+#include "entry.h"
+#include "builtin.h"
+
+using namespace sym;
+using namespace types;
+
+namespace trans {
+
+namespace {
+function *inittype();
+function *bootuptype();
+}
+
+vm::lambda *newLambda(string name) {
+ assert(!name.empty());
+ vm::lambda *l = new vm::lambda;
+#ifdef DEBUG_FRAME
+ l->name = name;
+#endif
+ return l;
+}
+
+
+// Used purely for global variables and static code blocks of file
+// level modules.
+coder::coder(position pos, string name, modifier sord)
+#if SIMPLE_FRAME
+ : level(frame::indirect_frame(name)),
+#else
+ : level(new frame(name, 0, 0)),
+#endif
+ recordLevel(0),
+ recordType(0),
+ isCodelet(false),
+ l(newLambda(name)),
+ funtype(bootuptype()),
+ parent(0),
+ sord(sord),
+ perm(DEFAULT_PERM),
+ program(new vm::program),
+ curPos(pos)
+{
+ sord_stack.push(sord);
+}
+
+// Defines a new function environment.
+coder::coder(position pos, string name, function *t, coder *parent,
+ modifier sord, bool reframe)
+ : level(reframe ? new frame(name,
+ parent->getFrame(),
+ t->sig.getNumFormals()) :
+ parent->getFrame()),
+ recordLevel(parent->recordLevel),
+ recordType(parent->recordType),
+ isCodelet(!reframe),
+ l(newLambda(name)),
+ funtype(t),
+ parent(parent),
+ sord(sord),
+ perm(DEFAULT_PERM),
+ program(new vm::program),
+ curPos(pos)
+{
+ sord_stack.push(sord);
+}
+
+// Start encoding the body of the record. The function being encoded
+// is the record's initializer.
+coder::coder(position pos, record *t, coder *parent, modifier sord)
+ : level(t->getLevel()),
+ recordLevel(t->getLevel()),
+ recordType(t),
+ isCodelet(false),
+ l(t->getInit()),
+ funtype(inittype()),
+ parent(parent),
+ sord(sord),
+ perm(DEFAULT_PERM),
+ program(new vm::program),
+ curPos(pos)
+{
+ sord_stack.push(sord);
+}
+
+coder coder::newFunction(position pos, string name, function *t, modifier sord)
+{
+ return coder(pos, name, t, this, sord);
+}
+
+coder coder::newCodelet(position pos)
+{
+ return coder(pos, "<codelet>", new function(primVoid()), this,
+ DEFAULT_DYNAMIC, false);
+}
+
+record *coder::newRecord(symbol id)
+{
+ frame *underlevel = getFrame();
+
+ frame *level = new frame(id, underlevel, 0);
+
+ record *r = new record(id, level);
+
+ return r;
+}
+
+coder coder::newRecordInit(position pos, record *r, modifier sord)
+{
+ return coder(pos, r, this, sord);
+}
+
+#ifdef DEBUG_BLTIN
+void assertBltinLookup(inst::opcode op, item it)
+{
+ if (op == inst::builtin) {
+ string name=lookupBltin(vm::get<vm::bltin>(it));
+ assert(!name.empty());
+ }
+}
+#endif
+
+
+void coder::encodePop()
+{
+ if (isStatic() && !isTopLevel()) {
+ assert(parent);
+ parent->encodePop();
+ }
+ else {
+#ifdef COMBO
+ vm::program::label end = program->end();
+ --end;
+ inst& lastInst = *end;
+ if (lastInst.op == inst::varsave) {
+ lastInst.op = inst::varpop;
+ return;
+ }
+ if (lastInst.op == inst::fieldsave) {
+ lastInst.op = inst::fieldpop;
+ return;
+ }
+ // TODO: push+pop into no op.
+#endif
+
+ // No combo applicable. Just encode a usual pop.
+ encode(inst::pop);
+ }
+}
+
+
+bool coder::encode(frame *f)
+{
+ frame *toplevel = getFrame();
+
+ if (f == 0) {
+ encode(inst::constpush,(item)0);
+ return true;
+ }
+ else if (f == toplevel) {
+ encode(inst::pushclosure);
+ return true;
+ }
+ else {
+ encode(inst::varpush,toplevel->parentIndex());
+ return encode(f, toplevel->getParent());
+ }
+}
+
+bool coder::encode(frame *dest, frame *top)
+{
+ if (dest == 0) {
+ // Change to encodePop?
+ encode(inst::pop);
+ encode(inst::constpush,(item)0);
+ }
+ else {
+ frame *level = top;
+ while (level != dest) {
+ if (level == 0) {
+ // Frame request was in an improper scope.
+ return false;
+ }
+
+ encode(inst::fieldpush, level->parentIndex());
+
+ level = level->getParent();
+ }
+ }
+
+ //cerr << "succeeded\n";
+ return true;
+}
+
+vm::program::label coder::encodeEmptyJump(inst::opcode op)
+{
+ // Get the end position before encoding the label. Once encoded, this will
+ // point to the instruction.
+ vm::program::label pos = program->end();
+
+ encode(op);
+
+ return pos;
+}
+
+void replaceEmptyJump(vm::program::label from, vm::program::label to)
+{
+ from->ref = to;
+}
+
+label coder::defNewLabel()
+{
+ if (isStatic())
+ return parent->defNewLabel();
+
+ label l = new label_t();
+ assert(!l->location.defined());
+ assert(!l->firstUse.defined());
+ return defLabel(l);
+}
+
+label coder::defLabel(label label)
+{
+ if (isStatic())
+ return parent->defLabel(label);
+
+ //cout << "defining label " << label << endl;
+
+ assert(!label->location.defined());
+ //vm::program::label here = program->end();
+ label->location = program->end();
+ assert(label->location.defined());
+
+ if (label->firstUse.defined()) {
+ replaceEmptyJump(label->firstUse, program->end());
+ //vm::printInst(cout, label->firstUse, program->begin());
+ //cout << endl;
+
+ if (label->moreUses) {
+ typedef label_t::useVector useVector;
+ useVector& v = *label->moreUses;
+ for (useVector::iterator p = v.begin(); p != v.end(); ++p) {
+ replaceEmptyJump(*p, program->end());
+ }
+ }
+ }
+
+ return label;
+}
+
+
+void coder::useLabel(inst::opcode op, label label)
+{
+ if (isStatic())
+ return parent->useLabel(op,label);
+
+ if (label->location.defined()) {
+ encode(op, label->location);
+ } else {
+ if (label->firstUse.defined()) {
+ // Store additional uses in the moreUses array.
+ if (!label->moreUses)
+ label->moreUses = new label_t::useVector;
+ label->moreUses->push_back(encodeEmptyJump(op));
+ }
+ else {
+ label->firstUse = encodeEmptyJump(op);
+ assert(label->firstUse.defined());
+ assert(!label->location.defined());
+ }
+ }
+}
+label coder::fwdLabel()
+{
+ if (isStatic())
+ return parent->fwdLabel();
+
+ // Create a new label without specifying its position.
+ label l = new label_t();
+ assert(!l->location.defined());
+ assert(!l->firstUse.defined());
+
+ //cout << "forward label " << l << endl;
+
+ return l;
+}
+
+bool coder::usesClosureSinceLabel(label l)
+{
+ assert(l->location.defined());
+ for (vm::program::label i = l->location; i != program->end(); ++i)
+ if (i->op == inst::pushclosure)
+ return true;
+ return false;
+}
+
+void coder::encodePatch(label from, label to)
+{
+ assert(from->location.defined());
+ assert(to->location.defined());
+
+ assert(from->location->op == inst::nop);
+
+ from->location->op = inst::jmp;
+ from->location->ref = to->location;
+}
+
+void coder::markPos(position pos)
+{
+ curPos = pos;
+}
+
+// When translating the function is finished, this ties up loose ends
+// and returns the lambda.
+vm::lambda *coder::close() {
+ // These steps must be done dynamically, not statically.
+ sord = EXPLICIT_DYNAMIC;
+ sord_stack.push(sord);
+
+ // Add a return for void types; may be redundant.
+ if (funtype->result->kind == types::ty_void)
+ encode(inst::ret);
+
+ l->code = program;
+
+ l->parentIndex = level->parentIndex();
+
+ l->framesize = level->size();
+
+ sord_stack.pop();
+ sord = sord_stack.top();
+
+ return l;
+}
+
+void coder::closeRecord()
+{
+ // Put record into finished state.
+ encode(inst::pushclosure);
+ close();
+}
+
+bool coder::isRecord()
+{
+ return (funtype==inittype());
+}
+
+namespace {
+function *inittype()
+{
+ static function t(types::primVoid());
+ return &t;
+}
+
+function *bootuptype()
+{
+ static function t(types::primVoid());
+ return &t;
+}
+} // private
+
+} // namespace trans
+