Extract CFC DocuComments from C headers

Write a quick and dirty parser that builds CFC classes with DocuComments
from C headers. Then the .pod files for Clownfish::CFC can be generated
using CFC itself.


Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/23804547
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/23804547
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/23804547

Branch: refs/heads/cfc-pod-wip2
Commit: 238045473f03f0bff8f736e06809fd2b3d0cd56f
Parents: fc81f67
Author: Nick Wellnhofer <[email protected]>
Authored: Wed Jun 25 17:42:00 2014 +0200
Committer: Nick Wellnhofer <[email protected]>
Committed: Wed Jun 25 17:44:59 2014 +0200

----------------------------------------------------------------------
 compiler/perl/.gitignore                        |   1 +
 compiler/perl/buildlib/Clownfish/CFC/Build.pm   |  67 ++++++++
 .../buildlib/Clownfish/CFC/Build/Binding.pm     | 151 +++++++++++++++++++
 3 files changed, 219 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/23804547/compiler/perl/.gitignore
----------------------------------------------------------------------
diff --git a/compiler/perl/.gitignore b/compiler/perl/.gitignore
index 5517019..36bb0e4 100644
--- a/compiler/perl/.gitignore
+++ b/compiler/perl/.gitignore
@@ -1,3 +1,4 @@
+*.pod
 /Build
 /Charmony.pm
 /MYMETA.json

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/23804547/compiler/perl/buildlib/Clownfish/CFC/Build.pm
----------------------------------------------------------------------
diff --git a/compiler/perl/buildlib/Clownfish/CFC/Build.pm 
b/compiler/perl/buildlib/Clownfish/CFC/Build.pm
index 93fa675..d3040f6 100644
--- a/compiler/perl/buildlib/Clownfish/CFC/Build.pm
+++ b/compiler/perl/buildlib/Clownfish/CFC/Build.pm
@@ -144,5 +144,72 @@ sub ACTION_code {
     $self->SUPER::ACTION_code;
 }
 
