/tags/rel-1-3-24/SWIG/Source/Modules/contract.cxx
C++ | 341 lines | 243 code | 48 blank | 50 comment | 41 complexity | 86307c392efa04101e8d85114272b144 MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
- /* -----------------------------------------------------------------------------
- * contract.cxx
- *
- * Support for Wrap by Contract in SWIG
- *
- * Author(s) : Songyan Feng (Tiger) (songyanf@cs.uchicago.edu)
- * David Beazley (beazley@cs.uchicago.edu)
- *
- * Department of Computer Science
- * University of Chicago
- *
- * Copyright (C) 1999-2003. The University of Chicago
- * See the file LICENSE for information on usage and redistribution.
- * ----------------------------------------------------------------------------- */
- char cvsroot_contract_cxx[] = "$Header$";
- #include "swigmod.h"
- /* Contract structure. This holds rules about the different kinds of contract sections
- and their combination rules */
- struct contract {
- const char *section;
- const char *combiner;
- };
- /* Contract rules. This table defines what contract sections are recognized as well as
- how contracts are to combined via inheritance */
- static contract Rules[] = {
- {"require:", "&&"},
- {"ensure:", "||"},
- { NULL, NULL}
- };
- /************************************************************************
- * class Contracts:
- *
- * This class defines the functions that need to be used in
- * "wrap by contract" module.
- *************************************************************************/
- class Contracts : public Dispatcher {
- String *make_expression(String *s, Node *n);
- void substitute_parms(String *s, ParmList *p, int method);
- public:
- Hash *ContractSplit(Node *n);
- int emit_contract(Node *n, int method);
- int cDeclaration(Node *n);
- int constructorDeclaration(Node *n);
- int externDeclaration(Node *n);
- int extendDirective(Node *n);
- int importDirective(Node *n);
- int includeDirective(Node *n);
- int classDeclaration(Node *n);
- virtual int top(Node *n);
- };
- static int Contract_Mode = 0; /* contract option */
- static int InClass = 0; /* Parsing C++ or not */
- static int InConstructor = 0;
- static Node *CurrentClass = 0;
- /* Set the contract mode, default is 0 (not open) */
- /* Normally set in main.cxx, when get the "-contracts" option */
- void Swig_contract_mode_set(int flag) {
- Contract_Mode = flag;
- }
- /* Get the contract mode */
- int Swig_contract_mode_get() {
- return Contract_Mode;
- }
- /* Apply contracts */
- void Swig_contracts(Node *n) {
- Contracts *a = new Contracts;
- a->top(n);
- delete a;
- }
- /* Split the whole contract into preassertion, postassertion and others */
- Hash *Contracts::ContractSplit(Node *n) {
- String *contract = Getattr(n, "feature:contract");
- Hash *result;
- if (!contract)
- return NULL;
- result = NewHash();
- String *current_section = NewString("");
- const char *current_section_name = Rules[0].section;
- List *l = SplitLines(contract);
- Iterator i;
- for (i = First(l); i.item; i = Next(i)) {
- int found = 0;
- if (Strstr(i.item,"{")) continue;
- if (Strstr(i.item,"}")) continue;
- for (int j = 0; Rules[j].section; j++) {
- if (Strstr(i.item,Rules[j].section)) {
- if (Len(current_section)) {
- Setattr(result,current_section_name,current_section);
- current_section = Getattr(result,Rules[j].section);
- if (!current_section) current_section = NewString("");
- }
- current_section_name = Rules[j].section;
- found = 1;
- break;
- }
- }
- if (!found) Append(current_section, i.item);
- }
- if (Len(current_section)) Setattr(result, current_section_name, current_section);
- return result;
- }
- /* This function looks in base classes and collects contracts found */
- void inherit_contracts(Node *c, Node *n, Hash *contracts, Hash *messages) {
-
- Node *b, *temp;
- String *name, *type, *local_decl, *base_decl;
- List *bases;
- int found = 0;
- bases = Getattr(c,"bases");
- if (!bases) return;
-
- name = Getattr(n, "name");
- type = Getattr(n, "type");
- local_decl = Getattr(n, "decl");
- if (local_decl) {
- local_decl = SwigType_typedef_resolve_all(local_decl);
- } else {
- return;
- }
- /* Width first search */
- for (int i = 0; i < Len(bases); i++) {
- b = Getitem(bases,i);
- temp = firstChild (b);
- while (temp) {
- base_decl = Getattr(temp, "decl");
- if (base_decl) {
- base_decl = SwigType_typedef_resolve_all(base_decl);
- if ( (checkAttribute(temp, "storage", "virtual")) &&
- (checkAttribute(temp, "name", name)) &&
- (checkAttribute(temp, "type", type)) &&
- (!Strcmp(local_decl, base_decl)) ) {
- /* Yes, match found. */
- Hash *icontracts = Getattr(temp,"contract:rules");
- Hash *imessages = Getattr(temp,"contract:messages");
- found = 1;
- if (icontracts && imessages) {
- /* Add inherited contracts and messages to the contract rules above */
- int j = 0;
- for (j = 0; Rules[j].section; j++) {
- String *t = Getattr(contracts, Rules[j].section);
- String *s = Getattr(icontracts, Rules[j].section);
- if (s) {
- if (t) {
- Insert(t,0,"(");
- Printf(t,") %s (%s)", Rules[j].combiner, s);
- String *m = Getattr(messages, Rules[j].section);
- Printf(m," %s [%s from %s]", Rules[j].combiner, Getattr(imessages,Rules[j].section), Getattr(b,"name"));
- } else {
- Setattr(contracts, Rules[j].section, NewString(s));
- Setattr(messages,Rules[j].section,NewStringf("[%s from %s]", Getattr(imessages,Rules[j].section), Getattr(b,"name")));
- }
- }
- }
- }
- }
- Delete(base_decl);
- }
- temp = nextSibling(temp);
- }
- }
- Delete(local_decl);
- if (!found) {
- for (int j = 0; j < Len(bases); j++) {
- b = Getitem(bases,j);
- inherit_contracts(b,n,contracts,messages);
- }
- }
- }
- /* This function cleans up the assertion string by removing some extraneous characters.
- Splitting the assertion into pieces */
- String *Contracts::make_expression(String *s, Node *n) {
- String *str_assert, *expr = 0;
- List *list_assert;
- str_assert = NewString(s);
- /* Omit all useless characters and split by ; */
- Replaceall(str_assert, "\n", "");
- Replaceall(str_assert, "{", "");
- Replaceall(str_assert, "}", "");
- Replace(str_assert, " ", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE);
- Replace(str_assert, "\t", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE);
- list_assert = Split(str_assert, ';', -1);
- Delete(str_assert);
-
- /* build up new assertion */
- str_assert = NewString("");
- Iterator ei;
- for (ei = First(list_assert); ei.item; ei = Next(ei)) {
- expr = ei.item;
- if (Len(expr)) {
- Replaceid(expr, Getattr(n,"name"), "result");
- if (Len(str_assert))
- Append(str_assert, "&&");
- Printf(str_assert, "(%s)", expr);
- }
- }
- Delete(list_assert);
- return str_assert;
- }
- /* This function substitutes parameter names for argument names in the
- contract specification. Note: it is assumed that the wrapper code
- uses arg1--argn for arguments. */
- void Contracts::substitute_parms(String *s, ParmList *p, int method) {
- int argnum = 1;
- char argname[32];
- if (method) {
- Replaceid(s,"self","arg0");
- argnum++;
- }
- while (p) {
- sprintf(argname,"arg%d",argnum);
- String *name = Getattr(p,"name");
- if (name) {
- Replaceid(s,name,argname);
- }
- argnum++;
- p = nextSibling(p);
- }
- }
- int Contracts::emit_contract(Node *n, int method) {
- Hash *contracts;
- Hash *messages;
- String *c;
- ParmList *cparms;
- if (!Getattr(n, "feature:contract"))
- return SWIG_ERROR;
- /* Get contract parameters */
- cparms = Getmeta(Getattr(n, "feature:contract"), "parms");
- /* Split contract into preassert & postassert */
- contracts = ContractSplit(n);
- if (!contracts) return SWIG_ERROR;
- /* This messages hash is used to hold the error messages that will be displayed on
- failed contract. */
- messages = NewHash();
- /* Take the different contract expressions and clean them up a bit */
- Iterator i;
- for (i = First(contracts); i.item; i = Next(i)) {
- String *e = make_expression(i.item, n);
- substitute_parms(e, cparms, method);
- Setattr(contracts,i.key,e);
- /* Make a string containing error messages */
- Setattr(messages,i.key, NewString(e));
- }
-
- /* If we're in a class. We need to inherit other assertions. */
- if (InClass) {
- inherit_contracts(CurrentClass, n, contracts, messages);
- }
- /* Save information */
- Setattr(n,"contract:rules", contracts);
- Setattr(n,"contract:messages", messages);
- /* Okay. Generate the contract runtime code. */
-
- if ((c = Getattr(contracts,"require:"))) {
- Setattr(n,"contract:preassert",
- NewStringf("SWIG_contract_assert(%s, \"Contract violation: require: %s\");\n",
- c, Getattr(messages,"require:")));
- }
- if ((c = Getattr(contracts,"ensure:"))) {
- Setattr(n,"contract:postassert",
- NewStringf("SWIG_contract_assert(%s, \"Contract violation: ensure: %s\");\n",
- c, Getattr(messages,"ensure:")));
- }
- return SWIG_OK;
- }
- int Contracts::cDeclaration(Node *n) {
- int ret = SWIG_OK;
- String *decl = Getattr(n,"decl");
- /* Not a function. Don't even bother with it (for now) */
- if (!SwigType_isfunction(decl)) return SWIG_OK;
- if (Getattr(n, "feature:contract"))
- ret = emit_contract(n, (InClass && !checkAttribute(n,"storage","static")));
- return ret;
- }
- int Contracts::constructorDeclaration(Node *n){
- int ret = SWIG_OK;
- InConstructor = 1;
- if (Getattr(n, "feature:contract"))
- ret = emit_contract(n,0);
- InConstructor = 0;
- return ret;
- }
- int Contracts::externDeclaration(Node *n) { return emit_children(n); }
- int Contracts::extendDirective(Node *n) { return emit_children(n); }
- int Contracts::importDirective(Node *n) { return emit_children(n); }
- int Contracts::includeDirective(Node *n) { return emit_children(n); }
- int Contracts::classDeclaration(Node *n) {
- int ret = SWIG_OK;
- InClass = 1;
- CurrentClass = n;
- emit_children(n);
- InClass = 0;
- CurrentClass = 0;
- return ret;
- }
- int Contracts::top(Node *n) {
- emit_children(n);
- return SWIG_OK;
- }