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 * pike.cxx
6 *
7 * Pike language module for SWIG.
8 * ----------------------------------------------------------------------------- */
9
10/*
11 * Notes:
12 *
13 * - The current approach used for "out" typemaps is inconsistent with
14 *   how "out" typemaps are handled by other language modules. Instead
15 *   of converting the C/C++ type ($1) to a Pike object type (e.g. a
16 *   struct svalue), we're just calling the appropriate push_XXX
17 *   (e.g. push_int) to push the return value onto the stack.
18 *
19 * - Pike classes can't have static member functions or data, so we need
20 *   to find some other appropriate mapping for C++ static member functions
21 *   and data.
22 *
23 * - Pike doesn't seem to provide any default way to print the memory
24 *   address, etc. for extension objects. Should we do something here?
25 *
26 */
27
28char cvsroot_pike_cxx[] = "$Id: pike.cxx 11133 2009-02-20 07:52:24Z wsfulton $";
29
30#include "swigmod.h"
31
32#include <ctype.h>		// for isalnum()
33
34static const char *usage = (char *) "\
35Pike Options (available with -pike)\n\
36     [None]\n\
37\n";
38
39class PIKE:public Language {
40private:
41
42  File *f_begin;
43  File *f_runtime;
44  File *f_header;
45  File *f_wrappers;
46  File *f_init;
47  File *f_classInit;
48
49  String *PrefixPlusUnderscore;
50  int current;
51
52  // Wrap modes
53  enum {
54    NO_CPP,
55    MEMBER_FUNC,
56    CONSTRUCTOR,
57    DESTRUCTOR,
58    MEMBER_VAR,
59    CLASS_CONST,
60    STATIC_FUNC,
61    STATIC_VAR
62  };
63
64public:
65
66  /* ---------------------------------------------------------------------
67   * PIKE()
68   *
69   * Initialize member data
70   * --------------------------------------------------------------------- */
71
72   PIKE() {
73    f_begin = 0;
74    f_runtime = 0;
75    f_header = 0;
76    f_wrappers = 0;
77    f_init = 0;
78    f_classInit = 0;
79    PrefixPlusUnderscore = 0;
80    current = NO_CPP;
81  }
82
83  /* ---------------------------------------------------------------------
84   * main()
85   *
86   * Parse command line options and initializes variables.
87   * --------------------------------------------------------------------- */
88
89   virtual void main(int argc, char *argv[]) {
90
91    /* Set location of SWIG library */
92    SWIG_library_directory("pike");
93
94    /* Look for certain command line options */
95    for (int i = 1; i < argc; i++) {
96      if (argv[i]) {
97	if (strcmp(argv[i], "-help") == 0) {
98	  fputs(usage, stdout);
99	}
100      }
101    }
102
103    /* Add a symbol to the parser for conditional compilation */
104    Preprocessor_define("SWIGPIKE 1", 0);
105
106    /* Set language-specific configuration file */
107    SWIG_config_file("pike.swg");
108
109    /* Set typemap language */
110    SWIG_typemap_lang("pike");
111
112    /* Enable overloaded methods support */
113    allow_overloading();
114  }
115
116  /* ---------------------------------------------------------------------
117   * top()
118   * --------------------------------------------------------------------- */
119
120  virtual int top(Node *n) {
121    /* Get the module name */
122    String *module = Getattr(n, "name");
123
124    /* Get the output file name */
125    String *outfile = Getattr(n, "outfile");
126
127    /* Open the output file */
128    f_begin = NewFile(outfile, "w", SWIG_output_files());
129    if (!f_begin) {
130      FileErrorDisplay(outfile);
131      SWIG_exit(EXIT_FAILURE);
132    }
133    f_runtime = NewString("");
134    f_init = NewString("");
135    f_classInit = NewString("");
136    f_header = NewString("");
137    f_wrappers = NewString("");
138
139    /* Register file targets with the SWIG file handler */
140    Swig_register_filebyname("header", f_header);
141    Swig_register_filebyname("wrapper", f_wrappers);
142    Swig_register_filebyname("begin", f_begin);
143    Swig_register_filebyname("runtime", f_runtime);
144    Swig_register_filebyname("init", f_init);
145    Swig_register_filebyname("classInit", f_classInit);
146
147    /* Standard stuff for the SWIG runtime section */
148    Swig_banner(f_begin);
149
150    Printf(f_runtime, "\n");
151    Printf(f_runtime, "#define SWIGPIKE\n");
152    Printf(f_runtime, "\n");
153
154    Printf(f_header, "#define SWIG_init    pike_module_init\n");
155    Printf(f_header, "#define SWIG_name    \"%s\"\n\n", module);
156
157    /* Change naming scheme for constructors and destructors */
158    Swig_name_register("construct", "%c_create");
159    Swig_name_register("destroy", "%c_destroy");
160
161    /* Current wrap type */
162    current = NO_CPP;
163
164    /* Emit code for children */
165    Language::top(n);
166
167    /* Close the initialization function */
168    Printf(f_init, "}\n");
169    SwigType_emit_type_table(f_runtime, f_wrappers);
170
171    /* Close all of the files */
172    Dump(f_runtime, f_begin);
173    Dump(f_header, f_begin);
174    Dump(f_wrappers, f_begin);
175    Wrapper_pretty_print(f_init, f_begin);
176
177    Delete(f_header);
178    Delete(f_wrappers);
179    Delete(f_init);
180    Delete(f_classInit);
181
182    Close(f_begin);
183    Delete(f_runtime);
184    Delete(f_begin);
185
186    /* Done */
187    return SWIG_OK;
188  }
189
190  /* ------------------------------------------------------------
191   * validIdentifier()
192   * ------------------------------------------------------------ */
193
194  virtual int validIdentifier(String *s) {
195    char *c = Char(s);
196    const char *c0 = c;
197    const char *c1 = c0 + 1;
198    while (*c) {
199      if (*c == '`' && c == c0) {
200	c++;
201	continue;
202      }
203      if ((*c == '+' || *c == '-' || *c == '*' || *c == '/') && c == c1) {
204	c++;
205	continue;
206      }
207      if (!(isalnum(*c) || (*c == '_')))
208	return 0;
209      c++;
210    }
211    return 1;
212  }
213
214  /* ------------------------------------------------------------
215   * importDirective()
216   * ------------------------------------------------------------ */
217
218  virtual int importDirective(Node *n) {
219    String *modname = Getattr(n, "module");
220    if (modname) {
221      Printf(f_init, "pike_require(\"%s\");\n", modname);
222    }
223    return Language::importDirective(n);
224  }
225
226  /* ------------------------------------------------------------
227   * strip()
228   *
229   * For names that begin with the current class prefix plus an
230   * underscore (e.g. "Foo_enum_test"), return the base function
231   * name (i.e. "enum_test").
232   * ------------------------------------------------------------ */
233
234  String *strip(const DOHconst_String_or_char_ptr name) {
235    String *s = Copy(name);
236    if (Strncmp(name, PrefixPlusUnderscore, Len(PrefixPlusUnderscore)) != 0) {
237      return s;
238    }
239    Replaceall(s, PrefixPlusUnderscore, "");
240    return s;
241  }
242
243  /* ------------------------------------------------------------
244   * add_method()
245   * ------------------------------------------------------------ */
246
247  void add_method(const DOHconst_String_or_char_ptr name, const DOHconst_String_or_char_ptr function, const DOHconst_String_or_char_ptr description) {
248    String *rename = NULL;
249    switch (current) {
250    case NO_CPP:
251      rename = NewString(name);
252      Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description);
253      break;
254    case STATIC_FUNC:
255    case STATIC_VAR:
256      rename = NewString(name);
257      Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description);
258      break;
259    case CONSTRUCTOR:
260    case DESTRUCTOR:
261    case MEMBER_FUNC:
262    case MEMBER_VAR:
263      rename = strip(name);
264      Printf(f_classInit, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description);
265      break;
266    case CLASS_CONST:
267      assert(false);		// shouldn't have gotten here for CLASS_CONST nodes
268    default:
269      assert(false);		// what is this?
270    }
271    Delete(rename);
272  }
273
274  /* ---------------------------------------------------------------------
275   * functionWrapper()
276   *
277   * Create a function declaration and register it with the interpreter.
278   * --------------------------------------------------------------------- */
279
280  virtual int functionWrapper(Node *n) {
281
282    String *name = Getattr(n, "name");
283    String *iname = Getattr(n, "sym:name");
284    SwigType *d = Getattr(n, "type");
285    ParmList *l = Getattr(n, "parms");
286
287    Parm *p;
288    String *tm;
289    int i;
290
291    String *overname = 0;
292    if (Getattr(n, "sym:overloaded")) {
293      overname = Getattr(n, "sym:overname");
294    } else {
295      if (!addSymbol(iname, n))
296	return SWIG_ERROR;
297    }
298
299    Wrapper *f = NewWrapper();
300
301    // Emit all of the local variables for holding arguments.
302    emit_parameter_variables(l, f);
303
304    /* Attach the standard typemaps */
305    emit_attach_parmmaps(l, f);
306    Setattr(n, "wrap:parms", l);
307
308    /* Get number of required and total arguments */
309    int num_arguments = emit_num_arguments(l);
310    int varargs = emit_isvarargs(l);
311
312    /* Which input argument to start with? */
313    int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0;
314
315    /* Offset to skip over the attribute name */
316    // int offset = (current == MEMBER_VAR) ? 1 : 0;
317    int offset = 0;
318
319    String *wname = Swig_name_wrapper(iname);
320    if (overname) {
321      Append(wname, overname);
322    }
323    Setattr(n, "wrap:name", wname);
324
325    Printv(f->def, "static void ", wname, "(INT32 args) {", NIL);
326
327    /* Generate code for argument marshalling */
328    String *description = NewString("");
329    char source[64];
330    for (i = 0, p = l; i < num_arguments; i++) {
331
332      while (checkAttribute(p, "tmap:in:numinputs", "0")) {
333	p = Getattr(p, "tmap:in:next");
334      }
335
336      SwigType *pt = Getattr(p, "type");
337      String *ln = Getattr(p, "lname");
338
339      if (i < start) {
340	String *lstr = SwigType_lstr(pt, 0);
341	Printf(f->code, "%s = (%s) THIS;\n", ln, lstr);
342	Delete(lstr);
343      } else {
344	/* Look for an input typemap */
345	sprintf(source, "Pike_sp[%d-args]", i - start + offset);
346	if ((tm = Getattr(p, "tmap:in"))) {
347	  Replaceall(tm, "$source", source);
348	  Replaceall(tm, "$target", ln);
349	  Replaceall(tm, "$input", source);
350	  Setattr(p, "emit:input", source);
351	  Printf(f->code, "%s\n", tm);
352	  String *pikedesc = Getattr(p, "tmap:in:pikedesc");
353	  if (pikedesc) {
354	    Printv(description, pikedesc, " ", NIL);
355	  }
356	  p = Getattr(p, "tmap:in:next");
357	  continue;
358	} else {
359	  Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0));
360	  break;
361	}
362      }
363      p = nextSibling(p);
364    }
365
366    /* Check for trailing varargs */
367    if (varargs) {
368      if (p && (tm = Getattr(p, "tmap:in"))) {
369	Replaceall(tm, "$input", "varargs");
370	Printv(f->code, tm, "\n", NIL);
371      }
372    }
373
374    /* Insert constraint checking code */
375    for (p = l; p;) {
376      if ((tm = Getattr(p, "tmap:check"))) {
377	Replaceall(tm, "$target", Getattr(p, "lname"));
378	Printv(f->code, tm, "\n", NIL);
379	p = Getattr(p, "tmap:check:next");
380      } else {
381	p = nextSibling(p);
382      }
383    }
384
385    /* Insert cleanup code */
386    String *cleanup = NewString("");
387    for (p = l; p;) {
388      if ((tm = Getattr(p, "tmap:freearg"))) {
389	Replaceall(tm, "$source", Getattr(p, "lname"));
390	Printv(cleanup, tm, "\n", NIL);
391	p = Getattr(p, "tmap:freearg:next");
392      } else {
393	p = nextSibling(p);
394      }
395    }
396
397    /* Insert argument output code */
398    String *outarg = NewString("");
399    for (p = l; p;) {
400      if ((tm = Getattr(p, "tmap:argout"))) {
401	Replaceall(tm, "$source", Getattr(p, "lname"));
402	Replaceall(tm, "$target", "resultobj");
403	Replaceall(tm, "$arg", Getattr(p, "emit:input"));
404	Replaceall(tm, "$input", Getattr(p, "emit:input"));
405	Printv(outarg, tm, "\n", NIL);
406	p = Getattr(p, "tmap:argout:next");
407      } else {
408	p = nextSibling(p);
409      }
410    }
411
412    /* Emit the function call */
413    String *actioncode = emit_action(n);
414
415    /* Clear the return stack */
416    Printf(actioncode, "pop_n_elems(args);\n");
417
418    /* Return the function value */
419    if (current == CONSTRUCTOR) {
420      Printv(actioncode, "THIS = (void *) result;\n", NIL);
421      Printv(description, ", tVoid", NIL);
422    } else if (current == DESTRUCTOR) {
423      Printv(description, ", tVoid", NIL);
424    } else {
425      Printv(description, ", ", NIL);
426      if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) {
427        actioncode = 0;
428	Replaceall(tm, "$source", "result");
429	Replaceall(tm, "$target", "resultobj");
430	Replaceall(tm, "$result", "resultobj");
431	if (GetFlag(n, "feature:new")) {
432	  Replaceall(tm, "$owner", "1");
433	} else {
434	  Replaceall(tm, "$owner", "0");
435	}
436	String *pikedesc = Getattr(n, "tmap:out:pikedesc");
437	if (pikedesc) {
438	  Printv(description, pikedesc, NIL);
439	}
440	Printf(f->code, "%s\n", tm);
441      } else {
442	Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name);
443      }
444    }
445    if (actioncode) {
446      Append(f->code, actioncode);
447      Delete(actioncode);
448    }
449    emit_return_variable(n, d, f);
450
451    /* Output argument output code */
452    Printv(f->code, outarg, NIL);
453
454    /* Output cleanup code */
455    Printv(f->code, cleanup, NIL);
456
457    /* Look to see if there is any newfree cleanup code */
458    if (GetFlag(n, "feature:new")) {
459      if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) {
460	Replaceall(tm, "$source", "result");
461	Printf(f->code, "%s\n", tm);
462      }
463    }
464
465    /* See if there is any return cleanup code */
466    if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) {
467      Replaceall(tm, "$source", "result");
468      Printf(f->code, "%s\n", tm);
469    }
470
471    /* Close the function */
472    Printf(f->code, "}\n");
473
474    /* Substitute the cleanup code */
475    Replaceall(f->code, "$cleanup", cleanup);
476
477    /* Substitute the function name */
478    Replaceall(f->code, "$symname", iname);
479    Replaceall(f->code, "$result", "resultobj");
480
481    /* Dump the function out */
482    Wrapper_print(f, f_wrappers);
483
484    /* Now register the function with the interpreter. */
485    if (!Getattr(n, "sym:overloaded")) {
486      add_method(iname, wname, description);
487    } else {
488      if (!Getattr(n, "sym:nextSibling")) {
489	dispatchFunction(n);
490      }
491    }
492
493    Delete(cleanup);
494    Delete(outarg);
495    Delete(description);
496    Delete(wname);
497    DelWrapper(f);
498
499    return SWIG_OK;
500  }
501
502  /* ------------------------------------------------------------
503   * dispatchFunction()
504   *
505   * Emit overloading dispatch function
506   * ------------------------------------------------------------ */
507
508  void dispatchFunction(Node *n) {
509    /* Last node in overloaded chain */
510
511    int maxargs;
512    String *tmp = NewString("");
513    String *dispatch = Swig_overload_dispatch(n, "%s(args); return;", &maxargs);
514
515    /* Generate a dispatch wrapper for all overloaded functions */
516
517    Wrapper *f = NewWrapper();
518    String *symname = Getattr(n, "sym:name");
519    String *wname = Swig_name_wrapper(symname);
520
521    Printf(f->def, "static void %s(INT32 args) {", wname);
522
523    Wrapper_add_local(f, "argc", "INT32 argc");
524    Printf(tmp, "struct svalue argv[%d]", maxargs);
525    Wrapper_add_local(f, "argv", tmp);
526    Wrapper_add_local(f, "ii", "INT32 ii");
527
528    Printf(f->code, "argc = args;\n");
529    Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs);
530    Printf(f->code, "argv[ii] = Pike_sp[ii-args];\n");
531    Printf(f->code, "}\n");
532
533    Replaceall(dispatch, "$args", "self, args");
534    Printv(f->code, dispatch, "\n", NIL);
535    Printf(f->code, "Pike_error(\"No matching function for overloaded '%s'.\");\n", symname);
536    Printv(f->code, "}\n", NIL);
537
538    Wrapper_print(f, f_wrappers);
539
540    String *description = NewString("");
541    Printf(description, "tAny,");
542    if (current == CONSTRUCTOR || current == DESTRUCTOR) {
543      Printf(description, " tVoid");
544    } else {
545      String *pd = Getattr(n, "tmap:out:pikedesc");
546      if (pd)
547	Printf(description, " %s", pd);
548    }
549    add_method(symname, wname, description);
550    Delete(description);
551
552    DelWrapper(f);
553    Delete(dispatch);
554    Delete(tmp);
555    Delete(wname);
556  }
557
558  /* ------------------------------------------------------------
559   * variableWrapper()
560   * ------------------------------------------------------------ */
561
562  virtual int variableWrapper(Node *n) {
563    return Language::variableWrapper(n);
564  }
565
566  /* ------------------------------------------------------------
567   * constantWrapper()
568   * ------------------------------------------------------------ */
569
570  virtual int constantWrapper(Node *n) {
571
572    Swig_require("constantWrapper", n, "*sym:name", "type", "value", NIL);
573
574    String *symname = Getattr(n, "sym:name");
575    SwigType *type = Getattr(n, "type");
576    String *value = Getattr(n, "value");
577
578    /* Special hook for member pointer */
579    if (SwigType_type(type) == T_MPOINTER) {
580      String *wname = Swig_name_wrapper(symname);
581      Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value);
582      value = wname;
583    }
584
585    /* Perform constant typemap substitution */
586    String *tm = Swig_typemap_lookup("constant", n, value, 0);
587    if (tm) {
588      Replaceall(tm, "$source", value);
589      Replaceall(tm, "$target", symname);
590      Replaceall(tm, "$symname", symname);
591      Replaceall(tm, "$value", value);
592      Printf(f_init, "%s\n", tm);
593    } else {
594      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value %s = %s\n", SwigType_str(type, 0), value);
595    }
596
597    Swig_restore(n);
598
599    return SWIG_OK;
600  }
601
602  /* ------------------------------------------------------------
603   * nativeWrapper()
604   * ------------------------------------------------------------ */
605
606  virtual int nativeWrapper(Node *n) {
607    //   return Language::nativeWrapper(n);
608    String *name = Getattr(n, "sym:name");
609    String *wrapname = Getattr(n, "wrap:name");
610
611    if (!addSymbol(wrapname, n))
612      return SWIG_ERROR;
613
614    add_method(name, wrapname, 0);
615    return SWIG_OK;
616  }
617
618  /* ------------------------------------------------------------
619   * enumDeclaration()
620   * ------------------------------------------------------------ */
621
622  virtual int enumDeclaration(Node *n) {
623    return Language::enumDeclaration(n);
624  }
625
626  /* ------------------------------------------------------------
627   * enumvalueDeclaration()
628   * ------------------------------------------------------------ */
629
630  virtual int enumvalueDeclaration(Node *n) {
631    return Language::enumvalueDeclaration(n);
632  }
633
634  /* ------------------------------------------------------------
635   * classDeclaration()
636   * ------------------------------------------------------------ */
637
638  virtual int classDeclaration(Node *n) {
639    return Language::classDeclaration(n);
640  }
641
642  /* ------------------------------------------------------------
643   * classHandler()
644   * ------------------------------------------------------------ */
645
646  virtual int classHandler(Node *n) {
647
648    String *symname = Getattr(n, "sym:name");
649    if (!addSymbol(symname, n))
650      return SWIG_ERROR;
651
652    PrefixPlusUnderscore = NewStringf("%s_", getClassPrefix());
653
654    Printf(f_classInit, "start_new_program();\n");
655
656    /* Handle inheritance */
657    List *baselist = Getattr(n, "bases");
658    if (baselist && Len(baselist) > 0) {
659      Iterator base = First(baselist);
660      while (base.item) {
661	String *basename = Getattr(base.item, "name");
662	SwigType *basetype = NewString(basename);
663	SwigType_add_pointer(basetype);
664	SwigType_remember(basetype);
665	String *basemangle = SwigType_manglestr(basetype);
666	Printf(f_classInit, "low_inherit((struct program *) SWIGTYPE%s->clientdata, 0, 0, 0, 0, 0);\n", basemangle);
667	Delete(basemangle);
668	Delete(basetype);
669	base = Next(base);
670      }
671    } else {
672      Printf(f_classInit, "ADD_STORAGE(swig_object_wrapper);\n");
673    }
674
675    Language::classHandler(n);
676
677    /* Accessors for member variables */
678    /*
679       List *membervariables = Getattr(n,"membervariables");
680       if (membervariables && Len(membervariables) > 0) {
681       membervariableAccessors(membervariables);
682       }
683     */
684
685    /* Done, close the class and dump its definition to the init function */
686    Printf(f_classInit, "add_program_constant(\"%s\", pr = end_program(), 0);\n", symname);
687    Dump(f_classInit, f_init);
688    Clear(f_classInit);
689
690    SwigType *tt = NewString(symname);
691    SwigType_add_pointer(tt);
692    SwigType_remember(tt);
693    String *tm = SwigType_manglestr(tt);
694    Printf(f_init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) pr);\n", tm);
695    Delete(tm);
696    Delete(tt);
697
698    Delete(PrefixPlusUnderscore);
699    PrefixPlusUnderscore = 0;
700
701    return SWIG_OK;
702  }
703
704  /* ------------------------------------------------------------
705   * memberfunctionHandler()
706   *
707   * Method for adding C++ member function
708   * ------------------------------------------------------------ */
709
710  virtual int memberfunctionHandler(Node *n) {
711    current = MEMBER_FUNC;
712    Language::memberfunctionHandler(n);
713    current = NO_CPP;
714    return SWIG_OK;
715  }
716
717  /* ------------------------------------------------------------
718   * constructorHandler()
719   *
720   * Method for adding C++ member constructor
721   * ------------------------------------------------------------ */
722
723  virtual int constructorHandler(Node *n) {
724    current = CONSTRUCTOR;
725    Language::constructorHandler(n);
726    current = NO_CPP;
727    return SWIG_OK;
728  }
729
730  /* ------------------------------------------------------------
731   * destructorHandler()
732   * ------------------------------------------------------------ */
733
734  virtual int destructorHandler(Node *n) {
735    current = DESTRUCTOR;
736    Language::destructorHandler(n);
737    current = NO_CPP;
738    return SWIG_OK;
739  }
740
741  /* ------------------------------------------------------------
742   * membervariableAccessors()
743   * ------------------------------------------------------------ */
744
745  void membervariableAccessors(List *membervariables) {
746    String *name;
747    Iterator i;
748    bool need_setter;
749    String *funcname;
750
751    /* If at least one of them is mutable, we need a setter */
752    need_setter = false;
753    i = First(membervariables);
754    while (i.item) {
755      if (!GetFlag(i.item, "feature:immutable")) {
756	need_setter = true;
757	break;
758      }
759      i = Next(i);
760    }
761
762    /* Create a function to set the values of the (mutable) variables */
763    if (need_setter) {
764      Wrapper *wrapper = NewWrapper();
765      String *setter = Swig_name_member(getClassPrefix(), (char *) "`->=");
766      String *wname = Swig_name_wrapper(setter);
767      Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL);
768      Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n");
769
770      i = First(membervariables);
771      while (i.item) {
772	if (!GetFlag(i.item, "feature:immutable")) {
773	  name = Getattr(i.item, "name");
774	  funcname = Swig_name_wrapper(Swig_name_set(Swig_name_member(getClassPrefix(), name)));
775	  Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name);
776	  Printf(wrapper->code, "%s(args);\n", funcname);
777	  Printf(wrapper->code, "return;\n");
778	  Printf(wrapper->code, "}\n");
779	  Delete(funcname);
780	}
781	i = Next(i);
782      }
783
784      /* Close the function */
785      Printf(wrapper->code, "pop_n_elems(args);\n");
786      Printf(wrapper->code, "}\n");
787
788      /* Dump wrapper code to the output file */
789      Wrapper_print(wrapper, f_wrappers);
790
791      /* Register it with Pike */
792      String *description = NewString("tStr tFloat, tVoid");
793      add_method("`->=", wname, description);
794      Delete(description);
795
796      /* Clean up */
797      Delete(wname);
798      Delete(setter);
799      DelWrapper(wrapper);
800    }
801
802    /* Create a function to get the values of the (mutable) variables */
803    Wrapper *wrapper = NewWrapper();
804    String *getter = Swig_name_member(getClassPrefix(), (char *) "`->");
805    String *wname = Swig_name_wrapper(getter);
806    Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL);
807    Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n");
808
809    i = First(membervariables);
810    while (i.item) {
811      name = Getattr(i.item, "name");
812      funcname = Swig_name_wrapper(Swig_name_get(Swig_name_member(getClassPrefix(), name)));
813      Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name);
814      Printf(wrapper->code, "%s(args);\n", funcname);
815      Printf(wrapper->code, "return;\n");
816      Printf(wrapper->code, "}\n");
817      Delete(funcname);
818      i = Next(i);
819    }
820
821    /* Close the function */
822    Printf(wrapper->code, "pop_n_elems(args);\n");
823    Printf(wrapper->code, "}\n");
824
825    /* Dump wrapper code to the output file */
826    Wrapper_print(wrapper, f_wrappers);
827
828    /* Register it with Pike */
829    String *description = NewString("tStr, tMix");
830    add_method("`->", wname, description);
831    Delete(description);
832
833    /* Clean up */
834    Delete(wname);
835    Delete(getter);
836    DelWrapper(wrapper);
837  }
838
839  /* ------------------------------------------------------------
840   * membervariableHandler()
841   * ------------------------------------------------------------ */
842
843  virtual int membervariableHandler(Node *n) {
844    List *membervariables = Getattr(getCurrentClass(), "membervariables");
845    if (!membervariables) {
846      membervariables = NewList();
847      Setattr(getCurrentClass(), "membervariables", membervariables);
848    }
849    Append(membervariables, n);
850    current = MEMBER_VAR;
851    Language::membervariableHandler(n);
852    current = NO_CPP;
853    return SWIG_OK;
854  }
855
856  /* -----------------------------------------------------------------------
857   * staticmemberfunctionHandler()
858   *
859   * Wrap a static C++ function
860   * ---------------------------------------------------------------------- */
861
862  virtual int staticmemberfunctionHandler(Node *n) {
863    current = STATIC_FUNC;
864    Language::staticmemberfunctionHandler(n);
865    current = NO_CPP;
866    return SWIG_OK;
867  }
868
869  /* ------------------------------------------------------------
870   * memberconstantHandler()
871   *
872   * Create a C++ constant
873   * ------------------------------------------------------------ */
874
875  virtual int memberconstantHandler(Node *n) {
876    current = CLASS_CONST;
877    constantWrapper(n);
878    current = NO_CPP;
879    return SWIG_OK;
880  }
881
882  /* ---------------------------------------------------------------------
883   * staticmembervariableHandler()
884   * --------------------------------------------------------------------- */
885
886  virtual int staticmembervariableHandler(Node *n) {
887    current = STATIC_VAR;
888    Language::staticmembervariableHandler(n);
889    current = NO_CPP;
890    return SWIG_OK;
891  }
892};
893
894/* -----------------------------------------------------------------------------
895 * swig_pike()    - Instantiate module
896 * ----------------------------------------------------------------------------- */
897
898static Language *new_swig_pike() {
899  return new PIKE();
900}
901extern "C" Language *swig_pike(void) {
902  return new_swig_pike();
903}
904