1 /* -----------------------------------------------------------------------------
2 * See the LICENSE file for information on copyright, usage and redistribution
3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
7 * Support for Wrap by Contract in SWIG.
8 * ----------------------------------------------------------------------------- */
10 char cvsroot_contract_cxx[] = "$Id: contract.cxx 11049 2009-01-10 01:15:03Z wsfulton $";
14 /* Contract structure. This holds rules about the different kinds of contract sections
15 and their combination rules */
21 /* Contract rules. This table defines what contract sections are recognized as well as
22 how contracts are to combined via inheritance */
24 static contract Rules[] = {
30 /* ----------------------------------------------------------------------------
33 * This class defines the functions that need to be used in
34 * "wrap by contract" module.
35 * ------------------------------------------------------------------------- */
37 class Contracts:public Dispatcher {
38 String *make_expression(String *s, Node *n);
39 void substitute_parms(String *s, ParmList *p, int method);
41 Hash *ContractSplit(Node *n);
42 int emit_contract(Node *n, int method);
43 int cDeclaration(Node *n);
44 int constructorDeclaration(Node *n);
45 int externDeclaration(Node *n);
46 int extendDirective(Node *n);
47 int importDirective(Node *n);
48 int includeDirective(Node *n);
49 int namespaceDeclaration(Node *n);
50 int classDeclaration(Node *n);
51 virtual int top(Node *n);
54 static int Contract_Mode = 0; /* contract option */
55 static int InClass = 0; /* Parsing C++ or not */
56 static int InConstructor = 0;
57 static Node *CurrentClass = 0;
59 /* Set the contract mode, default is 0 (not open) */
60 /* Normally set in main.cxx, when get the "-contracts" option */
61 void Swig_contract_mode_set(int flag) {
65 /* Get the contract mode */
66 int Swig_contract_mode_get() {
71 void Swig_contracts(Node *n) {
73 Contracts *a = new Contracts;
78 /* Split the whole contract into preassertion, postassertion and others */
79 Hash *Contracts::ContractSplit(Node *n) {
81 String *contract = Getattr(n, "feature:contract");
87 String *current_section = NewString("");
88 const char *current_section_name = Rules[0].section;
89 List *l = SplitLines(contract);
92 for (i = First(l); i.item; i = Next(i)) {
94 if (Strchr(i.item, '{'))
96 if (Strchr(i.item, '}'))
98 for (int j = 0; Rules[j].section; j++) {
99 if (Strstr(i.item, Rules[j].section)) {
100 if (Len(current_section)) {
101 Setattr(result, current_section_name, current_section);
102 current_section = Getattr(result, Rules[j].section);
103 if (!current_section)
104 current_section = NewString("");
106 current_section_name = Rules[j].section;
112 Append(current_section, i.item);
114 if (Len(current_section))
115 Setattr(result, current_section_name, current_section);
119 /* This function looks in base classes and collects contracts found */
120 void inherit_contracts(Node *c, Node *n, Hash *contracts, Hash *messages) {
123 String *name, *type, *local_decl, *base_decl;
127 bases = Getattr(c, "bases");
131 name = Getattr(n, "name");
132 type = Getattr(n, "type");
133 local_decl = Getattr(n, "decl");
135 local_decl = SwigType_typedef_resolve_all(local_decl);
139 /* Width first search */
140 for (int i = 0; i < Len(bases); i++) {
141 b = Getitem(bases, i);
142 temp = firstChild(b);
144 base_decl = Getattr(temp, "decl");
146 base_decl = SwigType_typedef_resolve_all(base_decl);
147 if ((checkAttribute(temp, "storage", "virtual")) &&
148 (checkAttribute(temp, "name", name)) && (checkAttribute(temp, "type", type)) && (!Strcmp(local_decl, base_decl))) {
149 /* Yes, match found. */
150 Hash *icontracts = Getattr(temp, "contract:rules");
151 Hash *imessages = Getattr(temp, "contract:messages");
153 if (icontracts && imessages) {
154 /* Add inherited contracts and messages to the contract rules above */
156 for (j = 0; Rules[j].section; j++) {
157 String *t = Getattr(contracts, Rules[j].section);
158 String *s = Getattr(icontracts, Rules[j].section);
162 Printf(t, ") %s (%s)", Rules[j].combiner, s);
163 String *m = Getattr(messages, Rules[j].section);
164 Printf(m, " %s [%s from %s]", Rules[j].combiner, Getattr(imessages, Rules[j].section), Getattr(b, "name"));
166 Setattr(contracts, Rules[j].section, NewString(s));
167 Setattr(messages, Rules[j].section, NewStringf("[%s from %s]", Getattr(imessages, Rules[j].section), Getattr(b, "name")));
175 temp = nextSibling(temp);
180 for (int j = 0; j < Len(bases); j++) {
181 b = Getitem(bases, j);
182 inherit_contracts(b, n, contracts, messages);
187 /* This function cleans up the assertion string by removing some extraneous characters.
188 Splitting the assertion into pieces */
190 String *Contracts::make_expression(String *s, Node *n) {
191 String *str_assert, *expr = 0;
194 str_assert = NewString(s);
195 /* Omit all useless characters and split by ; */
196 Replaceall(str_assert, "\n", "");
197 Replaceall(str_assert, "{", "");
198 Replaceall(str_assert, "}", "");
199 Replace(str_assert, " ", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE);
200 Replace(str_assert, "\t", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE);
202 list_assert = Split(str_assert, ';', -1);
205 /* build up new assertion */
206 str_assert = NewString("");
209 for (ei = First(list_assert); ei.item; ei = Next(ei)) {
212 Replaceid(expr, Getattr(n, "name"), "result");
214 Append(str_assert, "&&");
215 Printf(str_assert, "(%s)", expr);
222 /* This function substitutes parameter names for argument names in the
223 contract specification. Note: it is assumed that the wrapper code
224 uses arg1 for self and arg2..argn for arguments. */
226 void Contracts::substitute_parms(String *s, ParmList *p, int method) {
231 Replaceid(s, "$self", "arg1");
235 sprintf(argname, "arg%d", argnum);
236 String *name = Getattr(p, "name");
238 Replaceid(s, name, argname);
245 int Contracts::emit_contract(Node *n, int method) {
252 if (!Getattr(n, "feature:contract"))
255 /* Get contract parameters */
256 cparms = Getmeta(Getattr(n, "feature:contract"), "parms");
258 /* Split contract into preassert & postassert */
259 contracts = ContractSplit(n);
263 /* This messages hash is used to hold the error messages that will be displayed on
266 messages = NewHash();
268 /* Take the different contract expressions and clean them up a bit */
270 for (i = First(contracts); i.item; i = Next(i)) {
271 String *e = make_expression(i.item, n);
272 substitute_parms(e, cparms, method);
273 Setattr(contracts, i.key, e);
275 /* Make a string containing error messages */
276 Setattr(messages, i.key, NewString(e));
279 /* If we're in a class. We need to inherit other assertions. */
281 inherit_contracts(CurrentClass, n, contracts, messages);
284 /* Save information */
285 Setattr(n, "contract:rules", contracts);
286 Setattr(n, "contract:messages", messages);
288 /* Okay. Generate the contract runtime code. */
290 if ((c = Getattr(contracts, "require:"))) {
291 Setattr(n, "contract:preassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: require: %s\");\n", c, Getattr(messages, "require:")));
293 if ((c = Getattr(contracts, "ensure:"))) {
294 Setattr(n, "contract:postassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: ensure: %s\");\n", c, Getattr(messages, "ensure:")));
299 int Contracts::cDeclaration(Node *n) {
301 String *decl = Getattr(n, "decl");
303 /* Not a function. Don't even bother with it (for now) */
304 if (!SwigType_isfunction(decl))
307 if (Getattr(n, "feature:contract"))
308 ret = emit_contract(n, (InClass && !checkAttribute(n, "storage", "static")));
312 int Contracts::constructorDeclaration(Node *n) {
315 if (Getattr(n, "feature:contract"))
316 ret = emit_contract(n, 0);
321 int Contracts::externDeclaration(Node *n) {
322 return emit_children(n);
325 int Contracts::extendDirective(Node *n) {
326 return emit_children(n);
329 int Contracts::importDirective(Node *n) {
330 return emit_children(n);
333 int Contracts::includeDirective(Node *n) {
334 return emit_children(n);
337 int Contracts::namespaceDeclaration(Node *n) {
338 return emit_children(n);
341 int Contracts::classDeclaration(Node *n) {
351 int Contracts::top(Node *n) {