swig/SWIG/Source/Swig/map.c
2000-07-05 04:04:17 +00:00

200 lines
5.6 KiB
C

/* -----------------------------------------------------------------------------
* map.c
*
* This file provides support for defining %map rules that match lists of
* parameters to objects defining code generation rules.
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 1999-2000. The University of Chicago
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
#include "swig.h"
/* -----------------------------------------------------------------------------
* Synopsis
*
* One of the biggest problems in wrapper generation is that of defining
* the handling of various datatypes and function parameters. This module
* provides support for a generic object known as a 'mapping rule' that is
* defined using the %map directive like this:
*
* %map rulename(typelist) {
* vars;
* rule1 { ... }
* rule2 { ... }
* rule3 { ... }
* rule4 { ... }
* ...
* }
*
* A mapping rule is somewhat similar to a class or structure definition. The
* "vars" field is a list of variable declarations that will be local to the
* mapping rule when it is used. The "rulen" fields simply define code
* fragments and other information that language specific modules can examine
* for their own nefarious purposes.
*
* ----------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
* Swig_map_add()
*
* Adds a new mapping rule. The parms input to this function should be a
* properly constructed parameter list with associated attributes. The rules
* field can technically be any valid object.
*
* The structure of how data is stored is as follows:
*
* ruleset (hash)
* --------------
* rulename ------> nameset (hash)
* --------------
* parm1 ---------> rule (hash)
* -------------
* parm2 -----------> rule (hash)
* *obj* --> obj
*
*
* For multiple arguments, we end up building a large tree of hash tables.
* The object will be stored in the *obj* attribute of the last hash table.
* ----------------------------------------------------------------------------- */
void
Swig_map_add(DOHHash *ruleset, DOHString_or_char *rulename, DOHHash *parms, DOH *obj)
{
DOHHash *nameset;
DOHHash *p, *n;
/* Locate the appropriate nameset */
nameset = Getattr(ruleset,rulename);
if (!nameset) {
/* Hmmm. First time we've seen this. Let's add it to our mapping table */
nameset = NewHash();
Setattr(ruleset,rulename,nameset);
}
/* Now, we walk down the parms list and create a series of hash tables */
p = parms;
n = nameset;
while (p) {
DOHString *ty, *name, *key;
DOHHash *nn;
ty = Getattr(p,"type");
name = Getattr(p,"name");
/* Create a hash table key */
key = NewStringf("%s-%s",name,ty);
/* See if there is already a entry with this type in the table */
nn = Getattr(n,key);
if (!nn) {
/* No. Go ahead and create it */
nn = NewHash();
Setattr(n,key,nn);
}
Delete(key);
n = nn;
p = Swig_next(p);
}
/* No more parameters. At this point, n points to the very last hash table in our search.
We'll stick our object there */
Setattr(n,"*obj*",obj);
return;
}
/* -----------------------------------------------------------------------------
* Swig_map_match()
*
* Perform a longest map for a list of parameters and a set of mapping rules.
* Returns the corresponding rule object and the number of parameters that
* were matched.
* ----------------------------------------------------------------------------- */
/* Internal function used for recursively searching rulesets */
static DOH *
Swig_map_match_internal(DOHHash *nameset, DOHHash *parms, int *nmatch) {
DOHHash *nn1, *nn2;
DOHString *ty;
DOHString *name;
DOHString *key;
int mlen1 = 0, mlen2 = 0, bestlen = 0;
DOH *obj1 = 0, *obj2 = 0;
DOH *bestobj, *bestn;
DOHHash *nextp;
if (!parms) {
bestobj = Getattr(nameset,"*obj*");
if (bestobj) *nmatch++;
return bestobj;
}
ty = Getattr(parms,"type");
name = Getattr(parms,"name");
key = NewStringf("%s-%s",name,ty);
/* See if there is an exact name match */
nn1 = Getattr(nameset,key);
if (nn1) {
mlen1++;
obj1 = Swig_map_match_internal(nn1,Swig_next(parms), &mlen1);
}
/* See if there is a generic name match */
Clear(key);
Printf(key,"-%s",ty);
nn2 = Getattr(nameset,key);
if (nn2) {
mlen2++;
obj2 = Swig_map_match_internal(nn2, Swig_next(parms), &mlen2);
}
/* Pick the best match. Note: an exact name match is preferred */
if (obj1 && obj2) {
if (mlen2 > mlen1) {
bestlen = mlen2;
bestobj = obj2;
} else {
bestlen = mlen1;
bestobj = obj1;
}
} else if (obj1) {
bestobj = obj1;
bestlen = mlen1;
} else if (obj2) {
bestobj = obj2;
bestlen = mlen2;
}
if (!bestobj) {
bestobj = Getattr(nameset,"*obj*");
if (bestobj) bestlen = 1;
}
Delete(key);
*nmatch = *nmatch + bestlen;
return bestobj;
}
DOH *
Swig_map_match(DOHHash *ruleset, DOHString_or_char *rulename, DOHHash *parms, int *nmatch)
{
DOHHash *nameset;
int mlen = 0;
DOH *best;
/* Get the nameset */
nameset = Getattr(ruleset,rulename);
if (!nameset) return 0;
best = Swig_map_match_internal(nameset,parms,&mlen);
*nmatch = mlen;
return best;
}