+sub ACTION_pod {
+    my $self = shift;
+
+    $self->depends_on('code');
+
+    local @INC = ( @INC, qw( blib/lib blib/arch ) );
+    require Clownfish::CFC;
+
+    # Create a dummy hierarchy.
+    my $hierarchy = Clownfish::CFC::Model::Hierarchy->new(
+        dest => 'autogen',
+    );
+
+    # Process all Binding classes in buildlib.
+    my $pm_filepaths = $self->rscan_dir( 'buildlib', qr/\.pm$/ );
+    for my $pm_filepath (@$pm_filepaths) {
+        next unless $pm_filepath =~ /Binding/;
+        require $pm_filepath;
+        my $package_name = $pm_filepath;
+        $package_name =~ s/buildlib\/(.*)\.pm$/$1/;
+        $package_name =~ s/\//::/g;
+        $package_name->bind_all($hierarchy);
+    }
+
+    my $binding = Clownfish::CFC::Binding::Perl->new(
+        hierarchy  => $hierarchy,
+        lib_dir    => 'lib',
+        boot_class => 'Clownfish::CFC',
+        header     => $self->autogen_header,
+        footer     => '',
+    );
+
+    print "Writing POD...\n";
+    my $pod_files = $binding->write_pod;
+    $self->add_to_cleanup($_) for @$pod_files;
+}
+
+sub autogen_header {
+    my $self = shift;
+    return <<"END_AUTOGEN";
+/***********************************************
+
+ !!!! DO NOT EDIT !!!!
+
+ This file was auto-generated by Build.PL.
+
+ ***********************************************/
+
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+END_AUTOGEN
+}
+
 1;
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/23804547/compiler/perl/buildlib/Clownfish/CFC/Build/Binding.pm
----------------------------------------------------------------------
diff --git a/compiler/perl/buildlib/Clownfish/CFC/Build/Binding.pm 
b/compiler/perl/buildlib/Clownfish/CFC/Build/Binding.pm
new file mode 100644
index 0000000..fc4d8d9
--- /dev/null
+++ b/compiler/perl/buildlib/Clownfish/CFC/Build/Binding.pm
@@ -0,0 +1,151 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package Clownfish::CFC::Build::Binding;
+use strict;
+
+sub bind_all {
+    my $class = shift;
+}
+
+# Quick and dirty hack to create a CFC class from a C header.
+sub class_from_c {
+    my ($cfc_class_name, $class_name) = @_;
+
+    $class_name =~ /::(\w+)$/;
+    my $last_component = $1;
+
+    my $h_filename = "../src/$cfc_class_name.h";
+    open(my $h_file, '<', $h_filename)
+        or die("$h_filename: $!");
+
+    my ($class_doc, $function_doc, @functions);
+    my $state = 'before_class_doc';
+
+    while (my $line = <$h_file>) {
+        if ($state eq 'before_class_doc') {
+            if ($line =~ m"^/\*\*") {
+                $class_doc = $line;
+                $state = 'in_class_doc';
+            }
+        }
+        elsif ($state eq 'in_class_doc') {
+            $class_doc .= $line;
+            if ($line =~ m"\*/") {
+                $state = 'before_function_doc';
+            }
+        }
+        elsif ($state eq 'before_function_doc') {
+            if ($line =~ m"^/\*\*") {
+                $function_doc = $line;
+                $state = 'in_function_doc';
+            }
+        }
+        elsif ($state eq 'in_function_doc') {
+            $function_doc .= $line;
+            if ($line =~ m"\*/") {
+                $state = 'after_function_doc';
+            }
+        }
+        elsif ($state eq 'after_function_doc') {
+            if ($line =~ m"^${cfc_class_name}_(\w+)(\(.*)") {
+                my $function_name = $1;
+                my $c_params      = $2;
+
+                while ($c_params !~ /\)/) {
+                    $c_params .= <$h_file>;
+                }
+
+                $c_params =~ s/\).*/\)/;
+
+                push(@functions, {
+                    name     => $function_name,
+                    c_params => $c_params,
+                    doc      => $function_doc,
+                });
+
+                $state = 'before_function_doc';
+            }
+        }
+    }
+
+    close($h_file);
+
+    my $class = Clownfish::CFC::Model::Class->create(
+        parcel      => 'Clownfish',
+        class_name  => $class_name,
+        docucomment => Clownfish::CFC::Model::DocuComment->parse($class_doc),
+    );
+
+    my $parser    = Clownfish::CFC::Parser->new;
+    my $void_type = Clownfish::CFC::Model::Type->new_void;
+
+    $parser->parse('parcel Clownfish;');
+
+    for my $function (@functions) {
+        my $name     = $function->{name};
+        my $c_params = $function->{c_params};
+        my $dc = Clownfish::CFC::Model::DocuComment->parse($function->{doc});
+
+        # "struct" is not allowed in Clownfish types.
+        $c_params =~ s/\bstruct //g;
+        # Clownfish reserved words.
+        $c_params =~ s/\bparcel\b/_$&/g;
+        # Empty param list.
+        $c_params = '()' if $c_params eq '(void)';
+
+        if ($c_params =~ /\($cfc_class_name \*self/) {
+            my $macro_sym = $name;
+            $macro_sym =~ s/(^|_)([a-z])/$1 . uc($2)/ge;
+
+            $c_params =~ s/^\(\w+/($last_component/;
+            my $param_list = $parser->parse($c_params)
+                or die("Invalid param list: $c_params");
+
+            my $method = Clownfish::CFC::Model::Method->new(
+                parcel      => 'Clownfish',
+                class_name  => $class_name,
+                exposure    => 'public',
+                macro_sym   => $macro_sym,
+                docucomment => $dc,
+                return_type => $void_type,
+                param_list  => $param_list,
+            );
+            $class->add_method($method);
+        }
+        else {
+            $name = 'init' if $name eq 'new';
+
+            my $param_list = $parser->parse($c_params)
+                or die("Invalid param list: $c_params");
+
+            my $function = Clownfish::CFC::Model::Function->new(
+                parcel      => 'Clownfish',
+                class_name  => $class_name,
+                exposure    => 'public',
+                micro_sym   => $name,
+                docucomment => $dc,
+                return_type => $void_type,
+                param_list  => $param_list,
+            );
+            $class->add_function($function);
+        }
+    }
+
+    return $class;
+}
+
+1;
+

Reply via email to