summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/impdatum.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/asymptote/impdatum.cc')
-rw-r--r--Build/source/utils/asymptote/impdatum.cc615
1 files changed, 615 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/impdatum.cc b/Build/source/utils/asymptote/impdatum.cc
new file mode 100644
index 00000000000..9d0be54f156
--- /dev/null
+++ b/Build/source/utils/asymptote/impdatum.cc
@@ -0,0 +1,615 @@
+#include <cstring>
+
+#include "stack.h"
+#include "env.h"
+#include "exp.h"
+#include "stm.h"
+#include "refaccess.h"
+
+using std::strlen;
+
+using namespace absyntax;
+using namespace trans;
+
+using vm::item;
+using vm::get;
+
+
+#include "policy.h"
+
+coenv &coenvInOngoingProcess();
+void runInOngoingProcess(absyntax::runnable *r);
+
+void runExp(absyntax::exp *e)
+{
+ absyntax::expStm s(nullPos, e);
+ runInOngoingProcess(&s);
+}
+
+class ImpDatum;
+class ImpArguments;
+
+ImpDatum *datumError(const char *msg);
+
+// Expression used for non-item datums.
+class errorExp : public absyntax::exp {
+public:
+ errorExp() : exp(nullPos) {}
+
+ void prettyprint(ostream &out, Int indent)
+ {
+ absyntax::prettyname(out, "errorExp", indent);
+ }
+
+ void complain() {
+ em.error(nullPos); em << "cannot use datum as expression";
+ }
+
+ types::ty *getType(coenv &) { return types::primError(); }
+ types::ty *trans(coenv &e) { complain(); return getType(e); }
+
+ void transAsType(coenv &e, types::ty *target) { complain(); }
+};
+
+// Abstract base class for Datum types.
+class ImpDatum {
+public:
+ virtual operator handle_typ() { return (handle_typ)(this); }
+
+ virtual int_typ toInt() {
+ datumError("cannot convert to integer");
+
+ // Return a weird value that will hopefully be noticed.
+ return -777777;
+ }
+
+ virtual bool toBool() {
+ datumError("cannot convert to bool");
+ return false;
+ }
+
+ virtual double toDouble() {
+ datumError("cannot convert to double");
+ return -777e77;
+ }
+
+ virtual string_typ toString() {
+ datumError("cannot convert to string");
+
+ string_typ s = { "XXXXX", 5 };
+ return s;
+ }
+
+ virtual absyntax::exp *getExp() {
+ datumError("invalid use of datum");
+ return new errorExp;
+ }
+
+ // How to access a field of the datum.
+ virtual absyntax::exp *getFieldExp(symbol id) {
+ assert(id);
+ return new fieldExp(nullPos, this->getExp(), id);
+ }
+
+ virtual ImpDatum *getField(const char *name);
+
+ virtual ImpDatum *getCell(ImpDatum *index) {
+ return datumError("cannot index datatype");
+ }
+
+ virtual void addField(const char *name, ImpDatum *init)
+ {
+ datumError("cannot set field of datatype");
+ }
+
+};
+
+// An ever-growing list of handles, used to avoid garbage collecting the data.
+// TODO: Implement effective releaseHandle.
+mem::vector<handle_typ> handles;
+
+handle_typ wrap(ImpDatum *d)
+{
+ handle_typ h = (handle_typ)(d);
+ handles.push_back(h);
+ return h;
+}
+
+ImpDatum *unwrap(handle_typ handle)
+{
+ assert(handle != 0);
+ return (ImpDatum *)(handle);
+}
+
+class ErrorDatum : public ImpDatum {
+};
+
+error_callback_typ errorCallback = 0;
+
+ImpDatum *datumError(const char *msg)
+{
+ static ErrorDatum ed;
+
+ if (errorCallback) {
+ string_typ s = { msg, strlen(msg) };
+ errorCallback(s);
+ }
+ else {
+ cerr << msg << '\n';
+ }
+
+ return &ed;
+}
+
+handle_typ imp_copyHandle(handle_typ handle)
+{
+ //cout << "+";
+ // For now, don't do anything.
+ return handle;
+}
+
+void imp_releaseHandle()
+{
+ //cout << "-";
+ // Do nothing, for now.
+}
+
+// A datum representing a value in Asymptote. Both the runtime representation
+// of the value and its type are stored.
+class ItemDatum : public ImpDatum {
+ item i;
+ types::ty *t;
+
+public:
+ // Every itemDatum has a fixed (non-overloaded) type, t
+ ItemDatum(types::ty *t) : t(t) {
+ assert(t);
+ assert(t->isNotOverloaded());
+ assert(t->isNotError());
+ }
+
+ // An expression that can be used to get and set the datum.
+ // The value should only be set once, when the datum is created, and not
+ // changed.
+ absyntax::exp *getExp() {
+ // It may be faster to create this once on start, but then the datum will
+ // require more space. For now, we create the access and expression on
+ // demand.
+ return new varEntryExp(nullPos, t, new itemRefAccess(&i));
+ }
+
+ int_typ toInt() {
+ // TODO: Decide if we want to use casting.
+ if (t->kind == types::ty_Int)
+ return static_cast<int_typ>(get<Int>(i));
+ else
+ return ImpDatum::toInt();
+ }
+
+ bool toBool() {
+ if (t->kind == types::ty_boolean)
+ return get<bool>(i);
+ else
+ return ImpDatum::toBool();
+ }
+
+ double toDouble() {
+ if (t->kind == types::ty_real)
+ return get<double>(i);
+ else
+ return ImpDatum::toDouble();
+ }
+
+ string_typ toString() {
+ if (t->kind == types::ty_string) {
+ // TODO: Fix for strings containing NUL.
+ string *s = get<string *>(i);
+ string_typ st = { s->c_str(), s->length() };
+ return st;
+ }
+ else
+ return ImpDatum::toString();
+ }
+};
+
+ItemDatum *ItemDatumFromExp(types::ty *t, absyntax::exp *e)
+{
+ ItemDatum *d = new ItemDatum(t);
+ assignExp ae(nullPos, d->getExp(), e);
+ runExp(&ae);
+
+ return d;
+}
+
+ItemDatum *ItemDatumFromInt(int_typ x)
+{
+ intExp ie(nullPos, static_cast<Int>(x));
+ return ItemDatumFromExp(types::primInt(), &ie);
+}
+
+ItemDatum *ItemDatumFromBool(bool x)
+{
+ booleanExp be(nullPos, x);
+ return ItemDatumFromExp(types::primBoolean(), &be);
+}
+
+ItemDatum *ItemDatumFromDouble(double x)
+{
+ realExp re(nullPos, x);
+ return ItemDatumFromExp(types::primReal(), &re);
+}
+
+ItemDatum *ItemDatumFromString(string_typ x)
+{
+ mem::string s(x.buf, (size_t)x.length);
+ stringExp se(nullPos, s);
+ return ItemDatumFromExp(types::primString(), &se);
+}
+
+
+// If the interface is asked to return a field which is overloaded, a handle
+// to and OverloadedDatum is returned. No evaluation actually occurs. The
+// datum simply consists of the containing datum and the name of the field
+// requested. Subsequent use of the datum will resolve the overloading (or
+// report an error).
+class OverloadedDatum : public ImpDatum {
+ ImpDatum *parent;
+ symbol id;
+
+public:
+ OverloadedDatum(ImpDatum *parent, symbol id) : parent(parent), id(id)
+ {
+ assert(parent);
+ assert(id);
+ }
+
+ absyntax::exp *getExp() {
+ return parent->getFieldExp(id);
+ return new fieldExp(nullPos, parent->getExp(), id);
+ }
+};
+
+ImpDatum *ImpDatum::getField(const char *name)
+{
+ coenv &e = coenvInOngoingProcess();
+ symbol id = symbol::trans(name);
+
+ absyntax::exp *ex = getFieldExp(id);
+
+ types::ty *t = ex->getType(e);
+ if (t->isError())
+ return datumError("no field of that name");
+
+ if (t->isOverloaded())
+ return new OverloadedDatum(this, id);
+
+ // Create a new datum and assign the variable to it.
+ ItemDatum *d = new ItemDatum(t);
+ assignExp ae(nullPos, d->getExp(), ex);
+ runExp(&ae);
+
+ return d;
+}
+
+handle_typ imp_handleFromInt(int_typ x)
+{
+ return wrap(ItemDatumFromInt(x));
+}
+
+handle_typ imp_handleFromBool(int_typ x)
+{
+ if (x != 0 && x != 1)
+ return wrap(datumError("invalid boolean value"));
+
+ return wrap(ItemDatumFromBool(x == 1));
+}
+
+handle_typ imp_handleFromDouble(double x)
+{
+ return wrap(ItemDatumFromDouble(x));
+}
+
+int_typ imp_IntFromHandle(handle_typ handle)
+{
+ return unwrap(handle)->toInt();
+}
+
+int_typ imp_boolFromHandle(handle_typ handle)
+{
+ return unwrap(handle)->toBool() ? 1 : 0;
+}
+
+double imp_doubleFromHandle(handle_typ handle)
+{
+ return unwrap(handle)->toDouble();
+}
+
+
+handle_typ imp_handleFromString(string_typ x)
+{
+ return wrap(ItemDatumFromString(x));
+}
+
+string_typ imp_stringFromHandle(handle_typ handle)
+{
+ return unwrap(handle)->toString();
+}
+
+handle_typ imp_getField(handle_typ handle, const char *name)
+{
+ return wrap(unwrap(handle)->getField(name));
+}
+
+handle_typ imp_getCell(handle_typ handle, handle_typ index)
+{
+ return wrap(unwrap(handle)->getCell(unwrap(index)));
+}
+
+void imp_addField(handle_typ handle, const char *name, handle_typ init)
+{
+ unwrap(handle)->addField(name, unwrap(init));
+}
+
+class ImpArguments /* TODO: gc visible but not collected */ {
+ arglist args;
+public:
+
+ ImpArguments() {}
+
+ void add(const char *name, ImpDatum *arg, arg_rest_option isRest)
+ {
+ assert(isRest == NORMAL_ARG); // TODO: Implement rest.
+ symbol id = (name && name[0]) ? symbol::trans(name) : symbol::nullsym;
+
+ args.add(arg->getExp(), id);
+ }
+
+ arglist *getArgs() { return &args; }
+};
+
+arguments_typ wrapArgs(ImpArguments *args)
+{
+ return (arguments_typ)(args);
+}
+ImpArguments *unwrapArgs(arguments_typ args)
+{
+ return (ImpArguments *)(args);
+}
+
+arguments_typ imp_newArguments()
+{
+ return wrapArgs(new ImpArguments);
+}
+
+void imp_releaseArguments(arguments_typ args)
+{
+ // For now, do nothing.
+}
+
+void imp_addArgument(arguments_typ args, const char *name, handle_typ handle,
+ arg_rest_option isRest)
+{
+ unwrapArgs(args)->add(name, unwrap(handle), isRest);
+}
+
+ImpDatum *callDatum(ImpDatum *callee, ImpArguments *args)
+{
+ coenv &e = coenvInOngoingProcess();
+
+ callExp callex(nullPos, callee->getExp(), args->getArgs());
+
+ types::ty *t = callex.getType(e);
+ if (t->isError()) {
+ // Run for errors.
+ runExp(&callex); em.sync();
+ return datumError("invalid call");
+ }
+
+ assert(t->isNotOverloaded()); // Calls are never overloaded.
+
+ if (t->kind == types::ty_void) {
+ // Execute the call and return 0 to indicate void.
+ runExp(&callex);
+ return 0;
+ }
+ else
+ return ItemDatumFromExp(t, &callex);
+}
+
+handle_typ imp_call(handle_typ callee, arguments_typ args)
+{
+ return wrap(callDatum(unwrap(callee), unwrapArgs(args)));
+}
+
+class GlobalsDatum : public ImpDatum {
+ typedef std::map<const char*, ImpDatum *> gmap;
+ gmap base;
+
+ virtual absyntax::exp *getFieldExp(symbol id)
+ {
+ // Fields of the globals datum are global variables. Use the unqualified
+ // name.
+ return new nameExp(nullPos, id);
+ }
+
+ virtual void addField(const char *name, ImpDatum *init) {
+ datumError("addField not yet re-implemented");
+ }
+};
+
+class ImpState {
+ //ImpArguments *params;
+
+ ImpDatum *retval;
+public:
+ ImpState() : retval(0) {}
+
+ ImpDatum *globals() {
+ return new GlobalsDatum();
+ }
+
+ int_typ numParams() {
+ /*if (params)
+ return params->val.size();
+ else */ {
+ datumError("parameters accessed outside of function");
+ return 0;
+ }
+ }
+
+ ImpDatum *getParam(int_typ index) {
+ /*if (params) {
+ if (index >= 0 && index < static_cast<int_typ>(params->val.size()))
+ return params->val[index];
+ else
+ return datumError("invalid index for parameter");
+ }
+ else */ {
+ return datumError("parameters accessed outside of function");
+ }
+ }
+
+ void setReturnValue(ImpDatum *retval)
+ {
+ /*if (params) {
+ if (this->retval)
+ datumError("return value set more than once");
+ else
+ this->retval = retval;
+ }
+ else */ {
+ datumError("return value set outside of function");
+ }
+ }
+
+ ImpDatum *getReturnValue()
+ {
+ return retval;
+ }
+};
+
+state_typ wrapState(ImpState *s)
+{
+ return (state_typ)(s);
+}
+ImpState *unwrapState(state_typ s)
+{
+ return (ImpState *)(s);
+}
+
+
+handle_typ imp_globals(state_typ state)
+{
+ return wrap(unwrapState(state)->globals());
+}
+
+int_typ imp_numParams(state_typ state)
+{
+ return unwrapState(state)->numParams();
+}
+
+handle_typ imp_getParam(state_typ state, int_typ index)
+{
+ return wrap(unwrapState(state)->getParam(index));
+}
+
+void imp_setReturnValue(state_typ state, handle_typ handle)
+{
+ unwrapState(state)->setReturnValue(unwrap(handle));
+}
+
+state_typ cheatState()
+{
+ return wrapState(new ImpState());
+}
+
+#if 0
+class FunctionDatum : public ImpDatum {
+ function_typ f;
+ void *data;
+
+public:
+ FunctionDatum(function_typ f, void *data) : f(f), data(data) {}
+
+ ImpDatum *call(ImpArguments *args) {
+ ImpState state(args);
+
+ // Call the function.
+ f(wrapState(&state),data);
+
+ if (state.getReturnValue())
+ return state.getReturnValue();
+ else
+ // TODO: Decide on datum for void return.
+ return 0;
+ }
+};
+#endif
+
+handle_typ imp_handleFromFunction(const char *signature,
+ function_typ f, void *data)
+{
+ // TODO: Re-implement.
+ return 0; //wrap(new FunctionDatum(f, data));
+}
+
+void imp_setErrorCallback(error_callback_typ callback)
+{
+ errorCallback = callback;
+}
+
+extern policy_typ imp_policy;
+policy_typ imp_policy =
+{
+ /* version = */ 101,
+ imp_copyHandle,
+ imp_releaseHandle,
+ imp_handleFromInt,
+ imp_handleFromBool,
+ imp_handleFromDouble,
+ imp_handleFromString,
+ imp_handleFromFunction,
+ imp_IntFromHandle,
+ imp_boolFromHandle,
+ imp_doubleFromHandle,
+ imp_stringFromHandle,
+ imp_getField,
+ imp_getCell,
+ imp_addField,
+ imp_newArguments,
+ imp_releaseArguments,
+ imp_addArgument,
+ imp_call,
+ imp_globals,
+ imp_numParams,
+ imp_getParam,
+ imp_setReturnValue,
+ imp_setErrorCallback,
+};
+
+// Defined in process.cc
+void init(bool resetpath=true);
+
+extern "C" {
+
+policy_typ *_asy_getPolicy()
+{
+ return &imp_policy;
+}
+
+state_typ _asy_getState()
+{
+ static state_typ state = cheatState();
+
+ // TODO: Make sure this runs once.
+ char buf[] = "asymptote.so";
+ char *argv [] = { buf };
+ settings::setOptions(1,argv);
+
+ // Ensures uptodate is not used.
+ init();
+
+ return state;
+}
+
+}