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; +
