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