summaryrefslogtreecommitdiffstats
path: root/contrib/tools/swig/Source/Modules/ocaml.cxx
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-08-28 14:27:58 +0300
committerrobot-piglet <[email protected]>2025-08-28 14:57:06 +0300
commit81d828c32c8d5477cb2f0ce5da06a1a8d9392ca3 (patch)
tree3081d566f0d5158d76e9093261344f6406fd09f7 /contrib/tools/swig/Source/Modules/ocaml.cxx
parent77ea11423f959e51795cc3ef36a48d808b4ffb98 (diff)
Intermediate changes
commit_hash:d5b1af16dbe9030537a04c27eb410c88c2f496cd
Diffstat (limited to 'contrib/tools/swig/Source/Modules/ocaml.cxx')
-rw-r--r--contrib/tools/swig/Source/Modules/ocaml.cxx1837
1 files changed, 1837 insertions, 0 deletions
diff --git a/contrib/tools/swig/Source/Modules/ocaml.cxx b/contrib/tools/swig/Source/Modules/ocaml.cxx
new file mode 100644
index 00000000000..ce80eb0bbe2
--- /dev/null
+++ b/contrib/tools/swig/Source/Modules/ocaml.cxx
@@ -0,0 +1,1837 @@
+/* -----------------------------------------------------------------------------
+ * This file is part of SWIG, which is licensed as a whole under version 3
+ * (or any later version) of the GNU General Public License. Some additional
+ * terms also apply to certain portions of SWIG. The full details of the SWIG
+ * license and copyrights can be found in the LICENSE and COPYRIGHT files
+ * included with the SWIG source code as distributed by the SWIG developers
+ * and at https://www.swig.org/legal.html.
+ *
+ * ocaml.cxx
+ *
+ * Ocaml language module for SWIG.
+ * ----------------------------------------------------------------------------- */
+
+#include "swigmod.h"
+#include <ctype.h>
+
+static const char *usage = "\
+Ocaml Options (available with -ocaml)\n\
+ -oldvarnames - Old intermediary method names for variable wrappers\n\
+ -prefix <name> - Set a prefix <name> to be prepended to all names\n\
+ -where - Emit library location\n\
+\n";
+
+static int classmode = 0;
+static int in_constructor = 0, in_destructor = 0, in_copyconst = 0;
+static int const_enum = 0;
+static int static_member_function = 0;
+static int generate_sizeof = 0;
+static String *prefix = 0;
+static const char *ocaml_path = "ocaml";
+static bool old_variable_names = false;
+static String *classname = 0;
+static String *module = 0;
+static String *init_func_def = 0;
+static String *f_classtemplate = 0;
+static SwigType *name_qualifier_type = 0;
+
+static Hash *seen_enums = 0;
+static Hash *seen_enumvalues = 0;
+static Hash *seen_constructors = 0;
+
+static File *f_header = 0;
+static File *f_begin = 0;
+static File *f_runtime = 0;
+static File *f_wrappers = 0;
+static File *f_directors = 0;
+static File *f_directors_h = 0;
+static File *f_init = 0;
+static File *f_mlout = 0;
+static File *f_mliout = 0;
+static File *f_mlbody = 0;
+static File *f_mlibody = 0;
+static File *f_mltail = 0;
+static File *f_mlitail = 0;
+static File *f_enumtypes_type = 0;
+static File *f_enumtypes_value = 0;
+static File *f_class_ctors = 0;
+static File *f_class_ctors_end = 0;
+static File *f_enum_to_int = 0;
+static File *f_int_to_enum = 0;
+
+class OCAML:public Language {
+public:
+
+ OCAML() {
+ director_prot_ctor_code = NewString("");
+ Printv(director_prot_ctor_code,
+ "if ( $comparison ) { /* subclassed */\n",
+ " $director_new \n", "} else {\n", " caml_failwith(\"accessing abstract class or protected constructor\"); \n", "}\n", NIL);
+ director_multiple_inheritance = 1;
+ directorLanguage();
+ }
+
+ String *Swig_class_name(Node *n) {
+ String *name;
+ name = Copy(Getattr(n, "sym:name"));
+ return name;
+ }
+
+ void PrintIncludeArg() {
+ Printv(stdout, SWIG_LIB, SWIG_FILE_DELIMITER, ocaml_path, "\n", NIL);
+ }
+
+ /* ------------------------------------------------------------
+ * main()
+ * ------------------------------------------------------------ */
+
+ virtual void main(int argc, char *argv[]) {
+ int i;
+
+ prefix = 0;
+
+ SWIG_library_directory(ocaml_path);
+
+ // Look for certain command line options
+ for (i = 1; i < argc; i++) {
+ if (argv[i]) {
+ if (strcmp(argv[i], "-help") == 0) {
+ fputs(usage, stdout);
+ Exit(EXIT_SUCCESS);
+ } else if (strcmp(argv[i], "-where") == 0) {
+ PrintIncludeArg();
+ Exit(EXIT_SUCCESS);
+ } else if (strcmp(argv[i], "-prefix") == 0) {
+ if (argv[i + 1]) {
+ prefix = NewString(argv[i + 1]);
+ Swig_mark_arg(i);
+ Swig_mark_arg(i + 1);
+ i++;
+ } else {
+ Swig_arg_error();
+ }
+ } else if (strcmp(argv[i], "-oldvarnames") == 0) {
+ Swig_mark_arg(i);
+ old_variable_names = true;
+ }
+ }
+ }
+
+ // If a prefix has been specified make sure it ends in a '_' (not actually used!)
+ if (prefix) {
+ const char *px = Char(prefix);
+ if (px[Len(prefix) - 1] != '_')
+ Printf(prefix, "_");
+ } else
+ prefix = NewString("swig_");
+
+ // Add a symbol for this module
+
+ Preprocessor_define("SWIGOCAML 1", 0);
+
+ // Read in default typemaps */
+ SWIG_config_file("ocaml.i");
+ allow_overloading();
+
+ }
+
+ /* Swig_director_declaration()
+ *
+ * Generate the full director class declaration, complete with base classes.
+ * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {"
+ *
+ */
+
+ String *Swig_director_declaration(Node *n) {
+ String *classname = Swig_class_name(n);
+ String *directorname = NewStringf("SwigDirector_%s", classname);
+ String *base = Getattr(n, "classtype");
+ String *declaration = Swig_class_declaration(n, directorname);
+ Printf(declaration, " : public %s, public Swig::Director {\n", base);
+ Delete(classname);
+ Delete(directorname);
+ return declaration;
+ }
+
+ void emitBanner(File *f) {
+ Printf(f, "(* ----------------------------------------------------------------------------\n");
+ Swig_banner_target_lang(f, " *");
+ Printf(f, " * ---------------------------------------------------------------------------- *)\n\n");
+ }
+
+ /* ------------------------------------------------------------
+ * top()
+ *
+ * Recognize the %module, and capture the module name.
+ * Create the default enum cases.
+ * Set up the named outputs:
+ *
+ * init
+ * ml
+ * mli
+ * wrapper
+ * header
+ * runtime
+ * directors
+ * directors_h
+ * ------------------------------------------------------------ */
+
+ virtual int top(Node *n) {
+ /* Set comparison with none for ConstructorToFunction */
+ setSubclassInstanceCheck(NewString("caml_list_nth(args,0) != Val_unit"));
+
+ /* check if directors are enabled for this module. note: this
+ * is a "master" switch, without which no director code will be
+ * emitted. %feature("director") statements are also required
+ * to enable directors for individual classes or methods.
+ *
+ * use %module(directors="1") modulename at the start of the
+ * interface file to enable director generation.
+ */
+ String *mod_docstring = NULL;
+ {
+ Node *module = Getattr(n, "module");
+ if (module) {
+ Node *options = Getattr(module, "options");
+ if (options) {
+ if (Getattr(options, "directors")) {
+ allow_directors();
+ }
+ if (Getattr(options, "dirprot")) {
+ allow_dirprot();
+ }
+ if (Getattr(options, "sizeof")) {
+ generate_sizeof = 1;
+ }
+ mod_docstring = Getattr(options, "docstring");
+ }
+ }
+ }
+
+ /* Initialize all of the output files */
+ String *outfile = Getattr(n, "outfile");
+
+ f_begin = NewFile(outfile, "w", SWIG_output_files());
+ if (!f_begin) {
+ FileErrorDisplay(outfile);
+ Exit(EXIT_FAILURE);
+ }
+ f_runtime = NewString("");
+ f_init = NewString("");
+ f_header = NewString("");
+ f_wrappers = NewString("");
+ f_directors = NewString("");
+ f_directors_h = NewString("");
+ f_enumtypes_type = NewString("");
+ f_enumtypes_value = NewString("");
+ init_func_def = NewString("");
+ f_mlbody = NewString("");
+ f_mlibody = NewString("");
+ f_mltail = NewString("");
+ f_mlitail = NewString("");
+ f_class_ctors = NewString("");
+ f_class_ctors_end = NewString("");
+ f_enum_to_int = NewString("");
+ f_int_to_enum = NewString("");
+ f_classtemplate = NewString("");
+
+ module = Getattr(n, "name");
+
+ seen_constructors = NewHash();
+ seen_enums = NewHash();
+ seen_enumvalues = NewHash();
+
+ /* Register file targets with the SWIG file handler */
+ Swig_register_filebyname("init", init_func_def);
+ Swig_register_filebyname("header", f_header);
+ Swig_register_filebyname("wrapper", f_wrappers);
+ Swig_register_filebyname("begin", f_begin);
+ Swig_register_filebyname("runtime", f_runtime);
+ Swig_register_filebyname("mli", f_mlibody);
+ Swig_register_filebyname("ml", f_mlbody);
+ Swig_register_filebyname("mlitail", f_mlitail);
+ Swig_register_filebyname("mltail", f_mltail);
+ Swig_register_filebyname("director", f_directors);
+ Swig_register_filebyname("director_h", f_directors_h);
+ Swig_register_filebyname("classtemplate", f_classtemplate);
+ Swig_register_filebyname("class_ctors", f_class_ctors);
+
+ if (old_variable_names) {
+ Swig_name_register("set", "%n%v__set__");
+ Swig_name_register("get", "%n%v__get__");
+ }
+
+ Swig_banner(f_begin);
+
+ Swig_obligatory_macros(f_runtime, "OCAML");
+
+ Printf(f_runtime, "#define SWIG_MODULE \"%s\"\n", module);
+ /* Module name */
+ Printf(f_mlbody, "let module_name = \"%s\"\n", module);
+ Printf(f_mlibody, "val module_name : string\n");
+ Printf(f_enum_to_int,
+ "let enum_to_int x (v : c_obj) =\n"
+ " match v with\n"
+ " C_enum _y ->\n"
+ " (let y = _y in match (x : c_enum_type) with\n"
+ " `unknown -> " " (match y with\n" " `Int x -> (Swig.C_int x)\n" " | _ -> raise (LabelNotFromThisEnum v))\n");
+
+ Printf(f_int_to_enum, "let int_to_enum x y =\n" " match (x : c_enum_type) with\n" " `unknown -> C_enum (`Int y)\n");
+
+ if (Swig_directors_enabled()) {
+ Printf(f_runtime, "#define SWIG_DIRECTORS\n");
+ }
+
+ Printf(f_runtime, "\n");
+
+ /* Produce the enum_to_int and int_to_enum functions */
+
+ Printf(f_enumtypes_type, "open Swig\n" "type c_enum_type = [ \n `unknown\n");
+ Printf(f_enumtypes_value, "type c_enum_value = [ \n `Int of int\n");
+ String *mlfile = NewString("");
+ String *mlifile = NewString("");
+
+ Printv(mlfile, module, ".ml", NIL);
+ Printv(mlifile, module, ".mli", NIL);
+
+ String *mlfilen = NewStringf("%s%s", SWIG_output_directory(), mlfile);
+ if ((f_mlout = NewFile(mlfilen, "w", SWIG_output_files())) == 0) {
+ FileErrorDisplay(mlfilen);
+ Exit(EXIT_FAILURE);
+ }
+ String *mlifilen = NewStringf("%s%s", SWIG_output_directory(), mlifile);
+ if ((f_mliout = NewFile(mlifilen, "w", SWIG_output_files())) == 0) {
+ FileErrorDisplay(mlifilen);
+ Exit(EXIT_FAILURE);
+ }
+ emitBanner(f_mlout);
+ emitBanner(f_mliout);
+
+ Language::top(n);
+
+ if (mod_docstring) {
+ if (Len(mod_docstring)) {
+ Printv(f_mliout, "(** ", mod_docstring, " *)\n", NIL);
+ }
+ Delete(mod_docstring);
+ mod_docstring = NULL;
+ }
+
+ Printf(f_enum_to_int, ") | _ -> (C_int (get_int v))\n" "let _ = Callback.register \"%s_enum_to_int\" enum_to_int\n", module);
+ Printf(f_mlibody, "val enum_to_int : c_enum_type -> c_obj -> Swig.c_obj\n");
+
+ Printf(f_int_to_enum, "let _ = Callback.register \"%s_int_to_enum\" int_to_enum\n", module);
+ Printf(f_mlibody, "val int_to_enum : c_enum_type -> int -> c_obj\n");
+ Printf(f_init, "#define SWIG_init f_%s_init\n" "%s" "}\n", module, init_func_def);
+ Printf(f_mlbody, "external f_init : unit -> unit = \"f_%s_init\" ;;\n" "let _ = f_init ()\n", module);
+ Printf(f_enumtypes_type, "]\n");
+ Printf(f_enumtypes_value, "]\n\n" "type c_obj = c_enum_value c_obj_t\n");
+
+ if (Swig_directors_enabled()) {
+ // Insert director runtime into the f_runtime file (make it occur before %header section)
+ Swig_insert_file("director_common.swg", f_runtime);
+ Swig_insert_file("director.swg", f_runtime);
+ }
+
+ SwigType_emit_type_table(f_runtime, f_wrappers);
+ /* Close all of the files */
+ Dump(f_runtime, f_begin);
+ Dump(f_directors_h, f_header);
+ Dump(f_header, f_begin);
+ Dump(f_directors, f_wrappers);
+ Dump(f_wrappers, f_begin);
+ Wrapper_pretty_print(f_init, f_begin);
+ Delete(f_header);
+ Delete(f_wrappers);
+ Delete(f_init);
+ Delete(f_runtime);
+ Delete(f_begin);
+
+ Dump(f_enumtypes_type, f_mlout);
+ Dump(f_enumtypes_value, f_mlout);
+ Dump(f_mlbody, f_mlout);
+ Dump(f_enum_to_int, f_mlout);
+ Dump(f_int_to_enum, f_mlout);
+ Delete(f_int_to_enum);
+ Delete(f_enum_to_int);
+ Dump(f_class_ctors, f_mlout);
+ Dump(f_class_ctors_end, f_mlout);
+ Dump(f_mltail, f_mlout);
+ Delete(f_mlout);
+
+ Dump(f_enumtypes_type, f_mliout);
+ Dump(f_enumtypes_value, f_mliout);
+ Dump(f_mlibody, f_mliout);
+ Dump(f_mlitail, f_mliout);
+ Delete(f_mliout);
+
+ return SWIG_OK;
+ }
+
+ /* Produce an error for the given type */
+ void throw_unhandled_ocaml_type_error(SwigType *d, const char *types) {
+ Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s (%s).\n", SwigType_str(d, 0), types);
+ }
+
+ /* Return true iff T is a pointer type */
+ int
+ is_a_pointer(SwigType *t) {
+ return SwigType_ispointer(SwigType_typedef_resolve_all(t));
+ }
+
+ /*
+ * Delete one reference from a given type.
+ */
+
+ void oc_SwigType_del_reference(SwigType *t) {
+ if (SwigType_isqualifier(t)) {
+ SwigType_del_qualifier(t);
+ }
+ SwigType_del_reference(t);
+ }
+
+ void oc_SwigType_del_array(SwigType *t) {
+ if (SwigType_isqualifier(t)) {
+ SwigType_del_qualifier(t);
+ }
+ if (SwigType_isarray(t)) {
+ SwigType_del_array(t);
+ }
+ }
+
+ /*
+ * Return true iff T is a reference type
+ */
+
+ int
+ is_a_reference(SwigType *t) {
+ return SwigType_isreference(SwigType_typedef_resolve_all(t));
+ }
+
+ int
+ is_an_array(SwigType *t) {
+ return SwigType_isarray(SwigType_typedef_resolve_all(t));
+ }
+
+ virtual int membervariableHandler(Node *n) {
+ String *symname = Getattr(n, "sym:name");
+ Language::membervariableHandler(n);
+
+ String *mname = Swig_name_member(NSPACE_TODO, classname, symname);
+ String *getname = Swig_name_get(NSPACE_TODO, mname);
+ String *mangled_getname = mangleNameForCaml(getname);
+ Delete(getname);
+
+ if (!GetFlag(n, "feature:immutable")) {
+ String *setname = Swig_name_set(NSPACE_TODO, mname);
+ String *mangled_setname = mangleNameForCaml(setname);
+ Delete(setname);
+ Printf(f_class_ctors, " \"[%s]\", (fun args -> " "if args = (C_list [ raw_ptr ]) then _%s args else _%s args) ;\n", symname, mangled_getname, mangled_setname);
+ Delete(mangled_setname);
+ } else {
+ Printf(f_class_ctors, " \"[%s]\", (fun args -> " "if args = (C_list [ raw_ptr ]) then _%s args else C_void) ;\n", symname, mangled_getname);
+ }
+ Delete(mangled_getname);
+ Delete(mname);
+ return SWIG_OK;
+ }
+
+ /* ------------------------------------------------------------
+ * functionWrapper()
+ * Create a function declaration and register it with the interpreter.
+ * ------------------------------------------------------------ */
+
+ virtual int functionWrapper(Node *n) {
+ char *iname = GetChar(n, "sym:name");
+ SwigType *returntype = Getattr(n, "type");
+ String *return_type_normalized = normalizeTemplatedClassName(returntype);
+ ParmList *l = Getattr(n, "parms");
+ int director_method = 0;
+ Parm *p;
+
+ Wrapper *f = NewWrapper();
+ String *proc_name = NewString("");
+ String *target = NewString("");
+ String *arg = NewString("");
+ String *cleanup = NewString("");
+ String *outarg = NewString("");
+ String *build = NewString("");
+ String *tm;
+ int i = 0;
+ int numargs;
+ int numreq;
+ int newobj = GetFlag(n, "feature:new");
+ String *nodeType = Getattr(n, "nodeType");
+ int destructor = (!Cmp(nodeType, "destructor"));
+ String *overname = 0;
+ bool isOverloaded = Getattr(n, "sym:overloaded") ? true : false;
+ // For overloaded functions, only the dispatch function needs to be exposed in the ml and mli files.
+ bool expose_func = !isOverloaded || !Getattr(n, "sym:nextSibling");
+
+ // Make a wrapper name for this
+ String *wname = Swig_name_wrapper(iname);
+ if (isOverloaded) {
+ overname = Getattr(n, "sym:overname");
+ } else {
+ if (!addSymbol(iname, n)) {
+ DelWrapper(f);
+ return SWIG_ERROR;
+ }
+ }
+ if (overname) {
+ Append(wname, overname);
+ }
+ /* Do this to disambiguate functions emitted from different modules */
+ Append(wname, module);
+
+ Setattr(n, "wrap:name", wname);
+
+ // Build the name for Scheme.
+ Printv(proc_name, "_", iname, NIL);
+ String *mangled_name = mangleNameForCaml(proc_name);
+
+ if (classmode && in_constructor && expose_func) { // Emit constructor for object
+ String *mangled_name_nounder = NewString((char *) (Char(mangled_name)) + 1);
+ Printf(f_class_ctors_end, "let %s clst = _%s clst\n", mangled_name_nounder, mangled_name_nounder);
+ Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name_nounder);
+ Delete(mangled_name_nounder);
+ } else if (classmode && in_destructor) {
+ Printf(f_class_ctors, " \"~\", %s ;\n", mangled_name);
+ } else if (classmode && !in_constructor && !in_destructor && !static_member_function &&
+ !Getattr(n, "membervariableHandler:sym:name") && expose_func) {
+ String *opname = Copy(Getattr(n, "memberfunctionHandler:sym:name"));
+
+ Replaceall(opname, "operator ", "");
+ Printf(f_class_ctors, " \"%s\", %s ;\n", opname, mangled_name);
+ Delete(opname);
+ }
+
+ if (classmode && in_constructor) {
+ Setattr(seen_constructors, mangled_name, "true");
+ }
+ // writing the function wrapper function
+ Printv(f->def, "SWIGEXT value ", wname, " (", NIL);
+ Printv(f->def, "value args", NIL);
+ Printv(f->def, ")\n{", NIL);
+
+ /* Define the scheme name in C. This define is used by several
+ macros. */
+ //Printv(f->def, "#define FUNC_NAME \"", mangled_name, "\"", NIL);
+
+ // adds local variables
+ Wrapper_add_local(f, "args", "CAMLparam1(args)");
+ Wrapper_add_local(f, "ret", "CAMLlocal2(swig_result,rv)");
+ returntype = SwigType_typedef_qualified(returntype);
+ emit_parameter_variables(l, f);
+
+ /* Attach the standard typemaps */
+ emit_attach_parmmaps(l, f);
+ Setattr(n, "wrap:parms", l);
+
+ numargs = emit_num_arguments(l);
+ numreq = emit_num_required(l);
+ if (!isOverloaded) {
+ if (numargs > 0) {
+ if (numreq > 0) {
+ Printf(f->code, "if (caml_list_length(args) < %d || caml_list_length(args) > %d) {\n", numreq, numargs);
+ } else {
+ Printf(f->code, "if (caml_list_length(args) > %d) {\n", numargs);
+ }
+ Printf(f->code, "caml_invalid_argument(\"Incorrect number of arguments passed to '%s'\");\n}\n", iname);
+ } else {
+ Printf(f->code, "if (caml_list_length(args) > 0) caml_invalid_argument(\"'%s' takes no arguments\");\n", iname);
+ }
+ }
+ Printf(f->code, "swig_result = Val_unit;\n");
+
+ // Now write code to extract the parameters (this is super ugly)
+
+ for (i = 0, p = l; i < numargs; i++) {
+ /* Skip ignored arguments */
+ while (checkAttribute(p, "tmap:in:numinputs", "0")) {
+ p = Getattr(p, "tmap:in:next");
+ }
+
+ SwigType *pt = Getattr(p, "type");
+ String *ln = Getattr(p, "lname");
+ pt = SwigType_typedef_qualified(pt);
+
+ // Produce names of source and target
+ Clear(target);
+ Clear(arg);
+ String *source = NewStringf("caml_list_nth(args,%d)", i);
+ Printf(target, "%s", ln);
+ Printv(arg, Getattr(p, "name"), NIL);
+
+ if (i >= numreq) {
+ Printf(f->code, "if (caml_list_length(args) > %d) {\n", i);
+ }
+ // Handle parameter types.
+ if ((tm = Getattr(p, "tmap:in"))) {
+ Replaceall(tm, "$input", source);
+ Setattr(p, "emit:input", source);
+ Printv(f->code, tm, "\n", NIL);
+ p = Getattr(p, "tmap:in:next");
+ } else {
+ // no typemap found
+ // check if typedef and resolve
+ throw_unhandled_ocaml_type_error(pt, "in");
+ p = nextSibling(p);
+ }
+ if (i >= numreq) {
+ Printf(f->code, "}\n");
+ }
+ Delete(source);
+ }
+
+ /* Insert constraint checking code */
+ for (p = l; p;) {
+ if ((tm = Getattr(p, "tmap:check"))) {
+ Printv(f->code, tm, "\n", NIL);
+ p = Getattr(p, "tmap:check:next");
+ } else {
+ p = nextSibling(p);
+ }
+ }
+
+ // Pass output arguments back to the caller.
+
+ for (p = l; p;) {
+ if ((tm = Getattr(p, "tmap:argout"))) {
+ Replaceall(tm, "$arg", Getattr(p, "emit:input"));
+ Replaceall(tm, "$input", Getattr(p, "emit:input"));
+ Replaceall(tm, "$ntype", normalizeTemplatedClassName(Getattr(p, "type")));
+ Printv(outarg, tm, "\n", NIL);
+ p = Getattr(p, "tmap:argout:next");
+ } else {
+ p = nextSibling(p);
+ }
+ }
+
+ // Free up any memory allocated for the arguments.
+
+ /* Insert cleanup code */
+ for (p = l; p;) {
+ if ((tm = Getattr(p, "tmap:freearg"))) {
+ Printv(cleanup, tm, "\n", NIL);
+ p = Getattr(p, "tmap:freearg:next");
+ } else {
+ p = nextSibling(p);
+ }
+ }
+
+ /* if the object is a director, and the method call originated from its
+ * underlying ocaml object, resolve the call by going up the c++
+ * inheritance chain. otherwise try to resolve the method in ocaml.
+ * without this check an infinite loop is set up between the director and
+ * shadow class method calls.
+ */
+
+ // NOTE: this code should only be inserted if this class is the
+ // base class of a director class. however, in general we haven't
+ // yet analyzed all classes derived from this one to see if they are
+ // directors. furthermore, this class may be used as the base of
+ // a director class defined in a completely different module at a
+ // later time, so this test must be included whether or not directorbase
+ // is true. we do skip this code if directors have not been enabled
+ // at the command line to preserve source-level compatibility with
+ // non-polymorphic swig. also, if this wrapper is for a smart-pointer
+ // method, there is no need to perform the test since the calling object
+ // (the smart-pointer) and the director object (the "pointee") are
+ // distinct.
+
+ director_method = is_member_director(n) && !is_smart_pointer() && !destructor;
+ if (director_method) {
+ Wrapper_add_local(f, "director", "Swig::Director *director = 0");
+ Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n");
+ Wrapper_add_local(f, "upcall", "bool upcall = false");
+ Append(f->code, "upcall = (director);\n");
+ }
+
+ // Now write code to make the function call
+ Swig_director_emit_dynamic_cast(n, f);
+ String *actioncode = emit_action(n);
+
+ if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) {
+ Replaceall(tm, "$result", "rv");
+ Replaceall(tm, "$ntype", return_type_normalized);
+ Printv(f->code, tm, "\n", NIL);
+ } else {
+ throw_unhandled_ocaml_type_error(returntype, "out");
+ }
+ emit_return_variable(n, returntype, f);
+
+ // Dump the argument output code
+ Printv(f->code, Char(outarg), NIL);
+
+ // Dump the argument cleanup code
+ Printv(f->code, Char(cleanup), NIL);
+
+ // Look for any remaining cleanup
+
+ if (GetFlag(n, "feature:new")) {
+ if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) {
+ Printv(f->code, tm, "\n", NIL);
+ }
+ }
+
+ /* See if there is any return cleanup code */
+ if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) {
+ Printf(f->code, "%s\n", tm);
+ Delete(tm);
+ }
+
+ // Free any memory allocated by the function being wrapped..
+
+ if ((tm = Swig_typemap_lookup("swig_result", n, Swig_cresult_name(), 0))) {
+ Printv(f->code, tm, "\n", NIL);
+ }
+ // Wrap things up (in a manner of speaking)
+
+ Printv(f->code, tab4, "swig_result = caml_list_append(swig_result,rv);\n", NIL);
+ Printv(f->code, tab4, "CAMLreturn(swig_result);\n", NIL);
+ Printv(f->code, "}\n", NIL);
+
+ bool isvoid = !Cmp(returntype, "void");
+ Replaceall(f->code, "$isvoid", isvoid ? "1" : "0");
+
+ /* Substitute the function name */
+ Replaceall(f->code, "$symname", iname);
+
+ Wrapper_print(f, f_wrappers);
+
+ if (isOverloaded) {
+ if (!Getattr(n, "sym:nextSibling")) {
+ int maxargs;
+ Wrapper *df = NewWrapper();
+ String *dispatch = Swig_overload_dispatch(n,
+ "free(argv);\n" "CAMLreturn(%s(args));\n",
+ &maxargs);
+
+ Wrapper_add_local(df, "argv", "value *argv");
+
+ /* Undifferentiate name .. this is the dispatch function */
+ wname = Swig_name_wrapper(iname);
+ /* Do this to disambiguate functions emitted from different
+ * modules */
+ Append(wname, module);
+
+ Printv(df->def,
+ "SWIGEXT value ", wname, "(value args) {\n" " CAMLparam1(args);\n" " int i;\n" " int argc = caml_list_length(args);\n", NIL);
+ Printv(df->code,
+ "argv = (value *)malloc( argc * sizeof( value ) );\n"
+ "for( i = 0; i < argc; i++ ) {\n" " argv[i] = caml_list_nth(args,i);\n" "}\n", NIL);
+ Printv(df->code, dispatch, "\nfree(argv);\n", NIL);
+ Node *sibl = n;
+ while (Getattr(sibl, "sym:previousSibling"))
+ sibl = Getattr(sibl, "sym:previousSibling");
+ String *protoTypes = NewString("");
+ do {
+ String *fulldecl = Swig_name_decl(sibl);
+ Printf(protoTypes, "\n\" %s\\n\"", fulldecl);
+ Delete(fulldecl);
+ } while ((sibl = Getattr(sibl, "sym:nextSibling")));
+ Printf(df->code, "caml_failwith(\"Wrong number or type of arguments for overloaded function '%s'.\\n\""
+ "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", iname, protoTypes);
+ Delete(protoTypes);
+ Printv(df->code, "}\n", NIL);
+ Wrapper_print(df, f_wrappers);
+
+ DelWrapper(df);
+ Delete(dispatch);
+ }
+ }
+
+ if (expose_func) {
+ Printf(f_mlbody, "external %s_f : c_obj list -> c_obj list = \"%s\" ;;\n", mangled_name, wname);
+ Printf(f_mlbody, "let %s arg = match %s_f (%s(fnhelper arg)) with\n", mangled_name, mangled_name,
+ in_constructor && Swig_directorclass(getCurrentClass()) ? "director_core_helper " : "");
+ Printf(f_mlbody, " [] -> C_void\n"
+ "| [x] -> (if %s then Gc.finalise \n"
+ " (fun x -> ignore ((invoke x) \"~\" C_void)) x) ; x\n"
+ "| lst -> C_list lst ;;\n", newobj ? "true" : "false");
+ }
+
+ if ((!classmode || in_constructor || in_destructor || static_member_function) && expose_func)
+ Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name);
+
+ Delete(proc_name);
+ Delete(target);
+ Delete(arg);
+ Delete(outarg);
+ Delete(cleanup);
+ Delete(build);
+ DelWrapper(f);
+ return SWIG_OK;
+ }
+
+ /* ------------------------------------------------------------
+ * variableWrapper()
+ *
+ * Create a link to a C variable.
+ * This creates a single function _wrap_varname().
+ * This function takes a single optional argument. If supplied, it means
+ * we are setting this variable to some value. If omitted, it means we are
+ * simply evaluating this variable. We return the value of the variable
+ * in both cases.
+ *
+ * symname is the name of the variable with respect to C. This
+ * may need to differ from the original name in the case of enums.
+ * enumvname is the name of the variable with respect to ocaml. This
+ * will vary if the variable has been renamed.
+ * ------------------------------------------------------------ */
+
+ virtual int variableWrapper(Node *n) {
+ char *name = GetChar(n, "feature:symname");
+ String *iname = Getattr(n, "feature:enumvname");
+ String *mname = mangleNameForCaml(iname);
+ SwigType *t = Getattr(n, "type");
+
+ String *proc_name = NewString("");
+ String *tm;
+ Wrapper *f;
+
+ if (!name) {
+ name = GetChar(n, "name");
+ }
+
+ if (!iname) {
+ iname = Getattr(n, "sym:name");
+ mname = mangleNameForCaml(NewString(iname));
+ }
+
+ if (!iname || !addSymbol(iname, n))
+ return SWIG_ERROR;
+
+ f = NewWrapper();
+
+ // evaluation function names
+ String *var_name = Swig_name_wrapper(iname);
+
+ // Build the name for OCaml.
+ Printv(proc_name, iname, NIL);
+ Setattr(n, "wrap:name", proc_name);
+
+ Printf(f->def, "SWIGEXT value %s(value args) {\n", var_name);
+ // Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL);
+
+ Wrapper_add_local(f, "args", "CAMLparam1(args)");
+ Wrapper_add_local(f, "swig_result", "CAMLlocal1(swig_result)");
+ Printf(f->code, "swig_result = Val_unit;\n");
+
+ int assignable = !is_immutable(n);
+ if (assignable) {
+ /* Check for a setting of the variable value */
+ Printf(f->code, "if (args != Val_int(0)) {\n");
+ if ((tm = Swig_typemap_lookup("varin", n, name, 0))) {
+ Replaceall(tm, "$input", "args");
+ emit_action_code(n, f->code, tm);
+ } else if ((tm = Swig_typemap_lookup("in", n, name, 0))) {
+ Replaceall(tm, "$input", "args");
+ emit_action_code(n, f->code, tm);
+ } else {
+ throw_unhandled_ocaml_type_error(t, "varin/in");
+ }
+ Printf(f->code, "}\n");
+ }
+ // Now return the value of the variable (regardless
+ // of evaluating or setting)
+
+ if ((tm = Swig_typemap_lookup("varout", n, name, 0))) {
+ Replaceall(tm, "$result", "swig_result");
+ emit_action_code(n, f->code, tm);
+ } else if ((tm = Swig_typemap_lookup("out", n, name, 0))) {
+ Replaceall(tm, "$result", "swig_result");
+ emit_action_code(n, f->code, tm);
+ } else {
+ throw_unhandled_ocaml_type_error(t, "varout/out");
+ }
+
+ Printf(f->code, "\nCAMLreturn(swig_result);\n");
+ Printf(f->code, "}\n");
+
+ Wrapper_print(f, f_wrappers);
+
+ // Now add symbol to the Ocaml interpreter
+
+ if (!assignable) {
+ Printf(f_mlbody, "external _%s : c_obj -> Swig.c_obj = \"%s\" \n", mname, var_name);
+ Printf(f_mlibody, "val _%s : c_obj -> Swig.c_obj\n", iname);
+ if (const_enum) {
+ Printf(f_enum_to_int, " | `%s -> _%s C_void\n", mname, mname);
+ Printf(f_int_to_enum, " if y = (get_int (_%s C_void)) then `%s else\n", mname, mname);
+ }
+ } else {
+ Printf(f_mlbody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name);
+ Printf(f_mlibody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name);
+ }
+
+ Delete(var_name);
+ Delete(proc_name);
+ DelWrapper(f);
+ return SWIG_OK;
+ }
+
+ /* ------------------------------------------------------------
+ * staticmemberfunctionHandler --
+ * Overridden to set static_member_function
+ * ------------------------------------------------------------ */
+
+ virtual int staticmemberfunctionHandler(Node *n) {
+ static_member_function = 1;
+ Language::staticmemberfunctionHandler(n);
+ static_member_function = 0;
+ return SWIG_OK;
+ }
+
+ /* ------------------------------------------------------------
+ * constantWrapper()
+ *
+ * The one trick here is that we have to make sure we rename the
+ * constant to something useful that doesn't collide with the
+ * original if any exists.
+ * ------------------------------------------------------------ */
+
+ virtual int constantWrapper(Node *n) {
+ String *name = Getattr(n, "feature:symname");
+ SwigType *type = Getattr(n, "type");
+ String *value = Getattr(n, "value");
+ SwigType *qname = Getattr(n, "qualified:name");
+
+ if (qname)
+ value = qname;
+
+ if (!name) {
+ name = mangleNameForCaml(Getattr(n, "name"));
+ Insert(name, 0, "_swig_wrap_");
+ Setattr(n, "feature:symname", name);
+ }
+ // See if there's a typemap
+
+ // Create variable and assign it a value
+ Printf(f_header, "static %s = %s;\n", SwigType_str(type, name), value);
+ SetFlag(n, "feature:immutable");
+ variableWrapper(n);
+ return SWIG_OK;
+ }
+
+ int constructorHandler(Node *n) {
+ int ret;
+
+ in_constructor = 1;
+ ret = Language::constructorHandler(n);
+ in_constructor = 0;
+
+ return ret;
+ }
+
+ /* destructorHandler:
+ * Turn on destructor flag to inform decisions in functionWrapper
+ */
+
+ int destructorHandler(Node *n) {
+ int ret;
+
+ in_destructor = 1;
+ ret = Language::destructorHandler(n);
+ in_destructor = 0;
+
+ return ret;
+ }
+
+ /* copyconstructorHandler:
+ * Turn on constructor and copyconstructor flags for functionWrapper
+ */
+
+ int copyconstructorHandler(Node *n) {
+ int ret;
+
+ in_copyconst = 1;
+ in_constructor = 1;
+ ret = Language::copyconstructorHandler(n);
+ in_constructor = 0;
+ in_copyconst = 0;
+
+ return ret;
+ }
+
+ /**
+ * A simple, somewhat general purpose function for writing to multiple
+ * streams from a source template. This allows the user to define the
+ * class definition in ways different from the one I have here if they
+ * want to. It will also make the class definition system easier to
+ * fiddle with when I want to change methods, etc.
+ */
+
+ void Multiwrite(String *s) {
+ char *find_marker = strstr(Char(s), "(*Stream:");
+ while (find_marker) {
+ char *next = strstr(find_marker, "*)");
+ find_marker += strlen("(*Stream:");
+
+ if (next) {
+ int num_chars = (int)(next - find_marker);
+ String *stream_name = NewString(find_marker);
+ Delslice(stream_name, num_chars, Len(stream_name));
+ File *fout = Swig_filebyname(stream_name);
+ if (fout) {
+ next += strlen("*)");
+ char *following = strstr(next, "(*Stream:");
+ find_marker = following;
+ if (!following)
+ following = next + strlen(next);
+ String *chunk = NewString(next);
+ Delslice(chunk, (int)(following - next), Len(chunk));
+ Printv(fout, chunk, NIL);
+ }
+ }
+ }
+ }
+
+ bool isSimpleType(String *name) {
+ char *ch = Char(name);
+
+ return !(strchr(ch, '(') || strchr(ch, '<') || strchr(ch, ')') || strchr(ch, '>'));
+ }
+
+ /* We accept all chars in identifiers because we use strings to index
+ * them. */
+ int validIdentifier(String *name) {
+ return Len(name) > 0 ? 1 : 0;
+ }
+
+ /* classHandler
+ *
+ * Create a "class" definition for ocaml. I thought quite a bit about
+ * how I should do this part of it, and arrived here, using a function
+ * invocation to select a method, and dispatch. This can obviously be
+ * done better, but I can't see how, given that I want to support
+ * overloaded methods, out parameters, and operators.
+ *
+ * I needed a system that would do this:
+ *
+ * a Be able to call these methods:
+ * int foo( int x );
+ * float foo( int x, int &out );
+ *
+ * b Be typeable, even in the presence of mutually dependent classes.
+ *
+ * c Support some form of operator invocation.
+ *
+ * (c) I chose strings for the method names so that "+=" would be a
+ * valid method name, and the somewhat natural << (invoke x) "+=" y >>
+ * would work.
+ *
+ * (a) (b) Since the c_obj type exists, it's easy to return C_int in one
+ * case and C_list [ C_float ; C_int ] in the other. This makes tricky
+ * problems with out parameters disappear; they're simply appended to the
+ * return list.
+ *
+ * (b) Since every item that comes from C++ is the same type, there is no
+ * problem with the following:
+ *
+ * class Foo;
+ * class Bar { Foo *toFoo(); }
+ * class Foo { Bar *toBar(); }
+ *
+ * Since the Objective caml types of Foo and Bar are the same. Now that
+ * I correctly incorporate SWIG's typechecking, this isn't a big deal.
+ *
+ * The class is in the form of a function returning a c_obj. The c_obj
+ * is a C_obj containing a function which invokes a method on the
+ * underlying object given its type.
+ *
+ * The name emitted here is normalized before being sent to
+ * Callback.register, because we need this string to look up properly
+ * when the typemap passes the descriptor string. I've been considering
+ * some, possibly more forgiving method that would do some transformations
+ * on the $descriptor in order to find a potential match. This is for
+ * later.
+ *
+ * Important things to note:
+ *
+ * We rely on exception handling (BadMethodName) in order to call an
+ * ancestor. This can be improved.
+ *
+ * The method used to get :classof could be improved to look at the type
+ * info that the base pointer contains. It's really an error to have a
+ * SWIG-generated object that does not contain type info, since the
+ * existence of the object means that SWIG knows the type.
+ *
+ * :parents could use :classof to tell what class it is and make a better
+ * decision. This could be nice, (i.e. provide a run-time graph of C++
+ * classes represented);.
+ *
+ * I can't think of a more elegant way of converting a C_obj fun to a
+ * pointer than "operator &"...
+ *
+ * Added a 'sizeof' that will allow you to do the expected thing.
+ * This should help users to fill buffer structs and the like (as is
+ * typical in windows-styled code). It's only enabled if you give
+ * %feature(sizeof) and then, only for simple types.
+ *
+ * Overall, carrying the list of methods and base classes has worked well.
+ * It allows me to give the Ocaml user introspection over their objects.
+ */
+
+ int classHandler(Node *n) {
+ String *name = Getattr(n, "name");
+ classname = Getattr(n, "sym:name");
+
+ if (!name)
+ return SWIG_OK;
+
+ String *mangled_name = mangleNameForCaml(name);
+ String *this_class_def = NewString(f_classtemplate);
+ String *name_normalized = normalizeTemplatedClassName(name);
+ String *old_class_ctors = f_class_ctors;
+ String *base_classes = NewString("");
+ f_class_ctors = NewString("");
+ bool sizeof_feature = generate_sizeof && isSimpleType(name);
+
+
+ classmode = true;
+ int rv = Language::classHandler(n);
+ classmode = false;
+
+ if (sizeof_feature) {
+ Printf(f_wrappers,
+ "SWIGEXT value _wrap_%s_sizeof( value args ) {\n"
+ " CAMLparam1(args);\n" " CAMLreturn(Val_int(sizeof(%s)));\n" "}\n", mangled_name, name_normalized);
+
+ Printf(f_mlbody, "external __%s_sizeof : unit -> int = " "\"_wrap_%s_sizeof\"\n", mangled_name, mangled_name);
+ }
+
+
+ /* Insert sizeof operator for concrete classes */
+ if (sizeof_feature) {
+ Printv(f_class_ctors, "\"sizeof\" , (fun args -> C_int (__", mangled_name, "_sizeof ())) ;\n", NIL);
+ }
+ /* Handle up-casts in a nice way */
+ List *baselist = Getattr(n, "bases");
+ if (baselist && Len(baselist)) {
+ Iterator b;
+ b = First(baselist);
+ while (b.item) {
+ String *bname = Getattr(b.item, "name");
+ if (bname) {
+ String *base_create = NewString("");
+ Printv(base_create, "(create_class \"", bname, "\")", NIL);
+ Printv(f_class_ctors, " \"::", bname, "\", (fun args -> ", base_create, " args) ;\n", NIL);
+ Printv(base_classes, base_create, " ;\n", NIL);
+ }
+ b = Next(b);
+ }
+ }
+
+ Replaceall(this_class_def, "$classname", mangled_name);
+ Replaceall(this_class_def, "$normalized", name_normalized);
+ Replaceall(this_class_def, "$realname", name);
+ Replaceall(this_class_def, "$baselist", base_classes);
+ Replaceall(this_class_def, "$classbody", f_class_ctors);
+
+ Delete(f_class_ctors);
+ f_class_ctors = old_class_ctors;
+
+ // Actually write out the class definition
+
+ Multiwrite(this_class_def);
+
+ Setattr(n, "ocaml:ctor", mangled_name);
+
+ return rv;
+ }
+
+ String *normalizeTemplatedClassName(String *name) {
+ String *name_normalized = SwigType_typedef_resolve_all(name);
+ bool took_action;
+
+ do {
+ took_action = false;
+
+ if (is_a_pointer(name_normalized)) {
+ SwigType_del_pointer(name_normalized);
+ took_action = true;
+ }
+
+ if (is_a_reference(name_normalized)) {
+ oc_SwigType_del_reference(name_normalized);
+ took_action = true;
+ }
+
+ if (is_an_array(name_normalized)) {
+ oc_SwigType_del_array(name_normalized);
+ took_action = true;
+ }
+ } while (took_action);
+
+ return SwigType_str(name_normalized, 0);
+ }
+
+ /*
+ * Produce the symbol name that ocaml will use when referring to the
+ * target item. I wonder if there's a better way to do this:
+ * (WF - use Swig_name_mangle_string/Swig_name_mangle_type)
+ *
+ * I shudder to think about doing it with a hash lookup, but that would
+ * make a couple of things easier:
+ */
+
+ String *mangleNameForCaml(String *s) {
+ String *out = Copy(s);
+ Replaceall(out, " ", "_xx");
+ Replaceall(out, "::", "_xx");
+ Replaceall(out, ",", "_x");
+ Replaceall(out, "+", "_xx_plus");
+ Replaceall(out, "-", "_xx_minus");
+ Replaceall(out, "<", "_xx_ldbrace");
+ Replaceall(out, ">", "_xx_rdbrace");
+ Replaceall(out, "!", "_xx_not");
+ Replaceall(out, "%", "_xx_mod");
+ Replaceall(out, "^", "_xx_xor");
+ Replaceall(out, "*", "_xx_star");
+ Replaceall(out, "&", "_xx_amp");
+ Replaceall(out, "|", "_xx_or");
+ Replaceall(out, "(", "_xx_lparen");
+ Replaceall(out, ")", "_xx_rparen");
+ Replaceall(out, "[", "_xx_lbrace");
+ Replaceall(out, "]", "_xx_rbrace");
+ Replaceall(out, "~", "_xx_bnot");
+ Replaceall(out, "=", "_xx_equals");
+ Replaceall(out, "/", "_xx_slash");
+ Replaceall(out, ".", "_xx_dot");
+ Replaceall(out, "?", "_xx_question");
+ Replaceall(out, ":", "_xx_colon");
+ return out;
+ }
+
+ SwigType *fully_qualified_enum_type(Node *n) {
+ Node *parent = 0;
+ String *fully_qualified_name = NewString("");
+ String *parent_type = 0;
+
+ parent = parentNode(n);
+ while (parent) {
+ parent_type = nodeType(parent);
+ if (Getattr(parent, "name")) {
+ String *parent_copy = NewStringf("%s::", Getattr(parent, "name"));
+ if (Cmp(parent_type, "class") == 0 || Cmp(parent_type, "namespace") == 0)
+ Insert(fully_qualified_name, 0, parent_copy);
+ Delete(parent_copy);
+ }
+ if (!Cmp(parent_type, "class"))
+ break;
+ parent = parentNode(parent);
+ }
+
+ return fully_qualified_name;
+ }
+
+ /* Benedikt Grundmann inspired --> Enum wrap styles */
+
+ int enumvalueDeclaration(Node *n) {
+ String *name = Getattr(n, "name");
+ String *symname = Getattr(n, "sym:name");
+ SwigType *qtype = 0;
+
+ if (name_qualifier_type) {
+ qtype = Copy(name_qualifier_type);
+ Printv(qtype, name, NIL);
+ }
+
+ if (const_enum && qtype && symname && !Getattr(seen_enumvalues, symname)) {
+ Setattr(seen_enumvalues, symname, "true");
+ SetFlag(n, "feature:immutable");
+ Setattr(n, "feature:enumvalue", "1"); // this does not appear to be used
+
+ Setattr(n, "qualified:name", SwigType_namestr(qtype));
+
+ String *evname = SwigType_manglestr(qtype);
+ Insert(evname, 0, "SWIG_ENUM_");
+
+ Setattr(n, "feature:enumvname", symname);
+ Setattr(n, "feature:symname", evname);
+ Delete(evname);
+ Printf(f_enumtypes_value, "| `%s\n", symname);
+
+ return Language::enumvalueDeclaration(n);
+ } else
+ return SWIG_OK;
+ }
+
+ /* -------------------------------------------------------------------
+ * This function is a bit uglier than it deserves.
+ *
+ * I used to direct lookup the name of the enum. Now that certain fixes
+ * have been made in other places, the names of enums are now fully
+ * qualified, which is a good thing, overall, but requires me to do
+ * some legwork.
+ *
+ * The other thing that uglifies this function is the varying way that
+ * typedef enum and enum are handled. I need to produce consistent names,
+ * which means looking up and registering by typedef and enum name. */
+ int enumDeclaration(Node *n) {
+ if (getCurrentClass() && (cplus_mode != PUBLIC))
+ return SWIG_NOWRAP;
+
+ String *name = Getattr(n, "name");
+ if (name) {
+ String *oname = NewString(name);
+ /* name is now fully qualified */
+ String *fully_qualified_name = NewString(name);
+ bool seen_enum = false;
+ if (name_qualifier_type)
+ Delete(name_qualifier_type);
+ char *strip_position;
+ name_qualifier_type = fully_qualified_enum_type(n);
+
+ strip_position = strstr(Char(oname), "::");
+
+ while (strip_position) {
+ strip_position += 2;
+ oname = NewString(strip_position);
+ strip_position = strstr(Char(oname), "::");
+ }
+
+ seen_enum = (Getattr(seen_enums, fully_qualified_name) ? true : false);
+
+ if (!seen_enum) {
+ const_enum = true;
+ Printf(f_enum_to_int, "| `%s -> (match y with\n", oname);
+ Printf(f_int_to_enum, "| `%s -> C_enum (\n", oname);
+ /* * * * A note about enum name resolution * * * *
+ * This code should now work, but I think we can do a bit better.
+ * The problem I'm having is that swig isn't very precise about
+ * typedef name resolution. My opinion is that SwigType_typedef
+ * resolve_all should *always* return the enum tag if one exists,
+ * rather than the admittedly friendlier enclosing typedef.
+ *
+ * This would make one of the cases below unnecessary.
+ * * * */
+ Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", fully_qualified_name, oname);
+ if (!strncmp(Char(fully_qualified_name), "enum ", 5)) {
+ String *fq_noenum = NewString(Char(fully_qualified_name) + 5);
+ Printf(f_mlbody,
+ "let _ = Callback.register \"%s_marker\" (`%s)\n" "let _ = Callback.register \"%s_marker\" (`%s)\n", fq_noenum, oname, fq_noenum, name);
+ }
+
+ Printf(f_enumtypes_type, "| `%s\n", oname);
+ Insert(fully_qualified_name, 0, "enum ");
+ Setattr(seen_enums, fully_qualified_name, n);
+ }
+ }
+
+ int ret = Language::enumDeclaration(n);
+
+ if (const_enum) {
+ Printf(f_int_to_enum, "`Int y)\n");
+ Printf(f_enum_to_int, "| `Int x -> Swig.C_int x\n" "| _ -> raise (LabelNotFromThisEnum v))\n");
+ }
+
+ const_enum = false;
+
+ return ret;
+ }
+
+ /* ----------------------------------------------------------------------------
+ * BEGIN C++ Director Class modifications
+ * ------------------------------------------------------------------------- */
+
+ /*
+ * Modified polymorphism code for Ocaml language module.
+ *
+ * TODO
+ *
+ * Move some boilerplate code generation to Swig_...() functions.
+ *
+ */
+
+ /* ---------------------------------------------------------------
+ * classDirectorMethod()
+ *
+ * Emit a virtual director method to pass a method call on to the
+ * underlying Python object.
+ *
+ * --------------------------------------------------------------- */
+
+ int classDirectorMethod(Node *n, Node *parent, String *super) {
+ int is_void = 0;
+ int is_pointer = 0;
+ String *storage = Getattr(n, "storage");
+ String *value = Getattr(n, "value");
+ String *decl = Getattr(n, "decl");
+ SwigType *returntype = Getattr(n, "type");
+ String *name = Getattr(n, "name");
+ String *classname = Getattr(parent, "sym:name");
+ String *c_classname = Getattr(parent, "name");
+ String *symname = Getattr(n, "sym:name");
+ String *declaration = NewString("");
+ ParmList *l = Getattr(n, "parms");
+ Wrapper *w = NewWrapper();
+ String *tm;
+ String *wrap_args = NewString("");
+ int status = SWIG_OK;
+ int idx;
+ bool pure_virtual = false;
+ bool ignored_method = GetFlag(n, "feature:ignore") ? true : false;
+
+ if (Cmp(storage, "virtual") == 0) {
+ if (Cmp(value, "0") == 0) {
+ pure_virtual = true;
+ }
+ }
+ Printf(w->locals, "CAMLparam0();\n");
+
+ /* determine if the method returns a pointer */
+ is_pointer = SwigType_ispointer_return(decl);
+ is_void = (!Cmp(returntype, "void") && !is_pointer);
+
+ /* virtual method definition */
+ String *target;
+ String *pclassname = NewStringf("SwigDirector_%s", classname);
+ String *qualified_name = NewStringf("%s::%s", pclassname, name);
+ SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type");
+ target = Swig_method_decl(rtype, decl, qualified_name, l, 0);
+ Printf(w->def, "%s", target);
+ Delete(qualified_name);
+ Delete(target);
+ /* header declaration */
+ target = Swig_method_decl(rtype, decl, name, l, 1);
+ Printf(declaration, " virtual %s", target);
+ Delete(target);
+
+ // Get any exception classes in the throws typemap
+ if (Getattr(n, "noexcept")) {
+ Append(w->def, " noexcept");
+ Append(declaration, " noexcept");
+ }
+ ParmList *throw_parm_list = 0;
+ if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) {
+ Parm *p;
+ int gencomma = 0;
+
+ Append(w->def, " throw(");
+ Append(declaration, " throw(");
+
+ if (throw_parm_list)
+ Swig_typemap_attach_parms("throws", throw_parm_list, 0);
+ for (p = throw_parm_list; p; p = nextSibling(p)) {
+ if (Getattr(p, "tmap:throws")) {
+ if (gencomma++) {
+ Append(w->def, ", ");
+ Append(declaration, ", ");
+ }
+ String *str = SwigType_str(Getattr(p, "type"), 0);
+ Append(w->def, str);
+ Append(declaration, str);
+ Delete(str);
+ }
+ }
+ Append(w->def, ")");
+ Append(declaration, ")");
+ }
+ Append(w->def, " {");
+ Append(declaration, ";\n");
+ /* declare method return value
+ * if the return value is a reference or const reference, a specialized typemap must
+ * handle it, including declaration of c_result ($result).
+ */
+ if (!is_void && (!ignored_method || pure_virtual)) {
+ if (!SwigType_isclass(returntype)) {
+ if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) {
+ String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0));
+ Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL);
+ Delete(construct_result);
+ } else {
+ Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL);
+ }
+ } else {
+ String *cres = SwigType_lstr(returntype, "c_result");
+ Printf(w->code, "%s;\n", cres);
+ Delete(cres);
+ }
+ }
+
+ if (ignored_method) {
+ if (!pure_virtual) {
+ String *super_call = Swig_method_call(super, l);
+ if (is_void)
+ Printf(w->code, "%s;\n", super_call);
+ else
+ Printf(w->code, "CAMLreturnT(%s, %s);\n", SwigType_str(returntype, 0), super_call);
+ Delete(super_call);
+ } else {
+ Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname),
+ SwigType_namestr(name));
+ }
+ } else {
+ Wrapper_add_local(w, "swig_result", "CAMLlocal2(swig_result, args)");
+ /* attach typemaps to arguments (C/C++ -> Ocaml) */
+ String *arglist = NewString("");
+
+ Swig_director_parms_fixup(l);
+
+ Swig_typemap_attach_parms("in", l, 0);
+ Swig_typemap_attach_parms("directorin", l, w);
+ Swig_typemap_attach_parms("directorargout", l, w);
+
+ Parm *p;
+ int num_arguments = emit_num_arguments(l);
+ int i;
+ char source[256];
+
+ /* build argument list and type conversion string */
+ for (i = 0, idx = 0, p = l; i < num_arguments; i++) {
+ String *pname = Getattr(p, "name");
+ String *ptype = Getattr(p, "type");
+
+ Putc(',', arglist);
+ if ((tm = Getattr(p, "tmap:directorin")) != 0) {
+ Setattr(p, "emit:directorinput", pname);
+ Replaceall(tm, "$input", pname);
+ Replaceall(tm, "$owner", "0");
+ if (Len(tm) == 0)
+ Append(tm, pname);
+ Printv(wrap_args, tm, "\n", NIL);
+ p = Getattr(p, "tmap:directorin:next");
+ continue;
+ } else if (Cmp(ptype, "void")) {
+ /* special handling for pointers to other C++ director classes.
+ * ideally this would be left to a typemap, but there is currently no
+ * way to selectively apply the dynamic_cast<> to classes that have
+ * directors. in other words, the type "SwigDirector_$1_lname" only exists
+ * for classes with directors. we avoid the problem here by checking
+ * module.wrap::directormap, but it's not clear how to get a typemap to
+ * do something similar. perhaps a new default typemap (in addition
+ * to SWIGTYPE) called DIRECTORTYPE?
+ */
+ if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) {
+ Node *module = Getattr(parent, "module");
+ Node *target = Swig_directormap(module, ptype);
+ sprintf(source, "obj%d", idx++);
+ String *nonconst = 0;
+ /* strip pointer/reference --- should move to Swig/stype.c */
+ String *nptype = NewString(Char(ptype) + 2);
+ /* name as pointer */
+ String *ppname = Copy(pname);
+ if (SwigType_isreference(ptype)) {
+ Insert(ppname, 0, "&");
+ }
+ /* if necessary, cast away const since Python doesn't support it! */
+ if (SwigType_isconst(nptype)) {
+ nonconst = NewStringf("nc_tmp_%s", pname);
+ String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(ptype, 0), ppname);
+ Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL);
+ Delete(nonconst_i);
+ Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number,
+ "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(ptype, pname),
+ SwigType_namestr(c_classname), SwigType_namestr(name));
+ } else {
+ nonconst = Copy(ppname);
+ }
+ Delete(nptype);
+ Delete(ppname);
+ String *mangle = SwigType_manglestr(ptype);
+ if (target) {
+ String *director = NewStringf("director_%s", mangle);
+ Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL);
+ Wrapper_add_localv(w, source, "value", source, "= Val_unit", NIL);
+ Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst);
+ Printf(wrap_args, "if (!%s) {\n", director);
+ Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle);
+ Printf(wrap_args, "} else {\n");
+ Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director);
+ Printf(wrap_args, "}\n");
+ Delete(director);
+ Printv(arglist, source, NIL);
+ } else {
+ Wrapper_add_localv(w, source, "value", source, "= Val_unit", NIL);
+ Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle);
+ //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n",
+ // source, nonconst, base);
+ Printv(arglist, source, NIL);
+ }
+ Delete(mangle);
+ Delete(nonconst);
+ } else {
+ Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number,
+ "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0),
+ SwigType_namestr(c_classname), SwigType_namestr(name));
+ status = SWIG_NOWRAP;
+ break;
+ }
+ }
+ p = nextSibling(p);
+ }
+
+ Printv(w->code, "swig_result = Val_unit;\n", 0);
+ Printf(w->code, "args = Val_unit;\n");
+
+ /* wrap complex arguments to values */
+ Printv(w->code, wrap_args, NIL);
+
+ /* pass the method call on to the OCaml object */
+ Printv(w->code,
+ "swig_result = caml_swig_alloc(1,C_list);\n" "Store_field(swig_result,0,args);\n" "args = swig_result;\n" "swig_result = Val_unit;\n", 0);
+ Printf(w->code, "static const value *swig_ocaml_func_val = NULL;\n" "if (!swig_ocaml_func_val) {\n");
+ Printf(w->code, " swig_ocaml_func_val = caml_named_value(\"swig_runmethod\");\n }\n");
+ Printf(w->code, "swig_result = caml_callback3(*swig_ocaml_func_val,swig_get_self(),caml_copy_string(\"%s\"),args);\n", Getattr(n, "name"));
+ /* exception handling */
+ tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0);
+ if (!tm) {
+ tm = Getattr(n, "feature:director:except");
+ }
+ if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) {
+ Printf(w->code, "if (!%s) {\n", Swig_cresult_name());
+ Printf(w->code, " value error = *caml_named_value(\"director_except\");\n");
+ Replaceall(tm, "$error", "error");
+ Printv(w->code, Str(tm), "\n", NIL);
+ Printf(w->code, "}\n");
+ }
+
+ /*
+ * Python method may return a simple object, or a tuple.
+ * for in/out arguments, we have to extract the appropriate values from the
+ * argument list, then marshal everything back to C/C++ (return value and
+ * output arguments).
+ */
+
+ /* marshal return value and other outputs (if any) from value to C/C++
+ * type */
+
+ String *cleanup = NewString("");
+ String *outarg = NewString("");
+
+ tm = Swig_typemap_lookup("directorout", n, "c_result", w);
+ if (tm != 0) {
+ Replaceall(tm, "$input", "swig_result");
+ /* TODO check this */
+ if (Getattr(n, "wrap:disown")) {
+ Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN");
+ } else {
+ Replaceall(tm, "$disown", "0");
+ }
+ Replaceall(tm, "$result", "c_result");
+ Printv(w->code, tm, "\n", NIL);
+ }
+
+ /* marshal outputs */
+ for (p = l; p;) {
+ if ((tm = Getattr(p, "tmap:directorargout")) != 0) {
+ Replaceall(tm, "$result", "swig_result");
+ Replaceall(tm, "$input", Getattr(p, "emit:directorinput"));
+ Printv(w->code, tm, "\n", NIL);
+ p = Getattr(p, "tmap:directorargout:next");
+ } else {
+ p = nextSibling(p);
+ }
+ }
+
+ Delete(arglist);
+ Delete(cleanup);
+ Delete(outarg);
+ }
+
+ /* any existing helper functions to handle this? */
+ if (!is_void) {
+ if (!(ignored_method && !pure_virtual)) {
+ String *rettype = SwigType_str(returntype, 0);
+ if (!SwigType_isreference(returntype)) {
+ Printf(w->code, "CAMLreturnT(%s, (%s)c_result);\n", rettype, rettype);
+ } else {
+ Printf(w->code, "CAMLreturnT(%s, (%s)*c_result);\n", rettype, rettype);
+ }
+ Delete(rettype);
+ }
+ } else {
+ Printf(w->code, "CAMLreturn0;\n");
+ }
+
+ Printf(w->code, "}\n");
+
+ // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
+ String *inline_extra_method = NewString("");
+ if (dirprot_mode() && !is_public(n) && !pure_virtual) {
+ Printv(inline_extra_method, declaration, NIL);
+ String *extra_method_name = NewStringf("%sSwigPublic", name);
+ Replaceall(inline_extra_method, name, extra_method_name);
+ Replaceall(inline_extra_method, ";\n", " {\n ");
+ if (!is_void)
+ Printf(inline_extra_method, "return ");
+ String *methodcall = Swig_method_call(super, l);
+ Printv(inline_extra_method, methodcall, ";\n }\n", NIL);
+ Delete(methodcall);
+ Delete(extra_method_name);
+ }
+
+ /* emit the director method */
+ if (status == SWIG_OK) {
+ Replaceall(w->code, "$isvoid", is_void ? "1" : "0");
+ if (!Getattr(n, "defaultargs")) {
+ Replaceall(w->code, "$symname", symname);
+ Wrapper_print(w, f_directors);
+ Printv(f_directors_h, declaration, NIL);
+ Printv(f_directors_h, inline_extra_method, NIL);
+ }
+ }
+
+ /* clean up */
+ Delete(wrap_args);
+ Delete(pclassname);
+ DelWrapper(w);
+ return status;
+ }
+
+ /* ------------------------------------------------------------
+ * classDirectorConstructor()
+ * ------------------------------------------------------------ */
+
+ int classDirectorConstructor(Node *n) {
+ Node *parent = Getattr(n, "parentNode");
+ String *sub = NewString("");
+ String *decl = Getattr(n, "decl");
+ String *supername = Swig_class_name(parent);
+ String *classname = NewString("");
+ Printf(classname, "SwigDirector_%s", supername);
+
+ /* insert self parameter */
+ Parm *p, *q;
+ ParmList *superparms = Getattr(n, "parms");
+ ParmList *parms = CopyParmList(superparms);
+ String *type = NewString("value");
+ p = NewParm(type, NewString("self"), n);
+ q = Copy(p);
+ set_nextSibling(q, superparms);
+ set_nextSibling(p, parms);
+ parms = p;
+
+ if (!Getattr(n, "defaultargs")) {
+ /* constructor */
+ {
+ Wrapper *w = NewWrapper();
+ String *call;
+ String *basetype = Getattr(parent, "classtype");
+ String *target = Swig_method_decl(0, decl, classname, parms, 0);
+ call = Swig_csuperclass_call(0, basetype, superparms);
+ Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call);
+ Delete(target);
+ Wrapper_print(w, f_directors);
+ Delete(call);
+ DelWrapper(w);
+ }
+
+ /* constructor header */
+ {
+ String *target = Swig_method_decl(0, decl, classname, parms, 1);
+ Printf(f_directors_h, " %s;\n", target);
+ Delete(target);
+ }
+ }
+
+ Setattr(n, "parms", q);
+ Language::classDirectorConstructor(n);
+
+ Delete(sub);
+ Delete(classname);
+ Delete(supername);
+ //Delete(parms);
+
+ return SWIG_OK;
+ }
+
+ /* ------------------------------------------------------------
+ * classDirectorDefaultConstructor()
+ * ------------------------------------------------------------ */
+
+ int classDirectorDefaultConstructor(Node *n) {
+ String *classname;
+ classname = Swig_class_name(n);
+
+ /* insert self parameter */
+ Parm *p, *q;
+ ParmList *superparms = Getattr(n, "parms");
+ ParmList *parms = CopyParmList(superparms);
+ String *type = NewString("value");
+ p = NewParm(type, NewString("self"), n);
+ q = Copy(p);
+ set_nextSibling(p, parms);
+
+ {
+ Wrapper *w = NewWrapper();
+ Printf(w->def, "SwigDirector_%s::SwigDirector_%s(value self) : Swig::Director(self) { }", classname, classname);
+ Wrapper_print(w, f_directors);
+ DelWrapper(w);
+ }
+ Printf(f_directors_h, " SwigDirector_%s(value self);\n", classname);
+ Delete(classname);
+ Setattr(n, "parms", q);
+ return Language::classDirectorDefaultConstructor(n);
+ }
+
+ int classDirectorInit(Node *n) {
+ String *declaration = Swig_director_declaration(n);
+ Printf(f_directors_h, "\n" "%s\n" "public:\n", declaration);
+ Delete(declaration);
+ return Language::classDirectorInit(n);
+ }
+
+ int classDirectorEnd(Node *n) {
+ Printf(f_directors_h, "};\n\n");
+ return Language::classDirectorEnd(n);
+ }
+
+ /* ---------------------------------------------------------------------
+ * typedefHandler
+ *
+ * This is here in order to maintain the correct association between
+ * typedef names and enum names.
+ *
+ * Since I implement enums as polymorphic variant tags, I need to call
+ * back into ocaml to evaluate them. This requires a string that can
+ * be generated in the typemaps, and also at SWIG time to be the same
+ * string. The problem that arises is that SWIG variously generates
+ * enum e_name_tag
+ * e_name_tag
+ * e_typedef_name
+ * for
+ * typedef enum e_name_tag { ... } e_typedef_name;
+ *
+ * Since I need these strings to be consistent, I must maintain a correct
+ * association list between typedef and enum names.
+ * --------------------------------------------------------------------- */
+ int typedefHandler(Node *n) {
+ String *type = Getattr(n, "type");
+ Node *enum_node = type ? Getattr(seen_enums, type) : 0;
+ if (enum_node) {
+ String *name = Getattr(enum_node, "name");
+
+ Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", Getattr(n, "name"), name);
+
+ }
+ return SWIG_OK;
+ }
+
+ String *runtimeCode() {
+ String *s = Swig_include_sys("ocamlrun.swg");
+ if (!s) {
+ Printf(stderr, "*** Unable to open 'ocamlrun.swg'\n");
+ s = NewString("");
+ }
+ return s;
+ }
+
+ String *defaultExternalRuntimeFilename() {
+ return NewString("swigocamlrun.h");
+ }
+};
+
+/* -------------------------------------------------------------------------
+ * swig_ocaml() - Instantiate module
+ * ------------------------------------------------------------------------- */
+
+static Language *new_swig_ocaml() {
+ return new OCAML();
+}
+extern "C" Language *swig_ocaml(void) {
+ return new_swig_ocaml();
+}