swig/Source/Swig/map.c

348 lines
9 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.
* ----------------------------------------------------------------------------- */
static char cvsroot[] = "$Header$";
#include "swig.h"
/* -----------------------------------------------------------------------------
* Synopsis
*
* One of the problems in creating wrappers is that of defining rules for
* managing various datatypes and function parameters. In SWIG1.1,
* this sort of customization was managed using a mechanism known as
* "typemaps". This module generalizes the idea even further and provides
* generic set of functions that can be used to define and match rules
* that are associated with lists of datatypes.
*
* The functions in this file are intended to be rather generic. They are only
* responsible for the storage and matching of rules. Other parts of the
* code can use these to implement typemaps, argmaps, or anything else.
* ----------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
* Swig_map_add_parmrule()
*
* Adds a new mapping rule for a list of parameters. The parms input to this
* function should be a properly constructed parameter list with associated
* attributes (type and name). The 'obj' attribute can be any DOH object.
*
* The structure of how data might be stored is as follows:
*
* ruleset (hash)
* --------------
* parm1 ---------> rule (hash)
* -------------
* parm2 -----------> rule (hash)
* *obj* --> obj ------------
* parm3
* *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_parmrule(Hash *ruleset, Hash *parms, DOH *obj)
{
Hash *p, *n;
/* Walk down the parms list and create a series of hash tables */
p = parms;
n = ruleset;
while (p) {
String *ty, *name, *key;
Hash *nn;
ty = Getattr(p,"type");
name = Getattr(p,"name");
/* Create a hash table key */
key = NewStringf("*map:%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);
}
/* -----------------------------------------------------------------------------
* Swig_map_add_typerule()
*
* Adds a rule for a single type and name.
* ----------------------------------------------------------------------------- */
void
Swig_map_add_typerule(Hash *ruleset, DOH *type, String_or_char *name, DOH *obj) {
Hash *p;
p = NewHash();
Setattr(p,"type",type);
if (name)
Setattr(p,"name", name);
Swig_map_add_parmrule(ruleset,p,obj);
Delete(p);
}
typedef struct MatchObject {
Hash *ruleset; /* Hash table of rules */
Hash *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_parms()
*
* 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.
*
* Note: If the ruleset has a 'parent' attribute, this function will walk its
* way up and try to find a match. This can be used to implement scoped
* mappings.
* ----------------------------------------------------------------------------- */
DOH *
Swig_map_match_parms(Hash *ruleset, Hash *parms, int *nmatch)
{
MatchObject *mo;
DOH *bestobj = 0;
int bestdepth = -1;
*nmatch = 0;
mo = (MatchObject *) malloc(sizeof(MatchObject));
mo->ruleset = ruleset;
mo->depth = 0;
mo->p = parms;
mo->next = 0;
matchstack = mo;
/* Loop over all candidates until we find the best one */
while (matchstack) {
Hash *rs;
Hash *p;
int depth = 0;
DOH *obj;
String *key;
String *ty;
String *name;
String *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("*map:-%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,"*map:%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, n;
int ncheck;
String *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,"*map:-%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,"*map:%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;
String *key;
String *dty = SwigType_default(Getattr(parms,"type"));
key = NewStringf("*map:-%s",dty);
rs = Getattr(ruleset,key);
if (rs) {
bestobj = Getattr(rs,"*obj*");
if (bestobj) *nmatch = 1;
}
Delete(key);
Delete(dty);
}
if (!bestobj) {
DOH *prules = Getattr(ruleset,"parent");
if (prules) {
bestobj = Swig_map_match_parms(prules,parms,nmatch);
}
}
return bestobj;
}
/* -----------------------------------------------------------------------------
* Swig_map_match_type()
*
* Match a rule for a single type
* ----------------------------------------------------------------------------- */
DOH *
Swig_map_match_type(Hash *ruleset, DOH *type, String_or_char *name) {
Hash *p;
DOH *obj;
int nmatch;
p = NewHash();
Setattr(p,"type",type);
if (name)
Setattr(p,"name",name);
obj = Swig_map_match_parms(ruleset,p,&nmatch);
Delete(p);
return obj;
}