diff options
Diffstat (limited to 'lib/rdoc/parser')
-rw-r--r-- | lib/rdoc/parser/c.rb | 64 | ||||
-rw-r--r-- | lib/rdoc/parser/perl.rb | 165 | ||||
-rw-r--r-- | lib/rdoc/parser/ruby.rb | 12 | ||||
-rw-r--r-- | lib/rdoc/parser/simple.rb | 2 |
4 files changed, 206 insertions, 37 deletions
diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb index 43bb767da9..a5b06c2b04 100644 --- a/lib/rdoc/parser/c.rb +++ b/lib/rdoc/parser/c.rb @@ -120,7 +120,7 @@ class RDoc::Parser::C < RDoc::Parser @stats.add_alias as end - end + end def do_classes @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do @@ -155,7 +155,7 @@ class RDoc::Parser::C < RDoc::Parser \( \s*(\w+), \s*"(\w+)", - \s*(\w+)\s* + \s*([\w\*\s\(\)\.\->]+)\s* # for SWIG \s*\)/mx) do |var_name, in_module, class_name, parent| handle_class_module(var_name, "class", class_name, parent, in_module) end @@ -251,7 +251,7 @@ class RDoc::Parser::C < RDoc::Parser handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count) handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count) end - end + end def find_attr_comment(attr_name) if @content =~ %r{((?>/\*.*?\*/\s+)) @@ -267,10 +267,10 @@ class RDoc::Parser::C < RDoc::Parser ## # Find the C code corresponding to a Ruby method - def find_body(meth_name, meth_obj, body, quiet = false) + def find_body(class_name, meth_name, meth_obj, body, quiet = false) case body - when %r"((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name} - \s*(\([^)]*\))\s*\{.*?^\}"xm + when %r"((?>/\*.*?\*/\s*)*)(?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name} + \s*(\([^)]*\))([^;]|$)"xm comment, params = $1, $2 body_text = $& @@ -279,9 +279,7 @@ class RDoc::Parser::C < RDoc::Parser # see if we can find the whole body re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}' - if Regexp.new(re, Regexp::MULTILINE).match(body) - body_text = $& - end + body_text = $& if /#{re}/m =~ body # The comment block may have been overridden with a 'Document-method' # block. This happens in the interpreter when multiple methods are @@ -289,7 +287,7 @@ class RDoc::Parser::C < RDoc::Parser # distinct (for example Kernel.hash and Kernel.object_id share the same # implementation - override_comment = find_override_comment(meth_obj.name) + override_comment = find_override_comment(class_name, meth_obj.name) comment = override_comment if override_comment find_modifiers(comment, meth_obj) if comment @@ -300,18 +298,18 @@ class RDoc::Parser::C < RDoc::Parser meth_obj.comment = mangle_comment(comment) when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m comment = $1 - find_body($2, meth_obj, body, true) + find_body(class_name, $2, meth_obj, body, true) find_modifiers(comment, meth_obj) meth_obj.comment = mangle_comment(comment) + meth_obj.comment when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m - unless find_body($1, meth_obj, body, true) + unless find_body(class_name, $1, meth_obj, body, true) warn "No definition for #{meth_name}" unless @options.quiet return false end else # No body, but might still have an override comment - comment = find_override_comment(meth_obj.name) + comment = find_override_comment(class_name, meth_obj.name) if comment find_modifiers(comment, meth_obj) @@ -367,10 +365,10 @@ class RDoc::Parser::C < RDoc::Parser def find_class_comment(class_name, class_meth) comment = nil if @content =~ %r{((?>/\*.*?\*/\s+)) - (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi + (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then + comment = $1 + elsif @content =~ %r{Document-(?:class|module):\s#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m comment = $1 - elsif @content =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m - comment = $2 else if @content =~ /rb_define_(class|module)/m then class_name = class_name.split("::").last @@ -424,9 +422,11 @@ class RDoc::Parser::C < RDoc::Parser end end - def find_override_comment(meth_name) + def find_override_comment(class_name, meth_name) name = Regexp.escape(meth_name) - if @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m + if @content =~ %r{Document-method:\s+#{class_name}(?:\.|::)#{name}\s*?\n((?>.*?\*/))}m then + $1 + elsif @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m then $1 end end @@ -480,6 +480,10 @@ class RDoc::Parser::C < RDoc::Parser end if class_mod == "class" then + full_name = enclosure.full_name.to_s + "::#{class_name}" + if @content =~ %r{Document-class:\s+#{full_name}\s*<\s+([:,\w]+)} then + parent_name = $1 + end cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name @stats.add_class cm else @@ -562,18 +566,16 @@ class RDoc::Parser::C < RDoc::Parser return unless class_name - class_obj = find_class(var_name, class_name) + class_obj = find_class var_name, class_name - if class_obj - if meth_name == "initialize" + if class_obj then + if meth_name == "initialize" then meth_name = "new" type = "singleton_method" end - meth_obj = RDoc::AnyMethod.new("", meth_name) - meth_obj.singleton = - %w{singleton_method module_function}.include?(type) - @stats.add_method meth_obj + meth_obj = RDoc::AnyMethod.new '', meth_name + meth_obj.singleton = %w[singleton_method module_function].include? type p_count = (Integer(param_count) rescue -1) @@ -585,14 +587,16 @@ class RDoc::Parser::C < RDoc::Parser meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")" end - if source_file + if source_file then file_name = File.join(@file_dir, source_file) body = (@@known_bodies[source_file] ||= File.read(file_name)) else body = @content end - if find_body(meth_body, meth_obj, body) and meth_obj.document_self - class_obj.add_method(meth_obj) + + if find_body(class_name, meth_body, meth_obj, body) and meth_obj.document_self then + class_obj.add_method meth_obj + @stats.add_method meth_obj end end end @@ -628,8 +632,8 @@ class RDoc::Parser::C < RDoc::Parser end def remove_private_comments(comment) - comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '') - comment.sub!(/\/?\*--.*/m, '') + comment.gsub!(/\/?\*--\n(.*?)\/?\*\+\+/m, '') + comment.sub!(/\/?\*--\n.*/m, '') end ## diff --git a/lib/rdoc/parser/perl.rb b/lib/rdoc/parser/perl.rb new file mode 100644 index 0000000000..43d1e9ff69 --- /dev/null +++ b/lib/rdoc/parser/perl.rb @@ -0,0 +1,165 @@ +require 'rdoc/parser' + +## +# +# This is an attamept to write a basic parser for Perl's +# POD (Plain old Documentation) format. Ruby code must +# co-exist with Perl, and some tasks are easier in Perl +# than Ruby because of existing libraries. +# +# One difficult is that Perl POD has no means of identifying +# the classes (packages) and methods (subs) with which it +# is associated, it is more like literate programming in so +# far as it just happens to be in the same place as the code, +# but need not be. +# +# We would like to support all the markup the POD provides +# so that it will convert happily to HTML. At the moment +# I don't think I can do that: time constraints. +# + +class RDoc::Parser::PerlPOD < RDoc::Parser + + parse_files_matching(/.p[lm]$/) + + ## + # Prepare to parse a perl file + + def initialize(top_level, file_name, content, options, stats) + super + + preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include + + preprocess.handle @content do |directive, param| + warn "Unrecognized directive '#{directive}' in #{@file_name}" + end + end + + ## + # Extract the Pod(-like) comments from the code. + # At its most basic there will ne no need to distinguish + # between the different types of header, etc. + # + # This uses a simple finite state machine, in a very + # procedural pattern. I could "replace case with polymorphism" + # but I think it would obscure the intent, scatter the + # code all over tha place. This machine is necessary + # because POD requires that directives be preceded by + # blank lines, so reading line by line is necessary, + # and preserving state about what is seen is necesary. + + def scan + + @top_level.comment ||= "" + state=:code_blank + line_number = 0 + line = nil + + # This started out as a really long nested case statement, + # which also led to repetitive code. I'd like to avoid that + # so I'm using a "table" instead. + + # Firstly we need some procs to do the transition and processing + # work. Because these are procs they are closures, and they can + # use variables in the local scope. + # + # First, the "nothing to see here" stuff. + code_noop = lambda do + if line =~ /^\s+$/ + state = :code_blank + end + end + + pod_noop = lambda do + if line =~ /^\s+$/ + state = :pod_blank + end + @top_level.comment += filter(line) + end + + begin_noop = lambda do + if line =~ /^\s+$/ + state = :begin_blank + end + @top_level.comment += filter(line) + end + + # Now for the blocks that process code and comments... + + transit_to_pod = lambda do + case line + when /^=(?:pod|head\d+)/ + state = :pod_no_blank + @top_level.comment += filter(line) + when /^=over/ + state = :over_no_blank + @top_level.comment += filter(line) + when /^=(?:begin|for)/ + state = :begin_no_blank + end + end + + process_pod = lambda do + case line + when /^\s*$/ + state = :pod_blank + @top_level.comment += filter(line) + when /^=cut/ + state = :code_no_blank + when /^=end/ + $stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}" + else + @top_level.comment += filter(line) + end + end + + + process_begin = lambda do + case line + when /^\s*$/ + state = :begin_blank + @top_level.comment += filter(line) + when /^=end/ + state = :code_no_blank + when /^=cut/ + $stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}" + else + @top_level.comment += filter(line) + end + + end + + + transitions = { :code_no_blank => code_noop, + :code_blank => transit_to_pod, + :pod_no_blank => pod_noop, + :pod_blank => process_pod, + :begin_no_blank => begin_noop, + :begin_blank => process_begin} + @content.each_line do |l| + line = l + line_number += 1 + transitions[state].call + end # each line + + @top_level + end + + # Filter the perl markup that does the same as the rdoc + # filtering. Only basic for now. Will probably need a + # proper parser to cope with C<<...>> etc + def filter(comment) + return '' if comment =~ /^=pod\s*$/ + comment.gsub!(/^=pod/, '==') + comment.gsub!(/^=head(\d+)/) do + "=" * $1.to_i + end + comment.gsub!(/=item/, ''); + comment.gsub!(/C<(.*?)>/, '<tt>\1</tt>'); + comment.gsub!(/I<(.*?)>/, '<i>\1</i>'); + comment.gsub!(/B<(.*?)>/, '<b>\1</b>'); + comment + end + +end + diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb index abbc85bde7..865cb79d39 100644 --- a/lib/rdoc/parser/ruby.rb +++ b/lib/rdoc/parser/ruby.rb @@ -134,7 +134,7 @@ module RDoc::RubyToken TokenDefinitions = [ [:TkCLASS, TkKW, "class", EXPR_CLASS], - [:TkMODULE, TkKW, "module", EXPR_BEG], + [:TkMODULE, TkKW, "module", EXPR_CLASS], [:TkDEF, TkKW, "def", EXPR_FNAME], [:TkUNDEF, TkKW, "undef", EXPR_FNAME], [:TkBEGIN, TkKW, "begin", EXPR_BEG], @@ -1945,9 +1945,9 @@ class RDoc::Parser::Ruby < RDoc::Parser case tk when TkSEMICOLON break - when TkLPAREN, TkfLPAREN + when TkLPAREN, TkfLPAREN, TkLBRACE, TkLBRACK, TkDO nest += 1 - when TkRPAREN + when TkRPAREN, TkRBRACE, TkRBRACK, TkEND nest -= 1 when TkCOMMENT if nest <= 0 && @scanner.lex_state == EXPR_END @@ -1955,7 +1955,7 @@ class RDoc::Parser::Ruby < RDoc::Parser break end when TkNL - if (@scanner.lex_state == EXPR_END and nest <= 0) || !@scanner.continue + if (nest <= 0) && ((@scanner.lex_state == EXPR_END) || (!@scanner.continue)) unget_tk(tk) break end @@ -2683,8 +2683,8 @@ class RDoc::Parser::Ruby < RDoc::Parser end def remove_private_comments(comment) - comment.gsub!(/^#--.*?^#\+\+/m, '') - comment.sub!(/^#--.*/m, '') + comment.gsub!(/^#--\n.*?^#\+\+/m, '') + comment.sub!(/^#--\n.*/m, '') end def remove_token_listener(obj) diff --git a/lib/rdoc/parser/simple.rb b/lib/rdoc/parser/simple.rb index 6e123a4655..cdfe686718 100644 --- a/lib/rdoc/parser/simple.rb +++ b/lib/rdoc/parser/simple.rb @@ -31,7 +31,7 @@ class RDoc::Parser::Simple < RDoc::Parser end def remove_private_comments(comment) - comment.gsub(/^--[^-].*?^\+\+/m, '').sub(/^--.*/m, '') + comment.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '') end end |