git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@516 626c5289-ae23-0410-ae9c-e8d60b6d4f22
200 lines
5.6 KiB
C
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|