diff options
Diffstat (limited to 'Build/source/utils/asymptote/impdatum.cc')
-rw-r--r-- | Build/source/utils/asymptote/impdatum.cc | 615 |
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; +} + +} |