More implementation.
[wrappi.git] / generator / wrappi_c_impl.ml
index 8742fad..c3e2ed7 100644 (file)
@@ -46,12 +46,19 @@ let c_of_ptype ~param = function
 
 let c_of_rtype = function
   | RVoid -> "void"
+  | RStaticString -> "const char *"
   | Return t -> c_of_ptype ~param:false t
 
-let pr_decl ep =
+let pr_defn ?(impl = false) ep =
   let ret, req, opt = ep.ep_ftype in
-  pr "%s\n" (c_of_rtype ret);
-  pr "wrap_%s (wrap_h *w" ep.ep_name;
+
+  if not impl then (
+    pr "%s\n" (c_of_rtype ret);
+    pr "wrap_%s (wrap_h *w" ep.ep_name
+  ) else (
+    pr "static %s\n" (c_of_rtype ret);
+    pr "impl_%s (struct wrap_internal_h *w" ep.ep_name
+  );
 
   (* Required parameters. *)
   List.iter (
@@ -73,43 +80,81 @@ let generate_implementation ep =
   generate_header CStyle LGPLv2plus;
 
   pr "\
+/* Automatically generated implementation of '%s'.
+ * This API was defined in '%s' at line %d.
+ */
+
+" ep.ep_name (Loc.file_name ep.ep_loc) (Loc.start_line ep.ep_loc);
+
+  pr "\
 #include <config.h>
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
 ";
   List.iter (pr "#include <%s>\n") ep.ep_includes;
 
 pr "\
 
 #include \"wrappi.h\"
-
 #include \"internal.h\"
 
-/* Automatically generated implementation of '%s'.
- * This API was defined in '%s' at line %d.
- */
+";
 
-" ep.ep_name (Loc.file_name ep.ep_loc) (Loc.start_line ep.ep_loc);
+  pr_defn ~impl:(not ep.ep_local) ep;
 
-  (* Depending on whether this is a local or remote function, include
-   * different definitions here.
+  pr "{\n";
+
+  (match ep.ep_code with
+  | None -> () (* XXX implicit code *)
+  | Some { cc_loc = loc; cc_code = code } ->
+    pr "#line %d \"%s\"\n" (Loc.start_line loc) (Loc.file_name loc);
+    pr "%s" code
+  );
+
+  pr "}\n";
+
+  (* For remote functions only, we now need to generate the
+   * local binding code.
    *)
-  (*if ep.ep_local then ... *)
+  if not ep.ep_local then (
+    pr "\n";
 
-  pr_decl ep;
+    pr_defn ep;
 
-  pr "\
-{
-#line %d \"%s\"
-" (Loc.start_line ep.ep_loc) (Loc.file_name ep.ep_loc);
+    pr "{\n";
+    pr "  assert (w->scheme == NULL); /* XXX */;\n";
+    pr "\n";
+    pr "  ";
 
-  (match ep.ep_code with
-  | None -> ()
-  | Some code -> pr "%s" code
-  );
+    let ret, req, opt = ep.ep_ftype in
+
+    (match ret with
+    | RVoid -> ()
+    | _ -> pr "return "
+    );
+
+    pr "impl_%s ((struct wrap_internal_h *)w" ep.ep_name;
+
+    (* Required parameters. *)
+    List.iter (fun (name, _, _) -> pr ", %s" name) req;
+
+    (* Optional parameters. *)
+    if opt <> [] then
+      assert false; (* XXX not implemented *)
+
+    pr ");\n";
+
+    (match ret with
+    | RVoid -> pr "  return;\n"
+    | _ -> ()
+    );
 
-  pr "}\n"
+    pr "}\n"
+  )
 
 (* Make a unique, reproducible filename for each entry point. *)
 let filename_of_ep ep =
@@ -137,7 +182,7 @@ let generate_lib_implementation_files_mk api =
 
   pr "local_implementation_files := \\\n";
 
-  loop (List.filter (fun ep -> ep.ep_local) eps);
+  loop (List.filter (fun ep -> ep.ep_local && ep.ep_code <> None) eps);
 
   pr "\n";
   pr "remote_implementation_files := \\\n";
@@ -149,11 +194,17 @@ let generate api =
 
   iter_entry_points api (
     fun ep ->
-      let filename = filename_of_ep ep in
+      (* Local entry points which don't have associated code are
+       * assumed to be implemented in hand-written code elsewhere under
+       * lib/.
+       *)
+      if not ep.ep_local || ep.ep_code <> None then (
+        let filename = filename_of_ep ep in
 
-      gitignores := ("/" ^ filename) :: !gitignores;
+        gitignores := ("/" ^ filename) :: !gitignores;
 
-      output_to ("lib/" ^ filename) generate_implementation ep
+        output_to ("lib/" ^ filename) generate_implementation ep
+      )
   );
 
   let gitignores = List.rev !gitignores in