summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/application.h
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/asymptote/application.h')
-rw-r--r--Build/source/utils/asymptote/application.h313
1 files changed, 313 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/application.h b/Build/source/utils/asymptote/application.h
new file mode 100644
index 00000000000..fcf3f8e5114
--- /dev/null
+++ b/Build/source/utils/asymptote/application.h
@@ -0,0 +1,313 @@
+/*****
+ * application.h
+ * Andy Hammerlindl 2005/05/20
+ *
+ * An application is a matching of arguments in a call expression to formal
+ * parameters of a function. Since the language allows default arguments,
+ * keyword arguments, rest arguments, and anything else we think of, this
+ * is not a simple mapping.
+ *****/
+
+#ifndef APPLICATION_H
+#define APPLICATION_H
+
+#include "common.h"
+#include "types.h"
+#include "coenv.h"
+#include "exp.h"
+
+// Defined in runtime.in:
+namespace run {
+void pushDefault(vm::stack *Stack);
+}
+
+using absyntax::arglist;
+using absyntax::varinit;
+using absyntax::arrayinit;
+using absyntax::tempExp;
+
+// This is mid-way between trans and absyntax.
+namespace trans {
+
+typedef Int score;
+
+typedef mem::vector<score> score_vector;
+
+// This is used during the translation of arguments to store temporary
+// expressions for arguments that need to be translated for side-effects at a
+// certain point but used later on. The invariant maintained is that if the
+// vector has n elements, then the side-effects for the first n arguments have
+// been translated. Null is pushed onto the vector to indicate that the
+// expression was evaluated directly onto the stack, without the use of a
+// temporary.
+typedef mem::vector<tempExp *> temp_vector;
+
+struct arg : public gc {
+ types::ty *t;
+
+ arg(types::ty *t)
+ : t(t) {}
+ virtual ~arg() {}
+
+ virtual void trans(coenv &e, temp_vector &) = 0;
+};
+
+struct varinitArg : public arg {
+ varinit *v;
+
+ varinitArg(varinit *v, types::ty *t)
+ : arg(t), v(v) {}
+
+ virtual void trans(coenv &e, temp_vector &) {
+ // Open signatures can match overloaded variables, but there is no way to
+ // translate the result, so report an error.
+ if (t->kind == types::ty_overloaded) {
+ em.error(v->getPos());
+ em << "overloaded argument in function call";
+ }
+ else
+ v->transToType(e, t);
+ }
+};
+
+
+// Pushes a default argument token on the stack as a placeholder for the
+// argument.
+struct defaultArg : public arg {
+ defaultArg(types::ty *t)
+ : arg(t) {}
+
+ virtual void trans(coenv &e, temp_vector &) {
+ //e.c.encode(inst::builtin, run::pushDefault);
+ e.c.encode(inst::push_default);
+ }
+};
+
+// Handles translation of all the arguments matched to the rest formal.
+// NOTE: This code duplicates a lot of arrayinit.
+struct restArg : public gc {
+ mem::list<arg *> inits;
+
+ arg *rest;
+public:
+ restArg()
+ : rest(0) {}
+
+ virtual ~restArg()
+ {}
+
+ // Encodes the instructions to make an array from size elements on the stack.
+ static void transMaker(coenv &e, Int size, bool rest);
+
+ void trans(coenv &e, temp_vector &temps);
+
+ void add(arg *init) {
+ inits.push_back(init);
+ }
+
+ void addRest(arg *init) {
+ rest=init;
+ }
+};
+
+// This class generates sequenced args, args whose side-effects occur in order
+// according to their index, regardless of the order they are called. This is
+// used to ensure left-to-right order of evaluation of keyword arguments, even
+// if they are given out of the order specified in the declaration.
+class sequencer {
+ struct sequencedArg : public varinitArg {
+ sequencer &parent;
+ size_t i;
+ sequencedArg(varinit *v, types::ty *t, sequencer &parent, size_t i)
+ : varinitArg(v, t), parent(parent), i(i) {}
+
+ void trans(coenv &e, temp_vector &temps) {
+ parent.trans(e, i, temps);
+ }
+ };
+
+ typedef mem::vector<sequencedArg *> sa_vector;
+ sa_vector args;
+
+ // Makes a temporary for the next argument in the sequence.
+ void alias(coenv &e, temp_vector &temps) {
+ size_t n=temps.size();
+ assert(n < args.size());
+ sequencedArg *sa=args[n];
+ assert(sa);
+
+ temps.push_back(new tempExp(e, sa->v, sa->t));
+ }
+
+ // Get in a state to translate the i-th argument, aliasing any arguments that
+ // occur before it in the sequence.
+ void advance(coenv &e, size_t i, temp_vector &temps) {
+ while (temps.size() < i)
+ alias(e,temps);
+ }
+
+ void trans(coenv &e, size_t i, temp_vector &temps) {
+ if (i < temps.size()) {
+ // Already translated, use the alias.
+ assert(temps[i]);
+ temps[i]->trans(e);
+ }
+ else {
+ // Alias earlier args if necessary.
+ advance(e, i, temps);
+
+ // Translate using the base method.
+ args[i]->varinitArg::trans(e,temps);
+
+ // Push null to indicate the argument has been translated.
+ temps.push_back(0);
+ }
+ }
+
+public:
+ arg *addArg(varinit *v, types::ty *t, size_t i) {
+ if (args.size() <= i)
+ args.resize(i+1);
+ return args[i]=new sequencedArg(v, t, *this, i);
+ }
+};
+
+
+class application : public gc {
+ types::signature *sig;
+ types::function *t;
+
+ // Sequencer to ensure given arguments are evaluated in the proper order.
+ // Use of this sequencer means that transArgs can only be called once.
+ sequencer seq;
+
+ typedef mem::vector<arg *> arg_vector;
+ arg_vector args;
+ restArg *rest;
+
+ // Target formal to match with arguments to be packed into the rest array.
+ types::formal rf;
+
+ // During the matching of arguments to an application, this stores the index
+ // of the first unmatched formal.
+ size_t index;
+
+ // To resolve which is the best application in case of multiple matches of
+ // overloaded functions, a score is kept for every source argument matched,
+ // and an application with higher-scoring matches is chosen.
+ score_vector scores;
+
+ void initRest();
+
+ application(types::signature *sig)
+ : sig(sig),
+ t(0),
+ args(sig->formals.size()),
+ rest(0),
+ rf(0),
+ index(0)
+ { assert(sig); initRest(); }
+
+ application(types::function *t)
+ : sig(t->getSignature()),
+ t(t),
+ args(sig->formals.size()),
+ rest(0),
+ rf(0),
+ index(0)
+ { assert(sig); initRest(); }
+
+ types::formal &getTarget() {
+ return sig->getFormal(index);
+ }
+
+ // Move the index forward one, then keep going until we're at an unmatched
+ // argument.
+ void advanceIndex() {
+ do {
+ ++index;
+ } while (index < args.size() && args[index]!=0);
+ }
+
+ // Finds the first unmatched formal of the given name, returning the index.
+ // The rest formal is not tested. This function returns FAIL if no formals
+ // match.
+ Int find(symbol name);
+
+ // Match the formal at index to its default argument (if it has one).
+ bool matchDefault();
+
+ // Match the argument to the formal indexed by spot.
+ bool matchAtSpot(size_t spot, env &e, types::formal &source,
+ varinit *a, size_t evalIndex);
+
+ // Match the argument to be packed into the rest array, if possible.
+ bool matchArgumentToRest(env &e, types::formal& source,
+ varinit *a, size_t evalIndex);
+
+ // Matches the argument to a formal in the target signature (possibly causing
+ // other formals in the target to be matched to default values), and updates
+ // the matchpoint accordingly.
+ bool matchArgument(env &e, types::formal& source,
+ varinit *a, size_t evalIndex);
+
+ // Match an argument bound to a name, as in f(index=7).
+ bool matchNamedArgument(env &e, types::formal& source,
+ varinit *a, size_t evalIndex);
+
+ // After all source formals have been matched, checks if the match is
+ // complete (filling in final default values if necessary).
+ bool complete();
+
+ // Match a rest argument in the calling expression.
+ bool matchRest(env &e, types::formal& f, varinit *a, size_t evalIndex);
+
+ // Match the argument represented in signature to the target signature. On
+ // success, all of the arguments in args will be properly set up.
+ bool matchSignature(env &e, types::signature *source, arglist &al);
+
+ // Match a signature which is open, meaning that any sequence of arguments is
+ // matched.
+ bool matchOpen(env &e, signature *source, arglist &al);
+
+ friend class maximizer;
+public:
+ // Attempt to build an application given the target signature and the source
+ // signature (representing the given arguments). Return 0 if they cannot be
+ // matched.
+ static application *match(env &e,
+ types::function *t,
+ types::signature *source,
+ arglist &al);
+
+ // Translate the arguments so they appear in order on the stack in
+ // preparation for a call.
+ void transArgs(coenv &e);
+
+ types::function *getType() {
+ return t;
+ }
+
+ // This returns true in the special case that the arguments matched without
+ // casting or packing into the rest formal.
+ bool exact();
+
+ // The next best thing (score-wise) to an exact match. This returns true if
+ // there are two arguments, one of which is cast and one is matched exactly
+ // and neither are packed into the rest argument.
+ bool halfExact();
+};
+
+typedef mem::list<application *> app_list;
+
+// Given an overloaded list of types, determines which type to call. If none
+// are applicable, returns an empty vector, if there is ambiguity, several will
+// be returned.
+app_list multimatch(env &e,
+ types::overloaded *o,
+ types::signature *source,
+ arglist &al);
+
+} // namespace trans
+
+#endif