PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/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
  1. /* -----------------------------------------------------------------------------
  2. * contract.cxx
  3. *
  4. * Support for Wrap by Contract in SWIG
  5. *
  6. * Author(s) : Songyan Feng (Tiger) (songyanf@cs.uchicago.edu)
  7. * David Beazley (beazley@cs.uchicago.edu)
  8. *
  9. * Department of Computer Science
  10. * University of Chicago
  11. *
  12. * Copyright (C) 1999-2003. The University of Chicago
  13. * See the file LICENSE for information on usage and redistribution.
  14. * ----------------------------------------------------------------------------- */
  15. char cvsroot_contract_cxx[] = "$Header$";
  16. #include "swigmod.h"
  17. /* Contract structure. This holds rules about the different kinds of contract sections
  18. and their combination rules */
  19. struct contract {
  20. const char *section;
  21. const char *combiner;
  22. };
  23. /* Contract rules. This table defines what contract sections are recognized as well as
  24. how contracts are to combined via inheritance */
  25. static contract Rules[] = {
  26. {"require:", "&&"},
  27. {"ensure:", "||"},
  28. { NULL, NULL}
  29. };
  30. /************************************************************************
  31. * class Contracts:
  32. *
  33. * This class defines the functions that need to be used in
  34. * "wrap by contract" module.
  35. *************************************************************************/
  36. class Contracts : public Dispatcher {
  37. String *make_expression(String *s, Node *n);
  38. void substitute_parms(String *s, ParmList *p, int method);
  39. public:
  40. Hash *ContractSplit(Node *n);
  41. int emit_contract(Node *n, int method);
  42. int cDeclaration(Node *n);
  43. int constructorDeclaration(Node *n);
  44. int externDeclaration(Node *n);
  45. int extendDirective(Node *n);
  46. int importDirective(Node *n);
  47. int includeDirective(Node *n);
  48. int classDeclaration(Node *n);
  49. virtual int top(Node *n);
  50. };
  51. static int Contract_Mode = 0; /* contract option */
  52. static int InClass = 0; /* Parsing C++ or not */
  53. static int InConstructor = 0;
  54. static Node *CurrentClass = 0;
  55. /* Set the contract mode, default is 0 (not open) */
  56. /* Normally set in main.cxx, when get the "-contracts" option */
  57. void Swig_contract_mode_set(int flag) {
  58. Contract_Mode = flag;
  59. }
  60. /* Get the contract mode */
  61. int Swig_contract_mode_get() {
  62. return Contract_Mode;
  63. }
  64. /* Apply contracts */
  65. void Swig_contracts(Node *n) {
  66. Contracts *a = new Contracts;
  67. a->top(n);
  68. delete a;
  69. }
  70. /* Split the whole contract into preassertion, postassertion and others */
  71. Hash *Contracts::ContractSplit(Node *n) {
  72. String *contract = Getattr(n, "feature:contract");
  73. Hash *result;
  74. if (!contract)
  75. return NULL;
  76. result = NewHash();
  77. String *current_section = NewString("");
  78. const char *current_section_name = Rules[0].section;
  79. List *l = SplitLines(contract);
  80. Iterator i;
  81. for (i = First(l); i.item; i = Next(i)) {
  82. int found = 0;
  83. if (Strstr(i.item,"{")) continue;
  84. if (Strstr(i.item,"}")) continue;
  85. for (int j = 0; Rules[j].section; j++) {
  86. if (Strstr(i.item,Rules[j].section)) {
  87. if (Len(current_section)) {
  88. Setattr(result,current_section_name,current_section);
  89. current_section = Getattr(result,Rules[j].section);
  90. if (!current_section) current_section = NewString("");
  91. }
  92. current_section_name = Rules[j].section;
  93. found = 1;
  94. break;
  95. }
  96. }
  97. if (!found) Append(current_section, i.item);
  98. }
  99. if (Len(current_section)) Setattr(result, current_section_name, current_section);
  100. return result;
  101. }
  102. /* This function looks in base classes and collects contracts found */
  103. void inherit_contracts(Node *c, Node *n, Hash *contracts, Hash *messages) {
  104. Node *b, *temp;
  105. String *name, *type, *local_decl, *base_decl;
  106. List *bases;
  107. int found = 0;
  108. bases = Getattr(c,"bases");
  109. if (!bases) return;
  110. name = Getattr(n, "name");
  111. type = Getattr(n, "type");
  112. local_decl = Getattr(n, "decl");
  113. if (local_decl) {
  114. local_decl = SwigType_typedef_resolve_all(local_decl);
  115. } else {
  116. return;
  117. }
  118. /* Width first search */
  119. for (int i = 0; i < Len(bases); i++) {
  120. b = Getitem(bases,i);
  121. temp = firstChild (b);
  122. while (temp) {
  123. base_decl = Getattr(temp, "decl");
  124. if (base_decl) {
  125. base_decl = SwigType_typedef_resolve_all(base_decl);
  126. if ( (checkAttribute(temp, "storage", "virtual")) &&
  127. (checkAttribute(temp, "name", name)) &&
  128. (checkAttribute(temp, "type", type)) &&
  129. (!Strcmp(local_decl, base_decl)) ) {
  130. /* Yes, match found. */
  131. Hash *icontracts = Getattr(temp,"contract:rules");
  132. Hash *imessages = Getattr(temp,"contract:messages");
  133. found = 1;
  134. if (icontracts && imessages) {
  135. /* Add inherited contracts and messages to the contract rules above */
  136. int j = 0;
  137. for (j = 0; Rules[j].section; j++) {
  138. String *t = Getattr(contracts, Rules[j].section);
  139. String *s = Getattr(icontracts, Rules[j].section);
  140. if (s) {
  141. if (t) {
  142. Insert(t,0,"(");
  143. Printf(t,") %s (%s)", Rules[j].combiner, s);
  144. String *m = Getattr(messages, Rules[j].section);
  145. Printf(m," %s [%s from %s]", Rules[j].combiner, Getattr(imessages,Rules[j].section), Getattr(b,"name"));
  146. } else {
  147. Setattr(contracts, Rules[j].section, NewString(s));
  148. Setattr(messages,Rules[j].section,NewStringf("[%s from %s]", Getattr(imessages,Rules[j].section), Getattr(b,"name")));
  149. }
  150. }
  151. }
  152. }
  153. }
  154. Delete(base_decl);
  155. }
  156. temp = nextSibling(temp);
  157. }
  158. }
  159. Delete(local_decl);
  160. if (!found) {
  161. for (int j = 0; j < Len(bases); j++) {
  162. b = Getitem(bases,j);
  163. inherit_contracts(b,n,contracts,messages);
  164. }
  165. }
  166. }
  167. /* This function cleans up the assertion string by removing some extraneous characters.
  168. Splitting the assertion into pieces */
  169. String *Contracts::make_expression(String *s, Node *n) {
  170. String *str_assert, *expr = 0;
  171. List *list_assert;
  172. str_assert = NewString(s);
  173. /* Omit all useless characters and split by ; */
  174. Replaceall(str_assert, "\n", "");
  175. Replaceall(str_assert, "{", "");
  176. Replaceall(str_assert, "}", "");
  177. Replace(str_assert, " ", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE);
  178. Replace(str_assert, "\t", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE);
  179. list_assert = Split(str_assert, ';', -1);
  180. Delete(str_assert);
  181. /* build up new assertion */
  182. str_assert = NewString("");
  183. Iterator ei;
  184. for (ei = First(list_assert); ei.item; ei = Next(ei)) {
  185. expr = ei.item;
  186. if (Len(expr)) {
  187. Replaceid(expr, Getattr(n,"name"), "result");
  188. if (Len(str_assert))
  189. Append(str_assert, "&&");
  190. Printf(str_assert, "(%s)", expr);
  191. }
  192. }
  193. Delete(list_assert);
  194. return str_assert;
  195. }
  196. /* This function substitutes parameter names for argument names in the
  197. contract specification. Note: it is assumed that the wrapper code
  198. uses arg1--argn for arguments. */
  199. void Contracts::substitute_parms(String *s, ParmList *p, int method) {
  200. int argnum = 1;
  201. char argname[32];
  202. if (method) {
  203. Replaceid(s,"self","arg0");
  204. argnum++;
  205. }
  206. while (p) {
  207. sprintf(argname,"arg%d",argnum);
  208. String *name = Getattr(p,"name");
  209. if (name) {
  210. Replaceid(s,name,argname);
  211. }
  212. argnum++;
  213. p = nextSibling(p);
  214. }
  215. }
  216. int Contracts::emit_contract(Node *n, int method) {
  217. Hash *contracts;
  218. Hash *messages;
  219. String *c;
  220. ParmList *cparms;
  221. if (!Getattr(n, "feature:contract"))
  222. return SWIG_ERROR;
  223. /* Get contract parameters */
  224. cparms = Getmeta(Getattr(n, "feature:contract"), "parms");
  225. /* Split contract into preassert & postassert */
  226. contracts = ContractSplit(n);
  227. if (!contracts) return SWIG_ERROR;
  228. /* This messages hash is used to hold the error messages that will be displayed on
  229. failed contract. */
  230. messages = NewHash();
  231. /* Take the different contract expressions and clean them up a bit */
  232. Iterator i;
  233. for (i = First(contracts); i.item; i = Next(i)) {
  234. String *e = make_expression(i.item, n);
  235. substitute_parms(e, cparms, method);
  236. Setattr(contracts,i.key,e);
  237. /* Make a string containing error messages */
  238. Setattr(messages,i.key, NewString(e));
  239. }
  240. /* If we're in a class. We need to inherit other assertions. */
  241. if (InClass) {
  242. inherit_contracts(CurrentClass, n, contracts, messages);
  243. }
  244. /* Save information */
  245. Setattr(n,"contract:rules", contracts);
  246. Setattr(n,"contract:messages", messages);
  247. /* Okay. Generate the contract runtime code. */
  248. if ((c = Getattr(contracts,"require:"))) {
  249. Setattr(n,"contract:preassert",
  250. NewStringf("SWIG_contract_assert(%s, \"Contract violation: require: %s\");\n",
  251. c, Getattr(messages,"require:")));
  252. }
  253. if ((c = Getattr(contracts,"ensure:"))) {
  254. Setattr(n,"contract:postassert",
  255. NewStringf("SWIG_contract_assert(%s, \"Contract violation: ensure: %s\");\n",
  256. c, Getattr(messages,"ensure:")));
  257. }
  258. return SWIG_OK;
  259. }
  260. int Contracts::cDeclaration(Node *n) {
  261. int ret = SWIG_OK;
  262. String *decl = Getattr(n,"decl");
  263. /* Not a function. Don't even bother with it (for now) */
  264. if (!SwigType_isfunction(decl)) return SWIG_OK;
  265. if (Getattr(n, "feature:contract"))
  266. ret = emit_contract(n, (InClass && !checkAttribute(n,"storage","static")));
  267. return ret;
  268. }
  269. int Contracts::constructorDeclaration(Node *n){
  270. int ret = SWIG_OK;
  271. InConstructor = 1;
  272. if (Getattr(n, "feature:contract"))
  273. ret = emit_contract(n,0);
  274. InConstructor = 0;
  275. return ret;
  276. }
  277. int Contracts::externDeclaration(Node *n) { return emit_children(n); }
  278. int Contracts::extendDirective(Node *n) { return emit_children(n); }
  279. int Contracts::importDirective(Node *n) { return emit_children(n); }
  280. int Contracts::includeDirective(Node *n) { return emit_children(n); }
  281. int Contracts::classDeclaration(Node *n) {
  282. int ret = SWIG_OK;
  283. InClass = 1;
  284. CurrentClass = n;
  285. emit_children(n);
  286. InClass = 0;
  287. CurrentClass = 0;
  288. return ret;
  289. }
  290. int Contracts::top(Node *n) {
  291. emit_children(n);
  292. return SWIG_OK;
  293. }