diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index 3cdaa952e..36333f135 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -410,6 +410,9 @@ SWIG_InstallConstants(PyObject *d, swig_const_info constants[]) { #define SWIG_preassert(expr, msg) if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, msg #expr ); goto fail; } else #define SWIG_postassert(expr, msg) if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, msg #expr ); goto fail; } else +#define SWIG_inherit_preassert(expr, msg) if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, msg #expr ); goto fail; } else +#define SWIG_inherit_postassert(expr, msg) if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, msg #expr ); goto fail; } else + #define SWIG_invariant(expr, msg) if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, msg #expr ); goto fail; } else #define SWIG_invariant_begin(expr, msg) if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, msg #expr ); goto fail; } else #define SWIG_invariant_end(expr, msg) if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, msg #expr ); goto fail; } else @@ -417,4 +420,3 @@ SWIG_InstallConstants(PyObject *d, swig_const_info constants[]) { #ifdef __cplusplus } #endif - diff --git a/Source/Modules/contract.cxx b/Source/Modules/contract.cxx index b0e932417..146f6eeda 100644 --- a/Source/Modules/contract.cxx +++ b/Source/Modules/contract.cxx @@ -16,379 +16,32 @@ char cvsroot_contract_cxx[] = "$Header$"; #include "swigmod.h" -#define SWIG_PREASSERT "require:" -#define SWIG_POSTASSERT "ensure:" -#define SWIG_INVARIANT "invariant:" -#define SWIG_BEFORE "swig_before(" -#define SWIG_AFTER "swig_after(" +#define SWIG_PREASSERT "require:" +#define SWIG_POSTASSERT "ensure:" +#define SWIG_INVARIANT "invariant:" +#define SWIG_BEFORE "swig_before(" +#define SWIG_AFTER "swig_after(" +#define SWIG_CONTRACT_SET "SET" static int Contract_Mode = 0; /* contract option */ -static int InClass = 0; /* Parsing C++ or not */ -static Node *CurrentClass = 0; +static int InClass = 0; /* Parsing C++ or not */ static int InConstructor = 0; -static int InDestructor = 0; +static int InDestructor = 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; } -class Contracts : public Dispatcher { - -public: - - int SliptContract(Node *n) { - String *contract = Getattr(n, "feature:contract"); - if (!contract) - return SWIG_ERROR; - String *preassert = NewString(""); - String *postassert = NewString(""); - String *invariant = NewString(""); - char *mark_pre = Strstr(contract, SWIG_PREASSERT); - char *mark_post = Strstr(contract, SWIG_POSTASSERT); - char *mark_invar = Strstr(contract, SWIG_INVARIANT); - int len_pre = Len(SWIG_PREASSERT); - int len_post = Len(SWIG_POSTASSERT); - int len_invar = Len(SWIG_INVARIANT); - - if (!mark_invar) { /* No invar- */ - if (!mark_post) { /* No post- */ - if ( !mark_pre ) { /* No pre-, default is preassert */ - preassert = contract; - } else { /* with pre- only */ - mark_pre[len_pre-1]='{'; - mark_pre[len_pre]='\n'; - preassert = mark_pre+len_pre-1; - } - } else { /* with post- */ - if (!mark_pre) { /* with post- only, but maybe has preassert */ - preassert = contract; - mark_post[0] = '}'; - mark_post[1] = '\0'; - mark_post[len_post-2] = '{'; - mark_post[len_post-1] = '\n'; - postassert = mark_post+len_post-2; - } else { /* with both pre- & post- marks */ - mark_pre[len_pre-1]='{'; - mark_pre[len_pre]='\n'; - preassert = mark_pre+len_pre-1; - mark_post[0] = '}'; - mark_post[1] = '\0'; - mark_post[len_post-2] = '{'; - mark_post[len_post-1] = '\n'; - postassert = mark_post+len_post-2; - } - } - } else { /* with invar-mark */ - if (!mark_post) { /* No post- mark */ - if ( !mark_pre ) { /* with invar- only, but maybe has pre- */ - preassert = contract; - mark_invar[0] = '}'; - mark_invar[1] = '\0'; - mark_invar[len_invar-2] = '{'; - mark_invar[len_invar-1] = '\n'; - invariant = mark_invar+len_invar-2; - } else { /* with pre- & invar-, no postassert */ - mark_pre[len_pre-1]='{'; - mark_pre[len_pre]='\n'; - preassert = mark_pre+len_pre-1; - mark_invar[0] = '}'; - mark_invar[1] = '\0'; - mark_invar[len_invar-2] = '{'; - mark_invar[len_invar-1] = '\n'; - invariant = mark_invar+len_invar-2; - } - } else { /* with invar- & post- */ - if (!mark_pre) { /* with post- & invar- only, but maybe has preassert */ - preassert = contract; - mark_post[0] = '}'; - mark_post[1] = '\0'; - mark_post[len_post-2] = '{'; - mark_post[len_post-1] = '\n'; - postassert = mark_post+len_post-2; - mark_invar[0] = '}'; - mark_invar[1] = '\0'; - mark_invar[len_invar-2] = '{'; - mark_invar[len_invar-1] = '\n'; - invariant = mark_invar+len_invar-2; - } else { /* with pre-, post- & invar- */ - mark_pre[len_pre-1]='{'; - mark_pre[len_pre]='\n'; - preassert = mark_pre+len_pre-1; - mark_post[0] = '}'; - mark_post[1] = '\0'; - mark_post[len_post-2] = '{'; - mark_post[len_post-1] = '\n'; - postassert = mark_post+len_post-2; - mark_invar[0] = '}'; - mark_invar[1] = '\0'; - mark_invar[len_invar-2] = '{'; - mark_invar[len_invar-1] = '\n'; - invariant = mark_invar+len_invar-2; - } - } - } - - Setattr(n, "feature:preassert", preassert); - Setattr(n, "feature:postassert", postassert); - Setattr(n, "feature:invariant", invariant); - Delete(contract); - return SWIG_OK; - } - - int AssertModify(Node *n, int flag) { - String *str_assert, *expr, *tag_sync; - List *list_assert; - - if (flag == 1) { /* preassert */ - str_assert = NewString(Getattr(n, "feature:preassert")); - } else if (flag == 2){ /* postassert */ - str_assert = NewString(Getattr(n, "feature:postassert")); - } else if (flag == 3){ /* invariant */ - str_assert = NewString(Getattr(n, "feature:invariant")); - } else - return SWIG_ERROR; - - /* Omit all unuseful characters and split by ; */ - Replaceall(str_assert, "\n", ""); - Replaceall(str_assert, "{", ""); - Replaceall(str_assert, "}", ""); - Replaceall(str_assert, " ", ""); - list_assert = Split(str_assert, ';', -1); - Delete(str_assert); - - /* build up new assertion */ - str_assert = NewString(""); - for (expr = Firstitem(list_assert); expr; expr = Nextitem(list_assert)) { - if (Len(expr)) { - /* All sync staff are not complete and only experimental */ - if (Strstr(expr, SWIG_BEFORE)) { /* before sync assertion */ - tag_sync = NewString(" SWIG_sync("); - Append(tag_sync, Getattr(n, "name")); - Append(tag_sync, ", "); - Replaceall(expr, SWIG_BEFORE, tag_sync); - Append(str_assert, expr); - Append(str_assert, ";\n"); - Delete(tag_sync); - } else if (Strstr(expr, SWIG_AFTER)) { /* after sync assertion */ - tag_sync = NewString(" SWIG_sync("); - Replaceall(expr, SWIG_AFTER, tag_sync); - Replaceall(expr, ")", ", "); - Append(str_assert, expr); - Append(str_assert, Getattr(n,"name")); - Append(str_assert, ");\n"); - Delete(tag_sync); - } else { /* no sync assertion, only basic pre- post-, invar- */ - Replaceid(expr, Getattr(n,"name"), "result"); - if (Len(str_assert)) - Append(str_assert, "&&"); - Printf(str_assert, "(%s)", expr); - } - } - } - - if (flag == 1) { - Setattr(n, "feature:preassert", str_assert); - } else if (flag == 2) { - Setattr(n, "feature:postassert", str_assert); - } else { - Setattr(n, "feature:invariant", str_assert); - } - - Delete(str_assert); - Delete(list_assert); - Delete(expr); - return SWIG_OK; - } - - /* Modify format into { SWIG_xxxassert(...);\n ...} */ - int AssertAddTag(Node *n) { - String *str_assert, *tag; - /* preassert */ - str_assert = NewString(Getattr(n, "feature:preassert")); - if (Len(str_assert)) { - tag = NewString(" SWIG_preassert("); - Append(tag, str_assert); - Append(tag, ");\n"); - Setattr(n, "feature:preassert", tag); - Delete(tag); - } - Delete(str_assert); - - /* postassert */ - str_assert = NewString(Getattr(n, "feature:postassert")); - if (Len(str_assert)) { - tag = NewString(" SWIG_postassert("); - Append(tag, str_assert); - Append(tag, ");\n"); - Setattr(n, "feature:postassert", tag); - Delete(tag); - } - Delete(str_assert); - - /* invariant */ - str_assert = NewString(Getattr(n, "feature:invariant")); - if (Len(str_assert)) { - tag = NewString(" SWIG_invariant("); - Append(tag, str_assert); - Append(tag, ");\n"); - Setattr(n, "feature:invariant", tag); - Delete(tag); - } - Delete(str_assert); - return SWIG_OK; - } - - /* Append error message */ - int AssertAddErrorMsg(Node *n) { - String *str_assert, *error_msg; - /* preassert */ - str_assert = NewString(Getattr(n, "feature:preassert")); - Replaceall(str_assert, ");\n", ""); - if (Len(str_assert)) { - error_msg = NewString("\\nRequire assertion violation,"); - Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); - Printf(str_assert, ", \"%s\");\n", error_msg); - Setattr(n, "feature:preassert", str_assert); - Delete(error_msg); - } - Delete(str_assert); - - /* postassert */ - str_assert = NewString(Getattr(n, "feature:postassert")); - Replaceall(str_assert, ");\n", ""); - if (Len(str_assert)) { - error_msg = NewString("\\nEnsure assertion violation,"); - Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); - Printf(str_assert, ", \"%s\");\n", error_msg); - Setattr(n, "feature:postassert", str_assert); - Delete(error_msg); - } - Delete(str_assert); - - /* invariant */ - str_assert = NewString(Getattr(n, "feature:invariant")); - Replaceall(str_assert, ");\n", ""); - if (Len(str_assert)) { - error_msg = NewString("\\nInvariant assertion violation,"); - Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); - Printf(str_assert, ", \"%s\");\n", error_msg); - Setattr(n, "feature:invariant", str_assert); - Delete(error_msg); - } - Delete(str_assert); - return SWIG_OK; - } - - int AssertSetParms(Node *n) { - ParmList *list_params; - String *str_assert_pre,*str_assert_post,*str_assert_invar; - - str_assert_pre = NewString(Getattr(n, "feature:preassert")); - str_assert_post = NewString(Getattr(n, "feature:postassert")); - str_assert_invar = NewString(Getattr(n, "feature:invariant")); - - /* Set the params in preassert & postassert */ - list_params = Getmeta(Getattr(n, "feature:contract"), "parms"); - if ((InClass) && (!InConstructor) && (!InDestructor)){ - /* Insert function name as parm for class member functions */ - String *type = NewString(Getattr(n,"type")); - String *name = NewString("self"); - Parm *p = NewParm(type, name); - set_nextSibling(p, list_params); - list_params = p; - } - Setmeta(str_assert_pre, "parms", list_params); - Setmeta(str_assert_post, "parms", list_params); - Setmeta(str_assert_invar, "parms", list_params); - - Setattr(n, "feature:preassert", str_assert_pre); - Setattr(n, "feature:postassert", str_assert_post); - Setattr(n, "feature:invariant", str_assert_invar); - - Delete(list_params); - Delete(str_assert_pre); - Delete(str_assert_post); - Delete(str_assert_invar); - return SWIG_OK; - } - - int emit_contract(Node *n) { - int ret = SWIG_OK; - if (!Getattr(n, "feature:contract")) - return SWIG_ERROR; - /* Printf(stdout, "--------In emit_contract code:\nname is : %s\n", - Getattr(n,"name")); */ - - /* Split contracqt into preassert & postassert */ - if (!SliptContract(n)) - return SWIG_ERROR; - - /* Modify pre- , post- * invar- */ - ret = ret && AssertModify(n, 1); - ret = ret && AssertModify(n, 2); - ret = ret && AssertModify(n, 3); - ret = ret && AssertAddTag(n); - ret = ret && AssertAddErrorMsg(n); - ret = ret && AssertSetParms(n); - return ret; - } - - int cDeclaration(Node *n) { - int ret = SWIG_OK; - if (Getattr(n, "feature:contract")) - ret = emit_contract(n); - return ret; - } - - int constructorDeclaration(Node *n){ - int ret = SWIG_OK; - InConstructor = 1; - if (Getattr(n, "feature:contract")) - ret = emit_contract(n); - InConstructor = 0; - return ret; - } - - int destructorDeclaration(Node *n){ - int ret = SWIG_OK; - InDestructor = 1; - if (Getattr(n, "feature:contract")) - ret = emit_contract(n); - InDestructor = 0; - return ret; - } - - int externDeclaration(Node *n) { return emit_children(n); } - int extendDirective(Node *n) { return emit_children(n); } - int importDirective(Node *n) { return emit_children(n); } - int includeDirective(Node *n) { return emit_children(n); } - - int classDeclaration(Node *n) { - int ret = SWIG_OK; - InClass = 1; - CurrentClass = n; - ret = classHandler(n); - InClass = 0; - CurrentClass = 0; - return ret; - } - - int classHandler(Node *n) { - emit_children(n); - return SWIG_OK; - } - - virtual int top(Node *n) { - emit_children(n); - return SWIG_OK; - } -}; - +/* Apply contracts */ void Swig_contracts(Node *n) { Printf(stdout,"Applying contracts (experimental version)\n"); @@ -396,3 +49,526 @@ void Swig_contracts(Node *n) { a->top(n); delete a; } + +/* Split the whole contract into preassertion, postassertion and others */ +int Contracts::ContractSplit(Node *n) { + String *contract = Getattr(n, "feature:contract"); + if (!contract) + return SWIG_ERROR; + + String *preassert = NewString(""); /* preassertion */ + String *postassert = NewString(""); + String *invariant = NewString(""); + char *mark_pre = Strstr(contract, SWIG_PREASSERT); /* position of preassertion in whole contract */ + char *mark_post = Strstr(contract, SWIG_POSTASSERT); + char *mark_invar = Strstr(contract, SWIG_INVARIANT); + int len_pre = Len(SWIG_PREASSERT); /* length of preassertion */ + int len_post = Len(SWIG_POSTASSERT); + int len_invar = Len(SWIG_INVARIANT); + + if (!mark_invar) { /* No invar- */ + if (!mark_post) { /* No post- */ + if ( !mark_pre ) { /* No pre-, default is preassert */ + preassert = contract; + } else { /* with pre- only */ + mark_pre[len_pre-1]='{'; + mark_pre[len_pre]='\n'; + preassert = mark_pre+len_pre-1; /* strcpy? */ + } + } else { /* with post- */ + if (!mark_pre) { /* with post- only, but maybe has preassert */ + preassert = contract; + mark_post[0] = '}'; + mark_post[1] = '\0'; + mark_post[len_post-2] = '{'; + mark_post[len_post-1] = '\n'; + postassert = mark_post+len_post-2; + } else { /* with both pre- & post- marks */ + mark_pre[len_pre-1]='{'; + mark_pre[len_pre]='\n'; + preassert = mark_pre+len_pre-1; + mark_post[0] = '}'; + mark_post[1] = '\0'; + mark_post[len_post-2] = '{'; + mark_post[len_post-1] = '\n'; + postassert = mark_post+len_post-2; + } + } + } else { /* with invar-mark */ + if (!mark_post) { /* No post- mark */ + if ( !mark_pre ) { /* with invar- only, but maybe has pre- */ + preassert = contract; + mark_invar[0] = '}'; + mark_invar[1] = '\0'; + mark_invar[len_invar-2] = '{'; + mark_invar[len_invar-1] = '\n'; + invariant = mark_invar+len_invar-2; + } else { /* with pre- & invar-, no postassert */ + mark_pre[len_pre-1]='{'; + mark_pre[len_pre]='\n'; + preassert = mark_pre+len_pre-1; + mark_invar[0] = '}'; + mark_invar[1] = '\0'; + mark_invar[len_invar-2] = '{'; + mark_invar[len_invar-1] = '\n'; + invariant = mark_invar+len_invar-2; + } + } else { /* with invar- & post- */ + if (!mark_pre) { /* with post- & invar- only, but maybe has preassert */ + preassert = contract; + mark_post[0] = '}'; + mark_post[1] = '\0'; + mark_post[len_post-2] = '{'; + mark_post[len_post-1] = '\n'; + postassert = mark_post+len_post-2; + mark_invar[0] = '}'; + mark_invar[1] = '\0'; + mark_invar[len_invar-2] = '{'; + mark_invar[len_invar-1] = '\n'; + invariant = mark_invar+len_invar-2; + } else { /* with pre-, post- & invar- */ + mark_pre[len_pre-1]='{'; + mark_pre[len_pre]='\n'; + preassert = mark_pre+len_pre-1; + mark_post[0] = '}'; + mark_post[1] = '\0'; + mark_post[len_post-2] = '{'; + mark_post[len_post-1] = '\n'; + postassert = mark_post+len_post-2; + mark_invar[0] = '}'; + mark_invar[1] = '\0'; + mark_invar[len_invar-2] = '{'; + mark_invar[len_invar-1] = '\n'; + invariant = mark_invar+len_invar-2; + } + } + } + if (Len(preassert)) Setattr(n, "feature:preassert", preassert); + if (Len(postassert)) Setattr(n, "feature:postassert", postassert); + if (Len(invariant)) Setattr(n, "feature:invariant", invariant); + + Delete(contract); + return SWIG_OK; +} + +/* Modify the contract inheritance */ +int Contracts::InheritModify(Node *n) { + Node *parent, *bases; + String *str_assert_pre, *str_assert_post; + + /* Set the preassert to the inherit_preassert as the basic inherit */ + str_assert_pre = Getattr(n, "feature:preassert"); + if (Len(str_assert_pre) != 0) + Setattr(n, "feature:inherit_preassert", str_assert_pre); + /* Set the postassert to the inherit_postassert as the basic inherit */ + str_assert_post = Getattr(n, "feature:postassert"); + if (Len(str_assert_post) != 0) + Setattr(n, "feature:inherit_postassert", str_assert_post); + + parent = parentNode(n); /* class node of function node n */ + if (!parent) + return SWIG_OK; + + bases = Getattr(parent, "bases"); /* base class list of current class */ + if (!bases) + return SWIG_OK; + + InheritAssertAppend(n, bases); + return SWIG_OK; +} + +int Contracts::InheritAssertAppend(Node *n, Node *bases) { + /* check whether the method is inherited from the base */ + /* if inherited, then AND the ancestor's preassertion to its own preassertion */ + /* OR its own postassertion to the ancestor's postassertion */ + String *str_assert_pre; + String *str_inherit_pre; + String *str_assert_post; + String *str_inherit_post; + + Node *b, *temp_base; + String *local_name, *local_type, *local_decl, *base_decl; + + int defined = 0; + + if ( (!n) || (!bases) ) + return 0; + if (!Getattr(n, "feature:contract")) + return 0; + + local_name = Getattr(n, "name"); + local_type = Getattr(n, "type"); + local_decl = Getattr(n, "decl"); + if (local_decl) { + local_decl = SwigType_typedef_resolve_all(local_decl); + } else { + return 0; + } + + str_inherit_pre = NewString(Getattr(n, "feature:inherit_preassert")); + str_assert_post = NewString(Getattr(n, "feature:postassert")); + if ( (Len(str_inherit_pre)==0) && ((Len(str_assert_post) ==0)) ) + return 0; /* no need to modify inheritance of assertions */ + + /* Width first search */ + for (int i = 0; i < Len(bases); i++) { + b = Getitem(bases,i); + temp_base = firstChild (b); /* member function/variable of the base class */ + + while (temp_base) { + base_decl = Getattr(temp_base, "decl"); + if (base_decl) { + base_decl = SwigType_typedef_resolve_all(base_decl); + if ( (checkAttribute(temp_base, "name", local_name)) && + (checkAttribute(temp_base, "type", local_type)) && + (!Strcmp(local_decl, base_decl)) ) { + /* same declaration in base, append the the base pre to the current inherit_perassertion */ + str_assert_pre = NewString(Getattr(temp_base, "feature:preassert")); + if ( (Len(str_assert_pre)) && (Len(str_inherit_pre)) ) { + Printf(str_inherit_pre, " && %s", str_assert_pre); + } + str_inherit_post = NewString(Getattr(temp_base, "feature:inherit_postassert")); + if ( (Len(str_assert_post)) && (Len(str_inherit_post)) ) { + Printf(str_inherit_post, " || %s", str_assert_post); + Setattr(temp_base, "feature:inherit_postassert", str_inherit_post); + } + + Delete(str_assert_pre); + Delete(str_inherit_post); + defined = 1; + } + Delete(base_decl); + } /* end of if */ + temp_base = nextSibling(temp_base); + } /* end of while(temp) */ + } /* end of i */ + + if (Len(str_inherit_pre)) + Setattr(n, "feature:inherit_preassert", str_inherit_pre); + Delete(local_decl); + Delete(str_inherit_pre); + Delete(str_assert_post); + + /* recursive search */ + for (int j = 0; j < Len(bases); j++) { + b = Getitem(bases,j); + if (InheritAssertAppend(n, Getattr(b, "bases"))) + defined = 1; + } + if (defined) + return 1; + return 0; +} + +int Contracts::AssertModify(Node *n, int flag) { + String *str_assert, *expr, *tag_sync; + List *list_assert; + + if (flag == 1) { /* preassert */ + str_assert = NewString(Getattr(n, "feature:preassert")); + } else if (flag == 2){ /* postassert */ + str_assert = NewString(Getattr(n, "feature:postassert")); + } else if (flag == 3){ /* invariant */ + str_assert = NewString(Getattr(n, "feature:invariant")); + } else + return SWIG_ERROR; + + if (!Len(str_assert)) + return SWIG_OK; + + /* Omit all unuseful characters and split by ; */ + Replaceall(str_assert, "\n", ""); + Replaceall(str_assert, "{", ""); + Replaceall(str_assert, "}", ""); + Replaceall(str_assert, " ", ""); + list_assert = Split(str_assert, ';', -1); + Delete(str_assert); + + /* build up new assertion */ + str_assert = NewString(""); + for (expr = Firstitem(list_assert); expr; expr = Nextitem(list_assert)) { + if (Len(expr)) { + /* All sync staff are not complete and only experimental */ + if (Strstr(expr, SWIG_BEFORE)) { /* before sync assertion */ + tag_sync = NewString(" SWIG_sync("); + Append(tag_sync, Getattr(n, "name")); + Append(tag_sync, ", "); + Replaceall(expr, SWIG_BEFORE, tag_sync); + Append(str_assert, expr); + Append(str_assert, ";\n"); + Delete(tag_sync); + } else if (Strstr(expr, SWIG_AFTER)) { /* after sync assertion */ + tag_sync = NewString(" SWIG_sync("); + Replaceall(expr, SWIG_AFTER, tag_sync); + Replaceall(expr, ")", ", "); + Append(str_assert, expr); + Append(str_assert, Getattr(n,"name")); + Append(str_assert, ");\n"); + Delete(tag_sync); + } else { /* no sync assertion, only basic pre- post-, invar- */ + Replaceid(expr, Getattr(n,"name"), "result"); + if (Len(str_assert)) + Append(str_assert, "&&"); + Printf(str_assert, "(%s)", expr); + } + } + } + + if (flag == 1) { + Setattr(n, "feature:preassert", str_assert); + } else if (flag == 2) { + Setattr(n, "feature:postassert", str_assert); + } else { + Setattr(n, "feature:invariant", str_assert); + } + + Delete(str_assert); + Delete(list_assert); + Delete(expr); + return SWIG_OK; +} + +/* Modify format into { SWIG_xxxassert(...);\n ...} */ +int Contracts::AssertAddTag(Node *n) { + String *str_assert, *tag; + /* preassert */ + str_assert = NewString(Getattr(n, "feature:preassert")); + if (Len(str_assert)) { + tag = NewString(" SWIG_preassert("); + Append(tag, str_assert); + Append(tag, ");\n"); + Setattr(n, "feature:preassert", tag); + Delete(tag); + } + Delete(str_assert); + + /* inherit_preassert */ + str_assert = NewString(Getattr(n, "feature:inherit_preassert")); + if (Len(str_assert)) { + tag = NewString(" SWIG_inherit_preassert(("); + Append(tag, str_assert); + Append(tag, "));\n"); + Setattr(n, "feature:inherit_preassert", tag); + Delete(tag); + } + Delete(str_assert); + + /* postassert */ + str_assert = NewString(Getattr(n, "feature:postassert")); + if (Len(str_assert)) { + tag = NewString(" SWIG_postassert("); + Append(tag, str_assert); + Append(tag, ");\n"); + Setattr(n, "feature:postassert", tag); + Delete(tag); + } + Delete(str_assert); + + /* inherit_postassert */ + str_assert = NewString(Getattr(n, "feature:inherit_postassert")); + if (Len(str_assert)) { + tag = NewString(" SWIG_inherit_postassert(("); + Append(tag, str_assert); + Append(tag, "));\n"); + Setattr(n, "feature:inherit_postassert", tag); + Delete(tag); + } + Delete(str_assert); + + /* invariant */ + str_assert = NewString(Getattr(n, "feature:invariant")); + if (Len(str_assert)) { + tag = NewString(" SWIG_invariant("); + Append(tag, str_assert); + Append(tag, ");\n"); + Setattr(n, "feature:invariant", tag); + Delete(tag); + } + Delete(str_assert); + return SWIG_OK; +} + +/* Append error message */ +int Contracts::AssertAddErrorMsg(Node *n) { + String *str_assert, *error_msg; + /* preassert */ + str_assert = NewString(Getattr(n, "feature:preassert")); + Replaceall(str_assert, ");\n", ""); + if (Len(str_assert)) { + error_msg = NewString("\\nRequire assertion violation,"); + Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); + Printf(str_assert, ", \"%s\");\n", error_msg); + Setattr(n, "feature:preassert", str_assert); + Delete(error_msg); + } + Delete(str_assert); + + /* inherit_preassert */ + str_assert = NewString(Getattr(n, "feature:inherit_preassert")); + Replaceall(str_assert, ");\n", ""); + if (Len(str_assert)) { + error_msg = NewString("\\nInherited require assertion violation,"); + Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); + Printf(str_assert, ", \"%s\");\n", error_msg); + Setattr(n, "feature:inherit_preassert", str_assert); + Delete(error_msg); + } + Delete(str_assert); + + /* postassert */ + str_assert = NewString(Getattr(n, "feature:postassert")); + Replaceall(str_assert, ");\n", ""); + if (Len(str_assert)) { + error_msg = NewString("\\nEnsure assertion violation,"); + Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); + Printf(str_assert, ", \"%s\");\n", error_msg); + Setattr(n, "feature:postassert", str_assert); + Delete(error_msg); + } + Delete(str_assert); + + /* inherit_postassert */ + str_assert = NewString(Getattr(n, "feature:inherit_postassert")); + Replaceall(str_assert, ");\n", ""); + if (Len(str_assert)) { + error_msg = NewString("\\nInherited ensure assertion violation,"); + Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); + Printf(str_assert, ", \"%s\");\n", error_msg); + Setattr(n, "feature:inherit_postassert", str_assert); + Delete(error_msg); + } + Delete(str_assert); + + /* invariant */ + str_assert = NewString(Getattr(n, "feature:invariant")); + Replaceall(str_assert, ");\n", ""); + if (Len(str_assert)) { + error_msg = NewString("\\nInvariant assertion violation,"); + Printf(error_msg, "in function of <<%s>>\\n", Getattr(n, "name")); + Printf(str_assert, ", \"%s\");\n", error_msg); + Setattr(n, "feature:invariant", str_assert); + Delete(error_msg); + } + Delete(str_assert); + return SWIG_OK; +} + +int Contracts::AssertSetParms(Node *n) { + ParmList *list_params; + String *str_assert_pre,*str_assert_post,*str_assert_invar; + String *str_inherit_pre, *str_inherit_post; + + str_assert_pre = NewString(Getattr(n, "feature:preassert")); + str_assert_post = NewString(Getattr(n, "feature:postassert")); + str_assert_invar = NewString(Getattr(n, "feature:invariant")); + str_inherit_pre = NewString(Getattr(n, "feature:inherit_preassert")); + str_inherit_post = NewString(Getattr(n, "feature:inherit_postassert")); + + /* Set the params in preassert & postassert */ + list_params = Getmeta(Getattr(n, "feature:contract"), "parms"); + if (Getattr(n, "feature:contract_classparm")){ + /* Insert function name as parm for class member functions */ + String *type = NewString(Getattr(n,"type")); + String *name = NewString("self"); + Parm *p = NewParm(type, name); + set_nextSibling(p, list_params); + list_params = p; + } + Setmeta(str_assert_pre, "parms", list_params); + Setmeta(str_assert_post, "parms", list_params); + Setmeta(str_assert_invar, "parms", list_params); + Setmeta(str_inherit_pre, "parms", list_params); + Setmeta(str_inherit_post, "parms", list_params); + + if (Len(str_assert_pre)) + Setattr(n, "feature:preassert", str_assert_pre); + if (Len(str_assert_post)) + Setattr(n, "feature:postassert", str_assert_post); + if (Len(str_assert_invar)) + Setattr(n, "feature:invariant", str_assert_invar); + if (Len(str_inherit_pre)) + Setattr(n, "feature:inherit_preassert", str_inherit_pre); + if (Len(str_inherit_post)) + Setattr(n, "feature:inherit_postassert", str_inherit_post); + + Delete(list_params); + Delete(str_assert_pre); + Delete(str_assert_post); + Delete(str_assert_invar); + Delete(str_inherit_pre); + Delete(str_inherit_post); + return SWIG_OK; +} + +int Contracts::emit_contract(Node *n) { + int ret = SWIG_OK; + + if (!Getattr(n, "feature:contract")) + return SWIG_ERROR; + + /* Split contracqt into preassert & postassert */ + if (!ContractSplit(n)) + return SWIG_ERROR; + + /* Modify pre- , post- * invar- */ + ret = ret && AssertModify(n, 1); + ret = ret && AssertModify(n, 2); + ret = ret && AssertModify(n, 3); + ret = ret && InheritModify(n); + if ((InClass) && (!InConstructor) && (!InDestructor)){ + Setattr(n, "feature:contract_classparm", SWIG_CONTRACT_SET); + } + /* Add tags and error msgs later when emit, + and keep assertions as experisions in the parse tree */ + return ret; +} + +int Contracts::cDeclaration(Node *n) { + int ret = SWIG_OK; + if (Getattr(n, "feature:contract")) + ret = emit_contract(n); + return ret; +} + +int Contracts::constructorDeclaration(Node *n){ + int ret = SWIG_OK; + InConstructor = 1; + if (Getattr(n, "feature:contract")) + ret = emit_contract(n); + InConstructor = 0; + return ret; +} + +int Contracts::destructorDeclaration(Node *n){ + int ret = SWIG_OK; + InDestructor = 1; + if (Getattr(n, "feature:contract")) + ret = emit_contract(n); + InDestructor = 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; + ret = classHandler(n); + InClass = 0; + CurrentClass = 0; + return ret; +} + +int Contracts::classHandler(Node *n) { + emit_children(n); + return SWIG_OK; +} + +int Contracts::top(Node *n) { + emit_children(n); + return SWIG_OK; +} diff --git a/Source/Modules/emit.cxx b/Source/Modules/emit.cxx index 0e1b77e1b..f204d9bbd 100644 --- a/Source/Modules/emit.cxx +++ b/Source/Modules/emit.cxx @@ -428,20 +428,34 @@ void emit_action(Node *n, Wrapper *f) { /* Emit contract code (if any) */ if (Swig_contract_mode_get()) { + /* Modify contracts */ + Contracts *a = new Contracts; + if (Getattr(n, "feature:contract")) { + a->AssertAddTag(n); + a->AssertAddErrorMsg(n); + a->AssertSetParms(n); + } + delete a; + /* Preassertion */ - tm = Getattr(n,"feature:preassert"); - if (tm) { + tm = Getattr(n, "feature:preassert"); + if (Len(tm)) { replace_contract_args(Getmeta(tm,"parms"), Getattr(n,"parms"),tm); - Printf(stdout, "name: %s, preassert: %s\n", Getattr(n,"name"), tm); Printv(f->code,tm,"\n",NIL); } + /* Inherit_Preassertion */ + tm = Getattr(n, "feature:inherit_preassert"); + if (Len(tm)) { + replace_contract_args(Getmeta(tm,"parms"), Getattr(n,"parms"),tm); + Printv(f->code,tm,"\n",NIL); + } + /* Invariant -- EXPERIMENTAL */ - tm = Getattr(n,"feature:invariant"); - if (tm) { + tm = Getattr(n, "feature:invariant"); + if (Len(tm)) { replace_contract_args(Getmeta(tm,"parms"), Getattr(n,"parms"),tm); Replaceid(tm, "SWIG_invariant", "SWIG_invariant_begin"); - Printf(stdout, "name: %s, invarassert: %s\n", Getattr(n,"name"), tm); Printv(f->code,tm,"\n",NIL); } } @@ -492,18 +506,22 @@ void emit_action(Node *n, Wrapper *f) { /* Emit contract code (if any) */ if (Swig_contract_mode_get()) { /* Invariant -- EXPERIMENTAL */ - tm = Getattr(n,"feature:invariant"); - if (tm) { + tm = Getattr(n, "feature:invariant"); + if (Len(tm)) { replace_contract_args(Getmeta(tm,"parms"), Getattr(n,"parms"),tm); Replaceid(tm, "SWIG_invariant", "SWIG_invariant_end"); - Printf(stdout, "name: %s, invarassert: %s\n", Getattr(n,"name"), tm); Printv(f->code,tm,"\n",NIL); } - /* Postassertion - EXPERIMENTAL */ - tm = Getattr(n,"feature:postassert"); - if (tm) { + /* Inherit Postassertion */ + tm = Getattr(n, "feature:inherit_postassert"); + if (Len(tm)) { + replace_contract_args(Getmeta(tm,"parms"), Getattr(n,"parms"),tm); + Printv(f->code,tm,"\n",NIL); + } + /* Postassertion */ + tm = Getattr(n, "feature:postassert"); + if (Len(tm)) { replace_contract_args(Getmeta(tm,"parms"), Getattr(n,"parms"),tm); - Printf(stdout, "name: %s, postassert: %s\n", Getattr(n,"name"), tm); Printv(f->code,tm,"\n",NIL); } } diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h index e54eee6a0..2fbeff9c0 100644 --- a/Source/Modules/swigmod.h +++ b/Source/Modules/swigmod.h @@ -266,6 +266,36 @@ extern void emit_action(Node *n, Wrapper *f); extern List *Swig_overload_rank(Node *n); extern String *Swig_overload_dispatch(Node *n, const String_or_char *fmt, int *); +/************************************************************************ + * class Contracts: + * + * This class defines the functions that need to be used in + * "wrap by contract" module. + *************************************************************************/ + +class Contracts : public Dispatcher { +public: + int ContractSplit(Node *n); + int AssertModify(Node *n, int flag); + int InheritModify(Node *n); + int InheritAssertAppend(Node *n, Node *bases); + int AssertAddTag(Node *n); + int AssertAddErrorMsg(Node *n); + int AssertSetParms(Node *n); + + int emit_contract(Node *n); + int cDeclaration(Node *n); + int constructorDeclaration(Node *n); + int destructorDeclaration(Node *n); + int externDeclaration(Node *n); + int extendDirective(Node *n); + int importDirective(Node *n); + int includeDirective(Node *n); + int classDeclaration(Node *n); + int classHandler(Node *n); + virtual int top(Node *n); +}; + extern void Swig_contracts(Node *n); extern void Swig_contract_mode_set(int flag); extern int Swig_contract_mode_get();