summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/application.cc
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2009-05-16 00:19:13 +0000
committerKarl Berry <karl@freefriends.org>2009-05-16 00:19:13 +0000
commitbab45528d65eaafe68a705dbb2a57075c7b7cbd8 (patch)
tree10b4ae2b5195c8dede153ab89359ec00f55f325f /Build/source/utils/asymptote/application.cc
parent8643d90372e9c31e0f461c15c596b60a545bd7d3 (diff)
asymptote 1.72 sources (not integrated into build yet)
git-svn-id: svn://tug.org/texlive/trunk@13110 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/application.cc')
-rw-r--r--Build/source/utils/asymptote/application.cc371
1 files changed, 371 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/application.cc b/Build/source/utils/asymptote/application.cc
new file mode 100644
index 00000000000..7a146036722
--- /dev/null
+++ b/Build/source/utils/asymptote/application.cc
@@ -0,0 +1,371 @@
+/*****
+ * application.cc
+ * 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.
+ *****/
+
+#include "application.h"
+#include "exp.h"
+#include "coenv.h"
+#include "runtime.h"
+
+using namespace types;
+using absyntax::varinit;
+using absyntax::arrayinit;
+using absyntax::arglist;
+
+namespace trans {
+
+// Lower scores are better. Packed is added onto the other qualifiers so
+// we may score both exact and casted packed arguments.
+const score FAIL=0, EXACT=1, CAST=2;
+const score PACKED=2;
+
+bool castable(env &e, formal& target, formal& source) {
+ return target.Explicit ? equivalent(target.t,source.t)
+ : e.castable(target.t,source.t, symbol::castsym);
+}
+
+score castScore(env &e, formal& target, formal& source) {
+ return equivalent(target.t,source.t) ? EXACT :
+ (!target.Explicit &&
+ e.castable(target.t,source.t, symbol::castsym)) ? CAST : FAIL;
+}
+
+defaultArg::defaultArg(types::ty *t)
+ : arg(new absyntax::callExp(position(),
+ new absyntax::varEntryExp(position(),
+ new function(t),
+ run::pushDefault)),
+ t)
+{}
+
+void restArg::transMaker(coenv &e, Int size, bool rest) {
+ // Push the number of cells and call the array maker.
+ e.c.encode(inst::intpush, size);
+ e.c.encode(inst::builtin, rest ? run::newAppendedArray :
+ run::newInitializedArray);
+}
+
+void restArg::trans(coenv &e, temp_vector &temps)
+{
+ // Push the values on the stack.
+ for (mem::list<arg *>::iterator p = inits.begin(); p != inits.end(); ++p)
+ (*p)->trans(e, temps);
+
+ if (rest)
+ rest->trans(e, temps);
+
+ transMaker(e, (Int)inits.size(), (bool)rest);
+}
+
+class maximizer {
+ app_list l;
+
+ // Tests if x is as good (or better) an application as y.
+ bool asgood(application *x, application *y) {
+ // Matches to open signatures are always worse than matches to normal
+ // signatures.
+ if (x->sig->isOpen)
+ return y->sig->isOpen;
+ else if (y->sig->isOpen)
+ return true;
+
+ assert (x->scores.size() == y->scores.size());
+
+ // Test if each score in x is no higher than the corresponding score in
+ // y.
+ return std::equal(x->scores.begin(), x->scores.end(), y->scores.begin(),
+ std::less_equal<score>());
+ }
+
+ bool better(application *x, application *y) {
+ return asgood(x,y) && !asgood(y,x);
+ }
+
+ // Add an application that has already been determined to be maximal.
+ // Remove any other applications that are now not maximal because of its
+ // addition.
+ void addMaximal(application *x) {
+ app_list::iterator y=l.begin();
+ while (y!=l.end())
+ if (better(x,*y))
+ y=l.erase(y);
+ else
+ ++y;
+ l.push_front(x);
+ }
+
+ // Tests if x is maximal.
+ bool maximal(application *x) {
+ for (app_list::iterator y=l.begin(); y!=l.end(); ++y)
+ if (better(*y,x))
+ return false;
+ return true;
+ }
+
+public:
+ maximizer() {}
+
+ void add(application *x) {
+ if (maximal(x))
+ addMaximal(x);
+ }
+
+ app_list result() {
+ return l;
+ }
+};
+
+
+void application::initRest() {
+ types::formal& f=sig->getRest();
+ if (f.t) {
+ types::array *a=dynamic_cast<types::array *>(f.t);
+ if(!a)
+ vm::error("formal rest argument must be an array");
+
+ static symbol *null=0;
+ rf=types::formal(a->celltype, null, false, f.Explicit);
+ }
+
+ if (f.t || sig->isOpen) {
+ rest=new restArg();
+ }
+}
+
+//const Int REST=-1;
+const Int NOMATCH=-2;
+
+Int application::find(symbol *name) {
+ formal_vector &f=sig->formals;
+ for (size_t i=index; i<f.size(); ++i)
+ if (f[i].name==name && args[i]==0)
+ return (Int)i;
+ return NOMATCH;
+}
+
+bool application::matchDefault() {
+ if (index==args.size())
+ return false;
+ else {
+ formal &target=getTarget();
+ if (target.defval) {
+ args[index]=new defaultArg(target.t);
+ advanceIndex();
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool application::matchArgumentToRest(env &e, formal &source,
+ varinit *a, size_t evalIndex)
+{
+ if (rest) {
+ score s=castScore(e, rf, source);
+ if (s!=FAIL) {
+ rest->add(seq.addArg(a, rf.t, evalIndex));
+ scores.push_back(s+PACKED);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool application::matchAtSpot(size_t spot, env &e, formal &source,
+ varinit *a, size_t evalIndex)
+{
+ formal &target=sig->getFormal(spot);
+ score s=castScore(e, target, source);
+ if (s!=FAIL) {
+ // The argument matches.
+ args[spot]=seq.addArg(a, target.t, evalIndex);
+ if (spot==index)
+ advanceIndex();
+ scores.push_back(s);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool application::matchArgument(env &e, formal &source,
+ varinit *a, size_t evalIndex)
+{
+ assert(source.name==0);
+
+ if (index==args.size())
+ // Try to pack into the rest array.
+ return matchArgumentToRest(e, source, a, evalIndex);
+ else
+ // Match here, or failing that use a default and try to match at the next
+ // spot.
+ return matchAtSpot(index, e, source, a, evalIndex) ||
+ (matchDefault() && matchArgument(e, source, a, evalIndex));
+}
+
+bool application::matchNamedArgument(env &e, formal &source,
+ varinit *a, size_t evalIndex)
+{
+ assert(source.name!=0);
+
+ Int spot=find(source.name);
+ return spot!=NOMATCH && matchAtSpot(spot, e, source, a, evalIndex);
+}
+
+bool application::complete() {
+ if (index==args.size())
+ return true;
+ else if (matchDefault())
+ return complete();
+ else
+ return false;
+}
+
+bool application::matchRest(env &e, formal &source, varinit *a) {
+ // First make sure all non-rest arguments are matched (matching to defaults
+ // if necessary).
+ if (complete())
+ // Match rest to rest.
+ if (rest) {
+ formal &target=sig->getRest();
+ score s=castScore(e, target, source);
+ if (s!=FAIL) {
+ rest->addRest(new arg(a, target.t));
+ scores.push_back(s);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool application::matchSignature(env &e, types::signature *source,
+ arglist &al) {
+ formal_vector &f=source->formals;
+
+ // First, match all of the named (non-rest) arguments.
+ for (size_t i=0; i<f.size(); ++i)
+ if (f[i].name)
+ if (!matchNamedArgument(e, f[i], al[i].val, i))
+ return false;
+
+ // Then, the unnamed.
+ for (size_t i=0; i<f.size(); ++i)
+ if (!f[i].name)
+ if (!matchArgument(e, f[i], al[i].val, i))
+ return false;
+
+ // Then, the rest argument.
+ if (source->hasRest())
+ if (!matchRest(e, source->getRest(), al.rest.val))
+ return false;
+
+ // Fill in any remaining arguments with their defaults.
+ return complete();
+}
+
+#if 0
+application *application::matchHelper(env &e,
+ application *app,
+ signature *source)
+{
+ return app->matchSignature(e, source) ? app : 0;
+}
+
+application *application::match(env &e, signature *target, signature *source) {
+ application *app=new application(target);
+ return matchHelper(e, app, source);
+}
+#endif
+
+bool application::matchOpen(env &e, signature *source, arglist &al) {
+ assert(rest);
+
+ // Pack all given parameters into the rest argument.
+ formal_vector &f=source->formals;
+ for (size_t i = 0; i < f.size(); ++i)
+ if (al[i].name)
+ // Named arguments are not handled by open signatures.
+ return false;
+ else
+ rest->add(seq.addArg(al[i].val, f[i].t, i));
+
+ if (source->hasRest())
+ rest->addRest(new arg(al.rest.val, source->getRest().t));
+
+ return true;
+}
+
+application *application::match(env &e, function *t, signature *source,
+ arglist &al) {
+ assert(t->kind==ty_function);
+ application *app=new application(t);
+
+ if (t->getSignature()->isOpen)
+ return app->matchOpen(e, source, al) ? app : 0;
+ else
+ return app->matchSignature(e, source, al) ? app : 0;
+}
+
+void application::transArgs(coenv &e) {
+ temp_vector temps;
+
+ for(arg_vector::iterator a=args.begin(); a != args.end(); ++a)
+ (*a)->trans(e,temps);
+
+ if (rest)
+ rest->trans(e,temps);
+}
+
+app_list multimatch(env &e,
+ types::overloaded *o,
+ types::signature *source,
+ arglist &al)
+{
+ assert(source);
+
+ app_list l;
+
+ for(ty_vector::iterator t=o->sub.begin(); t!=o->sub.end(); ++t) {
+ if ((*t)->kind==ty_function) {
+ application *a=application::match(e, (function *)(*t), source, al);
+ if (a)
+ l.push_back(a);
+ }
+ }
+
+ if (l.size() > 1) {
+ // Return the most specific candidates.
+ maximizer m;
+ for (app_list::iterator x=l.begin(); x!=l.end(); ++x) {
+ assert(*x);
+ m.add(*x);
+ }
+ return m.result();
+ }
+ else
+ return l;
+}
+
+#if 0
+app_list resolve(env &e,
+ types::ty *t,
+ types::signature *source)
+{
+ if (t->kind == ty_overloaded)
+ return multimatch(e, (overloaded *)t, source);
+ else {
+ overloaded o;
+ o.add(t);
+ return multimatch(e, &o, source);
+ }
+}
+#endif
+
+} // namespace trans