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.
4 *
5 * cffi.cxx
6 *
7 * cffi language module for SWIG.
8 * ----------------------------------------------------------------------------- */
9
10char cvsroot_cffi_cxx[] = "$Id: cffi.cxx 11380 2009-07-08 12:17:45Z wsfulton $";
11
12#include "swigmod.h"
13#include "cparse.h"
14#include <ctype.h>
15
16//#define CFFI_DEBUG
17//#define CFFI_WRAP_DEBUG
18
19class CFFI:public Language {
20public:
21  String *f_cl;
22  String *f_clhead;
23  String *f_clwrap;
24  bool CWrap;     // generate wrapper file for C code?
25  File *f_begin;
26  File *f_runtime;
27  File *f_cxx_header;
28  File *f_cxx_wrapper;
29  File *f_clos;
30
31  String *module;
32  virtual void main(int argc, char *argv[]);
33  virtual int top(Node *n);
34  virtual int functionWrapper(Node *n);
35  virtual int variableWrapper(Node *n);
36  virtual int constantWrapper(Node *n);
37  //  virtual int classDeclaration(Node *n);
38  virtual int enumDeclaration(Node *n);
39  virtual int typedefHandler(Node *n);
40
41  //c++ specific code
42  virtual int constructorHandler(Node *n);
43  virtual int destructorHandler(Node *n);
44  virtual int memberfunctionHandler(Node *n);
45  virtual int membervariableHandler(Node *n);
46  virtual int classHandler(Node *n);
47
48private:
49  void emit_defun(Node *n, String *name);
50  void emit_defmethod(Node *n);
51  void emit_initialize_instance(Node *n);
52  void emit_getter(Node *n);
53  void emit_setter(Node *n);
54  void emit_class(Node *n);
55  void emit_struct_union(Node *n, bool un);
56  void emit_export(Node *n, String *name);
57  void emit_inline(Node *n, String *name);
58  String *lispy_name(char *name);
59  String *lispify_name(Node *n, String *ty, const char *flag, bool kw = false);
60  String *convert_literal(String *num_param, String *type, bool try_to_split = true);
61  String *infix_to_prefix(String *val, char split_op, const String *op, String *type);
62  String *strip_parens(String *string);
63  String *trim(String *string);
64  int generate_typedef_flag;
65  bool no_swig_lisp;
66};
67
68void CFFI::main(int argc, char *argv[]) {
69  int i;
70
71  Preprocessor_define("SWIGCFFI 1", 0);
72  SWIG_library_directory("cffi");
73  SWIG_config_file("cffi.swg");
74  generate_typedef_flag = 0;
75  no_swig_lisp = false;
76  CWrap = false;
77  for (i = 1; i < argc; i++) {
78    if (!Strcmp(argv[i], "-help")) {
79      Printf(stdout, "cffi Options (available with -cffi)\n");
80      Printf(stdout,
81       "   -generate-typedef\n"
82       "\tIf this option is given then defctype will be used to generate\n"
83       "\tshortcuts according to the typedefs in the input.\n"
84       "   -[no]cwrap\n"
85       "\tTurn on or turn off generation of an intermediate C file when\n"
86       "\tcreating a C interface. By default this is only done for C++ code.\n"
87       "   -[no]swig-lisp\n"
88       "\tTurns on or off generation of code for helper lisp macro, functions,\n"
89       "\tetc. which SWIG uses while generating wrappers. These macros, functions\n" "\tmay still be used by generated wrapper code.\n");
90    } else if (!strcmp(argv[i], "-cwrap")) {
91      CWrap = true;
92      Swig_mark_arg(i);
93    } else if ((Strcmp(argv[i], "-generate-typedef") == 0)) {
94      generate_typedef_flag = 1;
95      Swig_mark_arg(i);
96    } else if (!strcmp(argv[i], "-nocwrap")) {
97      CWrap = false;
98      Swig_mark_arg(i);
99    } else if (!strcmp(argv[i], "-swig-lisp")) {
100      no_swig_lisp = false;
101      Swig_mark_arg(i);
102    } else if (!strcmp(argv[i], "-noswig-lisp")) {
103      no_swig_lisp = true;
104      Swig_mark_arg(i);
105    }
106
107  }
108  f_clhead = NewString("");
109  f_clwrap = NewString("");
110  f_cl = NewString("");
111
112  allow_overloading();
113}
114
115int CFFI::top(Node *n) {
116  File *f_null = NewString("");
117  module = Getattr(n, "name");
118
119  String *cxx_filename = Getattr(n, "outfile");
120  String *lisp_filename = NewString("");
121
122  Printf(lisp_filename, "%s%s.lisp", SWIG_output_directory(), module);
123
124  File *f_lisp = NewFile(lisp_filename, "w", SWIG_output_files());
125  if (!f_lisp) {
126    FileErrorDisplay(lisp_filename);
127    SWIG_exit(EXIT_FAILURE);
128  }
129
130  if (CPlusPlus || CWrap) {
131    f_begin = NewFile(cxx_filename, "w", SWIG_output_files());
132    if (!f_begin) {
133      Close(f_lisp);
134      Delete(f_lisp);
135      Printf(stderr, "Unable to open %s for writing\n", cxx_filename);
136      SWIG_exit(EXIT_FAILURE);
137    }
138
139    String *clos_filename = NewString("");
140    Printf(clos_filename, "%s%s-clos.lisp", SWIG_output_directory(), module);
141    f_clos = NewFile(clos_filename, "w", SWIG_output_files());
142    if (!f_clos) {
143      Close(f_lisp);
144      Delete(f_lisp);
145      Printf(stderr, "Unable to open %s for writing\n", cxx_filename);
146      SWIG_exit(EXIT_FAILURE);
147    }
148  } else {
149    f_begin = NewString("");
150    f_clos = NewString("");
151  }
152
153  f_runtime = NewString("");
154  f_cxx_header = f_runtime;
155  f_cxx_wrapper = NewString("");
156
157  Swig_register_filebyname("header", f_cxx_header);
158  Swig_register_filebyname("wrapper", f_cxx_wrapper);
159  Swig_register_filebyname("begin", f_begin);
160  Swig_register_filebyname("runtime", f_runtime);
161  Swig_register_filebyname("lisphead", f_clhead);
162  if (!no_swig_lisp)
163    Swig_register_filebyname("swiglisp", f_cl);
164  else
165    Swig_register_filebyname("swiglisp", f_null);
166
167  Swig_banner(f_begin);
168
169  Printf(f_runtime, "\n");
170  Printf(f_runtime, "#define SWIGCFFI\n");
171  Printf(f_runtime, "\n");
172
173  Swig_banner_target_lang(f_lisp, ";;;");
174
175  Language::top(n);
176  Printf(f_lisp, "%s\n", f_clhead);
177  Printf(f_lisp, "%s\n", f_cl);
178  Printf(f_lisp, "%s\n", f_clwrap);
179
180  Close(f_lisp);
181  Delete(f_lisp);   // Deletes the handle, not the file
182  Delete(f_cl);
183  Delete(f_clhead);
184  Delete(f_clwrap);
185  Dump(f_runtime, f_begin);
186  Close(f_begin);
187  Delete(f_runtime);
188  Delete(f_begin);
189  Delete(f_cxx_wrapper);
190  Delete(f_null);
191
192  return SWIG_OK;
193}
194
195int CFFI::classHandler(Node *n) {
196#ifdef CFFI_DEBUG
197  Printf(stderr, "class %s::%s\n", "some namespace",  //current_namespace,
198   Getattr(n, "sym:name"));
199#endif
200  String *name = Getattr(n, "sym:name");
201  String *kind = Getattr(n, "kind");
202
203  // maybe just remove this check and get rid of the else clause below.
204  if (Strcmp(kind, "struct") == 0) {
205    emit_struct_union(n, false);
206    return SWIG_OK;
207  } else if (Strcmp(kind, "union") == 0) {
208    emit_struct_union(n, true);
209    return SWIG_OK;
210  } else if (Strcmp(kind, "class") == 0) {
211    emit_class(n);
212    Language::classHandler(n);
213  } else {
214    Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind);
215    Printf(stderr, " (name: %s)\n", name);
216    SWIG_exit(EXIT_FAILURE);
217    return SWIG_OK;
218  }
219
220  return SWIG_OK;
221}
222
223int CFFI::constructorHandler(Node *n) {
224#ifdef CFFI_DEBUG
225  Printf(stderr, "constructor %s\n", Getattr(n, "name"));
226  Printf(stderr, "constructor %s\n and %s and %s", Getattr(n, "kind"), Getattr(n, "sym:name"), Getattr(n, "allegrocl:old-sym:name"));
227#endif
228  Setattr(n, "cffi:constructorfunction", "1");
229  // Let SWIG generate a global forwarding function.
230  return Language::constructorHandler(n);
231}
232
233int CFFI::destructorHandler(Node *n) {
234#ifdef CFFI_DEBUG
235  Printf(stderr, "destructor %s\n", Getattr(n, "name"));
236#endif
237
238  // Let SWIG generate a global forwarding function.
239  return Language::destructorHandler(n);
240}
241
242void CFFI::emit_defmethod(Node *n) {
243  String *args_placeholder = NewStringf("");
244  String *args_call = NewStringf("");
245
246  ParmList *pl = Getattr(n, "parms");
247  int argnum = 0;
248  Node *parent = getCurrentClass();
249  bool first = 0;
250
251  for (Parm *p = pl; p; p = nextSibling(p), argnum++) {
252    String *argname = Getattr(p, "name");
253    String *ffitype = Swig_typemap_lookup("lispclass", p, "", 0);
254
255    int tempargname = 0;
256
257    if(!first)
258      first = true;
259    else
260      Printf(args_placeholder, " ");
261
262    if (!argname) {
263      argname = NewStringf("arg%d", argnum);
264      tempargname = 1;
265    } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) {
266      argname = NewStringf("t-arg%d", argnum);
267      tempargname = 1;
268    }
269    if (Len(ffitype) > 0)
270      Printf(args_placeholder, "(%s %s)", argname, ffitype);
271    else
272      Printf(args_placeholder, "%s", argname);
273
274    if (ffitype && Strcmp(ffitype, lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'classname")) == 0)
275      Printf(args_call, " (ff-pointer %s)", argname);
276    else
277      Printf(args_call, " %s", argname);
278
279    Delete(ffitype);
280
281    if (tempargname)
282      Delete(argname);
283  }
284
285  String *method_name = Getattr(n, "name");
286  int x = Replace(method_name, "operator ", "", DOH_REPLACE_FIRST); //
287
288  if (x == 1)
289    Printf(f_clos, "(cl:shadow \"%s\")\n", method_name);
290
291  Printf(f_clos, "(cl:defmethod %s (%s)\n  (%s%s))\n\n",
292         lispify_name(n, lispy_name(Char(method_name)), "'method"), args_placeholder,
293         lispify_name(n, Getattr(n, "sym:name"), "'function"), args_call);
294
295}
296
297void CFFI::emit_initialize_instance(Node *n) {
298  String *args_placeholder = NewStringf("");
299  String *args_call = NewStringf("");
300
301  ParmList *pl = Getattr(n, "parms");
302  int argnum = 0;
303  Node *parent = getCurrentClass();
304
305  for (Parm *p = pl; p; p = nextSibling(p), argnum++) {
306    String *argname = Getattr(p, "name");
307    String *ffitype = Swig_typemap_lookup("lispclass", p, "", 0);
308
309    int tempargname = 0;
310    if (!argname) {
311      argname = NewStringf("arg%d", argnum);
312      tempargname = 1;
313    } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) {
314      argname = NewStringf("t-arg%d", argnum);
315      tempargname = 1;
316    }
317    if (Len(ffitype) > 0)
318      Printf(args_placeholder, " (%s %s)", argname, ffitype);
319    else
320      Printf(args_placeholder, " %s", argname);
321
322    if (Strcmp(ffitype, lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'classname")) == 0)
323      Printf(args_call, " (ff-pointer %s)", argname);
324    else
325      Printf(args_call, " %s", argname);
326
327    Delete(ffitype);
328
329    if (tempargname)
330      Delete(argname);
331  }
332
333  Printf(f_clos, "(cl:defmethod initialize-instance :after ((obj %s) &key%s)\n  (setf (slot-value obj 'ff-pointer) (%s%s)))\n\n",
334         lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), args_placeholder,
335         lispify_name(n, Getattr(n, "sym:name"), "'function"), args_call);
336
337}
338
339void CFFI::emit_setter(Node *n) {
340  Node *parent = getCurrentClass();
341  Printf(f_clos, "(cl:defmethod (cl:setf %s) (arg0 (obj %s))\n  (%s (ff-pointer obj) arg0))\n\n",
342         lispify_name(n, Getattr(n, "name"), "'method"),
343         lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), lispify_name(n, Getattr(n, "sym:name"), "'function"));
344}
345
346
347void CFFI::emit_getter(Node *n) {
348  Node *parent = getCurrentClass();
349  Printf(f_clos, "(cl:defmethod %s ((obj %s))\n  (%s (ff-pointer obj)))\n\n",
350         lispify_name(n, Getattr(n, "name"), "'method"),
351         lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), lispify_name(n, Getattr(n, "sym:name"), "'function"));
352}
353
354int CFFI::memberfunctionHandler(Node *n) {
355  // Let SWIG generate a global forwarding function.
356  Setattr(n, "cffi:memberfunction", "1");
357  return Language::memberfunctionHandler(n);
358}
359
360int CFFI::membervariableHandler(Node *n) {
361  // Let SWIG generate a get/set function pair.
362  Setattr(n, "cffi:membervariable", "1");
363  return Language::membervariableHandler(n);
364}
365
366int CFFI::functionWrapper(Node *n) {
367
368  ParmList *parms = Getattr(n, "parms");
369  String *iname = Getattr(n, "sym:name");
370  Wrapper *f = NewWrapper();
371
372  String *raw_return_type = Swig_typemap_lookup("ctype", n, "", 0);
373  SwigType *return_type = Swig_cparse_type(raw_return_type);
374  SwigType *resolved = SwigType_typedef_resolve_all(return_type);
375  int is_void_return = (Cmp(resolved, "void") == 0);
376  Delete(resolved);
377
378  if (!is_void_return) {
379    String *lresult_init = NewStringf("lresult = (%s)0", raw_return_type);
380    Wrapper_add_localv(f, "lresult", raw_return_type, lresult_init, NIL);
381    Delete(lresult_init);
382  }
383
384  String *overname = 0;
385  if (Getattr(n, "sym:overloaded")) {
386    overname = Getattr(n, "sym:overname");
387  } else {
388    if (!addSymbol(iname, n)) {
389      DelWrapper(f);
390      return SWIG_ERROR;
391    }
392  }
393
394  String *wname = Swig_name_wrapper(iname);
395  if (overname) {
396    Append(wname, overname);
397  }
398  Setattr(n, "wrap:name", wname);
399
400  // Emit all of the local variables for holding arguments.
401  emit_parameter_variables(parms, f);
402
403  // Attach the standard typemaps
404  Swig_typemap_attach_parms("ctype", parms, f);
405  emit_attach_parmmaps(parms, f);
406
407  int num_arguments = emit_num_arguments(parms);
408  String *name_and_parms = NewStringf("%s (", wname);
409  int i;
410  Parm *p;
411  int gencomma = 0;
412
413#ifdef CFFI_DEBUG
414  Printf(stderr, "function  -  %s - %d\n", Getattr(n, "name"), num_arguments);
415#endif
416
417  for (i = 0, p = parms; i < num_arguments; i++) {
418
419    while (checkAttribute(p, "tmap:in:numinputs", "0")) {
420      p = Getattr(p, "tmap:in:next");
421    }
422
423    SwigType *c_parm_type = Swig_cparse_type(Getattr(p, "tmap:ctype"));
424    String *arg = NewStringf("l%s", Getattr(p, "lname"));
425
426    // Emit parameter declaration
427    if (gencomma)
428      Printf(name_and_parms, ", ");
429    String *parm_decl = SwigType_str(c_parm_type, arg);
430    Printf(name_and_parms, "%s", parm_decl);
431#ifdef CFFI_DEBUG
432    Printf(stderr, "  param: %s\n", parm_decl);
433#endif
434    Delete(parm_decl);
435    gencomma = 1;
436
437    // Emit parameter conversion code
438    String *parm_code = Getattr(p, "tmap:in");
439    {
440      Replaceall(parm_code, "$input", arg);
441      Setattr(p, "emit:input", arg);
442      Printf(f->code, "%s\n", parm_code);
443      p = Getattr(p, "tmap:in:next");
444    }
445
446    Delete(arg);
447  }
448  Printf(name_and_parms, ")");
449
450  // Emit the function definition
451  String *signature = SwigType_str(return_type, name_and_parms);
452  Printf(f->def, "EXPORT %s {", signature);
453  Printf(f->code, "  try {\n");
454
455  String *actioncode = emit_action(n);
456
457  String *result_convert = Swig_typemap_lookup_out("out", n, "result", f, actioncode);
458  Replaceall(result_convert, "$result", "lresult");
459  Printf(f->code, "%s\n", result_convert);
460  if(!is_void_return) Printf(f->code, "    return lresult;\n");
461  Delete(result_convert);
462  emit_return_variable(n, Getattr(n, "type"), f);
463
464  Printf(f->code, "  } catch (...) {\n");
465  if (!is_void_return)
466    Printf(f->code, "    return (%s)0;\n", raw_return_type);
467  Printf(f->code, "  }\n");
468  Printf(f->code, "}\n");
469
470  if (CPlusPlus)
471    Wrapper_print(f, f_runtime);
472
473  if (CPlusPlus) {
474    emit_defun(n, wname);
475    if (Getattr(n, "cffi:memberfunction"))
476      emit_defmethod(n);
477    else if (Getattr(n, "cffi:membervariable")) {
478      if (Getattr(n, "memberget"))
479        emit_getter(n);
480      else if (Getattr(n, "memberset"))
481        emit_setter(n);
482    }
483    else if (Getattr(n, "cffi:constructorfunction")) {
484      emit_initialize_instance(n);
485    }
486  } else
487    emit_defun(n, iname);
488
489  //   if (!overloaded || !Getattr(n, "sym:nextSibling")) {
490  //     update_package_if_needed(n);
491  //     emit_buffered_defuns(n);
492  //     // this is the last overload.
493  //     if (overloaded) {
494  //       emit_dispatch_defun(n);
495  //     }
496  //   }
497
498  Delete(wname);
499  DelWrapper(f);
500
501  return SWIG_OK;
502}
503
504
505void CFFI::emit_defun(Node *n, String *name) {
506
507  //   String *storage=Getattr(n,"storage");
508  //   if(!storage || (Strcmp(storage,"extern") && Strcmp(storage,"externc")))
509  //     return SWIG_OK;
510
511  String *func_name = Getattr(n, "sym:name");
512
513  ParmList *pl = Getattr(n, "parms");
514
515  int argnum = 0;
516
517  func_name = lispify_name(n, func_name, "'function");
518
519  emit_inline(n, func_name);
520
521  Printf(f_cl, "\n(cffi:defcfun (\"%s\" %s)", name, func_name);
522  String *ffitype = Swig_typemap_lookup("cout", n, ":pointer", 0);
523
524  Printf(f_cl, " %s", ffitype);
525  Delete(ffitype);
526
527  for (Parm *p = pl; p; p = nextSibling(p), argnum++) {
528
529    if (SwigType_isvarargs(Getattr(p, "type"))) {
530      Printf(f_cl, "\n  %s", NewString("&rest"));
531      continue;
532    }
533
534    String *argname = Getattr(p, "name");
535
536    ffitype = Swig_typemap_lookup("cin", p, "", 0);
537
538    int tempargname = 0;
539    if (!argname) {
540
541      argname = NewStringf("arg%d", argnum);
542      tempargname = 1;
543    } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) {
544      argname = NewStringf("t_arg%d", argnum);
545      tempargname = 1;
546    }
547
548    Printf(f_cl, "\n  (%s %s)", argname, ffitype);
549
550    Delete(ffitype);
551
552    if (tempargname)
553      Delete(argname);
554  }
555  Printf(f_cl, ")\n");    /* finish arg list */
556
557  emit_export(n, func_name);
558}
559
560
561int CFFI::constantWrapper(Node *n) {
562  String *type = Getattr(n, "type");
563  String *converted_value = convert_literal(Getattr(n, "value"), type);
564  String *name = lispify_name(n, Getattr(n, "sym:name"), "'constant");
565
566  if (Strcmp(name, "t") == 0 || Strcmp(name, "T") == 0)
567    name = NewStringf("t_var");
568
569  Printf(f_cl, "\n(cl:defconstant %s %s)\n", name, converted_value);
570  Delete(converted_value);
571
572  emit_export(n, name);
573  return SWIG_OK;
574}
575
576int CFFI::variableWrapper(Node *n) {
577  //  String *storage=Getattr(n,"storage");
578  //  Printf(stdout,"\"%s\" %s)\n",storage,Getattr(n, "sym:name"));
579
580  //  if(!storage || (Strcmp(storage,"extern") && Strcmp(storage,"externc")))
581  //    return SWIG_OK;
582
583  String *var_name = Getattr(n, "sym:name");
584  String *lisp_type = Swig_typemap_lookup("cin", n, "", 0);
585  String *lisp_name = lispify_name(n, var_name, "'variable");
586
587  if (Strcmp(lisp_name, "t") == 0 || Strcmp(lisp_name, "T") == 0)
588    lisp_name = NewStringf("t_var");
589
590  Printf(f_cl, "\n(cffi:defcvar (\"%s\" %s)\n %s)\n", var_name, lisp_name, lisp_type);
591
592  Delete(lisp_type);
593
594  emit_export(n, lisp_name);
595  return SWIG_OK;
596}
597
598int CFFI::typedefHandler(Node *n) {
599  if (generate_typedef_flag && strncmp(Char(Getattr(n, "type")), "enum", 4)) {
600    String *lisp_name = lispify_name(n, Getattr(n, "name"), "'typename");
601    Printf(f_cl, "\n(cffi:defctype %s %s)\n", lisp_name, Swig_typemap_lookup("cin", n, "", 0));
602    emit_export(n, lisp_name);
603  }
604  return Language::typedefHandler(n);
605}
606
607int CFFI::enumDeclaration(Node *n) {
608  String *name = Getattr(n, "sym:name");
609  bool slot_name_keywords;
610  String *lisp_name = 0;
611  if (name && Len(name) != 0) {
612    lisp_name = lispify_name(n, name, "'enumname");
613    if (GetFlag(n, "feature:bitfield")) {
614      Printf(f_cl, "\n(cffi:defbitfield %s", lisp_name);
615    } else {
616      Printf(f_cl, "\n(cffi:defcenum %s", lisp_name);
617    }
618    slot_name_keywords = true;
619
620    //Registering the enum name to the cin and cout typemaps
621    Parm *pattern = NewParm(name, NULL);
622    Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL);
623    Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL);
624    Delete(pattern);
625    //Registering with the kind, i.e., enum
626    pattern = NewParm(NewStringf("enum %s", name), NULL);
627    Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL);
628    Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL);
629    Delete(pattern);
630
631  } else {
632    Printf(f_cl, "\n(defanonenum %s", name);
633    slot_name_keywords = false;
634  }
635
636  for (Node *c = firstChild(n); c; c = nextSibling(c)) {
637
638    String *slot_name = lispify_name(c, Getattr(c, "name"), "'enumvalue", slot_name_keywords);
639    String *value = Getattr(c, "enumvalue");
640
641    if (!value || GetFlag(n, "feature:bitfield:ignore_values"))
642      Printf(f_cl, "\n\t%s", slot_name);
643    else {
644      String *type = Getattr(c, "type");
645      String *converted_value = convert_literal(value, type);
646      Printf(f_cl, "\n\t(%s #.%s)", slot_name, converted_value);
647      Delete(converted_value);
648    }
649    Delete(value);
650  }
651
652  Printf(f_cl, ")\n");
653
654  // No need to export keywords
655  if (lisp_name && Len(lisp_name) != 0) {
656    emit_export(n, lisp_name);
657  } else {
658    for (Node *c = firstChild(n); c; c = nextSibling(c))
659      emit_export(c, lispify_name(c, Getattr(c, "name"), "'enumvalue"));
660  }
661
662  return SWIG_OK;
663}
664void CFFI::emit_class(Node *n) {
665
666#ifdef CFFI_WRAP_DEBUG
667  Printf(stderr, "emit_class: ENTER... '%s'(%x)\n", Getattr(n, "sym:name"), n);
668#endif
669
670  String *name = Getattr(n, "sym:name");
671  String *lisp_name = lispify_name(n, lispy_name(Char(name)), "'classname");
672
673  String *bases = Getattr(n, "bases");
674  String *supers = NewString("(");
675  if (bases) {
676    int first = 1;
677    for (Iterator i = First(bases); i.item; i = Next(i)) {
678      if (!first)
679  Printf(supers, " ");
680      String *s = Getattr(i.item, "name");
681      Printf(supers, "%s", lispify_name(i.item, s, "'classname"));
682    }
683  } else {
684    // Printf(supers,"ff:foreign-pointer");
685  }
686
687  Printf(supers, ")");
688  Printf(f_clos, "\n(cl:defclass %s%s", lisp_name, supers);
689  Printf(f_clos, "\n  ((ff-pointer :reader ff-pointer)))\n\n");
690
691  Parm *pattern = NewParm(Getattr(n, "name"), NULL);
692
693  Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL);
694  SwigType_add_pointer(Getattr(pattern, "type"));
695  Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL);
696  SwigType_add_qualifier(Getattr(pattern, "type"), "const");
697  Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL);
698  SwigType_del_pointer(Getattr(pattern, "type"));
699  SwigType_add_reference(Getattr(pattern, "type"));
700  Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL);
701
702#ifdef CFFI_WRAP_DEBUG
703  Printf(stderr, "  pattern %s  name %s .. ... %s .\n", pattern, lisp_name);
704#endif
705
706  Delete(pattern);
707
708  // Walk children to generate type definition.
709  String *slotdefs = NewString("   ");
710
711#ifdef CFFI_WRAP_DEBUG
712  Printf(stderr, "  walking children...\n");
713#endif
714
715  Node *c;
716  for (c = firstChild(n); c; c = nextSibling(c)) {
717    String *storage_type = Getattr(c, "storage");
718    if ((!Strcmp(nodeType(c), "cdecl") && (!storage_type || Strcmp(storage_type, "typedef")))) {
719      String *access = Getattr(c, "access");
720
721      // hack. why would decl have a value of "variableHandler" and now "0"?
722      String *childDecl = Getattr(c, "decl");
723      // Printf(stderr,"childDecl = '%s' (%s)\n", childDecl, Getattr(c,"view"));
724      if (!Strcmp(childDecl, "0"))
725  childDecl = NewString("");
726
727      SwigType *childType = NewStringf("%s%s", childDecl,
728               Getattr(c, "type"));
729      String *cname = (access && Strcmp(access, "public")) ? NewString("nil") : Copy(Getattr(c, "name"));
730
731      if (!SwigType_isfunction(childType)) {
732  // Printf(slotdefs, ";;; member functions don't appear as slots.\n ");
733  // Printf(slotdefs, ";; ");
734  //        String *ns = listify_namespace(Getattr(n, "cffi:package"));
735  String *ns = NewString("");
736#ifdef CFFI_WRAP_DEBUG
737  Printf(stderr, "slot name = '%s' ns = '%s' class-of '%s' and type = '%s'\n", cname, ns, name, childType);
738#endif
739  Printf(slotdefs, "(#.(swig-insert-id \"%s\" %s :type :slot :class \"%s\") %s)", cname, ns, name, childType);  //compose_foreign_type(childType)
740  Delete(ns);
741  if (access && Strcmp(access, "public"))
742    Printf(slotdefs, " ;; %s member", access);
743
744  Printf(slotdefs, "\n   ");
745      }
746      Delete(childType);
747      Delete(cname);
748    }
749  }
750
751
752  //   String *ns_list = listify_namespace(Getattr(n,"cffi:namespace"));
753  //   update_package_if_needed(n,f_clhead);
754  //   Printf(f_clos,
755  //          "(swig-def-foreign-class \"%s\"\n %s\n  (:%s\n%s))\n\n",
756  //          name, supers, kind, slotdefs);
757
758  Delete(supers);
759  //  Delete(ns_list);
760
761  //  Parm *pattern = NewParm(name,NULL);
762  // Swig_typemap_register("cin",pattern,lisp_name,NULL,NULL);
763  //Swig_typemap_register("cout",pattern,lisp_name,NULL,NULL);
764  //Delete(pattern);
765
766#ifdef CFFI_WRAP_DEBUG
767  Printf(stderr, "emit_class: EXIT\n");
768#endif
769}
770
771// Includes structs
772void CFFI::emit_struct_union(Node *n, bool un = false) {
773#ifdef CFFI_DEBUG
774  Printf(stderr, "struct/union %s\n", Getattr(n, "name"));
775  Printf(stderr, "struct/union %s\n and %s", Getattr(n, "kind"), Getattr(n, "sym:name"));
776#endif
777
778  String *name = Getattr(n, "sym:name");
779  String *kind = Getattr(n, "kind");
780
781  if (Strcmp(kind, "struct") != 0 && Strcmp(kind, "union") != 0) {
782    Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind);
783    Printf(stderr, " (name: %s)\n", name);
784    SWIG_exit(EXIT_FAILURE);
785  }
786  String *lisp_name = lispify_name(n, name, "'classname");
787
788  //Register the struct/union name to the cin and cout typemaps
789
790  Parm *pattern = NewParm(name, NULL);
791  Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL);
792  Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL);
793  Delete(pattern);
794  //Registering with the kind, i.e., struct or union
795  pattern = NewParm(NewStringf("%s %s", kind, name), NULL);
796  Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL);
797  Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL);
798  Delete(pattern);
799
800  if (un) {
801    Printf(f_cl, "\n(cffi:defcunion %s", lisp_name);
802  } else
803    Printf(f_cl, "\n(cffi:defcstruct %s", lisp_name);
804
805
806  for (Node *c = firstChild(n); c; c = nextSibling(c)) {
807#ifdef CFFI_DEBUG
808    Printf(stderr, "struct/union %s\n", Getattr(c, "name"));
809    Printf(stderr, "struct/union %s and %s \n", Getattr(c, "kind"), Getattr(c, "sym:name"));
810#endif
811
812    if (Strcmp(nodeType(c), "cdecl")) {
813      //C declaration ignore
814      //        Printf(stderr, "Structure %s has a slot that we can't deal with.\n",
815      //               name);
816      //        Printf(stderr, "nodeType: %s, name: %s, type: %s\n",
817      //               nodeType(c),
818      //               Getattr(c, "name"),
819      //               Getattr(c, "type"));
820      //       SWIG_exit(EXIT_FAILURE);
821    } else {
822      SwigType *childType = NewStringf("%s%s", Getattr(c, "decl"), Getattr(c, "type"));
823
824      Node *node = NewHash();
825      Setattr(node, "type", childType);
826      Setfile(node, Getfile(n));
827      Setline(node, Getline(n));
828      const String *tm = Swig_typemap_lookup("cin", node, "", 0);
829
830      String *typespec = tm ? NewString(tm) : NewString("");
831
832      String *slot_name = lispify_name(c, Getattr(c, "sym:name"), "'slotname");
833      if (Strcmp(slot_name, "t") == 0 || Strcmp(slot_name, "T") == 0)
834	slot_name = NewStringf("t_var");
835
836      Printf(f_cl, "\n\t(%s %s)", slot_name, typespec);
837
838      Delete(node);
839      Delete(childType);
840      Delete(typespec);
841    }
842  }
843
844  Printf(f_cl, ")\n");
845
846  emit_export(n, lisp_name);
847  for (Node *child = firstChild(n); child; child = nextSibling(child)) {
848    if (!Strcmp(nodeType(child), "cdecl")) {
849      emit_export(child, lispify_name(child, Getattr(child, "sym:name"), "'slotname"));
850    }
851  }
852
853  /* Add this structure to the known lisp types */
854  //Printf(stdout, "Adding %s foreign type\n", name);
855  //  add_defined_foreign_type(name);
856
857}
858
859void CFFI::emit_export(Node *n, String *name) {
860  if (GetInt(n, "feature:export"))
861    Printf(f_cl, "\n(cl:export '%s)\n", name);
862}
863
864void CFFI::emit_inline(Node *n, String *name) {
865  if (GetInt(n, "feature:inline"))
866    Printf(f_cl, "\n(cl:declaim (cl:inline %s))\n", name);
867}
868
869String *CFFI::lispify_name(Node *n, String *ty, const char *flag, bool kw) {
870  String *intern_func = Getattr(n, "feature:intern_function");
871  if (intern_func) {
872    if (Strcmp(intern_func, "1") == 0)
873      intern_func = NewStringf("swig-lispify");
874    return NewStringf("#.(%s \"%s\" %s%s)", intern_func, ty, flag, kw ? " :keyword" : "");
875  } else if (kw)
876    return NewStringf(":%s", ty);
877  else
878    return ty;
879}
880
881/* utilities */
882/* returns new string w/ parens stripped */
883String *CFFI::strip_parens(String *string) {
884  char *s = Char(string), *p;
885  int len = Len(string);
886  String *res;
887
888  if (len == 0 || s[0] != '(' || s[len - 1] != ')') {
889    return NewString(string);
890  }
891
892  p = (char *) malloc(len - 2 + 1);
893  if (!p) {
894    Printf(stderr, "Malloc failed\n");
895    SWIG_exit(EXIT_FAILURE);
896  }
897
898  strncpy(p, s + 1, len - 1);
899  p[len - 2] = 0;   /* null terminate */
900
901  res = NewString(p);
902  free(p);
903
904  return res;
905}
906
907String *CFFI::trim(String *str) {
908  char *c = Char(str);
909  while (*c != '\0' && isspace((int) *c))
910    ++c;
911  String *result = NewString(c);
912  Chop(result);
913  return result;
914}
915
916String *CFFI::infix_to_prefix(String *val, char split_op, const String *op, String *type) {
917  List *ored = Split(val, split_op, -1);
918
919  // some float hackery
920  //i don't understand it, if you do then please explain
921  //   if ( ((split_op == '+') || (split_op == '-')) && Len(ored) == 2 &&
922  //        (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE ||
923  //    SwigType_type(type) == T_LONGDOUBLE) ) {
924  //     // check that we're not splitting a float
925  //     String *possible_result = convert_literal(val, type, false);
926  //     if (possible_result) return possible_result;
927
928  //   }
929
930  // try parsing the split results. if any part fails, kick out.
931  bool part_failed = false;
932  if (Len(ored) > 1) {
933    String *result = NewStringf("(%s", op);
934    for (Iterator i = First(ored); i.item; i = Next(i)) {
935      String *converted = convert_literal(i.item, type);
936      if (converted) {
937  Printf(result, " %s", converted);
938  Delete(converted);
939      } else {
940  part_failed = true;
941  break;
942      }
943    }
944    Printf(result, ")");
945    Delete(ored);
946    return part_failed ? 0 : result;
947  } else {
948    Delete(ored);
949  }
950  return 0;
951}
952
953/* To be called by code generating the lisp interface
954   Will return a String containing the literal based on type.
955   Will return null if there are problems.
956
957   try_to_split defaults to true (see stub above).
958*/
959String *CFFI::convert_literal(String *literal, String *type, bool try_to_split) {
960  String *num_param = Copy(literal);
961  String *trimmed = trim(num_param);
962  String *num = strip_parens(trimmed), *res = 0;
963  Delete(trimmed);
964  char *s = Char(num);
965
966  // very basic parsing of infix expressions.
967  if (try_to_split) {
968    if ((res = infix_to_prefix(num, '|', "cl:logior", type)))
969      return res;
970    if ((res = infix_to_prefix(num, '&', "cl:logand", type)))
971      return res;
972    if ((res = infix_to_prefix(num, '^', "cl:logxor", type)))
973      return res;
974    if ((res = infix_to_prefix(num, '*', "cl:*", type)))
975      return res;
976    if ((res = infix_to_prefix(num, '/', "cl:/", type)))
977      return res;
978    if ((res = infix_to_prefix(num, '+', "cl:+", type)))
979      return res;
980    if ((res = infix_to_prefix(num, '-', "cl:-", type)))
981      return res;
982  }
983
984  if (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || SwigType_type(type) == T_LONGDOUBLE) {
985    // Use CL syntax for float literals
986
987    // careful. may be a float identifier or float constant.
988    char *num_start = Char(num);
989    char *num_end = num_start + strlen(num_start) - 1;
990
991    bool is_literal = isdigit(*num_start) || (*num_start == '.') || (*num_start == '+') || (*num_start == '-');
992
993    String *lisp_exp = 0;
994    if (is_literal) {
995      if (*num_end == 'f' || *num_end == 'F') {
996        lisp_exp = NewString("f");
997      } else {
998        lisp_exp = NewString("d");
999      }
1000
1001      if (*num_end == 'l' || *num_end == 'L' || *num_end == 'f' || *num_end == 'F') {
1002        *num_end = '\0';
1003        num_end--;
1004      }
1005
1006      int exponents = Replaceall(num, "e", lisp_exp) + Replaceall(num, "E", lisp_exp);
1007
1008      if (!exponents)
1009        Printf(num, "%s0", lisp_exp);
1010
1011      if (exponents > 1 || (exponents + Replaceall(num, ".", ".") == 0)) {
1012        Delete(num);
1013        num = 0;
1014      }
1015    }
1016    return num;
1017  } else if (SwigType_type(type) == T_CHAR) {
1018    /* Use CL syntax for character literals */
1019    String* result = NewStringf("#\\%c", s[2]);
1020    Delete(num);
1021    //    Printf(stderr, "%s  %c %d", s, s[2], s);
1022    return result;
1023  } else if (SwigType_type(type) == T_STRING) {
1024    /* Use CL syntax for string literals */
1025    String* result = NewStringf("\"%s\"", num_param);
1026    Delete(num);
1027    return result;
1028  } else if (SwigType_type(type) == T_INT || SwigType_type(type) == T_UINT) {
1029    // Printf(stderr, "Is a T_INT or T_UINT %s, before replaceall\n", s);
1030    Replaceall(num, "u", "");
1031    Replaceall(num, "U", "");
1032    Replaceall(num, "l", "");
1033    Replaceall(num, "L", "");
1034
1035    int i, j;
1036    if (sscanf(s, "%d >> %d", &i, &j) == 2) {
1037      String* result = NewStringf("(cl:ash %d -%d)", i, j);
1038      Delete(num);
1039      return result;
1040    } else if (sscanf(s, "%d << %d", &i, &j) == 2) {
1041      String* result = NewStringf("(cl:ash %d %d)", i, j);
1042      Delete(num);
1043      return result;
1044    }
1045  }
1046
1047  if (Len(num) >= 2 && s[0] == '0') { /* octal or hex */
1048    if (s[1] == 'x'){
1049      DohReplace(num,"0","#",DOH_REPLACE_FIRST);
1050    }
1051    else{
1052      DohReplace(num,"0","#o",DOH_REPLACE_FIRST);
1053    }
1054  }
1055  return num;
1056}
1057
1058//less flexible as it does the conversion in C, the lispify name does the conversion in lisp
1059String *CFFI::lispy_name(char *name) {
1060  bool helper = false;
1061  String *new_name = NewString("");
1062  for (unsigned int i = 0; i < strlen(name); i++) {
1063    if (name[i] == '_' || name[i] == '-') {
1064      Printf(new_name, "%c", '-');
1065      helper = false;
1066    } else if (name[i] >= 'A' && name[i] <= 'Z') {
1067      if (helper)
1068  Printf(new_name, "%c", '-');
1069      Printf(new_name, "%c", ('a' + (name[i] - 'A')));
1070      helper = false;
1071    } else {
1072      helper = true;
1073      Printf(new_name, "%c", name[i]);
1074    }
1075  }
1076  return new_name;
1077}
1078
1079extern "C" Language *swig_cffi(void) {
1080  return new CFFI();
1081}
1082