swig/Source/Swig/map.c
Dave Beazley 76c442982f Work in progress
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@525 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2000-07-06 21:23:29 +00:00

322 lines
8.3 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;
}
typedef struct MatchObject {
DOH *ruleset; /* Hash table of rules */
DOHHash *p; /* Parameter on which checking starts */
int depth; /* Depth of the match */
struct MatchObject *next; /* Next match object */
} MatchObject;
static MatchObject *matchstack = 0;
/* -----------------------------------------------------------------------------
* Swig_map_match()
*
* Perform a longest map match for a list of parameters and a set of mapping rules.
* Returns the corresponding rule object and the number of parameters that were
* matched.
* ----------------------------------------------------------------------------- */
DOH *
Swig_map_match(DOHHash *ruleset, DOHString_or_char *rulename, DOHHash *parms, int *nmatch)
{
DOHHash *nameset;
MatchObject *mo;
DOH *bestobj = 0;
int bestdepth = -1;
*nmatch = 0;
/* Get the nameset */
nameset = Getattr(ruleset,rulename);
if (!nameset) return 0;
mo = (MatchObject *) malloc(sizeof(MatchObject));
mo->ruleset = nameset;
mo->depth = 0;
mo->p = parms;
mo->next = 0;
matchstack = mo;
/* Loop over all candidates until we find the best one */
while (matchstack) {
DOHHash *rs;
DOHHash *p;
int depth = 0;
DOH *obj;
DOHString *key;
DOHString *ty;
DOHString *name;
DOHString *nm;
int matched = 0;
mo = matchstack;
/* See if there is a match at this level */
rs = mo->ruleset;
obj = Getattr(rs,"*obj*");
if (obj) {
if (mo->depth > bestdepth) {
bestdepth = mo->depth;
bestobj = obj;
}
}
p = mo->p;
/* No more parameters. Oh well */
if (!p) {
matchstack = mo->next;
free(mo);
continue;
}
/* Generate some keys for checking the next parameter */
depth = mo->depth;
name = Getattr(p,"name");
ty = Getattr(p,"type");
if (!SwigType_isarray(ty)) {
key = NewStringf("-%s",ty);
/* See if there is a generic name match for this type */
nm = Getattr(rs,key);
if (nm) {
/* Yes! Add to our stack. Just reuse mo for this */
mo->ruleset = nm;
mo->p = Swig_next(p);
mo->depth++;
mo = 0;
matched++;
}
/* See if there is a specific name match for this type */
Clear(key);
Printf(key,"%s-%s",name,ty);
nm = Getattr(rs,key);
if (nm) {
if (!mo) {
mo = (MatchObject *) malloc(sizeof(MatchObject));
mo->next = matchstack;
matchstack = mo;
}
mo->ruleset = nm;
mo->p = Swig_next(p);
mo->depth = depth+1;
matched++;
}
Delete(key);
} else {
/* The next parameter is an array. This is pretty nasty because we have to do a bunch of checks
related to array indices */
int ndim;
int i, j, k, n;
int ncheck;
DOHString *ntype;
key = NewString("");
/* Drop the mo record. This is too complicated */
matchstack = mo->next;
free(mo);
mo = 0;
/* Get the number of array dimensions */
ndim = SwigType_array_ndim(ty);
/* First, we test all of the generic-unnamed parameters */
ncheck = 1 << ndim;
j = ncheck-1;
for (i = 0; i < ncheck; i++, j--) {
int k = j;
ntype = Copy(ty);
for (n = 0; n < ndim; n++, k = k >> 1) {
if (k & 1) {
SwigType_array_setdim(ntype,n,"");
}
}
Clear(key);
Printf(key,"-%s",ntype);
Printf(stdout,"matcharray : %s\n", key);
nm = Getattr(rs,key);
if (nm) {
mo = (MatchObject *) malloc(sizeof(MatchObject));
mo->ruleset = nm;
mo->p = Swig_next(p);
mo->depth = depth+1;
mo->next = matchstack;
matchstack = mo;
matched++;
mo = 0;
}
Delete(ntype);
}
/* Next check all of the named parameters */
ncheck = 1 << ndim;
j = ncheck-1;
for (i = 0; i < ncheck; i++, j--) {
int k = j;
ntype = Copy(ty);
for (n = 0; n < ndim; n++, k = k >> 1) {
if (k & 1) {
SwigType_array_setdim(ntype,n,"");
}
}
Clear(key);
Printf(key,"%s-%s",name,ntype);
Printf(stdout,"matcharray : %s\n", key);
nm = Getattr(rs,key);
if (nm) {
mo = (MatchObject *) malloc(sizeof(MatchObject));
mo->ruleset = nm;
mo->p = Swig_next(p);
mo->depth = depth+1;
mo->next = matchstack;
matchstack = mo;
matched++;
mo = 0;
}
Delete(ntype);
}
Delete(key);
}
if ((!matched) && mo) {
matchstack = mo->next;
free(mo);
}
}
if (bestobj) {
*nmatch = bestdepth;
} else {
/* If there is no match at all. I guess we can check for a default type */
DOH *rs;
DOHString *key, *name;
DOHString *dty = SwigType_default(Getattr(parms,"type"));
key = NewStringf("-%s",dty);
rs = Getattr(nameset,key);
if (rs) {
bestobj = Getattr(rs,"*obj*");
if (bestobj) *nmatch = 1;
}
Delete(key);
Delete(dty);
}
return bestobj;
}