Write host aliases and exclusions to parcel_perl.json
Write host-specific data like method aliases and exclusions to a JSON
file for each parcel. This file is installed in the Clownfish include
directory.
diff --git a/compiler/perl/lib/Clownfish/CFC.xs b/compiler/perl/lib/Clownfish/CFC.xs
index 74bce9d..3fda1c7 100644
--- a/compiler/perl/lib/Clownfish/CFC.xs
+++ b/compiler/perl/lib/Clownfish/CFC.xs
@@ -1884,6 +1884,13 @@
PPCODE:
CFCBindCore_copy_headers(self, dest_dir);
+void
+write_host_data_json(self, dest_dir)
+ CFCBindCore *self;
+ const char *dest_dir;
+PPCODE:
+ CFCBindCore_write_host_data_json(self, dest_dir, "perl");
+
MODULE = Clownfish::CFC PACKAGE = Clownfish::CFC::Binding::Core::Function
diff --git a/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm b/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
index f1c351f..ef0e0f3 100644
--- a/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
+++ b/compiler/perl/lib/Clownfish/CFC/Perl/Build.pm
@@ -288,14 +288,13 @@
footer => '',
);
print "Writing Clownfish autogenerated files...\n";
+ my $inc_dir = catdir( $self->blib, 'arch', 'Clownfish', '_include' );
my $cfh_modified = $core_binding->write_all_modified;
if ($cfh_modified) {
unlink('typemap');
print "Writing typemap...\n";
$self->add_to_cleanup('typemap');
$perl_binding->write_xs_typemap;
-
- my $inc_dir = catdir( $self->blib, 'arch', 'Clownfish', '_include' );
$core_binding->copy_headers($inc_dir);
}
@@ -316,6 +315,8 @@
);
}
+ $core_binding->write_host_data_json($inc_dir);
+
print "Writing POD...\n";
my $pod_files = $perl_binding->write_pod;
$self->add_to_cleanup($_) for @$pod_files;
diff --git a/compiler/src/CFCBindClass.c b/compiler/src/CFCBindClass.c
index ac8b8fd..75b77e9 100644
--- a/compiler/src/CFCBindClass.c
+++ b/compiler/src/CFCBindClass.c
@@ -642,3 +642,41 @@
return short_names;
}
+char*
+CFCBindClass_host_data_json(CFCBindClass *self) {
+ if (CFCClass_final(self->client)) { return CFCUtil_strdup(""); }
+
+ CFCMethod **fresh_methods = CFCClass_fresh_methods(self->client);
+ char *methods_json = CFCUtil_strdup("");
+
+ for (int i = 0; fresh_methods[i] != NULL; i++) {
+ CFCMethod *method = fresh_methods[i];
+ char *method_json = CFCBindMeth_host_data_json(method);
+ if (method_json[0] != '\0') {
+ const char *sep = methods_json[0] == '\0' ? "" : ",\n";
+ methods_json = CFCUtil_cat(methods_json, sep, method_json, NULL);
+ }
+ FREEMEM(method_json);
+ }
+
+ char *json;
+
+ if (methods_json[0] == '\0') {
+ json = CFCUtil_strdup("");
+ }
+ else {
+ const char *class_name = CFCClass_get_name(self->client);
+
+ const char *pattern =
+ " \"%s\": {\n"
+ " \"methods\": {\n"
+ "%s\n"
+ " }\n"
+ " }";
+ json = CFCUtil_sprintf(pattern, class_name, methods_json);
+ }
+
+ FREEMEM(methods_json);
+ return json;
+}
+
diff --git a/compiler/src/CFCBindClass.h b/compiler/src/CFCBindClass.h
index 4780bdc..450e0aa 100644
--- a/compiler/src/CFCBindClass.h
+++ b/compiler/src/CFCBindClass.h
@@ -54,6 +54,11 @@
char*
CFCBindClass_to_c_data(CFCBindClass *self);
+/** Return host-specific data for the class as JSON fragment.
+ */
+char*
+CFCBindClass_host_data_json(CFCBindClass *self);
+
#ifdef __cplusplus
}
#endif
diff --git a/compiler/src/CFCBindCore.c b/compiler/src/CFCBindCore.c
index c835cc9..ecdc091 100644
--- a/compiler/src/CFCBindCore.c
+++ b/compiler/src/CFCBindCore.c
@@ -74,6 +74,10 @@
static char*
S_charmony_alloca_defines();
+static void
+S_write_host_data_json(CFCBindCore *self, CFCParcel *parcel,
+ const char *dest_dir, const char *host_lang);
+
static const CFCMeta CFCBINDCORE_META = {
"Clownfish::CFC::Binding::Core",
sizeof(CFCBindCore),
@@ -759,4 +763,67 @@
FREEMEM(default_dest);
}
+void
+CFCBindCore_write_host_data_json(CFCBindCore *self, const char *dest_dir,
+ const char *host_lang) {
+ CFCParcel **parcels = CFCParcel_all_parcels();
+
+ for (size_t i = 0; parcels[i] != NULL; i++) {
+ CFCParcel *parcel = parcels[i];
+ if (!CFCParcel_included(parcel) && CFCParcel_is_installed(parcel)) {
+ S_write_host_data_json(self, parcel, dest_dir, host_lang);
+ }
+ }
+}
+
+static void
+S_write_host_data_json(CFCBindCore *self, CFCParcel *parcel,
+ const char *dest_dir, const char *host_lang) {
+ const char *prefix = CFCParcel_get_prefix(parcel);
+ const char *parcel_name = CFCParcel_get_name(parcel);
+ CFCVersion *version = CFCParcel_get_version(parcel);
+ const char *vstring = CFCVersion_get_vstring(version);
+
+ char *classes_json = CFCUtil_strdup("");
+ CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy);
+
+ for (size_t i = 0; ordered[i] != NULL; i++) {
+ CFCClass *klass = ordered[i];
+ const char *class_prefix = CFCClass_get_prefix(klass);
+ if (strcmp(class_prefix, prefix) != 0) { continue; }
+
+ CFCBindClass *class_binding = CFCBindClass_new(klass);
+
+ char *class_json = CFCBindClass_host_data_json(class_binding);
+ if (class_json[0] != '\0') {
+ const char *sep = classes_json[0] == '\0' ? "" : ",\n";
+ classes_json = CFCUtil_cat(classes_json, sep, class_json, NULL);
+ }
+
+ FREEMEM(class_json);
+ CFCBase_decref((CFCBase*)class_binding);
+ }
+ FREEMEM(ordered);
+
+ char *filepath = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s" CHY_DIR_SEP "%s"
+ CHY_DIR_SEP "parcel_%s.json", dest_dir,
+ parcel_name, vstring, host_lang);
+ remove(filepath);
+
+ if (classes_json[0] != '\0') {
+ const char *pattern =
+ "{\n"
+ " \"classes\": {\n"
+ "%s\n"
+ " }\n"
+ "}\n";
+ char *json = CFCUtil_sprintf(pattern, classes_json);
+ CFCUtil_write_file(filepath, json, strlen(json));
+ FREEMEM(json);
+ }
+
+ FREEMEM(filepath);
+ FREEMEM(classes_json);
+}
+
diff --git a/compiler/src/CFCBindCore.h b/compiler/src/CFCBindCore.h
index eff3efe..aa40bb2 100644
--- a/compiler/src/CFCBindCore.h
+++ b/compiler/src/CFCBindCore.h
@@ -66,6 +66,12 @@
void
CFCBindCore_copy_headers(CFCBindCore *self, const char *dest_dir);
+/* Write host-specific data to a JSON file for each source parcel.
+ */
+void
+CFCBindCore_write_host_data_json(CFCBindCore *self, const char *dest_dir,
+ const char *host_lang);
+
#ifdef __cplusplus
}
#endif
diff --git a/compiler/src/CFCBindMethod.c b/compiler/src/CFCBindMethod.c
index 400d554..d57a29e 100644
--- a/compiler/src/CFCBindMethod.c
+++ b/compiler/src/CFCBindMethod.c
@@ -228,3 +228,37 @@
return buf;
}
+char*
+CFCBindMeth_host_data_json(CFCMethod *method) {
+ if (!CFCMethod_novel(method)) { return CFCUtil_strdup(""); }
+
+ int excluded = CFCMethod_excluded_from_host(method);
+ const char *alias = CFCMethod_get_host_alias(method);
+ char *pair = NULL;
+ char *json = NULL;
+
+ if (excluded) {
+ pair = CFCUtil_strdup("\"excluded\": true");
+ }
+ else if (alias) {
+ pair = CFCUtil_sprintf("\"alias\": \"%s\"", alias);
+ }
+
+ if (pair) {
+ const char *method_name = CFCMethod_get_name(method);
+
+ const char *pattern =
+ " \"%s\": {\n"
+ " %s\n"
+ " }";
+ json = CFCUtil_sprintf(pattern, method_name, pair);
+
+ FREEMEM(pair);
+ }
+ else {
+ json = CFCUtil_strdup("");
+ }
+
+ return json;
+}
+
diff --git a/compiler/src/CFCBindMethod.h b/compiler/src/CFCBindMethod.h
index 4928c70..f1b0bd4 100644
--- a/compiler/src/CFCBindMethod.h
+++ b/compiler/src/CFCBindMethod.h
@@ -57,6 +57,12 @@
char*
CFCBindMeth_imp_declaration(struct CFCMethod *method, struct CFCClass *klass);
+/** Return a JSON fragment for method data specified by the host bindings
+ * (alias or excluded).
+ */
+char*
+CFCBindMeth_host_data_json(struct CFCMethod *method);
+
#ifdef __cplusplus
}
#endif