1 /* 2 * Copyright 2011 Sven Verdoolaege. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * The views and conclusions contained in the software and documentation 29 * are those of the authors and should not be interpreted as 30 * representing official policies, either expressed or implied, of 31 * Sven Verdoolaege. 32 */ 33 34 #include "isl_config.h" 35 36 #include <stdio.h> 37 #include <iostream> 38 #include <map> 39 #include <clang/AST/Attr.h> 40 #include "extract_interface.h" 41 #include "python.h" 42 43 /* Is the given type declaration marked as being a subtype of some other 44 * type? If so, return that other type in "super". 45 */ 46 static bool is_subclass(RecordDecl *decl, string &super) 47 { 48 if (!decl->hasAttrs()) 49 return false; 50 51 string sub = "isl_subclass"; 52 size_t len = sub.length(); 53 AttrVec attrs = decl->getAttrs(); 54 for (AttrVec::const_iterator i = attrs.begin() ; i != attrs.end(); ++i) { 55 const AnnotateAttr *ann = dyn_cast<AnnotateAttr>(*i); 56 if (!ann) 57 continue; 58 string s = ann->getAnnotation().str(); 59 if (s.substr(0, len) == sub) { 60 super = s.substr(len + 1, s.length() - len - 2); 61 return true; 62 } 63 } 64 65 return false; 66 } 67 68 /* Is decl marked as a constructor? 69 */ 70 static bool is_constructor(Decl *decl) 71 { 72 return has_annotation(decl, "isl_constructor"); 73 } 74 75 /* Is decl marked as consuming a reference? 76 */ 77 static bool takes(Decl *decl) 78 { 79 return has_annotation(decl, "isl_take"); 80 } 81 82 /* isl_class collects all constructors and methods for an isl "class". 83 * "name" is the name of the class. 84 * "type" is the declaration that introduces the type. 85 */ 86 struct isl_class { 87 string name; 88 RecordDecl *type; 89 set<FunctionDecl *> constructors; 90 set<FunctionDecl *> methods; 91 92 void print(map<string, isl_class> &classes, set<string> &done); 93 void print_constructor(FunctionDecl *method); 94 void print_method(FunctionDecl *method, bool subclass, string super); 95 }; 96 97 /* Return the class that has a name that matches the initial part 98 * of the namd of function "fd". 99 */ 100 static isl_class &method2class(map<string, isl_class> &classes, 101 FunctionDecl *fd) 102 { 103 string best; 104 map<string, isl_class>::iterator ci; 105 string name = fd->getNameAsString(); 106 107 for (ci = classes.begin(); ci != classes.end(); ++ci) { 108 if (name.substr(0, ci->first.length()) == ci->first) 109 best = ci->first; 110 } 111 112 return classes[best]; 113 } 114 115 /* Is "type" the type "isl_ctx *"? 116 */ 117 static bool is_isl_ctx(QualType type) 118 { 119 if (!type->isPointerType()) 120 return 0; 121 type = type->getPointeeType(); 122 if (type.getAsString() != "isl_ctx") 123 return false; 124 125 return true; 126 } 127 128 /* Is the first argument of "fd" of type "isl_ctx *"? 129 */ 130 static bool first_arg_is_isl_ctx(FunctionDecl *fd) 131 { 132 ParmVarDecl *param; 133 134 if (fd->getNumParams() < 1) 135 return false; 136 137 param = fd->getParamDecl(0); 138 return is_isl_ctx(param->getOriginalType()); 139 } 140 141 /* Is "type" that of a pointer to an isl_* structure? 142 */ 143 static bool is_isl_type(QualType type) 144 { 145 if (type->isPointerType()) { 146 string s = type->getPointeeType().getAsString(); 147 return s.substr(0, 4) == "isl_"; 148 } 149 150 return false; 151 } 152 153 /* Is "type" that of a pointer to a function? 154 */ 155 static bool is_callback(QualType type) 156 { 157 if (!type->isPointerType()) 158 return false; 159 type = type->getPointeeType(); 160 return type->isFunctionType(); 161 } 162 163 /* Is "type" that of "char *" of "const char *"? 164 */ 165 static bool is_string(QualType type) 166 { 167 if (type->isPointerType()) { 168 string s = type->getPointeeType().getAsString(); 169 return s == "const char" || s == "char"; 170 } 171 172 return false; 173 } 174 175 /* Return the name of the type that "type" points to. 176 * The input "type" is assumed to be a pointer type. 177 */ 178 static string extract_type(QualType type) 179 { 180 if (type->isPointerType()) 181 return type->getPointeeType().getAsString(); 182 assert(0); 183 } 184 185 /* Drop the "isl_" initial part of the type name "name". 186 */ 187 static string type2python(string name) 188 { 189 return name.substr(4); 190 } 191 192 /* Construct a wrapper for a callback argument (at position "arg"). 193 * Assign the wrapper to "cb". We assume here that a function call 194 * has at most one callback argument. 195 * 196 * The wrapper converts the arguments of the callback to python types. 197 * If any exception is thrown, the wrapper keeps track of it in exc_info[0] 198 * and returns -1. Otherwise the wrapper returns 0. 199 */ 200 static void print_callback(QualType type, int arg) 201 { 202 const FunctionProtoType *fn = type->getAs<FunctionProtoType>(); 203 unsigned n_arg = fn->getNumArgs(); 204 205 printf(" exc_info = [None]\n"); 206 printf(" fn = CFUNCTYPE(c_int"); 207 for (int i = 0; i < n_arg - 1; ++i) { 208 QualType arg_type = fn->getArgType(i); 209 assert(is_isl_type(arg_type)); 210 printf(", c_void_p"); 211 } 212 printf(", c_void_p)\n"); 213 printf(" def cb_func("); 214 for (int i = 0; i < n_arg; ++i) { 215 if (i) 216 printf(", "); 217 printf("cb_arg%d", i); 218 } 219 printf("):\n"); 220 for (int i = 0; i < n_arg - 1; ++i) { 221 string arg_type; 222 arg_type = type2python(extract_type(fn->getArgType(i))); 223 printf(" cb_arg%d = %s(ctx=arg0.ctx, " 224 "ptr=cb_arg%d)\n", i, arg_type.c_str(), i); 225 } 226 printf(" try:\n"); 227 printf(" arg%d(", arg); 228 for (int i = 0; i < n_arg - 1; ++i) { 229 if (i) 230 printf(", "); 231 printf("cb_arg%d", i); 232 } 233 printf(")\n"); 234 printf(" except:\n"); 235 printf(" import sys\n"); 236 printf(" exc_info[0] = sys.exc_info()\n"); 237 printf(" return -1\n"); 238 printf(" return 0\n"); 239 printf(" cb = fn(cb_func)\n"); 240 } 241 242 /* Print a python method corresponding to the C function "method". 243 * "subclass" is set if the method belongs to a class that is a subclass 244 * of some other class ("super"). 245 * 246 * If the function has a callback argument, then it also has a "user" 247 * argument. Since Python has closures, there is no need for such 248 * a user argument in the Python interface, so we simply drop it. 249 * We also create a wrapper ("cb") for the callback. 250 * 251 * For each argument of the function that refers to an isl structure, 252 * including the object on which the method is called, 253 * we check if the corresponding actual argument is of the right type. 254 * If not, we try to convert it to the right type. 255 * It that doesn't work and if subclass is set, we try to convert self 256 * to the type of the superclass and call the corresponding method. 257 * 258 * If the function consumes a reference, then we pass it a copy of 259 * the actual argument. 260 */ 261 void isl_class::print_method(FunctionDecl *method, bool subclass, string super) 262 { 263 string fullname = method->getName(); 264 string cname = fullname.substr(name.length() + 1); 265 int num_params = method->getNumParams(); 266 int drop_user = 0; 267 268 for (int i = 1; i < num_params; ++i) { 269 ParmVarDecl *param = method->getParamDecl(i); 270 QualType type = param->getOriginalType(); 271 if (is_callback(type)) 272 drop_user = 1; 273 } 274 275 printf(" def %s(arg0", cname.c_str()); 276 for (int i = 1; i < num_params - drop_user; ++i) 277 printf(", arg%d", i); 278 printf("):\n"); 279 280 for (int i = 0; i < num_params; ++i) { 281 ParmVarDecl *param = method->getParamDecl(i); 282 string type; 283 if (!is_isl_type(param->getOriginalType())) 284 continue; 285 type = type2python(extract_type(param->getOriginalType())); 286 printf(" try:\n"); 287 printf(" if not arg%d.__class__ is %s:\n", 288 i, type.c_str()); 289 printf(" arg%d = %s(arg%d)\n", 290 i, type.c_str(), i); 291 printf(" except:\n"); 292 if (i > 0 && subclass) { 293 printf(" return %s(arg0).%s(", 294 type2python(super).c_str(), cname.c_str()); 295 for (int i = 1; i < num_params - drop_user; ++i) { 296 if (i != 1) 297 printf(", "); 298 printf("arg%d", i); 299 } 300 printf(")\n"); 301 } else 302 printf(" raise\n"); 303 } 304 for (int i = 1; i < num_params; ++i) { 305 ParmVarDecl *param = method->getParamDecl(i); 306 QualType type = param->getOriginalType(); 307 if (!is_callback(type)) 308 continue; 309 print_callback(type->getPointeeType(), i); 310 } 311 printf(" res = isl.%s(", fullname.c_str()); 312 if (takes(method->getParamDecl(0))) 313 printf("isl.%s_copy(arg0.ptr)", name.c_str()); 314 else 315 printf("arg0.ptr"); 316 for (int i = 1; i < num_params - drop_user; ++i) { 317 ParmVarDecl *param = method->getParamDecl(i); 318 QualType type = param->getOriginalType(); 319 if (is_callback(type)) 320 printf(", cb"); 321 else if (takes(param)) { 322 string type_s = extract_type(type); 323 printf(", isl.%s_copy(arg%d.ptr)", type_s.c_str(), i); 324 } else 325 printf(", arg%d.ptr", i); 326 } 327 if (drop_user) 328 printf(", None"); 329 printf(")\n"); 330 331 if (is_isl_type(method->getReturnType())) { 332 string type; 333 type = type2python(extract_type(method->getReturnType())); 334 printf(" return %s(ctx=arg0.ctx, ptr=res)\n", 335 type.c_str()); 336 } else { 337 if (drop_user) { 338 printf(" if exc_info[0] != None:\n"); 339 printf(" raise exc_info[0][0], " 340 "exc_info[0][1], exc_info[0][2]\n"); 341 } 342 printf(" return res\n"); 343 } 344 } 345 346 /* Print part of the constructor for this isl_class. 347 * 348 * In particular, check if the actual arguments correspond to the 349 * formal arguments of "cons" and if so call "cons" and put the 350 * result in self.ptr and a reference to the default context in self.ctx. 351 * 352 * If the function consumes a reference, then we pass it a copy of 353 * the actual argument. 354 */ 355 void isl_class::print_constructor(FunctionDecl *cons) 356 { 357 string fullname = cons->getName(); 358 string cname = fullname.substr(name.length() + 1); 359 int num_params = cons->getNumParams(); 360 int drop_ctx = first_arg_is_isl_ctx(cons); 361 362 printf(" if len(args) == %d", num_params - drop_ctx); 363 for (int i = drop_ctx; i < num_params; ++i) { 364 ParmVarDecl *param = cons->getParamDecl(i); 365 if (is_isl_type(param->getOriginalType())) { 366 string type; 367 type = extract_type(param->getOriginalType()); 368 type = type2python(type); 369 printf(" and args[%d].__class__ is %s", 370 i - drop_ctx, type.c_str()); 371 } else 372 printf(" and type(args[%d]) == str", i - drop_ctx); 373 } 374 printf(":\n"); 375 printf(" self.ctx = Context.getDefaultInstance()\n"); 376 printf(" self.ptr = isl.%s(", fullname.c_str()); 377 if (drop_ctx) 378 printf("self.ctx"); 379 for (int i = drop_ctx; i < num_params; ++i) { 380 ParmVarDecl *param = cons->getParamDecl(i); 381 if (i) 382 printf(", "); 383 if (is_isl_type(param->getOriginalType())) { 384 if (takes(param)) { 385 string type; 386 type = extract_type(param->getOriginalType()); 387 printf("isl.%s_copy(args[%d].ptr)", 388 type.c_str(), i - drop_ctx); 389 } else 390 printf("args[%d].ptr", i - drop_ctx); 391 } else 392 printf("args[%d]", i - drop_ctx); 393 } 394 printf(")\n"); 395 printf(" return\n"); 396 } 397 398 /* Print out the definition of this isl_class. 399 * 400 * We first check if this isl_class is a subclass of some other class. 401 * If it is, we make sure the superclass is printed out first. 402 * 403 * Then we print a constructor with several cases, one for constructing 404 * a Python object from a return value and one for each function that 405 * was marked as a constructor. 406 * 407 * Next, we print out some common methods and the methods corresponding 408 * to functions that are not marked as constructors. 409 * 410 * Finally, we tell ctypes about the types of the arguments of the 411 * constructor functions and the return types of those function returning 412 * an isl object. 413 */ 414 void isl_class::print(map<string, isl_class> &classes, set<string> &done) 415 { 416 string super; 417 string p_name = type2python(name); 418 set<FunctionDecl *>::iterator in; 419 bool subclass = is_subclass(type, super); 420 421 if (subclass && done.find(super) == done.end()) 422 classes[super].print(classes, done); 423 done.insert(name); 424 425 printf("\n"); 426 printf("class %s", p_name.c_str()); 427 if (subclass) 428 printf("(%s)", type2python(super).c_str()); 429 printf(":\n"); 430 printf(" def __init__(self, *args, **keywords):\n"); 431 432 printf(" if \"ptr\" in keywords:\n"); 433 printf(" self.ctx = keywords[\"ctx\"]\n"); 434 printf(" self.ptr = keywords[\"ptr\"]\n"); 435 printf(" return\n"); 436 437 for (in = constructors.begin(); in != constructors.end(); ++in) 438 print_constructor(*in); 439 printf(" raise Error\n"); 440 printf(" def __del__(self):\n"); 441 printf(" if hasattr(self, 'ptr'):\n"); 442 printf(" isl.%s_free(self.ptr)\n", name.c_str()); 443 printf(" def __str__(self):\n"); 444 printf(" ptr = isl.%s_to_str(self.ptr)\n", name.c_str()); 445 printf(" res = str(cast(ptr, c_char_p).value)\n"); 446 printf(" libc.free(ptr)\n"); 447 printf(" return res\n"); 448 printf(" def __repr__(self):\n"); 449 printf(" return 'isl.%s(\"%%s\")' %% str(self)\n", 450 p_name.c_str()); 451 452 for (in = methods.begin(); in != methods.end(); ++in) 453 print_method(*in, subclass, super); 454 455 printf("\n"); 456 for (in = constructors.begin(); in != constructors.end(); ++in) { 457 string fullname = (*in)->getName(); 458 printf("isl.%s.restype = c_void_p\n", fullname.c_str()); 459 printf("isl.%s.argtypes = [", fullname.c_str()); 460 for (int i = 0; i < (*in)->getNumParams(); ++i) { 461 ParmVarDecl *param = (*in)->getParamDecl(i); 462 QualType type = param->getOriginalType(); 463 if (i) 464 printf(", "); 465 if (is_isl_ctx(type)) 466 printf("Context"); 467 else if (is_isl_type(type)) 468 printf("c_void_p"); 469 else if (is_string(type)) 470 printf("c_char_p"); 471 else 472 printf("c_int"); 473 } 474 printf("]\n"); 475 } 476 for (in = methods.begin(); in != methods.end(); ++in) { 477 string fullname = (*in)->getName(); 478 if (is_isl_type((*in)->getReturnType())) 479 printf("isl.%s.restype = c_void_p\n", fullname.c_str()); 480 } 481 printf("isl.%s_free.argtypes = [c_void_p]\n", name.c_str()); 482 printf("isl.%s_to_str.argtypes = [c_void_p]\n", name.c_str()); 483 printf("isl.%s_to_str.restype = POINTER(c_char)\n", name.c_str()); 484 } 485 486 /* Generate a python interface based on the extracted types and functions. 487 * We first collect all functions that belong to a certain type, 488 * separating constructors from regular methods. 489 * 490 * Then we print out each class in turn. If one of these is a subclass 491 * of some other class, it will make sure the superclass is printed out first. 492 */ 493 void generate_python(set<RecordDecl *> &types, set<FunctionDecl *> functions) 494 { 495 map<string, isl_class> classes; 496 map<string, isl_class>::iterator ci; 497 set<string> done; 498 499 set<RecordDecl *>::iterator it; 500 for (it = types.begin(); it != types.end(); ++it) { 501 RecordDecl *decl = *it; 502 string name = decl->getName(); 503 classes[name].name = name; 504 classes[name].type = decl; 505 } 506 507 set<FunctionDecl *>::iterator in; 508 for (in = functions.begin(); in != functions.end(); ++in) { 509 isl_class &c = method2class(classes, *in); 510 if (is_constructor(*in)) 511 c.constructors.insert(*in); 512 else 513 c.methods.insert(*in); 514 } 515 516 for (ci = classes.begin(); ci != classes.end(); ++ci) { 517 if (done.find(ci->first) == done.end()) 518 ci->second.print(classes, done); 519 } 520 } 521